summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/devicetree/bindings/pwm/imx-pwm.txt17
-rw-r--r--Documentation/devicetree/bindings/pwm/mxs-pwm.txt2
-rw-r--r--Documentation/devicetree/bindings/pwm/nvidia,tegra20-pwm.txt2
-rw-r--r--Documentation/driver-model/devres.txt4
-rw-r--r--Documentation/filesystems/nfs/nfs.txt44
-rw-r--r--Documentation/kernel-parameters.txt5
-rw-r--r--Documentation/leds/leds-lp5523.txt21
-rw-r--r--Documentation/pwm.txt3
-rwxr-xr-xDocumentation/target/tcm_mod_builder.py16
-rw-r--r--arch/mips/include/asm/mach-jz4740/platform.h1
-rw-r--r--arch/mips/include/asm/mach-jz4740/timer.h113
-rw-r--r--arch/mips/jz4740/Kconfig3
-rw-r--r--arch/mips/jz4740/Makefile2
-rw-r--r--arch/mips/jz4740/board-qi_lb60.c1
-rw-r--r--arch/mips/jz4740/platform.c6
-rw-r--r--arch/mips/jz4740/pwm.c177
-rw-r--r--arch/mips/jz4740/time.c2
-rw-r--r--arch/mips/jz4740/timer.c4
-rw-r--r--arch/mips/jz4740/timer.h136
-rw-r--r--arch/s390/Kconfig.debug12
-rw-r--r--arch/s390/include/asm/Kbuild14
-rw-r--r--arch/s390/include/asm/chpid.h19
-rw-r--r--arch/s390/include/asm/cmb.h51
-rw-r--r--arch/s390/include/asm/css_chars.h3
-rw-r--r--arch/s390/include/asm/debug.h28
-rw-r--r--arch/s390/include/asm/kvm_para.h14
-rw-r--r--arch/s390/include/asm/mman.h6
-rw-r--r--arch/s390/include/asm/page.h14
-rw-r--r--arch/s390/include/asm/pgtable.h30
-rw-r--r--arch/s390/include/asm/ptrace.h462
-rw-r--r--arch/s390/include/asm/schid.h15
-rw-r--r--arch/s390/include/asm/setup.h21
-rw-r--r--arch/s390/include/asm/signal.h128
-rw-r--r--arch/s390/include/asm/termios.h42
-rw-r--r--arch/s390/include/asm/types.h15
-rw-r--r--arch/s390/include/asm/unistd.h367
-rw-r--r--arch/s390/include/uapi/asm/Kbuild45
-rw-r--r--arch/s390/include/uapi/asm/auxvec.h (renamed from arch/s390/include/asm/auxvec.h)0
-rw-r--r--arch/s390/include/uapi/asm/bitsperlong.h (renamed from arch/s390/include/asm/bitsperlong.h)0
-rw-r--r--arch/s390/include/uapi/asm/byteorder.h (renamed from arch/s390/include/asm/byteorder.h)0
-rw-r--r--arch/s390/include/uapi/asm/chpid.h22
-rw-r--r--arch/s390/include/uapi/asm/chsc.h (renamed from arch/s390/include/asm/chsc.h)10
-rw-r--r--arch/s390/include/uapi/asm/cmb.h53
-rw-r--r--arch/s390/include/uapi/asm/dasd.h (renamed from arch/s390/include/asm/dasd.h)0
-rw-r--r--arch/s390/include/uapi/asm/debug.h34
-rw-r--r--arch/s390/include/uapi/asm/errno.h (renamed from arch/s390/include/asm/errno.h)0
-rw-r--r--arch/s390/include/uapi/asm/fcntl.h (renamed from arch/s390/include/asm/fcntl.h)0
-rw-r--r--arch/s390/include/uapi/asm/ioctl.h (renamed from arch/s390/include/asm/ioctl.h)0
-rw-r--r--arch/s390/include/uapi/asm/ioctls.h (renamed from arch/s390/include/asm/ioctls.h)0
-rw-r--r--arch/s390/include/uapi/asm/ipcbuf.h (renamed from arch/s390/include/asm/ipcbuf.h)0
-rw-r--r--arch/s390/include/uapi/asm/kvm.h (renamed from arch/s390/include/asm/kvm.h)0
-rw-r--r--arch/s390/include/uapi/asm/kvm_para.h0
-rw-r--r--arch/s390/include/uapi/asm/kvm_virtio.h (renamed from arch/s390/include/asm/kvm_virtio.h)0
-rw-r--r--arch/s390/include/uapi/asm/mman.h6
-rw-r--r--arch/s390/include/uapi/asm/monwriter.h (renamed from arch/s390/include/asm/monwriter.h)0
-rw-r--r--arch/s390/include/uapi/asm/msgbuf.h (renamed from arch/s390/include/asm/msgbuf.h)0
-rw-r--r--arch/s390/include/uapi/asm/param.h (renamed from arch/s390/include/asm/param.h)0
-rw-r--r--arch/s390/include/uapi/asm/poll.h (renamed from arch/s390/include/asm/poll.h)0
-rw-r--r--arch/s390/include/uapi/asm/posix_types.h (renamed from arch/s390/include/asm/posix_types.h)0
-rw-r--r--arch/s390/include/uapi/asm/ptrace.h472
-rw-r--r--arch/s390/include/uapi/asm/qeth.h (renamed from arch/s390/include/asm/qeth.h)0
-rw-r--r--arch/s390/include/uapi/asm/resource.h (renamed from arch/s390/include/asm/resource.h)0
-rw-r--r--arch/s390/include/uapi/asm/schid.h16
-rw-r--r--arch/s390/include/uapi/asm/sembuf.h (renamed from arch/s390/include/asm/sembuf.h)0
-rw-r--r--arch/s390/include/uapi/asm/setup.h13
-rw-r--r--arch/s390/include/uapi/asm/shmbuf.h (renamed from arch/s390/include/asm/shmbuf.h)0
-rw-r--r--arch/s390/include/uapi/asm/sigcontext.h (renamed from arch/s390/include/asm/sigcontext.h)0
-rw-r--r--arch/s390/include/uapi/asm/siginfo.h (renamed from arch/s390/include/asm/siginfo.h)0
-rw-r--r--arch/s390/include/uapi/asm/signal.h135
-rw-r--r--arch/s390/include/uapi/asm/socket.h (renamed from arch/s390/include/asm/socket.h)0
-rw-r--r--arch/s390/include/uapi/asm/sockios.h (renamed from arch/s390/include/asm/sockios.h)0
-rw-r--r--arch/s390/include/uapi/asm/stat.h (renamed from arch/s390/include/asm/stat.h)0
-rw-r--r--arch/s390/include/uapi/asm/statfs.h (renamed from arch/s390/include/asm/statfs.h)0
-rw-r--r--arch/s390/include/uapi/asm/swab.h (renamed from arch/s390/include/asm/swab.h)0
-rw-r--r--arch/s390/include/uapi/asm/tape390.h (renamed from arch/s390/include/asm/tape390.h)0
-rw-r--r--arch/s390/include/uapi/asm/termbits.h (renamed from arch/s390/include/asm/termbits.h)0
-rw-r--r--arch/s390/include/uapi/asm/termios.h49
-rw-r--r--arch/s390/include/uapi/asm/types.h22
-rw-r--r--arch/s390/include/uapi/asm/ucontext.h (renamed from arch/s390/include/asm/ucontext.h)0
-rw-r--r--arch/s390/include/uapi/asm/unistd.h374
-rw-r--r--arch/s390/include/uapi/asm/vtoc.h (renamed from arch/s390/include/asm/vtoc.h)0
-rw-r--r--arch/s390/include/uapi/asm/zcrypt.h (renamed from arch/s390/include/asm/zcrypt.h)0
-rw-r--r--arch/s390/kernel/early.c17
-rw-r--r--arch/s390/kernel/entry64.S2
-rw-r--r--arch/s390/kernel/head.S101
-rw-r--r--arch/s390/kernel/head31.S3
-rw-r--r--arch/s390/kernel/head64.S3
-rw-r--r--arch/s390/kernel/module.c11
-rw-r--r--arch/s390/kernel/setup.c51
-rw-r--r--arch/s390/mm/Makefile1
-rw-r--r--arch/s390/mm/dump_pagetables.c226
-rw-r--r--arch/s390/mm/pageattr.c40
-rw-r--r--arch/s390/mm/vmem.c45
-rw-r--r--arch/unicore32/Kconfig12
-rw-r--r--arch/unicore32/include/mach/regs-ost.h18
-rw-r--r--arch/unicore32/kernel/Makefile1
-rw-r--r--arch/unicore32/kernel/pwm.c263
-rw-r--r--drivers/gpu/drm/nouveau/core/core/parent.c17
-rw-r--r--drivers/gpu/drm/nouveau/core/include/core/parent.h3
-rw-r--r--drivers/gpu/drm/nouveau/core/include/subdev/timer.h2
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/bios/base.c21
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/clock/nv50.c1
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/therm/nv50.c2
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/timer/nv04.c2
-rw-r--r--drivers/infiniband/ulp/srpt/ib_srpt.c12
-rw-r--r--drivers/leds/Kconfig26
-rw-r--r--drivers/leds/Makefile3
-rw-r--r--drivers/leds/led-class.c15
-rw-r--r--drivers/leds/led-core.c16
-rw-r--r--drivers/leds/led-triggers.c17
-rw-r--r--drivers/leds/leds-clevo-mail.c10
-rw-r--r--drivers/leds/leds-gpio.c19
-rw-r--r--drivers/leds/leds-lm3530.c16
-rw-r--r--drivers/leds/leds-lm3556.c512
-rw-r--r--drivers/leds/leds-lm355x.c572
-rw-r--r--drivers/leds/leds-lm3642.c462
-rw-r--r--drivers/leds/leds-lp5523.c75
-rw-r--r--drivers/leds/leds-pca9633.c19
-rw-r--r--drivers/leds/leds-wm8350.c29
-rw-r--r--drivers/leds/leds.h2
-rw-r--r--drivers/misc/Kconfig10
-rw-r--r--drivers/misc/Makefile1
-rw-r--r--drivers/pwm/Kconfig29
-rw-r--r--drivers/pwm/Makefile3
-rw-r--r--drivers/pwm/core.c82
-rw-r--r--drivers/pwm/pwm-ab8500.c (renamed from drivers/misc/ab8500-pwm.c)116
-rw-r--r--drivers/pwm/pwm-bfin.c3
-rw-r--r--drivers/pwm/pwm-imx.c278
-rw-r--r--drivers/pwm/pwm-jz4740.c221
-rw-r--r--drivers/pwm/pwm-puv3.c161
-rw-r--r--drivers/pwm/pwm-pxa.c3
-rw-r--r--drivers/pwm/pwm-samsung.c3
-rw-r--r--drivers/pwm/pwm-tiecap.c24
-rw-r--r--drivers/pwm/pwm-tiehrpwm.c75
-rw-r--r--drivers/s390/block/dcssblk.c52
-rw-r--r--drivers/s390/crypto/zcrypt_pcixcc.c1
-rw-r--r--drivers/scsi/qla2xxx/qla_target.c2
-rw-r--r--drivers/scsi/qla2xxx/tcm_qla2xxx.c15
-rw-r--r--drivers/target/iscsi/iscsi_target.c196
-rw-r--r--drivers/target/iscsi/iscsi_target.h5
-rw-r--r--drivers/target/iscsi/iscsi_target_configfs.c42
-rw-r--r--drivers/target/iscsi/iscsi_target_core.h15
-rw-r--r--drivers/target/iscsi/iscsi_target_erl0.c94
-rw-r--r--drivers/target/iscsi/iscsi_target_erl1.c4
-rw-r--r--drivers/target/iscsi/iscsi_target_erl1.h4
-rw-r--r--drivers/target/iscsi/iscsi_target_erl2.c9
-rw-r--r--drivers/target/iscsi/iscsi_target_erl2.h2
-rw-r--r--drivers/target/iscsi/iscsi_target_login.c20
-rw-r--r--drivers/target/iscsi/iscsi_target_nego.c31
-rw-r--r--drivers/target/iscsi/iscsi_target_parameters.c71
-rw-r--r--drivers/target/iscsi/iscsi_target_parameters.h7
-rw-r--r--drivers/target/iscsi/iscsi_target_seq_pdu_list.c61
-rw-r--r--drivers/target/iscsi/iscsi_target_tmr.c31
-rw-r--r--drivers/target/iscsi/iscsi_target_tpg.c12
-rw-r--r--drivers/target/iscsi/iscsi_target_tq.c6
-rw-r--r--drivers/target/iscsi/iscsi_target_tq.h1
-rw-r--r--drivers/target/iscsi/iscsi_target_util.c16
-rw-r--r--drivers/target/iscsi/iscsi_target_util.h8
-rw-r--r--drivers/target/loopback/tcm_loop.c74
-rw-r--r--drivers/target/sbp/sbp_target.c27
-rw-r--r--drivers/target/target_core_alua.c2
-rw-r--r--drivers/target/target_core_configfs.c18
-rw-r--r--drivers/target/target_core_device.c16
-rw-r--r--drivers/target/target_core_fabric_configfs.c1
-rw-r--r--drivers/target/target_core_fabric_lib.c8
-rw-r--r--drivers/target/target_core_file.c43
-rw-r--r--drivers/target/target_core_file.h1
-rw-r--r--drivers/target/target_core_iblock.c17
-rw-r--r--drivers/target/target_core_pr.c14
-rw-r--r--drivers/target/target_core_pscsi.c2
-rw-r--r--drivers/target/target_core_sbc.c23
-rw-r--r--drivers/target/target_core_spc.c48
-rw-r--r--drivers/target/target_core_stat.c1
-rw-r--r--drivers/target/target_core_tpg.c2
-rw-r--r--drivers/target/target_core_transport.c268
-rw-r--r--drivers/target/tcm_fc/tfc_cmd.c1
-rw-r--r--drivers/target/tcm_fc/tfc_conf.c12
-rw-r--r--drivers/target/tcm_fc/tfc_io.c4
-rw-r--r--drivers/target/tcm_fc/tfc_sess.c1
-rw-r--r--drivers/usb/gadget/tcm_usb_gadget.c15
-rw-r--r--drivers/vhost/tcm_vhost.c81
-rw-r--r--drivers/vhost/tcm_vhost.h8
-rw-r--r--drivers/video/backlight/pwm_bl.c7
-rw-r--r--fs/lockd/mon.c86
-rw-r--r--fs/lockd/netns.h4
-rw-r--r--fs/lockd/svc.c1
-rw-r--r--fs/nfs/Kconfig4
-rw-r--r--fs/nfs/blocklayout/blocklayout.c306
-rw-r--r--fs/nfs/blocklayout/blocklayout.h2
-rw-r--r--fs/nfs/blocklayout/blocklayoutdev.c25
-rw-r--r--fs/nfs/blocklayout/extents.c3
-rw-r--r--fs/nfs/callback.c321
-rw-r--r--fs/nfs/callback.h3
-rw-r--r--fs/nfs/callback_proc.c31
-rw-r--r--fs/nfs/client.c23
-rw-r--r--fs/nfs/dir.c16
-rw-r--r--fs/nfs/direct.c32
-rw-r--r--fs/nfs/file.c41
-rw-r--r--fs/nfs/getroot.c2
-rw-r--r--fs/nfs/idmap.c114
-rw-r--r--fs/nfs/inode.c10
-rw-r--r--fs/nfs/internal.h15
-rw-r--r--fs/nfs/netns.h4
-rw-r--r--fs/nfs/nfs4_fs.h19
-rw-r--r--fs/nfs/nfs4client.c256
-rw-r--r--fs/nfs/nfs4file.c29
-rw-r--r--fs/nfs/nfs4filelayout.c41
-rw-r--r--fs/nfs/nfs4filelayout.h16
-rw-r--r--fs/nfs/nfs4filelayoutdev.c17
-rw-r--r--fs/nfs/nfs4namespace.c16
-rw-r--r--fs/nfs/nfs4proc.c342
-rw-r--r--fs/nfs/nfs4state.c228
-rw-r--r--fs/nfs/nfs4sysctl.c1
-rw-r--r--fs/nfs/nfs4xdr.c31
-rw-r--r--fs/nfs/objlayout/objio_osd.c9
-rw-r--r--fs/nfs/pagelist.c12
-rw-r--r--fs/nfs/pnfs.c417
-rw-r--r--fs/nfs/pnfs.h57
-rw-r--r--fs/nfs/pnfs_dev.c27
-rw-r--r--fs/nfs/super.c31
-rw-r--r--fs/nfs/write.c11
-rw-r--r--include/linux/leds-lp5523.h1
-rw-r--r--include/linux/leds.h4
-rw-r--r--include/linux/nfs_fs.h11
-rw-r--r--include/linux/nfs_fs_sb.h3
-rw-r--r--include/linux/nfs_xdr.h5
-rw-r--r--include/linux/platform_data/leds-lm3556.h50
-rw-r--r--include/linux/platform_data/leds-lm355x.h66
-rw-r--r--include/linux/platform_data/leds-lm3642.h38
-rw-r--r--include/linux/platform_data/leds-pca9633.h35
-rw-r--r--include/linux/pwm.h108
-rw-r--r--include/linux/sunrpc/clnt.h2
-rw-r--r--include/linux/sunrpc/xprt.h3
-rw-r--r--include/target/target_core_backend.h3
-rw-r--r--include/target/target_core_fabric.h5
-rw-r--r--net/sunrpc/auth_gss/auth_gss.c58
-rw-r--r--net/sunrpc/clnt.c105
-rw-r--r--net/sunrpc/rpc_pipe.c8
-rw-r--r--net/sunrpc/sched.c2
-rw-r--r--net/sunrpc/xdr.c21
-rw-r--r--net/sunrpc/xprt.c8
-rw-r--r--net/sunrpc/xprtrdma/transport.c22
-rw-r--r--net/sunrpc/xprtsock.c40
243 files changed, 6954 insertions, 4353 deletions
diff --git a/Documentation/devicetree/bindings/pwm/imx-pwm.txt b/Documentation/devicetree/bindings/pwm/imx-pwm.txt
new file mode 100644
index 000000000000..8522bfbccfd7
--- /dev/null
+++ b/Documentation/devicetree/bindings/pwm/imx-pwm.txt
@@ -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>;
+};
diff --git a/Documentation/devicetree/bindings/pwm/mxs-pwm.txt b/Documentation/devicetree/bindings/pwm/mxs-pwm.txt
index 11963e4d6bc4..9e3f8f1d46a2 100644
--- a/Documentation/devicetree/bindings/pwm/mxs-pwm.txt
+++ b/Documentation/devicetree/bindings/pwm/mxs-pwm.txt
@@ -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:
diff --git a/Documentation/devicetree/bindings/pwm/nvidia,tegra20-pwm.txt b/Documentation/devicetree/bindings/pwm/nvidia,tegra20-pwm.txt
index bbbeedb4ec05..01438ecd6628 100644
--- a/Documentation/devicetree/bindings/pwm/nvidia,tegra20-pwm.txt
+++ b/Documentation/devicetree/bindings/pwm/nvidia,tegra20-pwm.txt
@@ -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:
diff --git a/Documentation/driver-model/devres.txt b/Documentation/driver-model/devres.txt
index 950856bd2e39..43cff70465ab 100644
--- a/Documentation/driver-model/devres.txt
+++ b/Documentation/driver-model/devres.txt
@@ -284,3 +284,7 @@ CLOCK
PINCTRL
devm_pinctrl_get()
devm_pinctrl_put()
+
+PWM
+ devm_pwm_get()
+ devm_pwm_put()
diff --git a/Documentation/filesystems/nfs/nfs.txt b/Documentation/filesystems/nfs/nfs.txt
index f50f26ce6cd0..f2571c8bef74 100644
--- a/Documentation/filesystems/nfs/nfs.txt
+++ b/Documentation/filesystems/nfs/nfs.txt
@@ -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
================
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index f777fa96243d..e2ed3360b708 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -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
diff --git a/Documentation/leds/leds-lp5523.txt b/Documentation/leds/leds-lp5523.txt
index fad2feb8b7ce..c2743f59f9ac 100644
--- a/Documentation/leds/leds-lp5523.txt
+++ b/Documentation/leds/leds-lp5523.txt
@@ -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,
diff --git a/Documentation/pwm.txt b/Documentation/pwm.txt
index 554290ebab94..7d2b4c9b544b 100644
--- a/Documentation/pwm.txt
+++ b/Documentation/pwm.txt
@@ -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:
diff --git a/Documentation/target/tcm_mod_builder.py b/Documentation/target/tcm_mod_builder.py
index a78879b01f09..3fe0d812dcec 100755
--- a/Documentation/target/tcm_mod_builder.py
+++ b/Documentation/target/tcm_mod_builder.py
@@ -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"
diff --git a/arch/mips/include/asm/mach-jz4740/platform.h b/arch/mips/include/asm/mach-jz4740/platform.h
index 564ab81d6cdc..163e81db880d 100644
--- a/arch/mips/include/asm/mach-jz4740/platform.h
+++ b/arch/mips/include/asm/mach-jz4740/platform.h
@@ -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);
diff --git a/arch/mips/include/asm/mach-jz4740/timer.h b/arch/mips/include/asm/mach-jz4740/timer.h
index 9baa03ce748c..a7759fb1f73d 100644
--- a/arch/mips/include/asm/mach-jz4740/timer.h
+++ b/arch/mips/include/asm/mach-jz4740/timer.h
@@ -16,7 +16,120 @@
#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
diff --git a/arch/mips/jz4740/Kconfig b/arch/mips/jz4740/Kconfig
index 3e7141f0746c..468903053883 100644
--- a/arch/mips/jz4740/Kconfig
+++ b/arch/mips/jz4740/Kconfig
@@ -7,6 +7,3 @@ config JZ4740_QI_LB60
bool "Qi Hardware Ben NanoNote"
endchoice
-
-config HAVE_PWM
- bool
diff --git a/arch/mips/jz4740/Makefile b/arch/mips/jz4740/Makefile
index e44abea9c209..63bad0e491d0 100644
--- a/arch/mips/jz4740/Makefile
+++ b/arch/mips/jz4740/Makefile
@@ -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
diff --git a/arch/mips/jz4740/board-qi_lb60.c b/arch/mips/jz4740/board-qi_lb60.c
index 9a3d9de4d04e..43d964d36288 100644
--- a/arch/mips/jz4740/board-qi_lb60.c
+++ b/arch/mips/jz4740/board-qi_lb60.c
@@ -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,
diff --git a/arch/mips/jz4740/platform.c b/arch/mips/jz4740/platform.c
index e342ed4cbd43..6d14dcdbd908 100644
--- a/arch/mips/jz4740/platform.c
+++ b/arch/mips/jz4740/platform.c
@@ -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
index a26a6faec9a6..000000000000
--- a/arch/mips/jz4740/pwm.c
+++ /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);
diff --git a/arch/mips/jz4740/time.c b/arch/mips/jz4740/time.c
index f83c2dd07a27..39bb4bbf43e7 100644
--- a/arch/mips/jz4740/time.c
+++ b/arch/mips/jz4740/time.c
@@ -20,10 +20,10 @@
#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
diff --git a/arch/mips/jz4740/timer.c b/arch/mips/jz4740/timer.c
index 654d5c3900b6..22f11d73a17d 100644
--- a/arch/mips/jz4740/timer.c
+++ b/arch/mips/jz4740/timer.c
@@ -17,11 +17,11 @@
#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
index fca3994f2e6d..000000000000
--- a/arch/mips/jz4740/timer.h
+++ /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
diff --git a/arch/s390/Kconfig.debug b/arch/s390/Kconfig.debug
index d76cef3fef37..fc32a2df4974 100644
--- a/arch/s390/Kconfig.debug
+++ b/arch/s390/Kconfig.debug
@@ -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
diff --git a/arch/s390/include/asm/Kbuild b/arch/s390/include/asm/Kbuild
index f18fc796beef..0633dc6d254d 100644
--- a/arch/s390/include/asm/Kbuild
+++ b/arch/s390/include/asm/Kbuild
@@ -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
diff --git a/arch/s390/include/asm/chpid.h b/arch/s390/include/asm/chpid.h
index e5bde9f9291f..38c405ef89ce 100644
--- a/arch/s390/include/asm/chpid.h
+++ b/arch/s390/include/asm/chpid.h
@@ -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 */
diff --git a/arch/s390/include/asm/cmb.h b/arch/s390/include/asm/cmb.h
index 39ae03294794..806eac12e3bd 100644
--- a/arch/s390/include/asm/cmb.h
+++ b/arch/s390/include/asm/cmb.h
@@ -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 */
diff --git a/arch/s390/include/asm/css_chars.h b/arch/s390/include/asm/css_chars.h
index a06ebc2623fb..7e1c917bbba2 100644
--- a/arch/s390/include/asm/css_chars.h
+++ b/arch/s390/include/asm/css_chars.h
@@ -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
diff --git a/arch/s390/include/asm/debug.h b/arch/s390/include/asm/debug.h
index f39677e6ccde..188c5052a20a 100644
--- a/arch/s390/include/asm/debug.h
+++ b/arch/s390/include/asm/debug.h
@@ -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 */
diff --git a/arch/s390/include/asm/kvm_para.h b/arch/s390/include/asm/kvm_para.h
index da44867de60f..e0f842308a68 100644
--- a/arch/s390/include/asm/kvm_para.h
+++ b/arch/s390/include/asm/kvm_para.h
@@ -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
@@ -29,6 +23,12 @@
*
* 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 */
diff --git a/arch/s390/include/asm/mman.h b/arch/s390/include/asm/mman.h
index abc1932ac4e1..0e47a576d666 100644
--- a/arch/s390/include/asm/mman.h
+++ b/arch/s390/include/asm/mman.h
@@ -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__ */
diff --git a/arch/s390/include/asm/page.h b/arch/s390/include/asm/page.h
index 27ab3c7c1e8b..6d5367060a56 100644
--- a/arch/s390/include/asm/page.h
+++ b/arch/s390/include/asm/page.h
@@ -30,12 +30,20 @@
#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;
diff --git a/arch/s390/include/asm/pgtable.h b/arch/s390/include/asm/pgtable.h
index 979fe3dc0788..dd647c919a66 100644
--- a/arch/s390/include/asm/pgtable.h
+++ b/arch/s390/include/asm/pgtable.h
@@ -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;
diff --git a/arch/s390/include/asm/ptrace.h b/arch/s390/include/asm/ptrace.h
index ce20a53afe91..3ee5da3bc10c 100644
--- a/arch/s390/include/asm/ptrace.h
+++ b/arch/s390/include/asm/ptrace.h
@@ -3,316 +3,17 @@
* 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 */
diff --git a/arch/s390/include/asm/schid.h b/arch/s390/include/asm/schid.h
index 3e4d401b4e45..40b47dfa9d66 100644
--- a/arch/s390/include/asm/schid.h
+++ b/arch/s390/include/asm/schid.h
@@ -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 */
diff --git a/arch/s390/include/asm/setup.h b/arch/s390/include/asm/setup.h
index 8cfd731a18d8..f69f76b3447a 100644
--- a/arch/s390/include/asm/setup.h
+++ b/arch/s390/include/asm/setup.h
@@ -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 */
diff --git a/arch/s390/include/asm/signal.h b/arch/s390/include/asm/signal.h
index 6d4d9d1faee9..bffdbdd5b3d7 100644
--- a/arch/s390/include/asm/signal.h
+++ b/arch/s390/include/asm/signal.h
@@ -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
diff --git a/arch/s390/include/asm/termios.h b/arch/s390/include/asm/termios.h
index cb9fe2786b81..db028d17f061 100644
--- a/arch/s390/include/asm/termios.h
+++ b/arch/s390/include/asm/termios.h
@@ -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 */
diff --git a/arch/s390/include/asm/types.h b/arch/s390/include/asm/types.h
index 6ba7c2c7217a..dccef3ca91fa 100644
--- a/arch/s390/include/asm/types.h
+++ b/arch/s390/include/asm/types.h
@@ -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 */
diff --git a/arch/s390/include/asm/unistd.h b/arch/s390/include/asm/unistd.h
index 8192e292753a..bbbae41fa9a5 100644
--- a/arch/s390/include/asm/unistd.h
+++ b/arch/s390/include/asm/unistd.h
@@ -3,375 +3,11 @@
*
* 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
@@ -428,5 +64,4 @@
*/
#define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall")
-#endif /* __KERNEL__ */
#endif /* _ASM_S390_UNISTD_H_ */
diff --git a/arch/s390/include/uapi/asm/Kbuild b/arch/s390/include/uapi/asm/Kbuild
index baebb3da1d44..7bf68fff7c5d 100644
--- a/arch/s390/include/uapi/asm/Kbuild
+++ b/arch/s390/include/uapi/asm/Kbuild
@@ -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/asm/auxvec.h b/arch/s390/include/uapi/asm/auxvec.h
index a1f153e89133..a1f153e89133 100644
--- a/arch/s390/include/asm/auxvec.h
+++ b/arch/s390/include/uapi/asm/auxvec.h
diff --git a/arch/s390/include/asm/bitsperlong.h b/arch/s390/include/uapi/asm/bitsperlong.h
index 6b235aea9c66..6b235aea9c66 100644
--- a/arch/s390/include/asm/bitsperlong.h
+++ b/arch/s390/include/uapi/asm/bitsperlong.h
diff --git a/arch/s390/include/asm/byteorder.h b/arch/s390/include/uapi/asm/byteorder.h
index a332e59e26fc..a332e59e26fc 100644
--- a/arch/s390/include/asm/byteorder.h
+++ b/arch/s390/include/uapi/asm/byteorder.h
diff --git a/arch/s390/include/uapi/asm/chpid.h b/arch/s390/include/uapi/asm/chpid.h
new file mode 100644
index 000000000000..581992dfae27
--- /dev/null
+++ b/arch/s390/include/uapi/asm/chpid.h
@@ -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 */
diff --git a/arch/s390/include/asm/chsc.h b/arch/s390/include/uapi/asm/chsc.h
index aea451fd182e..1c6a7f85a581 100644
--- a/arch/s390/include/asm/chsc.h
+++ b/arch/s390/include/uapi/asm/chsc.h
@@ -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
index 000000000000..0c086d00d89e
--- /dev/null
+++ b/arch/s390/include/uapi/asm/cmb.h
@@ -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/asm/dasd.h b/arch/s390/include/uapi/asm/dasd.h
index 38eca3ba40e2..38eca3ba40e2 100644
--- a/arch/s390/include/asm/dasd.h
+++ b/arch/s390/include/uapi/asm/dasd.h
diff --git a/arch/s390/include/uapi/asm/debug.h b/arch/s390/include/uapi/asm/debug.h
new file mode 100644
index 000000000000..c59fc79125f2
--- /dev/null
+++ b/arch/s390/include/uapi/asm/debug.h
@@ -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/asm/errno.h b/arch/s390/include/uapi/asm/errno.h
index 395e97d8005e..395e97d8005e 100644
--- a/arch/s390/include/asm/errno.h
+++ b/arch/s390/include/uapi/asm/errno.h
diff --git a/arch/s390/include/asm/fcntl.h b/arch/s390/include/uapi/asm/fcntl.h
index 46ab12db5739..46ab12db5739 100644
--- a/arch/s390/include/asm/fcntl.h
+++ b/arch/s390/include/uapi/asm/fcntl.h
diff --git a/arch/s390/include/asm/ioctl.h b/arch/s390/include/uapi/asm/ioctl.h
index b279fe06dfe5..b279fe06dfe5 100644
--- a/arch/s390/include/asm/ioctl.h
+++ b/arch/s390/include/uapi/asm/ioctl.h
diff --git a/arch/s390/include/asm/ioctls.h b/arch/s390/include/uapi/asm/ioctls.h
index 960a4c1ebdf1..960a4c1ebdf1 100644
--- a/arch/s390/include/asm/ioctls.h
+++ b/arch/s390/include/uapi/asm/ioctls.h
diff --git a/arch/s390/include/asm/ipcbuf.h b/arch/s390/include/uapi/asm/ipcbuf.h
index 37f293d12c8f..37f293d12c8f 100644
--- a/arch/s390/include/asm/ipcbuf.h
+++ b/arch/s390/include/uapi/asm/ipcbuf.h
diff --git a/arch/s390/include/asm/kvm.h b/arch/s390/include/uapi/asm/kvm.h
index d25da598ec62..d25da598ec62 100644
--- a/arch/s390/include/asm/kvm.h
+++ b/arch/s390/include/uapi/asm/kvm.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
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/arch/s390/include/uapi/asm/kvm_para.h
diff --git a/arch/s390/include/asm/kvm_virtio.h b/arch/s390/include/uapi/asm/kvm_virtio.h
index 44a438ca9e72..44a438ca9e72 100644
--- a/arch/s390/include/asm/kvm_virtio.h
+++ b/arch/s390/include/uapi/asm/kvm_virtio.h
diff --git a/arch/s390/include/uapi/asm/mman.h b/arch/s390/include/uapi/asm/mman.h
new file mode 100644
index 000000000000..de23da1f41b2
--- /dev/null
+++ b/arch/s390/include/uapi/asm/mman.h
@@ -0,0 +1,6 @@
+/*
+ * S390 version
+ *
+ * Derived from "include/asm-i386/mman.h"
+ */
+#include <asm-generic/mman.h>
diff --git a/arch/s390/include/asm/monwriter.h b/arch/s390/include/uapi/asm/monwriter.h
index f845c8e2f861..f845c8e2f861 100644
--- a/arch/s390/include/asm/monwriter.h
+++ b/arch/s390/include/uapi/asm/monwriter.h
diff --git a/arch/s390/include/asm/msgbuf.h b/arch/s390/include/uapi/asm/msgbuf.h
index 1bbdee927924..1bbdee927924 100644
--- a/arch/s390/include/asm/msgbuf.h
+++ b/arch/s390/include/uapi/asm/msgbuf.h
diff --git a/arch/s390/include/asm/param.h b/arch/s390/include/uapi/asm/param.h
index c616821bf2ac..c616821bf2ac 100644
--- a/arch/s390/include/asm/param.h
+++ b/arch/s390/include/uapi/asm/param.h
diff --git a/arch/s390/include/asm/poll.h b/arch/s390/include/uapi/asm/poll.h
index c98509d3149e..c98509d3149e 100644
--- a/arch/s390/include/asm/poll.h
+++ b/arch/s390/include/uapi/asm/poll.h
diff --git a/arch/s390/include/asm/posix_types.h b/arch/s390/include/uapi/asm/posix_types.h
index bf2a2ad2f800..bf2a2ad2f800 100644
--- a/arch/s390/include/asm/posix_types.h
+++ b/arch/s390/include/uapi/asm/posix_types.h
diff --git a/arch/s390/include/uapi/asm/ptrace.h b/arch/s390/include/uapi/asm/ptrace.h
new file mode 100644
index 000000000000..705588a16d70
--- /dev/null
+++ b/arch/s390/include/uapi/asm/ptrace.h
@@ -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/asm/qeth.h b/arch/s390/include/uapi/asm/qeth.h
index 3a896cf52589..3a896cf52589 100644
--- a/arch/s390/include/asm/qeth.h
+++ b/arch/s390/include/uapi/asm/qeth.h
diff --git a/arch/s390/include/asm/resource.h b/arch/s390/include/uapi/asm/resource.h
index ec23d1c73c92..ec23d1c73c92 100644
--- a/arch/s390/include/asm/resource.h
+++ b/arch/s390/include/uapi/asm/resource.h
diff --git a/arch/s390/include/uapi/asm/schid.h b/arch/s390/include/uapi/asm/schid.h
new file mode 100644
index 000000000000..32f3ab2a8200
--- /dev/null
+++ b/arch/s390/include/uapi/asm/schid.h
@@ -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/asm/sembuf.h b/arch/s390/include/uapi/asm/sembuf.h
index 32626b0cac4b..32626b0cac4b 100644
--- a/arch/s390/include/asm/sembuf.h
+++ b/arch/s390/include/uapi/asm/sembuf.h
diff --git a/arch/s390/include/uapi/asm/setup.h b/arch/s390/include/uapi/asm/setup.h
new file mode 100644
index 000000000000..5a637e3e385e
--- /dev/null
+++ b/arch/s390/include/uapi/asm/setup.h
@@ -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/asm/shmbuf.h b/arch/s390/include/uapi/asm/shmbuf.h
index eed2e280ce37..eed2e280ce37 100644
--- a/arch/s390/include/asm/shmbuf.h
+++ b/arch/s390/include/uapi/asm/shmbuf.h
diff --git a/arch/s390/include/asm/sigcontext.h b/arch/s390/include/uapi/asm/sigcontext.h
index 584787f6ce44..584787f6ce44 100644
--- a/arch/s390/include/asm/sigcontext.h
+++ b/arch/s390/include/uapi/asm/sigcontext.h
diff --git a/arch/s390/include/asm/siginfo.h b/arch/s390/include/uapi/asm/siginfo.h
index 91fd3e4b70ce..91fd3e4b70ce 100644
--- a/arch/s390/include/asm/siginfo.h
+++ b/arch/s390/include/uapi/asm/siginfo.h
diff --git a/arch/s390/include/uapi/asm/signal.h b/arch/s390/include/uapi/asm/signal.h
new file mode 100644
index 000000000000..8c6a49e392ee
--- /dev/null
+++ b/arch/s390/include/uapi/asm/signal.h
@@ -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/asm/socket.h b/arch/s390/include/uapi/asm/socket.h
index 69718cd6d635..69718cd6d635 100644
--- a/arch/s390/include/asm/socket.h
+++ b/arch/s390/include/uapi/asm/socket.h
diff --git a/arch/s390/include/asm/sockios.h b/arch/s390/include/uapi/asm/sockios.h
index 6f60eee73242..6f60eee73242 100644
--- a/arch/s390/include/asm/sockios.h
+++ b/arch/s390/include/uapi/asm/sockios.h
diff --git a/arch/s390/include/asm/stat.h b/arch/s390/include/uapi/asm/stat.h
index b4ca97d91466..b4ca97d91466 100644
--- a/arch/s390/include/asm/stat.h
+++ b/arch/s390/include/uapi/asm/stat.h
diff --git a/arch/s390/include/asm/statfs.h b/arch/s390/include/uapi/asm/statfs.h
index 5acca0a34c20..5acca0a34c20 100644
--- a/arch/s390/include/asm/statfs.h
+++ b/arch/s390/include/uapi/asm/statfs.h
diff --git a/arch/s390/include/asm/swab.h b/arch/s390/include/uapi/asm/swab.h
index da3bfe5cc161..da3bfe5cc161 100644
--- a/arch/s390/include/asm/swab.h
+++ b/arch/s390/include/uapi/asm/swab.h
diff --git a/arch/s390/include/asm/tape390.h b/arch/s390/include/uapi/asm/tape390.h
index b2bc4bab7929..b2bc4bab7929 100644
--- a/arch/s390/include/asm/tape390.h
+++ b/arch/s390/include/uapi/asm/tape390.h
diff --git a/arch/s390/include/asm/termbits.h b/arch/s390/include/uapi/asm/termbits.h
index 71bf6ac6a2b9..71bf6ac6a2b9 100644
--- a/arch/s390/include/asm/termbits.h
+++ b/arch/s390/include/uapi/asm/termbits.h
diff --git a/arch/s390/include/uapi/asm/termios.h b/arch/s390/include/uapi/asm/termios.h
new file mode 100644
index 000000000000..554f973db1e6
--- /dev/null
+++ b/arch/s390/include/uapi/asm/termios.h
@@ -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
index 000000000000..038f2b9178a4
--- /dev/null
+++ b/arch/s390/include/uapi/asm/types.h
@@ -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/asm/ucontext.h b/arch/s390/include/uapi/asm/ucontext.h
index 200e06325c6a..200e06325c6a 100644
--- a/arch/s390/include/asm/ucontext.h
+++ b/arch/s390/include/uapi/asm/ucontext.h
diff --git a/arch/s390/include/uapi/asm/unistd.h b/arch/s390/include/uapi/asm/unistd.h
new file mode 100644
index 000000000000..63e6078699f1
--- /dev/null
+++ b/arch/s390/include/uapi/asm/unistd.h
@@ -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_ */
diff --git a/arch/s390/include/asm/vtoc.h b/arch/s390/include/uapi/asm/vtoc.h
index 221419de275e..221419de275e 100644
--- a/arch/s390/include/asm/vtoc.h
+++ b/arch/s390/include/uapi/asm/vtoc.h
diff --git a/arch/s390/include/asm/zcrypt.h b/arch/s390/include/uapi/asm/zcrypt.h
index e83fc116f5bf..e83fc116f5bf 100644
--- a/arch/s390/include/asm/zcrypt.h
+++ b/arch/s390/include/uapi/asm/zcrypt.h
diff --git a/arch/s390/kernel/early.c b/arch/s390/kernel/early.c
index 00d114445068..1f0eee9e7daa 100644
--- a/arch/s390/kernel/early.c
+++ b/arch/s390/kernel/early.c
@@ -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);
diff --git a/arch/s390/kernel/entry64.S b/arch/s390/kernel/entry64.S
index f9761f806c9e..07d8de353984 100644
--- a/arch/s390/kernel/entry64.S
+++ b/arch/s390/kernel/entry64.S
@@ -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
diff --git a/arch/s390/kernel/head.S b/arch/s390/kernel/head.S
index 805b6686b641..984726cbce16 100644
--- a/arch/s390/kernel/head.S
+++ b/arch/s390/kernel/head.S
@@ -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 %r4 # 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
diff --git a/arch/s390/kernel/head31.S b/arch/s390/kernel/head31.S
index a1372ae24ae1..9a99856df1c9 100644
--- a/arch/s390/kernel/head31.S
+++ b/arch/s390/kernel/head31.S
@@ -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
#
diff --git a/arch/s390/kernel/head64.S b/arch/s390/kernel/head64.S
index c108af28bbe8..b9e25ae2579c 100644
--- a/arch/s390/kernel/head64.S
+++ b/arch/s390/kernel/head64.S
@@ -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
#
diff --git a/arch/s390/kernel/module.c b/arch/s390/kernel/module.c
index 46412b1d7e1e..4610deafd953 100644
--- a/arch/s390/kernel/module.c
+++ b/arch/s390/kernel/module.c
@@ -44,6 +44,17 @@
#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)
{
diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c
index afa9fdba200e..b1f2be9aaaad 100644
--- a/arch/s390/kernel/setup.c
+++ b/arch/s390/kernel/setup.c
@@ -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);
diff --git a/arch/s390/mm/Makefile b/arch/s390/mm/Makefile
index 0f5536b0c1a1..1bea6d1f55ab 100644
--- a/arch/s390/mm/Makefile
+++ b/arch/s390/mm/Makefile
@@ -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
index 000000000000..cbc6668acb85
--- /dev/null
+++ b/arch/s390/mm/dump_pagetables.c
@@ -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);
diff --git a/arch/s390/mm/pageattr.c b/arch/s390/mm/pageattr.c
index b36537a5f43e..00be01c4b4f3 100644
--- a/arch/s390/mm/pageattr.c
+++ b/arch/s390/mm/pageattr.c
@@ -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)
{
diff --git a/arch/s390/mm/vmem.c b/arch/s390/mm/vmem.c
index c22abf900c9e..387c7c60b5b8 100644
--- a/arch/s390/mm/vmem.c
+++ b/arch/s390/mm/vmem.c
@@ -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)
diff --git a/arch/unicore32/Kconfig b/arch/unicore32/Kconfig
index 1e638e75a6b7..35ee2bf66354 100644
--- a/arch/unicore32/Kconfig
+++ b/arch/unicore32/Kconfig
@@ -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"
diff --git a/arch/unicore32/include/mach/regs-ost.h b/arch/unicore32/include/mach/regs-ost.h
index 7b91fe698eed..4a85fb463848 100644
--- a/arch/unicore32/include/mach/regs-ost.h
+++ b/arch/unicore32/include/mach/regs-ost.h
@@ -33,18 +33,16 @@
* 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
diff --git a/arch/unicore32/kernel/Makefile b/arch/unicore32/kernel/Makefile
index 324010156958..fa497e0efe5a 100644
--- a/arch/unicore32/kernel/Makefile
+++ b/arch/unicore32/kernel/Makefile
@@ -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
index 4615d51e3ba6..000000000000
--- a/arch/unicore32/kernel/pwm.c
+++ /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");
diff --git a/drivers/gpu/drm/nouveau/core/core/parent.c b/drivers/gpu/drm/nouveau/core/core/parent.c
index a1ea034611d5..db7c54943102 100644
--- a/drivers/gpu/drm/nouveau/core/core/parent.c
+++ b/drivers/gpu/drm/nouveau/core/core/parent.c
@@ -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)
{
diff --git a/drivers/gpu/drm/nouveau/core/include/core/parent.h b/drivers/gpu/drm/nouveau/core/include/core/parent.h
index d3aa251a5eb6..3c2e940eb0f8 100644
--- a/drivers/gpu/drm/nouveau/core/include/core/parent.h
+++ b/drivers/gpu/drm/nouveau/core/include/core/parent.h
@@ -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
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/timer.h b/drivers/gpu/drm/nouveau/core/include/subdev/timer.h
index 49bff901544c..c24ec8ab3db4 100644
--- a/drivers/gpu/drm/nouveau/core/include/subdev/timer.h
+++ b/drivers/gpu/drm/nouveau/core/include/subdev/timer.h
@@ -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 *
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/base.c b/drivers/gpu/drm/nouveau/core/subdev/bios/base.c
index 2fbb6df697cd..dcb5c2befc92 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/bios/base.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/bios/base.c
@@ -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;
}
}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/clock/nv50.c b/drivers/gpu/drm/nouveau/core/subdev/clock/nv50.c
index fd181fbceddb..f4147f67eda6 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/clock/nv50.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/clock/nv50.c
@@ -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;
}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/therm/nv50.c b/drivers/gpu/drm/nouveau/core/subdev/therm/nv50.c
index f87a7a3eb4e7..9360ddd469e7 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/therm/nv50.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/therm/nv50.c
@@ -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;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/timer/nv04.c b/drivers/gpu/drm/nouveau/core/subdev/timer/nv04.c
index 49976be4d73b..c26ca9bef671 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/timer/nv04.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/timer/nv04.c
@@ -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;
diff --git a/drivers/infiniband/ulp/srpt/ib_srpt.c b/drivers/infiniband/ulp/srpt/ib_srpt.c
index 9e1449f8c6a2..cf23c46185b2 100644
--- a/drivers/infiniband/ulp/srpt/ib_srpt.c
+++ b/drivers/infiniband/ulp/srpt/ib_srpt.c
@@ -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
diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
index 16578d3b52bb..f508defc0d96 100644
--- a/drivers/leds/Kconfig
+++ b/drivers/leds/Kconfig
@@ -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"
diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile
index a9b627c4f8ba..3fb9641b6194 100644
--- a/drivers/leds/Makefile
+++ b/drivers/leds/Makefile
@@ -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
diff --git a/drivers/leds/led-class.c b/drivers/leds/led-class.c
index c599095bc005..48cce18e9d6d 100644
--- a/drivers/leds/led-class.c
+++ b/drivers/leds/led-class.c
@@ -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);
diff --git a/drivers/leds/led-core.c b/drivers/leds/led-core.c
index 2ab05af3de31..ce8921a753a3 100644
--- a/drivers/leds/led-core.c
+++ b/drivers/leds/led-core.c
@@ -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);
}
diff --git a/drivers/leds/led-triggers.c b/drivers/leds/led-triggers.c
index 363975b3c925..262eb4193710 100644
--- a/drivers/leds/led-triggers.c
+++ b/drivers/leds/led-triggers.c
@@ -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);
}
diff --git a/drivers/leds/leds-clevo-mail.c b/drivers/leds/leds-clevo-mail.c
index 1ed1677c916f..e024b0b1c3b1 100644
--- a/drivers/leds/leds-clevo-mail.c
+++ b/drivers/leds/leds-clevo-mail.c
@@ -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. "
diff --git a/drivers/leds/leds-gpio.c b/drivers/leds/leds-gpio.c
index c032b2180340..087d1e66f4f7 100644
--- a/drivers/leds/leds-gpio.c
+++ b/drivers/leds/leds-gpio.c
@@ -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),
},
};
diff --git a/drivers/leds/leds-lm3530.c b/drivers/leds/leds-lm3530.c
index 23637bdb275d..b26306f6724d 100644
--- a/drivers/leds/leds-lm3530.c
+++ b/drivers/leds/leds-lm3530.c
@@ -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
index 3062abd9a532..000000000000
--- a/drivers/leds/leds-lm3556.c
+++ /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
index 000000000000..065ec015d67a
--- /dev/null
+++ b/drivers/leds/leds-lm355x.c
@@ -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
index 000000000000..3285006e9888
--- /dev/null
+++ b/drivers/leds/leds-lm3642.c
@@ -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");
diff --git a/drivers/leds/leds-lp5523.c b/drivers/leds/leds-lp5523.c
index fbc12acada95..97994ffdc014 100644
--- a/drivers/leds/leds-lp5523.c
+++ b/drivers/leds/leds-lp5523.c
@@ -104,6 +104,11 @@
#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,
diff --git a/drivers/leds/leds-pca9633.c b/drivers/leds/leds-pca9633.c
index edcd706c5631..2f2f9c43535d 100644
--- a/drivers/leds/leds-pca9633.c
+++ b/drivers/leds/leds-pca9633.c
@@ -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);
diff --git a/drivers/leds/leds-wm8350.c b/drivers/leds/leds-wm8350.c
index 4c62113f7a77..88f23f845595 100644
--- a/drivers/leds/leds-wm8350.c
+++ b/drivers/leds/leds-wm8350.c
@@ -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;
}
diff --git a/drivers/leds/leds.h b/drivers/leds/leds.h
index d02acd496126..4c50365344a9 100644
--- a/drivers/leds/leds.h
+++ b/drivers/leds/leds.h
@@ -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;
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 99c73352c430..b151b7c1bd59 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -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)
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index b88df7a350b8..2129377c0de6 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -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
diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig
index d7c6b83097c1..ed81720e7b2b 100644
--- a/drivers/pwm/Kconfig
+++ b/drivers/pwm/Kconfig
@@ -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
diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile
index 78f123dca30d..acfe4821c58b 100644
--- a/drivers/pwm/Makefile
+++ b/drivers/pwm/Makefile
@@ -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
diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c
index c6e05078d3ad..f5acdaa52707 100644
--- a/drivers/pwm/core.c
+++ b/drivers/pwm/core.c
@@ -371,7 +371,7 @@ 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);
@@ -379,6 +379,28 @@ int pwm_config(struct pwm_device *pwm, int duty_ns, int 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)
{
diff --git a/drivers/misc/ab8500-pwm.c b/drivers/pwm/pwm-ab8500.c
index d7a9aa14e5d5..cfb72ca873d1 100644
--- a/drivers/misc/ab8500-pwm.c
+++ b/drivers/pwm/pwm-ab8500.c
@@ -24,16 +24,12 @@
#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");
diff --git a/drivers/pwm/pwm-bfin.c b/drivers/pwm/pwm-bfin.c
index d53c4e7941ef..5da8e185e838 100644
--- a/drivers/pwm/pwm-bfin.c
+++ b/drivers/pwm/pwm-bfin.c
@@ -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;
diff --git a/drivers/pwm/pwm-imx.c b/drivers/pwm/pwm-imx.c
index 2a0b35333972..8a5d3ae2946a 100644
--- a/drivers/pwm/pwm-imx.c
+++ b/drivers/pwm/pwm-imx.c
@@ -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: */
@@ -40,110 +40,165 @@
#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
index 000000000000..10250fcefb98
--- /dev/null
+++ b/drivers/pwm/pwm-jz4740.c
@@ -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
index 000000000000..2a93f37c46ad
--- /dev/null
+++ b/drivers/pwm/pwm-puv3.c
@@ -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");
diff --git a/drivers/pwm/pwm-pxa.c b/drivers/pwm/pwm-pxa.c
index bd5867a1c700..260c3a88564d 100644
--- a/drivers/pwm/pwm-pxa.c
+++ b/drivers/pwm/pwm-pxa.c
@@ -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);
diff --git a/drivers/pwm/pwm-samsung.c b/drivers/pwm/pwm-samsung.c
index e5187c0ade9f..023a3bee76e7 100644
--- a/drivers/pwm/pwm-samsung.c
+++ b/drivers/pwm/pwm-samsung.c
@@ -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;
diff --git a/drivers/pwm/pwm-tiecap.c b/drivers/pwm/pwm-tiecap.c
index 4b6688909fee..d6d4cf05565e 100644
--- a/drivers/pwm/pwm-tiecap.c
+++ b/drivers/pwm/pwm-tiecap.c
@@ -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,
diff --git a/drivers/pwm/pwm-tiehrpwm.c b/drivers/pwm/pwm-tiehrpwm.c
index b1996bcd5b78..d3c1dff0a0dc 100644
--- a/drivers/pwm/pwm-tiehrpwm.c
+++ b/drivers/pwm/pwm-tiehrpwm.c
@@ -81,6 +81,15 @@
#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,
diff --git a/drivers/s390/block/dcssblk.c b/drivers/s390/block/dcssblk.c
index a5a55da2a1ac..b6ad0de07930 100644
--- a/drivers/s390/block/dcssblk.c
+++ b/drivers/s390/block/dcssblk.c
@@ -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);
}
diff --git a/drivers/s390/crypto/zcrypt_pcixcc.c b/drivers/s390/crypto/zcrypt_pcixcc.c
index c7275e303a0d..899ffa19f5ec 100644
--- a/drivers/s390/crypto/zcrypt_pcixcc.c
+++ b/drivers/s390/crypto/zcrypt_pcixcc.c
@@ -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 */
diff --git a/drivers/scsi/qla2xxx/qla_target.c b/drivers/scsi/qla2xxx/qla_target.c
index bddc97c5c8e9..0e09d8f433d1 100644
--- a/drivers/scsi/qla2xxx/qla_target.c
+++ b/drivers/scsi/qla2xxx/qla_target.c
@@ -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);
}
diff --git a/drivers/scsi/qla2xxx/tcm_qla2xxx.c b/drivers/scsi/qla2xxx/tcm_qla2xxx.c
index 4752f65a9272..2358c16c4c8e 100644
--- a/drivers/scsi/qla2xxx/tcm_qla2xxx.c
+++ b/drivers/scsi/qla2xxx/tcm_qla2xxx.c
@@ -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
diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c
index 97c0f78c3c9c..d6ce2182e672 100644
--- a/drivers/target/iscsi/iscsi_target.c
+++ b/drivers/target/iscsi/iscsi_target.c
@@ -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);
diff --git a/drivers/target/iscsi/iscsi_target.h b/drivers/target/iscsi/iscsi_target.h
index 12abb4c9e34e..f1e4f3155bac 100644
--- a/drivers/target/iscsi/iscsi_target.h
+++ b/drivers/target/iscsi/iscsi_target.h
@@ -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 ***/
diff --git a/drivers/target/iscsi/iscsi_target_configfs.c b/drivers/target/iscsi/iscsi_target_configfs.c
index a7b25e783b58..ff6fd4fb624d 100644
--- a/drivers/target/iscsi/iscsi_target_configfs.c
+++ b/drivers/target/iscsi/iscsi_target_configfs.c
@@ -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
*/
diff --git a/drivers/target/iscsi/iscsi_target_core.h b/drivers/target/iscsi/iscsi_target_core.h
index 8a908b28d8b2..2ba9f9b9435c 100644
--- a/drivers/target/iscsi/iscsi_target_core.h
+++ b/drivers/target/iscsi/iscsi_target_core.h
@@ -25,10 +25,10 @@
#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;
diff --git a/drivers/target/iscsi/iscsi_target_erl0.c b/drivers/target/iscsi/iscsi_target_erl0.c
index 1a02016ecdab..8aacf611b86d 100644
--- a/drivers/target/iscsi/iscsi_target_erl0.c
+++ b/drivers/target/iscsi/iscsi_target_erl0.c
@@ -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)) {
diff --git a/drivers/target/iscsi/iscsi_target_erl1.c b/drivers/target/iscsi/iscsi_target_erl1.c
index 3df8a2cef86f..21f29d91a8cb 100644
--- a/drivers/target/iscsi/iscsi_target_erl1.c
+++ b/drivers/target/iscsi/iscsi_target_erl1.c
@@ -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)
diff --git a/drivers/target/iscsi/iscsi_target_erl1.h b/drivers/target/iscsi/iscsi_target_erl1.h
index 85e67e29de6b..2a3ebf118a34 100644
--- a/drivers/target/iscsi/iscsi_target_erl1.h
+++ b/drivers/target/iscsi/iscsi_target_erl1.h
@@ -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 *);
diff --git a/drivers/target/iscsi/iscsi_target_erl2.c b/drivers/target/iscsi/iscsi_target_erl2.c
index 65aac14fd831..17d8c20094fd 100644
--- a/drivers/target/iscsi/iscsi_target_erl2.c
+++ b/drivers/target/iscsi/iscsi_target_erl2.c
@@ -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);
diff --git a/drivers/target/iscsi/iscsi_target_erl2.h b/drivers/target/iscsi/iscsi_target_erl2.h
index 22f8d24780a6..63f2501f3fe0 100644
--- a/drivers/target/iscsi/iscsi_target_erl2.h
+++ b/drivers/target/iscsi/iscsi_target_erl2.h
@@ -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);
diff --git a/drivers/target/iscsi/iscsi_target_login.c b/drivers/target/iscsi/iscsi_target_login.c
index 6aba4395e8d8..cdc8a10939c3 100644
--- a/drivers/target/iscsi/iscsi_target_login.c
+++ b/drivers/target/iscsi/iscsi_target_login.c
@@ -39,10 +39,6 @@
#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.
diff --git a/drivers/target/iscsi/iscsi_target_nego.c b/drivers/target/iscsi/iscsi_target_nego.c
index 2dba448cac19..e9053a04f24c 100644
--- a/drivers/target/iscsi/iscsi_target_nego.c
+++ b/drivers/target/iscsi/iscsi_target_nego.c
@@ -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;
}
diff --git a/drivers/target/iscsi/iscsi_target_parameters.c b/drivers/target/iscsi/iscsi_target_parameters.c
index 240f7aa76ed1..90b740048f26 100644
--- a/drivers/target/iscsi/iscsi_target_parameters.c
+++ b/drivers/target/iscsi/iscsi_target_parameters.c
@@ -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",
diff --git a/drivers/target/iscsi/iscsi_target_parameters.h b/drivers/target/iscsi/iscsi_target_parameters.h
index 6a37fd6f1285..1e1b7504a76b 100644
--- a/drivers/target/iscsi/iscsi_target_parameters.h
+++ b/drivers/target/iscsi/iscsi_target_parameters.h
@@ -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"
diff --git a/drivers/target/iscsi/iscsi_target_seq_pdu_list.c b/drivers/target/iscsi/iscsi_target_seq_pdu_list.c
index 85a306e067ba..edb592a368ef 100644
--- a/drivers/target/iscsi/iscsi_target_seq_pdu_list.c
+++ b/drivers/target/iscsi/iscsi_target_seq_pdu_list.c
@@ -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) {
diff --git a/drivers/target/iscsi/iscsi_target_tmr.c b/drivers/target/iscsi/iscsi_target_tmr.c
index f62fe123d902..4a99820d063b 100644
--- a/drivers/target/iscsi/iscsi_target_tmr.c
+++ b/drivers/target/iscsi/iscsi_target_tmr.c
@@ -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)
{
diff --git a/drivers/target/iscsi/iscsi_target_tpg.c b/drivers/target/iscsi/iscsi_target_tpg.c
index a38a3f8ab0d9..de9ea32b6104 100644
--- a/drivers/target/iscsi/iscsi_target_tpg.c
+++ b/drivers/target/iscsi/iscsi_target_tpg.c
@@ -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) ?
diff --git a/drivers/target/iscsi/iscsi_target_tq.c b/drivers/target/iscsi/iscsi_target_tq.c
index 977e1cf90e83..9d881a000e42 100644
--- a/drivers/target/iscsi/iscsi_target_tq.c
+++ b/drivers/target/iscsi/iscsi_target_tq.c
@@ -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;
diff --git a/drivers/target/iscsi/iscsi_target_tq.h b/drivers/target/iscsi/iscsi_target_tq.h
index 26e6a95ec203..547d11831282 100644
--- a/drivers/target/iscsi/iscsi_target_tq.h
+++ b/drivers/target/iscsi/iscsi_target_tq.h
@@ -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 *);
diff --git a/drivers/target/iscsi/iscsi_target_util.c b/drivers/target/iscsi/iscsi_target_util.c
index b42cdeb153df..afd98ccd40ae 100644
--- a/drivers/target/iscsi/iscsi_target_util.c
+++ b/drivers/target/iscsi/iscsi_target_util.c
@@ -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;
diff --git a/drivers/target/iscsi/iscsi_target_util.h b/drivers/target/iscsi/iscsi_target_util.h
index e1c729b8a1c5..44054bd35437 100644
--- a/drivers/target/iscsi/iscsi_target_util.h
+++ b/drivers/target/iscsi/iscsi_target_util.h
@@ -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);
diff --git a/drivers/target/loopback/tcm_loop.c b/drivers/target/loopback/tcm_loop.c
index 5491c632a15e..2d444b1ccd33 100644
--- a/drivers/target/loopback/tcm_loop.c
+++ b/drivers/target/loopback/tcm_loop.c
@@ -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
diff --git a/drivers/target/sbp/sbp_target.c b/drivers/target/sbp/sbp_target.c
index 39ddba584b30..0d6d7c1f025e 100644
--- a/drivers/target/sbp/sbp_target.c
+++ b/drivers/target/sbp/sbp_target.c
@@ -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;
diff --git a/drivers/target/target_core_alua.c b/drivers/target/target_core_alua.c
index 41641ba54828..9a5f9a7aecd2 100644
--- a/drivers/target/target_core_alua.c
+++ b/drivers/target/target_core_alua.c
@@ -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);
diff --git a/drivers/target/target_core_configfs.c b/drivers/target/target_core_configfs.c
index 801efa892046..015f5be27bf6 100644
--- a/drivers/target/target_core_configfs.c
+++ b/drivers/target/target_core_configfs.c
@@ -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;
}
diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c
index 9fc9a6006ca0..8d774da16320 100644
--- a/drivers/target/target_core_device.c
+++ b/drivers/target/target_core_device.c
@@ -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;
diff --git a/drivers/target/target_core_fabric_configfs.c b/drivers/target/target_core_fabric_configfs.c
index ea479e54f5fd..bca737bb813d 100644
--- a/drivers/target/target_core_fabric_configfs.c
+++ b/drivers/target/target_core_fabric_configfs.c
@@ -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>
diff --git a/drivers/target/target_core_fabric_lib.c b/drivers/target/target_core_fabric_lib.c
index 283a36e464e6..e460d6233a0a 100644
--- a/drivers/target/target_core_fabric_lib.c
+++ b/drivers/target/target_core_fabric_lib.c
@@ -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;
/*
diff --git a/drivers/target/target_core_file.c b/drivers/target/target_core_file.c
index cbb5aaf3e567..0360383dfb94 100644
--- a/drivers/target/target_core_file.c
+++ b/drivers/target/target_core_file.c
@@ -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,
diff --git a/drivers/target/target_core_file.h b/drivers/target/target_core_file.h
index 70ce7fd7111d..876ae53ef5b8 100644
--- a/drivers/target/target_core_file.h
+++ b/drivers/target/target_core_file.h
@@ -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;
diff --git a/drivers/target/target_core_iblock.c b/drivers/target/target_core_iblock.c
index 9ba495477fd2..29408d46a6d9 100644
--- a/drivers/target/target_core_iblock.c
+++ b/drivers/target/target_core_iblock.c
@@ -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,
diff --git a/drivers/target/target_core_pr.c b/drivers/target/target_core_pr.c
index 956c84c6b666..8c323a98c4a0 100644
--- a/drivers/target/target_core_pr.c
+++ b/drivers/target/target_core_pr.c
@@ -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
diff --git a/drivers/target/target_core_pscsi.c b/drivers/target/target_core_pscsi.c
index 9d7ce3daa262..617c086a8a02 100644
--- a/drivers/target/target_core_pscsi.c
+++ b/drivers/target/target_core_pscsi.c
@@ -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) {
diff --git a/drivers/target/target_core_sbc.c b/drivers/target/target_core_sbc.c
index a9dd9469e3bd..868f8aa04f13 100644
--- a/drivers/target/target_core_sbc.c
+++ b/drivers/target/target_core_sbc.c
@@ -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;
diff --git a/drivers/target/target_core_spc.c b/drivers/target/target_core_spc.c
index 388a922c8f6d..9229bd9ad61b 100644
--- a/drivers/target/target_core_spc.c
+++ b/drivers/target/target_core_spc.c
@@ -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;
diff --git a/drivers/target/target_core_stat.c b/drivers/target/target_core_stat.c
index 3d44beb0cf1f..cb6b0036ae95 100644
--- a/drivers/target/target_core_stat.c
+++ b/drivers/target/target_core_stat.c
@@ -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>
diff --git a/drivers/target/target_core_tpg.c b/drivers/target/target_core_tpg.c
index b8628a5014b9..a531fe282b1e 100644
--- a/drivers/target/target_core_tpg.c
+++ b/drivers/target/target_core_tpg.c
@@ -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) ||
diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c
index 269f54488397..c33baff86aa6 100644
--- a/drivers/target/target_core_transport.c
+++ b/drivers/target/target_core_transport.c
@@ -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);
diff --git a/drivers/target/tcm_fc/tfc_cmd.c b/drivers/target/tcm_fc/tfc_cmd.c
index 823e6922249d..b406f178ff39 100644
--- a/drivers/target/tcm_fc/tfc_cmd.c
+++ b/drivers/target/tcm_fc/tfc_cmd.c
@@ -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>
diff --git a/drivers/target/tcm_fc/tfc_conf.c b/drivers/target/tcm_fc/tfc_conf.c
index 9501844fae2d..b74feb0d5133 100644
--- a/drivers/target/tcm_fc/tfc_conf.c
+++ b/drivers/target/tcm_fc/tfc_conf.c
@@ -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
diff --git a/drivers/target/tcm_fc/tfc_io.c b/drivers/target/tcm_fc/tfc_io.c
index ad36ede1a1ea..b6fd4cf42840 100644
--- a/drivers/target/tcm_fc/tfc_io.c
+++ b/drivers/target/tcm_fc/tfc_io.c
@@ -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) {
diff --git a/drivers/target/tcm_fc/tfc_sess.c b/drivers/target/tcm_fc/tfc_sess.c
index 3c9e5b57caab..9585010964ec 100644
--- a/drivers/target/tcm_fc/tfc_sess.c
+++ b/drivers/target/tcm_fc/tfc_sess.c
@@ -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>
diff --git a/drivers/usb/gadget/tcm_usb_gadget.c b/drivers/usb/gadget/tcm_usb_gadget.c
index eaa1005377fc..97e68b38cfdf 100644
--- a/drivers/usb/gadget/tcm_usb_gadget.c
+++ b/drivers/usb/gadget/tcm_usb_gadget.c
@@ -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,
diff --git a/drivers/vhost/tcm_vhost.c b/drivers/vhost/tcm_vhost.c
index ed8e2e6c8df2..aa31692064dd 100644
--- a/drivers/vhost/tcm_vhost.c
+++ b/drivers/vhost/tcm_vhost.c
@@ -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
*/
diff --git a/drivers/vhost/tcm_vhost.h b/drivers/vhost/tcm_vhost.h
index d9e93557d669..7e87c63ecbcd 100644
--- a/drivers/vhost/tcm_vhost.h
+++ b/drivers/vhost/tcm_vhost.h
@@ -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() */
diff --git a/drivers/video/backlight/pwm_bl.c b/drivers/video/backlight/pwm_bl.c
index 995f0164c9b0..069983ca49ff 100644
--- a/drivers/video/backlight/pwm_bl.c
+++ b/drivers/video/backlight/pwm_bl.c
@@ -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;
diff --git a/fs/lockd/mon.c b/fs/lockd/mon.c
index 7ef14b3c5bee..e4fb3ba5a58a 100644
--- a/fs/lockd/mon.c
+++ b/fs/lockd/mon.c
@@ -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);
diff --git a/fs/lockd/netns.h b/fs/lockd/netns.h
index 4eee248ba96e..5010b55628b4 100644
--- a/fs/lockd/netns.h
+++ b/fs/lockd/netns.h
@@ -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;
diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c
index 31a63f87b806..7e355870d519 100644
--- a/fs/lockd/svc.c
+++ b/fs/lockd/svc.c
@@ -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;
}
diff --git a/fs/nfs/Kconfig b/fs/nfs/Kconfig
index db7ad719628a..13ca196385f5 100644
--- a/fs/nfs/Kconfig
+++ b/fs/nfs/Kconfig
@@ -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
diff --git a/fs/nfs/blocklayout/blocklayout.c b/fs/nfs/blocklayout/blocklayout.c
index dd392ed5f2e2..f1027b06a1a9 100644
--- a/fs/nfs/blocklayout/blocklayout.c
+++ b/fs/nfs/blocklayout/blocklayout.c
@@ -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,
};
diff --git a/fs/nfs/blocklayout/blocklayout.h b/fs/nfs/blocklayout/blocklayout.h
index 03350690118e..f4891bde8851 100644
--- a/fs/nfs/blocklayout/blocklayout.h
+++ b/fs/nfs/blocklayout/blocklayout.h
@@ -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);
diff --git a/fs/nfs/blocklayout/blocklayoutdev.c b/fs/nfs/blocklayout/blocklayoutdev.c
index c96554245ccf..a86c5bdad9e3 100644
--- a/fs/nfs/blocklayout/blocklayoutdev.c
+++ b/fs/nfs/blocklayout/blocklayoutdev.c
@@ -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;
}
diff --git a/fs/nfs/blocklayout/extents.c b/fs/nfs/blocklayout/extents.c
index 1f9a6032796b..9c3e117c3ed1 100644
--- a/fs/nfs/blocklayout/extents.c
+++ b/fs/nfs/blocklayout/extents.c
@@ -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++;
}
diff --git a/fs/nfs/callback.c b/fs/nfs/callback.c
index 4c8459e5bdee..2245bef50f37 100644
--- a/fs/nfs/callback.c
+++ b/fs/nfs/callback.c
@@ -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;
diff --git a/fs/nfs/callback.h b/fs/nfs/callback.h
index b44d7b128b71..4251c2ae06ad 100644
--- a/fs/nfs/callback.h
+++ b/fs/nfs/callback.h
@@ -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 */
diff --git a/fs/nfs/callback_proc.c b/fs/nfs/callback_proc.c
index 1b5d809a105e..76b4a7a3e559 100644
--- a/fs/nfs/callback_proc.c
+++ b/fs/nfs/callback_proc.c
@@ -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;
diff --git a/fs/nfs/client.c b/fs/nfs/client.c
index 99694442b93f..8b39a42ac35e 100644
--- a/fs/nfs/client.c
+++ b/fs/nfs/client.c
@@ -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);
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
index 627f108ede23..ce8cb926526b 100644
--- a/fs/nfs/dir.c
+++ b/fs/nfs/dir.c
@@ -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)
{
diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c
index 1ba385b7c90d..cae26cbd59ee 100644
--- a/fs/nfs/direct.c
+++ b/fs/nfs/direct.c
@@ -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;
diff --git a/fs/nfs/file.c b/fs/nfs/file.c
index f692be97676d..582bb8866131 100644
--- a/fs/nfs/file.c
+++ b/fs/nfs/file.c
@@ -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;
}
diff --git a/fs/nfs/getroot.c b/fs/nfs/getroot.c
index 4654ced096a6..033803c36644 100644
--- a/fs/nfs/getroot.c
+++ b/fs/nfs/getroot.c
@@ -32,6 +32,8 @@
#include <asm/uaccess.h>
+#include "internal.h"
+
#define NFSDBG_FACILITY NFSDBG_CLIENT
/*
diff --git a/fs/nfs/idmap.c b/fs/nfs/idmap.c
index a850079467d8..9cc4a3fbf4b0 100644
--- a/fs/nfs/idmap.c
+++ b/fs/nfs/idmap.c
@@ -55,18 +55,19 @@
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)
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index e4c716d374a8..5c7325c5c5e6 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -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);
diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h
index 31fdb03225cd..59b133c5d652 100644
--- a/fs/nfs/internal.h
+++ b/fs/nfs/internal.h
@@ -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
diff --git a/fs/nfs/netns.h b/fs/nfs/netns.h
index 0539de1b8d1f..8ee1fab83268 100644
--- a/fs/nfs/netns.h
+++ b/fs/nfs/netns.h
@@ -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;
diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h
index da0618aeeadb..a525fdefccde 100644
--- a/fs/nfs/nfs4_fs.h
+++ b/fs/nfs/nfs4_fs.h
@@ -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);
diff --git a/fs/nfs/nfs4client.c b/fs/nfs/nfs4client.c
index 24eb663f8ed5..6bacfde1319a 100644
--- a/fs/nfs/nfs4client.c
+++ b/fs/nfs/nfs4client.c
@@ -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);
diff --git a/fs/nfs/nfs4file.c b/fs/nfs/nfs4file.c
index eb5eb8eef4d3..afddd6639afb 100644
--- a/fs/nfs/nfs4file.c
+++ b/fs/nfs/nfs4file.c
@@ -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;
}
diff --git a/fs/nfs/nfs4filelayout.c b/fs/nfs/nfs4filelayout.c
index 53f94d915bd1..52d847212066 100644
--- a/fs/nfs/nfs4filelayout.c
+++ b/fs/nfs/nfs4filelayout.c
@@ -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 */
diff --git a/fs/nfs/nfs4filelayout.h b/fs/nfs/nfs4filelayout.h
index 43fe802dd678..dca47d786710 100644
--- a/fs/nfs/nfs4filelayout.h
+++ b/fs/nfs/nfs4filelayout.h
@@ -129,23 +129,13 @@ filelayout_mark_devid_invalid(struct nfs4_deviceid_node *node)
}
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 */
diff --git a/fs/nfs/nfs4filelayoutdev.c b/fs/nfs/nfs4filelayoutdev.c
index f81231f30d94..3336d5eaf879 100644
--- a/fs/nfs/nfs4filelayoutdev.c
+++ b/fs/nfs/nfs4filelayoutdev.c
@@ -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);
diff --git a/fs/nfs/nfs4namespace.c b/fs/nfs/nfs4namespace.c
index 017b4b01a69c..79fbb61ce202 100644
--- a/fs/nfs/nfs4namespace.c
+++ b/fs/nfs/nfs4namespace.c
@@ -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,
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index 1e50326d00dd..68b21d81b7ac 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -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 */
diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c
index 55148def5540..c351e6b39838 100644
--- a/fs/nfs/nfs4state.c
+++ b/fs/nfs/nfs4state.c
@@ -51,18 +51,21 @@
#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);
}
diff --git a/fs/nfs/nfs4sysctl.c b/fs/nfs/nfs4sysctl.c
index 5729bc8aa75d..2628d921b7e3 100644
--- a/fs/nfs/nfs4sysctl.c
+++ b/fs/nfs/nfs4sysctl.c
@@ -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;
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c
index 8dba6bd48557..40836ee5dc3a 100644
--- a/fs/nfs/nfs4xdr.c
+++ b/fs/nfs/nfs4xdr.c
@@ -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;
diff --git a/fs/nfs/objlayout/objio_osd.c b/fs/nfs/objlayout/objio_osd.c
index ea6d111b03e9..be731e6b7b9c 100644
--- a/fs/nfs/objlayout/objio_osd.c
+++ b/fs/nfs/objlayout/objio_osd.c
@@ -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 */
diff --git a/fs/nfs/pagelist.c b/fs/nfs/pagelist.c
index 311a79681e2b..e56e846e9d2d 100644
--- a/fs/nfs/pagelist.c
+++ b/fs/nfs/pagelist.c
@@ -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;
diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c
index 2e00feacd4be..fe624c91bd00 100644
--- a/fs/nfs/pnfs.c
+++ b/fs/nfs/pnfs.c
@@ -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;
diff --git a/fs/nfs/pnfs.h b/fs/nfs/pnfs.h
index 745aa1b39e7c..2d722dba1111 100644
--- a/fs/nfs/pnfs.h
+++ b/fs/nfs/pnfs.h
@@ -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;
}
diff --git a/fs/nfs/pnfs_dev.c b/fs/nfs/pnfs_dev.c
index 73f701f1f4d3..d35b62e83ea6 100644
--- a/fs/nfs/pnfs_dev.c
+++ b/fs/nfs/pnfs_dev.c
@@ -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();
}
+
diff --git a/fs/nfs/super.c b/fs/nfs/super.c
index d2c7f5db0847..e831bce49766 100644
--- a/fs/nfs/super.c
+++ b/fs/nfs/super.c
@@ -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 */
diff --git a/fs/nfs/write.c b/fs/nfs/write.c
index e3b55372726c..9347ab7c9574 100644
--- a/fs/nfs/write.c
+++ b/fs/nfs/write.c
@@ -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);
}
diff --git a/include/linux/leds-lp5523.h b/include/linux/leds-lp5523.h
index 2694289babd0..727877fb406d 100644
--- a/include/linux/leds-lp5523.h
+++ b/include/linux/leds-lp5523.h
@@ -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;
diff --git a/include/linux/leds.h b/include/linux/leds.h
index c6f8dad2ceb0..6e53bb31c220 100644
--- a/include/linux/leds.h
+++ b/include/linux/leds.h
@@ -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;
diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h
index 4b03f56e280e..334a2f5f6bf1 100644
--- a/include/linux/nfs_fs.h
+++ b/include/linux/nfs_fs.h
@@ -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 *);
diff --git a/include/linux/nfs_fs_sb.h b/include/linux/nfs_fs_sb.h
index 310c63c8ab2c..a9e76ee1adca 100644
--- a/include/linux/nfs_fs_sb.h
+++ b/include/linux/nfs_fs_sb.h
@@ -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 */
diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h
index be9cf3c7e79e..a73ea89789d1 100644
--- a/include/linux/nfs_xdr.h
+++ b/include/linux/nfs_xdr.h
@@ -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
index 4b4e7d6b0527..000000000000
--- a/include/linux/platform_data/leds-lm3556.h
+++ /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
index 000000000000..b88724bb0b46
--- /dev/null
+++ b/include/linux/platform_data/leds-lm355x.h
@@ -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
index 000000000000..72d6ee6ade57
--- /dev/null
+++ b/include/linux/platform_data/leds-lm3642.h
@@ -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
index 000000000000..c5bf29b6fa7f
--- /dev/null
+++ b/include/linux/platform_data/leds-pca9633.h
@@ -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*/
diff --git a/include/linux/pwm.h b/include/linux/pwm.h
index 21d076c5089e..112b31436848 100644
--- a/include/linux/pwm.h
+++ b/include/linux/pwm.h
@@ -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 */
diff --git a/include/linux/sunrpc/clnt.h b/include/linux/sunrpc/clnt.h
index 523547ecfee2..34206b84d8da 100644
--- a/include/linux/sunrpc/clnt.h
+++ b/include/linux/sunrpc/clnt.h
@@ -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 *);
diff --git a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h
index bf8c49ff7530..951cb9b7d02b 100644
--- a/include/linux/sunrpc/xprt.h
+++ b/include/linux/sunrpc/xprt.h
@@ -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 */
diff --git a/include/target/target_core_backend.h b/include/target/target_core_backend.h
index 941c84bf1065..2acd54018b64 100644
--- a/include/target/target_core_backend.h
+++ b/include/target/target_core_backend.h
@@ -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);
diff --git a/include/target/target_core_fabric.h b/include/target/target_core_fabric.h
index 69fb3cfd02d7..81ddb4ae6c3f 100644
--- a/include/target/target_core_fabric.h
+++ b/include/target/target_core_fabric.h
@@ -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,
diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c
index 34c522021004..909dc0c31aab 100644
--- a/net/sunrpc/auth_gss/auth_gss.c
+++ b/net/sunrpc/auth_gss/auth_gss.c
@@ -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;
}
diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c
index fa48c60aef23..cdc7564b4512 100644
--- a/net/sunrpc/clnt.c
+++ b/net/sunrpc/clnt.c
@@ -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?
diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c
index 21fde99e5c56..80f5dd23417d 100644
--- a/net/sunrpc/rpc_pipe.c
+++ b/net/sunrpc/rpc_pipe.c
@@ -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);
diff --git a/net/sunrpc/sched.c b/net/sunrpc/sched.c
index 128494ec9a64..6357fcb00c7e 100644
--- a/net/sunrpc/sched.c
+++ b/net/sunrpc/sched.c
@@ -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;
}
diff --git a/net/sunrpc/xdr.c b/net/sunrpc/xdr.c
index 0afba1b4b656..08f50afd5f2a 100644
--- a/net/sunrpc/xdr.c
+++ b/net/sunrpc/xdr.c
@@ -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;
}
diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c
index 5d7f61d7559c..bd462a532acf 100644
--- a/net/sunrpc/xprt.c
+++ b/net/sunrpc/xprt.c
@@ -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);
diff --git a/net/sunrpc/xprtrdma/transport.c b/net/sunrpc/xprtrdma/transport.c
index 5d9202dc7cb1..c9aa7a35f3bf 100644
--- a/net/sunrpc/xprtrdma/transport.c
+++ b/net/sunrpc/xprtrdma/transport.c
@@ -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;
diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c
index a35b8e52e551..aaaadfbe36e9 100644
--- a/net/sunrpc/xprtsock.c
+++ b/net/sunrpc/xprtsock.c
@@ -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,