Merge tag 'scsi-misc' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi
Pull SCSI updates from James Bottomley:
"This series is slightly unusual because it includes Arnd's compat
ioctl tree here:
1c46a2cf2d Merge tag 'block-ioctl-cleanup-5.6' into 5.6/scsi-queue
Excluding Arnd's changes, this is mostly an update of the usual
drivers: megaraid_sas, mpt3sas, qla2xxx, ufs, lpfc, hisi_sas.
There are a couple of core and base updates around error propagation
and atomicity in the attribute container base we use for the SCSI
transport classes.
The rest is minor changes and updates"
* tag 'scsi-misc' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi: (149 commits)
scsi: hisi_sas: Rename hisi_sas_cq.pci_irq_mask
scsi: hisi_sas: Add prints for v3 hw interrupt converge and automatic affinity
scsi: hisi_sas: Modify the file permissions of trigger_dump to write only
scsi: hisi_sas: Replace magic number when handle channel interrupt
scsi: hisi_sas: replace spin_lock_irqsave/spin_unlock_restore with spin_lock/spin_unlock
scsi: hisi_sas: use threaded irq to process CQ interrupts
scsi: ufs: Use UFS device indicated maximum LU number
scsi: ufs: Add max_lu_supported in struct ufs_dev_info
scsi: ufs: Delete is_init_prefetch from struct ufs_hba
scsi: ufs: Inline two functions into their callers
scsi: ufs: Move ufshcd_get_max_pwr_mode() to ufshcd_device_params_init()
scsi: ufs: Split ufshcd_probe_hba() based on its called flow
scsi: ufs: Delete struct ufs_dev_desc
scsi: ufs: Fix ufshcd_probe_hba() reture value in case ufshcd_scsi_add_wlus() fails
scsi: ufs-mediatek: enable low-power mode for hibern8 state
scsi: ufs: export some functions for vendor usage
scsi: ufs-mediatek: add dbg_register_dump implementation
scsi: qla2xxx: Fix a NULL pointer dereference in an error path
scsi: qla1280: Make checking for 64bit support consistent
scsi: megaraid_sas: Update driver version to 07.713.01.00-rc1
...
This commit is contained in:
@@ -40,6 +40,7 @@ Core utilities
|
||||
gcc-plugins
|
||||
symbol-namespaces
|
||||
padata
|
||||
ioctl
|
||||
|
||||
|
||||
Interfaces for kernel debugging
|
||||
|
||||
253
Documentation/core-api/ioctl.rst
Normal file
253
Documentation/core-api/ioctl.rst
Normal file
@@ -0,0 +1,253 @@
|
||||
======================
|
||||
ioctl based interfaces
|
||||
======================
|
||||
|
||||
ioctl() is the most common way for applications to interface
|
||||
with device drivers. It is flexible and easily extended by adding new
|
||||
commands and can be passed through character devices, block devices as
|
||||
well as sockets and other special file descriptors.
|
||||
|
||||
However, it is also very easy to get ioctl command definitions wrong,
|
||||
and hard to fix them later without breaking existing applications,
|
||||
so this documentation tries to help developers get it right.
|
||||
|
||||
Command number definitions
|
||||
==========================
|
||||
|
||||
The command number, or request number, is the second argument passed to
|
||||
the ioctl system call. While this can be any 32-bit number that uniquely
|
||||
identifies an action for a particular driver, there are a number of
|
||||
conventions around defining them.
|
||||
|
||||
``include/uapi/asm-generic/ioctl.h`` provides four macros for defining
|
||||
ioctl commands that follow modern conventions: ``_IO``, ``_IOR``,
|
||||
``_IOW``, and ``_IOWR``. These should be used for all new commands,
|
||||
with the correct parameters:
|
||||
|
||||
_IO/_IOR/_IOW/_IOWR
|
||||
The macro name specifies how the argument will be used. It may be a
|
||||
pointer to data to be passed into the kernel (_IOW), out of the kernel
|
||||
(_IOR), or both (_IOWR). _IO can indicate either commands with no
|
||||
argument or those passing an integer value instead of a pointer.
|
||||
It is recommended to only use _IO for commands without arguments,
|
||||
and use pointers for passing data.
|
||||
|
||||
type
|
||||
An 8-bit number, often a character literal, specific to a subsystem
|
||||
or driver, and listed in :doc:`../userspace-api/ioctl/ioctl-number`
|
||||
|
||||
nr
|
||||
An 8-bit number identifying the specific command, unique for a give
|
||||
value of 'type'
|
||||
|
||||
data_type
|
||||
The name of the data type pointed to by the argument, the command number
|
||||
encodes the ``sizeof(data_type)`` value in a 13-bit or 14-bit integer,
|
||||
leading to a limit of 8191 bytes for the maximum size of the argument.
|
||||
Note: do not pass sizeof(data_type) type into _IOR/_IOW/IOWR, as that
|
||||
will lead to encoding sizeof(sizeof(data_type)), i.e. sizeof(size_t).
|
||||
_IO does not have a data_type parameter.
|
||||
|
||||
|
||||
Interface versions
|
||||
==================
|
||||
|
||||
Some subsystems use version numbers in data structures to overload
|
||||
commands with different interpretations of the argument.
|
||||
|
||||
This is generally a bad idea, since changes to existing commands tend
|
||||
to break existing applications.
|
||||
|
||||
A better approach is to add a new ioctl command with a new number. The
|
||||
old command still needs to be implemented in the kernel for compatibility,
|
||||
but this can be a wrapper around the new implementation.
|
||||
|
||||
Return code
|
||||
===========
|
||||
|
||||
ioctl commands can return negative error codes as documented in errno(3);
|
||||
these get turned into errno values in user space. On success, the return
|
||||
code should be zero. It is also possible but not recommended to return
|
||||
a positive 'long' value.
|
||||
|
||||
When the ioctl callback is called with an unknown command number, the
|
||||
handler returns either -ENOTTY or -ENOIOCTLCMD, which also results in
|
||||
-ENOTTY being returned from the system call. Some subsystems return
|
||||
-ENOSYS or -EINVAL here for historic reasons, but this is wrong.
|
||||
|
||||
Prior to Linux 5.5, compat_ioctl handlers were required to return
|
||||
-ENOIOCTLCMD in order to use the fallback conversion into native
|
||||
commands. As all subsystems are now responsible for handling compat
|
||||
mode themselves, this is no longer needed, but it may be important to
|
||||
consider when backporting bug fixes to older kernels.
|
||||
|
||||
Timestamps
|
||||
==========
|
||||
|
||||
Traditionally, timestamps and timeout values are passed as ``struct
|
||||
timespec`` or ``struct timeval``, but these are problematic because of
|
||||
incompatible definitions of these structures in user space after the
|
||||
move to 64-bit time_t.
|
||||
|
||||
The ``struct __kernel_timespec`` type can be used instead to be embedded
|
||||
in other data structures when separate second/nanosecond values are
|
||||
desired, or passed to user space directly. This is still not ideal though,
|
||||
as the structure matches neither the kernel's timespec64 nor the user
|
||||
space timespec exactly. The get_timespec64() and put_timespec64() helper
|
||||
functions can be used to ensure that the layout remains compatible with
|
||||
user space and the padding is treated correctly.
|
||||
|
||||
As it is cheap to convert seconds to nanoseconds, but the opposite
|
||||
requires an expensive 64-bit division, a simple __u64 nanosecond value
|
||||
can be simpler and more efficient.
|
||||
|
||||
Timeout values and timestamps should ideally use CLOCK_MONOTONIC time,
|
||||
as returned by ktime_get_ns() or ktime_get_ts64(). Unlike
|
||||
CLOCK_REALTIME, this makes the timestamps immune from jumping backwards
|
||||
or forwards due to leap second adjustments and clock_settime() calls.
|
||||
|
||||
ktime_get_real_ns() can be used for CLOCK_REALTIME timestamps that
|
||||
need to be persistent across a reboot or between multiple machines.
|
||||
|
||||
32-bit compat mode
|
||||
==================
|
||||
|
||||
In order to support 32-bit user space running on a 64-bit machine, each
|
||||
subsystem or driver that implements an ioctl callback handler must also
|
||||
implement the corresponding compat_ioctl handler.
|
||||
|
||||
As long as all the rules for data structures are followed, this is as
|
||||
easy as setting the .compat_ioctl pointer to a helper function such as
|
||||
compat_ptr_ioctl() or blkdev_compat_ptr_ioctl().
|
||||
|
||||
compat_ptr()
|
||||
------------
|
||||
|
||||
On the s390 architecture, 31-bit user space has ambiguous representations
|
||||
for data pointers, with the upper bit being ignored. When running such
|
||||
a process in compat mode, the compat_ptr() helper must be used to
|
||||
clear the upper bit of a compat_uptr_t and turn it into a valid 64-bit
|
||||
pointer. On other architectures, this macro only performs a cast to a
|
||||
``void __user *`` pointer.
|
||||
|
||||
In an compat_ioctl() callback, the last argument is an unsigned long,
|
||||
which can be interpreted as either a pointer or a scalar depending on
|
||||
the command. If it is a scalar, then compat_ptr() must not be used, to
|
||||
ensure that the 64-bit kernel behaves the same way as a 32-bit kernel
|
||||
for arguments with the upper bit set.
|
||||
|
||||
The compat_ptr_ioctl() helper can be used in place of a custom
|
||||
compat_ioctl file operation for drivers that only take arguments that
|
||||
are pointers to compatible data structures.
|
||||
|
||||
Structure layout
|
||||
----------------
|
||||
|
||||
Compatible data structures have the same layout on all architectures,
|
||||
avoiding all problematic members:
|
||||
|
||||
* ``long`` and ``unsigned long`` are the size of a register, so
|
||||
they can be either 32-bit or 64-bit wide and cannot be used in portable
|
||||
data structures. Fixed-length replacements are ``__s32``, ``__u32``,
|
||||
``__s64`` and ``__u64``.
|
||||
|
||||
* Pointers have the same problem, in addition to requiring the
|
||||
use of compat_ptr(). The best workaround is to use ``__u64``
|
||||
in place of pointers, which requires a cast to ``uintptr_t`` in user
|
||||
space, and the use of u64_to_user_ptr() in the kernel to convert
|
||||
it back into a user pointer.
|
||||
|
||||
* On the x86-32 (i386) architecture, the alignment of 64-bit variables
|
||||
is only 32-bit, but they are naturally aligned on most other
|
||||
architectures including x86-64. This means a structure like::
|
||||
|
||||
struct foo {
|
||||
__u32 a;
|
||||
__u64 b;
|
||||
__u32 c;
|
||||
};
|
||||
|
||||
has four bytes of padding between a and b on x86-64, plus another four
|
||||
bytes of padding at the end, but no padding on i386, and it needs a
|
||||
compat_ioctl conversion handler to translate between the two formats.
|
||||
|
||||
To avoid this problem, all structures should have their members
|
||||
naturally aligned, or explicit reserved fields added in place of the
|
||||
implicit padding. The ``pahole`` tool can be used for checking the
|
||||
alignment.
|
||||
|
||||
* On ARM OABI user space, structures are padded to multiples of 32-bit,
|
||||
making some structs incompatible with modern EABI kernels if they
|
||||
do not end on a 32-bit boundary.
|
||||
|
||||
* On the m68k architecture, struct members are not guaranteed to have an
|
||||
alignment greater than 16-bit, which is a problem when relying on
|
||||
implicit padding.
|
||||
|
||||
* Bitfields and enums generally work as one would expect them to,
|
||||
but some properties of them are implementation-defined, so it is better
|
||||
to avoid them completely in ioctl interfaces.
|
||||
|
||||
* ``char`` members can be either signed or unsigned, depending on
|
||||
the architecture, so the __u8 and __s8 types should be used for 8-bit
|
||||
integer values, though char arrays are clearer for fixed-length strings.
|
||||
|
||||
Information leaks
|
||||
=================
|
||||
|
||||
Uninitialized data must not be copied back to user space, as this can
|
||||
cause an information leak, which can be used to defeat kernel address
|
||||
space layout randomization (KASLR), helping in an attack.
|
||||
|
||||
For this reason (and for compat support) it is best to avoid any
|
||||
implicit padding in data structures. Where there is implicit padding
|
||||
in an existing structure, kernel drivers must be careful to fully
|
||||
initialize an instance of the structure before copying it to user
|
||||
space. This is usually done by calling memset() before assigning to
|
||||
individual members.
|
||||
|
||||
Subsystem abstractions
|
||||
======================
|
||||
|
||||
While some device drivers implement their own ioctl function, most
|
||||
subsystems implement the same command for multiple drivers. Ideally the
|
||||
subsystem has an .ioctl() handler that copies the arguments from and
|
||||
to user space, passing them into subsystem specific callback functions
|
||||
through normal kernel pointers.
|
||||
|
||||
This helps in various ways:
|
||||
|
||||
* Applications written for one driver are more likely to work for
|
||||
another one in the same subsystem if there are no subtle differences
|
||||
in the user space ABI.
|
||||
|
||||
* The complexity of user space access and data structure layout is done
|
||||
in one place, reducing the potential for implementation bugs.
|
||||
|
||||
* It is more likely to be reviewed by experienced developers
|
||||
that can spot problems in the interface when the ioctl is shared
|
||||
between multiple drivers than when it is only used in a single driver.
|
||||
|
||||
Alternatives to ioctl
|
||||
=====================
|
||||
|
||||
There are many cases in which ioctl is not the best solution for a
|
||||
problem. Alternatives include:
|
||||
|
||||
* System calls are a better choice for a system-wide feature that
|
||||
is not tied to a physical device or constrained by the file system
|
||||
permissions of a character device node
|
||||
|
||||
* netlink is the preferred way of configuring any network related
|
||||
objects through sockets.
|
||||
|
||||
* debugfs is used for ad-hoc interfaces for debugging functionality
|
||||
that does not need to be exposed as a stable interface to applications.
|
||||
|
||||
* sysfs is a good way to expose the state of an in-kernel object
|
||||
that is not tied to a file descriptor.
|
||||
|
||||
* configfs can be used for more complex configuration than sysfs
|
||||
|
||||
* A custom file system can provide extra flexibility with a simple
|
||||
user interface but adds a lot of complexity to the implementation.
|
||||
@@ -4,6 +4,9 @@
|
||||
*/
|
||||
#ifndef __ASM_COMPAT_H
|
||||
#define __ASM_COMPAT_H
|
||||
|
||||
#include <asm-generic/compat.h>
|
||||
|
||||
#ifdef CONFIG_COMPAT
|
||||
|
||||
/*
|
||||
@@ -13,8 +16,6 @@
|
||||
#include <linux/sched.h>
|
||||
#include <linux/sched/task_stack.h>
|
||||
|
||||
#include <asm-generic/compat.h>
|
||||
|
||||
#define COMPAT_USER_HZ 100
|
||||
#ifdef __AARCH64EB__
|
||||
#define COMPAT_UTS_MACHINE "armv8b\0\0"
|
||||
@@ -113,23 +114,6 @@ typedef u32 compat_sigset_word;
|
||||
|
||||
#define COMPAT_OFF_T_MAX 0x7fffffff
|
||||
|
||||
/*
|
||||
* A pointer passed in from user mode. This should not
|
||||
* be used for syscall parameters, just declare them
|
||||
* as pointers because the syscall entry code will have
|
||||
* appropriately converted them already.
|
||||
*/
|
||||
|
||||
static inline void __user *compat_ptr(compat_uptr_t uptr)
|
||||
{
|
||||
return (void __user *)(unsigned long)uptr;
|
||||
}
|
||||
|
||||
static inline compat_uptr_t ptr_to_compat(void __user *uptr)
|
||||
{
|
||||
return (u32)(unsigned long)uptr;
|
||||
}
|
||||
|
||||
#define compat_user_stack_pointer() (user_stack_pointer(task_pt_regs(current)))
|
||||
#define COMPAT_MINSIGSTKSZ 2048
|
||||
|
||||
|
||||
@@ -100,24 +100,6 @@ typedef u32 compat_sigset_word;
|
||||
|
||||
#define COMPAT_OFF_T_MAX 0x7fffffff
|
||||
|
||||
/*
|
||||
* A pointer passed in from user mode. This should not
|
||||
* be used for syscall parameters, just declare them
|
||||
* as pointers because the syscall entry code will have
|
||||
* appropriately converted them already.
|
||||
*/
|
||||
|
||||
static inline void __user *compat_ptr(compat_uptr_t uptr)
|
||||
{
|
||||
/* cast to a __user pointer via "unsigned long" makes sparse happy */
|
||||
return (void __user *)(unsigned long)(long)uptr;
|
||||
}
|
||||
|
||||
static inline compat_uptr_t ptr_to_compat(void __user *uptr)
|
||||
{
|
||||
return (u32)(unsigned long)uptr;
|
||||
}
|
||||
|
||||
static inline void __user *arch_compat_alloc_user_space(long len)
|
||||
{
|
||||
struct pt_regs *regs = (struct pt_regs *)
|
||||
|
||||
@@ -173,23 +173,6 @@ struct compat_shmid64_ds {
|
||||
#define COMPAT_ELF_NGREG 80
|
||||
typedef compat_ulong_t compat_elf_gregset_t[COMPAT_ELF_NGREG];
|
||||
|
||||
/*
|
||||
* A pointer passed in from user mode. This should not
|
||||
* be used for syscall parameters, just declare them
|
||||
* as pointers because the syscall entry code will have
|
||||
* appropriately converted them already.
|
||||
*/
|
||||
|
||||
static inline void __user *compat_ptr(compat_uptr_t uptr)
|
||||
{
|
||||
return (void __user *)(unsigned long)uptr;
|
||||
}
|
||||
|
||||
static inline compat_uptr_t ptr_to_compat(void __user *uptr)
|
||||
{
|
||||
return (u32)(unsigned long)uptr;
|
||||
}
|
||||
|
||||
static __inline__ void __user *arch_compat_alloc_user_space(long len)
|
||||
{
|
||||
struct pt_regs *regs = ¤t->thread.regs;
|
||||
|
||||
@@ -96,23 +96,6 @@ typedef u32 compat_sigset_word;
|
||||
|
||||
#define COMPAT_OFF_T_MAX 0x7fffffff
|
||||
|
||||
/*
|
||||
* A pointer passed in from user mode. This should not
|
||||
* be used for syscall parameters, just declare them
|
||||
* as pointers because the syscall entry code will have
|
||||
* appropriately converted them already.
|
||||
*/
|
||||
|
||||
static inline void __user *compat_ptr(compat_uptr_t uptr)
|
||||
{
|
||||
return (void __user *)(unsigned long)uptr;
|
||||
}
|
||||
|
||||
static inline compat_uptr_t ptr_to_compat(void __user *uptr)
|
||||
{
|
||||
return (u32)(unsigned long)uptr;
|
||||
}
|
||||
|
||||
static inline void __user *arch_compat_alloc_user_space(long len)
|
||||
{
|
||||
struct pt_regs *regs = current->thread.regs;
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
#include <linux/sched.h>
|
||||
#include <asm/processor.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <asm/compat.h>
|
||||
#include <linux/compat.h>
|
||||
#include <asm/oprofile_impl.h>
|
||||
|
||||
#define STACK_SP(STACK) *(STACK)
|
||||
|
||||
@@ -177,11 +177,7 @@ static inline void __user *compat_ptr(compat_uptr_t uptr)
|
||||
{
|
||||
return (void __user *)(unsigned long)(uptr & 0x7fffffffUL);
|
||||
}
|
||||
|
||||
static inline compat_uptr_t ptr_to_compat(void __user *uptr)
|
||||
{
|
||||
return (u32)(unsigned long)uptr;
|
||||
}
|
||||
#define compat_ptr(uptr) compat_ptr(uptr)
|
||||
|
||||
#ifdef CONFIG_COMPAT
|
||||
|
||||
|
||||
@@ -125,23 +125,6 @@ typedef u32 compat_sigset_word;
|
||||
|
||||
#define COMPAT_OFF_T_MAX 0x7fffffff
|
||||
|
||||
/*
|
||||
* A pointer passed in from user mode. This should not
|
||||
* be used for syscall parameters, just declare them
|
||||
* as pointers because the syscall entry code will have
|
||||
* appropriately converted them already.
|
||||
*/
|
||||
|
||||
static inline void __user *compat_ptr(compat_uptr_t uptr)
|
||||
{
|
||||
return (void __user *)(unsigned long)uptr;
|
||||
}
|
||||
|
||||
static inline compat_uptr_t ptr_to_compat(void __user *uptr)
|
||||
{
|
||||
return (u32)(unsigned long)uptr;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_COMPAT
|
||||
static inline void __user *arch_compat_alloc_user_space(long len)
|
||||
{
|
||||
|
||||
@@ -113,6 +113,7 @@ static const struct block_device_operations ubd_blops = {
|
||||
.open = ubd_open,
|
||||
.release = ubd_release,
|
||||
.ioctl = ubd_ioctl,
|
||||
.compat_ioctl = blkdev_compat_ptr_ioctl,
|
||||
.getgeo = ubd_getgeo,
|
||||
};
|
||||
|
||||
|
||||
@@ -177,23 +177,6 @@ typedef struct user_regs_struct compat_elf_gregset_t;
|
||||
(!!(task_pt_regs(current)->orig_ax & __X32_SYSCALL_BIT))
|
||||
#endif
|
||||
|
||||
/*
|
||||
* A pointer passed in from user mode. This should not
|
||||
* be used for syscall parameters, just declare them
|
||||
* as pointers because the syscall entry code will have
|
||||
* appropriately converted them already.
|
||||
*/
|
||||
|
||||
static inline void __user *compat_ptr(compat_uptr_t uptr)
|
||||
{
|
||||
return (void __user *)(unsigned long)uptr;
|
||||
}
|
||||
|
||||
static inline compat_uptr_t ptr_to_compat(void __user *uptr)
|
||||
{
|
||||
return (u32)(unsigned long)uptr;
|
||||
}
|
||||
|
||||
static inline void __user *arch_compat_alloc_user_space(long len)
|
||||
{
|
||||
compat_uptr_t sp;
|
||||
|
||||
@@ -25,7 +25,6 @@ obj-$(CONFIG_MQ_IOSCHED_KYBER) += kyber-iosched.o
|
||||
bfq-y := bfq-iosched.o bfq-wf2q.o bfq-cgroup.o
|
||||
obj-$(CONFIG_IOSCHED_BFQ) += bfq.o
|
||||
|
||||
obj-$(CONFIG_BLOCK_COMPAT) += compat_ioctl.o
|
||||
obj-$(CONFIG_BLK_CMDLINE_PARSER) += cmdline-parser.o
|
||||
obj-$(CONFIG_BLK_DEV_INTEGRITY) += bio-integrity.o blk-integrity.o
|
||||
obj-$(CONFIG_BLK_DEV_INTEGRITY_T10) += t10-pi.o
|
||||
|
||||
@@ -382,6 +382,7 @@ static const struct file_operations bsg_fops = {
|
||||
.open = bsg_open,
|
||||
.release = bsg_release,
|
||||
.unlocked_ioctl = bsg_ioctl,
|
||||
.compat_ioctl = compat_ptr_ioctl,
|
||||
.owner = THIS_MODULE,
|
||||
.llseek = default_llseek,
|
||||
};
|
||||
|
||||
@@ -1,427 +0,0 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
#include <linux/blkdev.h>
|
||||
#include <linux/blkpg.h>
|
||||
#include <linux/blktrace_api.h>
|
||||
#include <linux/cdrom.h>
|
||||
#include <linux/compat.h>
|
||||
#include <linux/elevator.h>
|
||||
#include <linux/hdreg.h>
|
||||
#include <linux/pr.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/syscalls.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/uaccess.h>
|
||||
|
||||
static int compat_put_ushort(unsigned long arg, unsigned short val)
|
||||
{
|
||||
return put_user(val, (unsigned short __user *)compat_ptr(arg));
|
||||
}
|
||||
|
||||
static int compat_put_int(unsigned long arg, int val)
|
||||
{
|
||||
return put_user(val, (compat_int_t __user *)compat_ptr(arg));
|
||||
}
|
||||
|
||||
static int compat_put_uint(unsigned long arg, unsigned int val)
|
||||
{
|
||||
return put_user(val, (compat_uint_t __user *)compat_ptr(arg));
|
||||
}
|
||||
|
||||
static int compat_put_long(unsigned long arg, long val)
|
||||
{
|
||||
return put_user(val, (compat_long_t __user *)compat_ptr(arg));
|
||||
}
|
||||
|
||||
static int compat_put_ulong(unsigned long arg, compat_ulong_t val)
|
||||
{
|
||||
return put_user(val, (compat_ulong_t __user *)compat_ptr(arg));
|
||||
}
|
||||
|
||||
static int compat_put_u64(unsigned long arg, u64 val)
|
||||
{
|
||||
return put_user(val, (compat_u64 __user *)compat_ptr(arg));
|
||||
}
|
||||
|
||||
struct compat_hd_geometry {
|
||||
unsigned char heads;
|
||||
unsigned char sectors;
|
||||
unsigned short cylinders;
|
||||
u32 start;
|
||||
};
|
||||
|
||||
static int compat_hdio_getgeo(struct gendisk *disk, struct block_device *bdev,
|
||||
struct compat_hd_geometry __user *ugeo)
|
||||
{
|
||||
struct hd_geometry geo;
|
||||
int ret;
|
||||
|
||||
if (!ugeo)
|
||||
return -EINVAL;
|
||||
if (!disk->fops->getgeo)
|
||||
return -ENOTTY;
|
||||
|
||||
memset(&geo, 0, sizeof(geo));
|
||||
/*
|
||||
* We need to set the startsect first, the driver may
|
||||
* want to override it.
|
||||
*/
|
||||
geo.start = get_start_sect(bdev);
|
||||
ret = disk->fops->getgeo(bdev, &geo);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = copy_to_user(ugeo, &geo, 4);
|
||||
ret |= put_user(geo.start, &ugeo->start);
|
||||
if (ret)
|
||||
ret = -EFAULT;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int compat_hdio_ioctl(struct block_device *bdev, fmode_t mode,
|
||||
unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
unsigned long __user *p;
|
||||
int error;
|
||||
|
||||
p = compat_alloc_user_space(sizeof(unsigned long));
|
||||
error = __blkdev_driver_ioctl(bdev, mode,
|
||||
cmd, (unsigned long)p);
|
||||
if (error == 0) {
|
||||
unsigned int __user *uvp = compat_ptr(arg);
|
||||
unsigned long v;
|
||||
if (get_user(v, p) || put_user(v, uvp))
|
||||
error = -EFAULT;
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
struct compat_cdrom_read_audio {
|
||||
union cdrom_addr addr;
|
||||
u8 addr_format;
|
||||
compat_int_t nframes;
|
||||
compat_caddr_t buf;
|
||||
};
|
||||
|
||||
struct compat_cdrom_generic_command {
|
||||
unsigned char cmd[CDROM_PACKET_SIZE];
|
||||
compat_caddr_t buffer;
|
||||
compat_uint_t buflen;
|
||||
compat_int_t stat;
|
||||
compat_caddr_t sense;
|
||||
unsigned char data_direction;
|
||||
compat_int_t quiet;
|
||||
compat_int_t timeout;
|
||||
compat_caddr_t reserved[1];
|
||||
};
|
||||
|
||||
static int compat_cdrom_read_audio(struct block_device *bdev, fmode_t mode,
|
||||
unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
struct cdrom_read_audio __user *cdread_audio;
|
||||
struct compat_cdrom_read_audio __user *cdread_audio32;
|
||||
__u32 data;
|
||||
void __user *datap;
|
||||
|
||||
cdread_audio = compat_alloc_user_space(sizeof(*cdread_audio));
|
||||
cdread_audio32 = compat_ptr(arg);
|
||||
|
||||
if (copy_in_user(&cdread_audio->addr,
|
||||
&cdread_audio32->addr,
|
||||
(sizeof(*cdread_audio32) -
|
||||
sizeof(compat_caddr_t))))
|
||||
return -EFAULT;
|
||||
|
||||
if (get_user(data, &cdread_audio32->buf))
|
||||
return -EFAULT;
|
||||
datap = compat_ptr(data);
|
||||
if (put_user(datap, &cdread_audio->buf))
|
||||
return -EFAULT;
|
||||
|
||||
return __blkdev_driver_ioctl(bdev, mode, cmd,
|
||||
(unsigned long)cdread_audio);
|
||||
}
|
||||
|
||||
static int compat_cdrom_generic_command(struct block_device *bdev, fmode_t mode,
|
||||
unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
struct cdrom_generic_command __user *cgc;
|
||||
struct compat_cdrom_generic_command __user *cgc32;
|
||||
u32 data;
|
||||
unsigned char dir;
|
||||
int itmp;
|
||||
|
||||
cgc = compat_alloc_user_space(sizeof(*cgc));
|
||||
cgc32 = compat_ptr(arg);
|
||||
|
||||
if (copy_in_user(&cgc->cmd, &cgc32->cmd, sizeof(cgc->cmd)) ||
|
||||
get_user(data, &cgc32->buffer) ||
|
||||
put_user(compat_ptr(data), &cgc->buffer) ||
|
||||
copy_in_user(&cgc->buflen, &cgc32->buflen,
|
||||
(sizeof(unsigned int) + sizeof(int))) ||
|
||||
get_user(data, &cgc32->sense) ||
|
||||
put_user(compat_ptr(data), &cgc->sense) ||
|
||||
get_user(dir, &cgc32->data_direction) ||
|
||||
put_user(dir, &cgc->data_direction) ||
|
||||
get_user(itmp, &cgc32->quiet) ||
|
||||
put_user(itmp, &cgc->quiet) ||
|
||||
get_user(itmp, &cgc32->timeout) ||
|
||||
put_user(itmp, &cgc->timeout) ||
|
||||
get_user(data, &cgc32->reserved[0]) ||
|
||||
put_user(compat_ptr(data), &cgc->reserved[0]))
|
||||
return -EFAULT;
|
||||
|
||||
return __blkdev_driver_ioctl(bdev, mode, cmd, (unsigned long)cgc);
|
||||
}
|
||||
|
||||
struct compat_blkpg_ioctl_arg {
|
||||
compat_int_t op;
|
||||
compat_int_t flags;
|
||||
compat_int_t datalen;
|
||||
compat_caddr_t data;
|
||||
};
|
||||
|
||||
static int compat_blkpg_ioctl(struct block_device *bdev, fmode_t mode,
|
||||
unsigned int cmd, struct compat_blkpg_ioctl_arg __user *ua32)
|
||||
{
|
||||
struct blkpg_ioctl_arg __user *a = compat_alloc_user_space(sizeof(*a));
|
||||
compat_caddr_t udata;
|
||||
compat_int_t n;
|
||||
int err;
|
||||
|
||||
err = get_user(n, &ua32->op);
|
||||
err |= put_user(n, &a->op);
|
||||
err |= get_user(n, &ua32->flags);
|
||||
err |= put_user(n, &a->flags);
|
||||
err |= get_user(n, &ua32->datalen);
|
||||
err |= put_user(n, &a->datalen);
|
||||
err |= get_user(udata, &ua32->data);
|
||||
err |= put_user(compat_ptr(udata), &a->data);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
return blkdev_ioctl(bdev, mode, cmd, (unsigned long)a);
|
||||
}
|
||||
|
||||
#define BLKBSZGET_32 _IOR(0x12, 112, int)
|
||||
#define BLKBSZSET_32 _IOW(0x12, 113, int)
|
||||
#define BLKGETSIZE64_32 _IOR(0x12, 114, int)
|
||||
|
||||
static int compat_blkdev_driver_ioctl(struct block_device *bdev, fmode_t mode,
|
||||
unsigned cmd, unsigned long arg)
|
||||
{
|
||||
switch (cmd) {
|
||||
case HDIO_GET_UNMASKINTR:
|
||||
case HDIO_GET_MULTCOUNT:
|
||||
case HDIO_GET_KEEPSETTINGS:
|
||||
case HDIO_GET_32BIT:
|
||||
case HDIO_GET_NOWERR:
|
||||
case HDIO_GET_DMA:
|
||||
case HDIO_GET_NICE:
|
||||
case HDIO_GET_WCACHE:
|
||||
case HDIO_GET_ACOUSTIC:
|
||||
case HDIO_GET_ADDRESS:
|
||||
case HDIO_GET_BUSSTATE:
|
||||
return compat_hdio_ioctl(bdev, mode, cmd, arg);
|
||||
case CDROMREADAUDIO:
|
||||
return compat_cdrom_read_audio(bdev, mode, cmd, arg);
|
||||
case CDROM_SEND_PACKET:
|
||||
return compat_cdrom_generic_command(bdev, mode, cmd, arg);
|
||||
|
||||
/*
|
||||
* No handler required for the ones below, we just need to
|
||||
* convert arg to a 64 bit pointer.
|
||||
*/
|
||||
case BLKSECTSET:
|
||||
/*
|
||||
* 0x03 -- HD/IDE ioctl's used by hdparm and friends.
|
||||
* Some need translations, these do not.
|
||||
*/
|
||||
case HDIO_GET_IDENTITY:
|
||||
case HDIO_DRIVE_TASK:
|
||||
case HDIO_DRIVE_CMD:
|
||||
/* 0x330 is reserved -- it used to be HDIO_GETGEO_BIG */
|
||||
case 0x330:
|
||||
/* CDROM stuff */
|
||||
case CDROMPAUSE:
|
||||
case CDROMRESUME:
|
||||
case CDROMPLAYMSF:
|
||||
case CDROMPLAYTRKIND:
|
||||
case CDROMREADTOCHDR:
|
||||
case CDROMREADTOCENTRY:
|
||||
case CDROMSTOP:
|
||||
case CDROMSTART:
|
||||
case CDROMEJECT:
|
||||
case CDROMVOLCTRL:
|
||||
case CDROMSUBCHNL:
|
||||
case CDROMMULTISESSION:
|
||||
case CDROM_GET_MCN:
|
||||
case CDROMRESET:
|
||||
case CDROMVOLREAD:
|
||||
case CDROMSEEK:
|
||||
case CDROMPLAYBLK:
|
||||
case CDROMCLOSETRAY:
|
||||
case CDROM_DISC_STATUS:
|
||||
case CDROM_CHANGER_NSLOTS:
|
||||
case CDROM_GET_CAPABILITY:
|
||||
/* Ignore cdrom.h about these next 5 ioctls, they absolutely do
|
||||
* not take a struct cdrom_read, instead they take a struct cdrom_msf
|
||||
* which is compatible.
|
||||
*/
|
||||
case CDROMREADMODE2:
|
||||
case CDROMREADMODE1:
|
||||
case CDROMREADRAW:
|
||||
case CDROMREADCOOKED:
|
||||
case CDROMREADALL:
|
||||
/* DVD ioctls */
|
||||
case DVD_READ_STRUCT:
|
||||
case DVD_WRITE_STRUCT:
|
||||
case DVD_AUTH:
|
||||
arg = (unsigned long)compat_ptr(arg);
|
||||
/* These intepret arg as an unsigned long, not as a pointer,
|
||||
* so we must not do compat_ptr() conversion. */
|
||||
case HDIO_SET_MULTCOUNT:
|
||||
case HDIO_SET_UNMASKINTR:
|
||||
case HDIO_SET_KEEPSETTINGS:
|
||||
case HDIO_SET_32BIT:
|
||||
case HDIO_SET_NOWERR:
|
||||
case HDIO_SET_DMA:
|
||||
case HDIO_SET_PIO_MODE:
|
||||
case HDIO_SET_NICE:
|
||||
case HDIO_SET_WCACHE:
|
||||
case HDIO_SET_ACOUSTIC:
|
||||
case HDIO_SET_BUSSTATE:
|
||||
case HDIO_SET_ADDRESS:
|
||||
case CDROMEJECT_SW:
|
||||
case CDROM_SET_OPTIONS:
|
||||
case CDROM_CLEAR_OPTIONS:
|
||||
case CDROM_SELECT_SPEED:
|
||||
case CDROM_SELECT_DISC:
|
||||
case CDROM_MEDIA_CHANGED:
|
||||
case CDROM_DRIVE_STATUS:
|
||||
case CDROM_LOCKDOOR:
|
||||
case CDROM_DEBUG:
|
||||
break;
|
||||
default:
|
||||
/* unknown ioctl number */
|
||||
return -ENOIOCTLCMD;
|
||||
}
|
||||
|
||||
return __blkdev_driver_ioctl(bdev, mode, cmd, arg);
|
||||
}
|
||||
|
||||
/* Most of the generic ioctls are handled in the normal fallback path.
|
||||
This assumes the blkdev's low level compat_ioctl always returns
|
||||
ENOIOCTLCMD for unknown ioctls. */
|
||||
long compat_blkdev_ioctl(struct file *file, unsigned cmd, unsigned long arg)
|
||||
{
|
||||
int ret = -ENOIOCTLCMD;
|
||||
struct inode *inode = file->f_mapping->host;
|
||||
struct block_device *bdev = inode->i_bdev;
|
||||
struct gendisk *disk = bdev->bd_disk;
|
||||
fmode_t mode = file->f_mode;
|
||||
loff_t size;
|
||||
unsigned int max_sectors;
|
||||
|
||||
/*
|
||||
* O_NDELAY can be altered using fcntl(.., F_SETFL, ..), so we have
|
||||
* to updated it before every ioctl.
|
||||
*/
|
||||
if (file->f_flags & O_NDELAY)
|
||||
mode |= FMODE_NDELAY;
|
||||
else
|
||||
mode &= ~FMODE_NDELAY;
|
||||
|
||||
switch (cmd) {
|
||||
case HDIO_GETGEO:
|
||||
return compat_hdio_getgeo(disk, bdev, compat_ptr(arg));
|
||||
case BLKPBSZGET:
|
||||
return compat_put_uint(arg, bdev_physical_block_size(bdev));
|
||||
case BLKIOMIN:
|
||||
return compat_put_uint(arg, bdev_io_min(bdev));
|
||||
case BLKIOOPT:
|
||||
return compat_put_uint(arg, bdev_io_opt(bdev));
|
||||
case BLKALIGNOFF:
|
||||
return compat_put_int(arg, bdev_alignment_offset(bdev));
|
||||
case BLKDISCARDZEROES:
|
||||
return compat_put_uint(arg, 0);
|
||||
case BLKFLSBUF:
|
||||
case BLKROSET:
|
||||
case BLKDISCARD:
|
||||
case BLKSECDISCARD:
|
||||
case BLKZEROOUT:
|
||||
/*
|
||||
* the ones below are implemented in blkdev_locked_ioctl,
|
||||
* but we call blkdev_ioctl, which gets the lock for us
|
||||
*/
|
||||
case BLKRRPART:
|
||||
case BLKREPORTZONE:
|
||||
case BLKRESETZONE:
|
||||
case BLKOPENZONE:
|
||||
case BLKCLOSEZONE:
|
||||
case BLKFINISHZONE:
|
||||
case BLKGETZONESZ:
|
||||
case BLKGETNRZONES:
|
||||
return blkdev_ioctl(bdev, mode, cmd,
|
||||
(unsigned long)compat_ptr(arg));
|
||||
case BLKBSZSET_32:
|
||||
return blkdev_ioctl(bdev, mode, BLKBSZSET,
|
||||
(unsigned long)compat_ptr(arg));
|
||||
case BLKPG:
|
||||
return compat_blkpg_ioctl(bdev, mode, cmd, compat_ptr(arg));
|
||||
case BLKRAGET:
|
||||
case BLKFRAGET:
|
||||
if (!arg)
|
||||
return -EINVAL;
|
||||
return compat_put_long(arg,
|
||||
(bdev->bd_bdi->ra_pages * PAGE_SIZE) / 512);
|
||||
case BLKROGET: /* compatible */
|
||||
return compat_put_int(arg, bdev_read_only(bdev) != 0);
|
||||
case BLKBSZGET_32: /* get the logical block size (cf. BLKSSZGET) */
|
||||
return compat_put_int(arg, block_size(bdev));
|
||||
case BLKSSZGET: /* get block device hardware sector size */
|
||||
return compat_put_int(arg, bdev_logical_block_size(bdev));
|
||||
case BLKSECTGET:
|
||||
max_sectors = min_t(unsigned int, USHRT_MAX,
|
||||
queue_max_sectors(bdev_get_queue(bdev)));
|
||||
return compat_put_ushort(arg, max_sectors);
|
||||
case BLKROTATIONAL:
|
||||
return compat_put_ushort(arg,
|
||||
!blk_queue_nonrot(bdev_get_queue(bdev)));
|
||||
case BLKRASET: /* compatible, but no compat_ptr (!) */
|
||||
case BLKFRASET:
|
||||
if (!capable(CAP_SYS_ADMIN))
|
||||
return -EACCES;
|
||||
bdev->bd_bdi->ra_pages = (arg * 512) / PAGE_SIZE;
|
||||
return 0;
|
||||
case BLKGETSIZE:
|
||||
size = i_size_read(bdev->bd_inode);
|
||||
if ((size >> 9) > ~0UL)
|
||||
return -EFBIG;
|
||||
return compat_put_ulong(arg, size >> 9);
|
||||
|
||||
case BLKGETSIZE64_32:
|
||||
return compat_put_u64(arg, i_size_read(bdev->bd_inode));
|
||||
|
||||
case BLKTRACESETUP32:
|
||||
case BLKTRACESTART: /* compatible */
|
||||
case BLKTRACESTOP: /* compatible */
|
||||
case BLKTRACETEARDOWN: /* compatible */
|
||||
ret = blk_trace_ioctl(bdev, cmd, compat_ptr(arg));
|
||||
return ret;
|
||||
case IOC_PR_REGISTER:
|
||||
case IOC_PR_RESERVE:
|
||||
case IOC_PR_RELEASE:
|
||||
case IOC_PR_PREEMPT:
|
||||
case IOC_PR_PREEMPT_ABORT:
|
||||
case IOC_PR_CLEAR:
|
||||
return blkdev_ioctl(bdev, mode, cmd,
|
||||
(unsigned long)compat_ptr(arg));
|
||||
default:
|
||||
if (disk->fops->compat_ioctl)
|
||||
ret = disk->fops->compat_ioctl(bdev, mode, cmd, arg);
|
||||
if (ret == -ENOIOCTLCMD)
|
||||
ret = compat_blkdev_driver_ioctl(bdev, mode, cmd, arg);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
321
block/ioctl.c
321
block/ioctl.c
@@ -1,5 +1,6 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
#include <linux/capability.h>
|
||||
#include <linux/compat.h>
|
||||
#include <linux/blkdev.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/gfp.h>
|
||||
@@ -11,12 +12,12 @@
|
||||
#include <linux/pr.h>
|
||||
#include <linux/uaccess.h>
|
||||
|
||||
static int blkpg_ioctl(struct block_device *bdev, struct blkpg_ioctl_arg __user *arg)
|
||||
static int blkpg_do_ioctl(struct block_device *bdev,
|
||||
struct blkpg_partition __user *upart, int op)
|
||||
{
|
||||
struct block_device *bdevp;
|
||||
struct gendisk *disk;
|
||||
struct hd_struct *part, *lpart;
|
||||
struct blkpg_ioctl_arg a;
|
||||
struct blkpg_partition p;
|
||||
struct disk_part_iter piter;
|
||||
long long start, length;
|
||||
@@ -24,9 +25,7 @@ static int blkpg_ioctl(struct block_device *bdev, struct blkpg_ioctl_arg __user
|
||||
|
||||
if (!capable(CAP_SYS_ADMIN))
|
||||
return -EACCES;
|
||||
if (copy_from_user(&a, arg, sizeof(struct blkpg_ioctl_arg)))
|
||||
return -EFAULT;
|
||||
if (copy_from_user(&p, a.data, sizeof(struct blkpg_partition)))
|
||||
if (copy_from_user(&p, upart, sizeof(struct blkpg_partition)))
|
||||
return -EFAULT;
|
||||
disk = bdev->bd_disk;
|
||||
if (bdev != bdev->bd_contains)
|
||||
@@ -34,7 +33,7 @@ static int blkpg_ioctl(struct block_device *bdev, struct blkpg_ioctl_arg __user
|
||||
partno = p.pno;
|
||||
if (partno <= 0)
|
||||
return -EINVAL;
|
||||
switch (a.op) {
|
||||
switch (op) {
|
||||
case BLKPG_ADD_PARTITION:
|
||||
start = p.start >> 9;
|
||||
length = p.length >> 9;
|
||||
@@ -155,6 +154,39 @@ static int blkpg_ioctl(struct block_device *bdev, struct blkpg_ioctl_arg __user
|
||||
}
|
||||
}
|
||||
|
||||
static int blkpg_ioctl(struct block_device *bdev,
|
||||
struct blkpg_ioctl_arg __user *arg)
|
||||
{
|
||||
struct blkpg_partition __user *udata;
|
||||
int op;
|
||||
|
||||
if (get_user(op, &arg->op) || get_user(udata, &arg->data))
|
||||
return -EFAULT;
|
||||
|
||||
return blkpg_do_ioctl(bdev, udata, op);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_COMPAT
|
||||
struct compat_blkpg_ioctl_arg {
|
||||
compat_int_t op;
|
||||
compat_int_t flags;
|
||||
compat_int_t datalen;
|
||||
compat_caddr_t data;
|
||||
};
|
||||
|
||||
static int compat_blkpg_ioctl(struct block_device *bdev,
|
||||
struct compat_blkpg_ioctl_arg __user *arg)
|
||||
{
|
||||
compat_caddr_t udata;
|
||||
int op;
|
||||
|
||||
if (get_user(op, &arg->op) || get_user(udata, &arg->data))
|
||||
return -EFAULT;
|
||||
|
||||
return blkpg_do_ioctl(bdev, compat_ptr(udata), op);
|
||||
}
|
||||
#endif
|
||||
|
||||
static int blkdev_reread_part(struct block_device *bdev)
|
||||
{
|
||||
int ret;
|
||||
@@ -238,36 +270,48 @@ static int blk_ioctl_zeroout(struct block_device *bdev, fmode_t mode,
|
||||
BLKDEV_ZERO_NOUNMAP);
|
||||
}
|
||||
|
||||
static int put_ushort(unsigned long arg, unsigned short val)
|
||||
static int put_ushort(unsigned short __user *argp, unsigned short val)
|
||||
{
|
||||
return put_user(val, (unsigned short __user *)arg);
|
||||
return put_user(val, argp);
|
||||
}
|
||||
|
||||
static int put_int(unsigned long arg, int val)
|
||||
static int put_int(int __user *argp, int val)
|
||||
{
|
||||
return put_user(val, (int __user *)arg);
|
||||
return put_user(val, argp);
|
||||
}
|
||||
|
||||
static int put_uint(unsigned long arg, unsigned int val)
|
||||
static int put_uint(unsigned int __user *argp, unsigned int val)
|
||||
{
|
||||
return put_user(val, (unsigned int __user *)arg);
|
||||
return put_user(val, argp);
|
||||
}
|
||||
|
||||
static int put_long(unsigned long arg, long val)
|
||||
static int put_long(long __user *argp, long val)
|
||||
{
|
||||
return put_user(val, (long __user *)arg);
|
||||
return put_user(val, argp);
|
||||
}
|
||||
|
||||
static int put_ulong(unsigned long arg, unsigned long val)
|
||||
static int put_ulong(unsigned long __user *argp, unsigned long val)
|
||||
{
|
||||
return put_user(val, (unsigned long __user *)arg);
|
||||
return put_user(val, argp);
|
||||
}
|
||||
|
||||
static int put_u64(unsigned long arg, u64 val)
|
||||
static int put_u64(u64 __user *argp, u64 val)
|
||||
{
|
||||
return put_user(val, (u64 __user *)arg);
|
||||
return put_user(val, argp);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_COMPAT
|
||||
static int compat_put_long(compat_long_t *argp, long val)
|
||||
{
|
||||
return put_user(val, argp);
|
||||
}
|
||||
|
||||
static int compat_put_ulong(compat_ulong_t *argp, compat_ulong_t val)
|
||||
{
|
||||
return put_user(val, argp);
|
||||
}
|
||||
#endif
|
||||
|
||||
int __blkdev_driver_ioctl(struct block_device *bdev, fmode_t mode,
|
||||
unsigned cmd, unsigned long arg)
|
||||
{
|
||||
@@ -285,6 +329,26 @@ int __blkdev_driver_ioctl(struct block_device *bdev, fmode_t mode,
|
||||
*/
|
||||
EXPORT_SYMBOL_GPL(__blkdev_driver_ioctl);
|
||||
|
||||
#ifdef CONFIG_COMPAT
|
||||
/*
|
||||
* This is the equivalent of compat_ptr_ioctl(), to be used by block
|
||||
* drivers that implement only commands that are completely compatible
|
||||
* between 32-bit and 64-bit user space
|
||||
*/
|
||||
int blkdev_compat_ptr_ioctl(struct block_device *bdev, fmode_t mode,
|
||||
unsigned cmd, unsigned long arg)
|
||||
{
|
||||
struct gendisk *disk = bdev->bd_disk;
|
||||
|
||||
if (disk->fops->ioctl)
|
||||
return disk->fops->ioctl(bdev, mode, cmd,
|
||||
(unsigned long)compat_ptr(arg));
|
||||
|
||||
return -ENOIOCTLCMD;
|
||||
}
|
||||
EXPORT_SYMBOL(blkdev_compat_ptr_ioctl);
|
||||
#endif
|
||||
|
||||
static int blkdev_pr_register(struct block_device *bdev,
|
||||
struct pr_registration __user *arg)
|
||||
{
|
||||
@@ -455,6 +519,45 @@ static int blkdev_getgeo(struct block_device *bdev,
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_COMPAT
|
||||
struct compat_hd_geometry {
|
||||
unsigned char heads;
|
||||
unsigned char sectors;
|
||||
unsigned short cylinders;
|
||||
u32 start;
|
||||
};
|
||||
|
||||
static int compat_hdio_getgeo(struct block_device *bdev,
|
||||
struct compat_hd_geometry __user *ugeo)
|
||||
{
|
||||
struct gendisk *disk = bdev->bd_disk;
|
||||
struct hd_geometry geo;
|
||||
int ret;
|
||||
|
||||
if (!ugeo)
|
||||
return -EINVAL;
|
||||
if (!disk->fops->getgeo)
|
||||
return -ENOTTY;
|
||||
|
||||
memset(&geo, 0, sizeof(geo));
|
||||
/*
|
||||
* We need to set the startsect first, the driver may
|
||||
* want to override it.
|
||||
*/
|
||||
geo.start = get_start_sect(bdev);
|
||||
ret = disk->fops->getgeo(bdev, &geo);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = copy_to_user(ugeo, &geo, 4);
|
||||
ret |= put_user(geo.start, &ugeo->start);
|
||||
if (ret)
|
||||
ret = -EFAULT;
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* set the logical block size */
|
||||
static int blkdev_bszset(struct block_device *bdev, fmode_t mode,
|
||||
int __user *argp)
|
||||
@@ -481,13 +584,13 @@ static int blkdev_bszset(struct block_device *bdev, fmode_t mode,
|
||||
}
|
||||
|
||||
/*
|
||||
* always keep this in sync with compat_blkdev_ioctl()
|
||||
* Common commands that are handled the same way on native and compat
|
||||
* user space. Note the separate arg/argp parameters that are needed
|
||||
* to deal with the compat_ptr() conversion.
|
||||
*/
|
||||
int blkdev_ioctl(struct block_device *bdev, fmode_t mode, unsigned cmd,
|
||||
unsigned long arg)
|
||||
static int blkdev_common_ioctl(struct block_device *bdev, fmode_t mode,
|
||||
unsigned cmd, unsigned long arg, void __user *argp)
|
||||
{
|
||||
void __user *argp = (void __user *)arg;
|
||||
loff_t size;
|
||||
unsigned int max_sectors;
|
||||
|
||||
switch (cmd) {
|
||||
@@ -510,60 +613,39 @@ int blkdev_ioctl(struct block_device *bdev, fmode_t mode, unsigned cmd,
|
||||
case BLKFINISHZONE:
|
||||
return blkdev_zone_mgmt_ioctl(bdev, mode, cmd, arg);
|
||||
case BLKGETZONESZ:
|
||||
return put_uint(arg, bdev_zone_sectors(bdev));
|
||||
return put_uint(argp, bdev_zone_sectors(bdev));
|
||||
case BLKGETNRZONES:
|
||||
return put_uint(arg, blkdev_nr_zones(bdev->bd_disk));
|
||||
case HDIO_GETGEO:
|
||||
return blkdev_getgeo(bdev, argp);
|
||||
case BLKRAGET:
|
||||
case BLKFRAGET:
|
||||
if (!arg)
|
||||
return -EINVAL;
|
||||
return put_long(arg, (bdev->bd_bdi->ra_pages*PAGE_SIZE) / 512);
|
||||
return put_uint(argp, blkdev_nr_zones(bdev->bd_disk));
|
||||
case BLKROGET:
|
||||
return put_int(arg, bdev_read_only(bdev) != 0);
|
||||
case BLKBSZGET: /* get block device soft block size (cf. BLKSSZGET) */
|
||||
return put_int(arg, block_size(bdev));
|
||||
return put_int(argp, bdev_read_only(bdev) != 0);
|
||||
case BLKSSZGET: /* get block device logical block size */
|
||||
return put_int(arg, bdev_logical_block_size(bdev));
|
||||
return put_int(argp, bdev_logical_block_size(bdev));
|
||||
case BLKPBSZGET: /* get block device physical block size */
|
||||
return put_uint(arg, bdev_physical_block_size(bdev));
|
||||
return put_uint(argp, bdev_physical_block_size(bdev));
|
||||
case BLKIOMIN:
|
||||
return put_uint(arg, bdev_io_min(bdev));
|
||||
return put_uint(argp, bdev_io_min(bdev));
|
||||
case BLKIOOPT:
|
||||
return put_uint(arg, bdev_io_opt(bdev));
|
||||
return put_uint(argp, bdev_io_opt(bdev));
|
||||
case BLKALIGNOFF:
|
||||
return put_int(arg, bdev_alignment_offset(bdev));
|
||||
return put_int(argp, bdev_alignment_offset(bdev));
|
||||
case BLKDISCARDZEROES:
|
||||
return put_uint(arg, 0);
|
||||
return put_uint(argp, 0);
|
||||
case BLKSECTGET:
|
||||
max_sectors = min_t(unsigned int, USHRT_MAX,
|
||||
queue_max_sectors(bdev_get_queue(bdev)));
|
||||
return put_ushort(arg, max_sectors);
|
||||
return put_ushort(argp, max_sectors);
|
||||
case BLKROTATIONAL:
|
||||
return put_ushort(arg, !blk_queue_nonrot(bdev_get_queue(bdev)));
|
||||
return put_ushort(argp, !blk_queue_nonrot(bdev_get_queue(bdev)));
|
||||
case BLKRASET:
|
||||
case BLKFRASET:
|
||||
if(!capable(CAP_SYS_ADMIN))
|
||||
return -EACCES;
|
||||
bdev->bd_bdi->ra_pages = (arg * 512) / PAGE_SIZE;
|
||||
return 0;
|
||||
case BLKBSZSET:
|
||||
return blkdev_bszset(bdev, mode, argp);
|
||||
case BLKPG:
|
||||
return blkpg_ioctl(bdev, argp);
|
||||
case BLKRRPART:
|
||||
return blkdev_reread_part(bdev);
|
||||
case BLKGETSIZE:
|
||||
size = i_size_read(bdev->bd_inode);
|
||||
if ((size >> 9) > ~0UL)
|
||||
return -EFBIG;
|
||||
return put_ulong(arg, size >> 9);
|
||||
case BLKGETSIZE64:
|
||||
return put_u64(arg, i_size_read(bdev->bd_inode));
|
||||
case BLKTRACESTART:
|
||||
case BLKTRACESTOP:
|
||||
case BLKTRACESETUP:
|
||||
case BLKTRACETEARDOWN:
|
||||
return blk_trace_ioctl(bdev, cmd, argp);
|
||||
case IOC_PR_REGISTER:
|
||||
@@ -579,7 +661,132 @@ int blkdev_ioctl(struct block_device *bdev, fmode_t mode, unsigned cmd,
|
||||
case IOC_PR_CLEAR:
|
||||
return blkdev_pr_clear(bdev, argp);
|
||||
default:
|
||||
return __blkdev_driver_ioctl(bdev, mode, cmd, arg);
|
||||
return -ENOIOCTLCMD;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(blkdev_ioctl);
|
||||
|
||||
/*
|
||||
* Always keep this in sync with compat_blkdev_ioctl()
|
||||
* to handle all incompatible commands in both functions.
|
||||
*
|
||||
* New commands must be compatible and go into blkdev_common_ioctl
|
||||
*/
|
||||
int blkdev_ioctl(struct block_device *bdev, fmode_t mode, unsigned cmd,
|
||||
unsigned long arg)
|
||||
{
|
||||
int ret;
|
||||
loff_t size;
|
||||
void __user *argp = (void __user *)arg;
|
||||
|
||||
switch (cmd) {
|
||||
/* These need separate implementations for the data structure */
|
||||
case HDIO_GETGEO:
|
||||
return blkdev_getgeo(bdev, argp);
|
||||
case BLKPG:
|
||||
return blkpg_ioctl(bdev, argp);
|
||||
|
||||
/* Compat mode returns 32-bit data instead of 'long' */
|
||||
case BLKRAGET:
|
||||
case BLKFRAGET:
|
||||
if (!argp)
|
||||
return -EINVAL;
|
||||
return put_long(argp, (bdev->bd_bdi->ra_pages*PAGE_SIZE) / 512);
|
||||
case BLKGETSIZE:
|
||||
size = i_size_read(bdev->bd_inode);
|
||||
if ((size >> 9) > ~0UL)
|
||||
return -EFBIG;
|
||||
return put_ulong(argp, size >> 9);
|
||||
|
||||
/* The data is compatible, but the command number is different */
|
||||
case BLKBSZGET: /* get block device soft block size (cf. BLKSSZGET) */
|
||||
return put_int(argp, block_size(bdev));
|
||||
case BLKBSZSET:
|
||||
return blkdev_bszset(bdev, mode, argp);
|
||||
case BLKGETSIZE64:
|
||||
return put_u64(argp, i_size_read(bdev->bd_inode));
|
||||
|
||||
/* Incompatible alignment on i386 */
|
||||
case BLKTRACESETUP:
|
||||
return blk_trace_ioctl(bdev, cmd, argp);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
ret = blkdev_common_ioctl(bdev, mode, cmd, arg, argp);
|
||||
if (ret == -ENOIOCTLCMD)
|
||||
return __blkdev_driver_ioctl(bdev, mode, cmd, arg);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(blkdev_ioctl); /* for /dev/raw */
|
||||
|
||||
#ifdef CONFIG_COMPAT
|
||||
|
||||
#define BLKBSZGET_32 _IOR(0x12, 112, int)
|
||||
#define BLKBSZSET_32 _IOW(0x12, 113, int)
|
||||
#define BLKGETSIZE64_32 _IOR(0x12, 114, int)
|
||||
|
||||
/* Most of the generic ioctls are handled in the normal fallback path.
|
||||
This assumes the blkdev's low level compat_ioctl always returns
|
||||
ENOIOCTLCMD for unknown ioctls. */
|
||||
long compat_blkdev_ioctl(struct file *file, unsigned cmd, unsigned long arg)
|
||||
{
|
||||
int ret;
|
||||
void __user *argp = compat_ptr(arg);
|
||||
struct inode *inode = file->f_mapping->host;
|
||||
struct block_device *bdev = inode->i_bdev;
|
||||
struct gendisk *disk = bdev->bd_disk;
|
||||
fmode_t mode = file->f_mode;
|
||||
loff_t size;
|
||||
|
||||
/*
|
||||
* O_NDELAY can be altered using fcntl(.., F_SETFL, ..), so we have
|
||||
* to updated it before every ioctl.
|
||||
*/
|
||||
if (file->f_flags & O_NDELAY)
|
||||
mode |= FMODE_NDELAY;
|
||||
else
|
||||
mode &= ~FMODE_NDELAY;
|
||||
|
||||
switch (cmd) {
|
||||
/* These need separate implementations for the data structure */
|
||||
case HDIO_GETGEO:
|
||||
return compat_hdio_getgeo(bdev, argp);
|
||||
case BLKPG:
|
||||
return compat_blkpg_ioctl(bdev, argp);
|
||||
|
||||
/* Compat mode returns 32-bit data instead of 'long' */
|
||||
case BLKRAGET:
|
||||
case BLKFRAGET:
|
||||
if (!argp)
|
||||
return -EINVAL;
|
||||
return compat_put_long(argp,
|
||||
(bdev->bd_bdi->ra_pages * PAGE_SIZE) / 512);
|
||||
case BLKGETSIZE:
|
||||
size = i_size_read(bdev->bd_inode);
|
||||
if ((size >> 9) > ~0UL)
|
||||
return -EFBIG;
|
||||
return compat_put_ulong(argp, size >> 9);
|
||||
|
||||
/* The data is compatible, but the command number is different */
|
||||
case BLKBSZGET_32: /* get the logical block size (cf. BLKSSZGET) */
|
||||
return put_int(argp, bdev_logical_block_size(bdev));
|
||||
case BLKBSZSET_32:
|
||||
return blkdev_bszset(bdev, mode, argp);
|
||||
case BLKGETSIZE64_32:
|
||||
return put_u64(argp, i_size_read(bdev->bd_inode));
|
||||
|
||||
/* Incompatible alignment on i386 */
|
||||
case BLKTRACESETUP32:
|
||||
return blk_trace_ioctl(bdev, cmd, argp);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
ret = blkdev_common_ioctl(bdev, mode, cmd, arg, argp);
|
||||
if (ret == -ENOIOCTLCMD && disk->fops->compat_ioctl)
|
||||
ret = disk->fops->compat_ioctl(bdev, mode, cmd, arg);
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include <scsi/scsi.h>
|
||||
#include <scsi/scsi_ioctl.h>
|
||||
#include <scsi/scsi_cmnd.h>
|
||||
#include <scsi/sg.h>
|
||||
|
||||
struct blk_cmd_filter {
|
||||
unsigned long read_ok[BLK_SCSI_CMD_PER_LONG];
|
||||
@@ -550,34 +551,6 @@ static inline int blk_send_start_stop(struct request_queue *q,
|
||||
return __blk_send_generic(q, bd_disk, GPCMD_START_STOP_UNIT, data);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_COMPAT
|
||||
struct compat_sg_io_hdr {
|
||||
compat_int_t interface_id; /* [i] 'S' for SCSI generic (required) */
|
||||
compat_int_t dxfer_direction; /* [i] data transfer direction */
|
||||
unsigned char cmd_len; /* [i] SCSI command length ( <= 16 bytes) */
|
||||
unsigned char mx_sb_len; /* [i] max length to write to sbp */
|
||||
unsigned short iovec_count; /* [i] 0 implies no scatter gather */
|
||||
compat_uint_t dxfer_len; /* [i] byte count of data transfer */
|
||||
compat_uint_t dxferp; /* [i], [*io] points to data transfer memory
|
||||
or scatter gather list */
|
||||
compat_uptr_t cmdp; /* [i], [*i] points to command to perform */
|
||||
compat_uptr_t sbp; /* [i], [*o] points to sense_buffer memory */
|
||||
compat_uint_t timeout; /* [i] MAX_UINT->no timeout (unit: millisec) */
|
||||
compat_uint_t flags; /* [i] 0 -> default, see SG_FLAG... */
|
||||
compat_int_t pack_id; /* [i->o] unused internally (normally) */
|
||||
compat_uptr_t usr_ptr; /* [i->o] unused internally */
|
||||
unsigned char status; /* [o] scsi status */
|
||||
unsigned char masked_status; /* [o] shifted, masked scsi status */
|
||||
unsigned char msg_status; /* [o] messaging level data (optional) */
|
||||
unsigned char sb_len_wr; /* [o] byte count actually written to sbp */
|
||||
unsigned short host_status; /* [o] errors from host adapter */
|
||||
unsigned short driver_status; /* [o] errors from software driver */
|
||||
compat_int_t resid; /* [o] dxfer_len - actual_transferred */
|
||||
compat_uint_t duration; /* [o] time taken by cmd (unit: millisec) */
|
||||
compat_uint_t info; /* [o] auxiliary information */
|
||||
};
|
||||
#endif
|
||||
|
||||
int put_sg_io_hdr(const struct sg_io_hdr *hdr, void __user *argp)
|
||||
{
|
||||
#ifdef CONFIG_COMPAT
|
||||
@@ -666,6 +639,136 @@ int get_sg_io_hdr(struct sg_io_hdr *hdr, const void __user *argp)
|
||||
}
|
||||
EXPORT_SYMBOL(get_sg_io_hdr);
|
||||
|
||||
#ifdef CONFIG_COMPAT
|
||||
struct compat_cdrom_generic_command {
|
||||
unsigned char cmd[CDROM_PACKET_SIZE];
|
||||
compat_caddr_t buffer;
|
||||
compat_uint_t buflen;
|
||||
compat_int_t stat;
|
||||
compat_caddr_t sense;
|
||||
unsigned char data_direction;
|
||||
compat_int_t quiet;
|
||||
compat_int_t timeout;
|
||||
compat_caddr_t reserved[1];
|
||||
};
|
||||
#endif
|
||||
|
||||
static int scsi_get_cdrom_generic_arg(struct cdrom_generic_command *cgc,
|
||||
const void __user *arg)
|
||||
{
|
||||
#ifdef CONFIG_COMPAT
|
||||
if (in_compat_syscall()) {
|
||||
struct compat_cdrom_generic_command cgc32;
|
||||
|
||||
if (copy_from_user(&cgc32, arg, sizeof(cgc32)))
|
||||
return -EFAULT;
|
||||
|
||||
*cgc = (struct cdrom_generic_command) {
|
||||
.buffer = compat_ptr(cgc32.buffer),
|
||||
.buflen = cgc32.buflen,
|
||||
.stat = cgc32.stat,
|
||||
.sense = compat_ptr(cgc32.sense),
|
||||
.data_direction = cgc32.data_direction,
|
||||
.quiet = cgc32.quiet,
|
||||
.timeout = cgc32.timeout,
|
||||
.reserved[0] = compat_ptr(cgc32.reserved[0]),
|
||||
};
|
||||
memcpy(&cgc->cmd, &cgc32.cmd, CDROM_PACKET_SIZE);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
if (copy_from_user(cgc, arg, sizeof(*cgc)))
|
||||
return -EFAULT;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int scsi_put_cdrom_generic_arg(const struct cdrom_generic_command *cgc,
|
||||
void __user *arg)
|
||||
{
|
||||
#ifdef CONFIG_COMPAT
|
||||
if (in_compat_syscall()) {
|
||||
struct compat_cdrom_generic_command cgc32 = {
|
||||
.buffer = (uintptr_t)(cgc->buffer),
|
||||
.buflen = cgc->buflen,
|
||||
.stat = cgc->stat,
|
||||
.sense = (uintptr_t)(cgc->sense),
|
||||
.data_direction = cgc->data_direction,
|
||||
.quiet = cgc->quiet,
|
||||
.timeout = cgc->timeout,
|
||||
.reserved[0] = (uintptr_t)(cgc->reserved[0]),
|
||||
};
|
||||
memcpy(&cgc32.cmd, &cgc->cmd, CDROM_PACKET_SIZE);
|
||||
|
||||
if (copy_to_user(arg, &cgc32, sizeof(cgc32)))
|
||||
return -EFAULT;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
if (copy_to_user(arg, cgc, sizeof(*cgc)))
|
||||
return -EFAULT;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int scsi_cdrom_send_packet(struct request_queue *q,
|
||||
struct gendisk *bd_disk,
|
||||
fmode_t mode, void __user *arg)
|
||||
{
|
||||
struct cdrom_generic_command cgc;
|
||||
struct sg_io_hdr hdr;
|
||||
int err;
|
||||
|
||||
err = scsi_get_cdrom_generic_arg(&cgc, arg);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
cgc.timeout = clock_t_to_jiffies(cgc.timeout);
|
||||
memset(&hdr, 0, sizeof(hdr));
|
||||
hdr.interface_id = 'S';
|
||||
hdr.cmd_len = sizeof(cgc.cmd);
|
||||
hdr.dxfer_len = cgc.buflen;
|
||||
switch (cgc.data_direction) {
|
||||
case CGC_DATA_UNKNOWN:
|
||||
hdr.dxfer_direction = SG_DXFER_UNKNOWN;
|
||||
break;
|
||||
case CGC_DATA_WRITE:
|
||||
hdr.dxfer_direction = SG_DXFER_TO_DEV;
|
||||
break;
|
||||
case CGC_DATA_READ:
|
||||
hdr.dxfer_direction = SG_DXFER_FROM_DEV;
|
||||
break;
|
||||
case CGC_DATA_NONE:
|
||||
hdr.dxfer_direction = SG_DXFER_NONE;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
hdr.dxferp = cgc.buffer;
|
||||
hdr.sbp = cgc.sense;
|
||||
if (hdr.sbp)
|
||||
hdr.mx_sb_len = sizeof(struct request_sense);
|
||||
hdr.timeout = jiffies_to_msecs(cgc.timeout);
|
||||
hdr.cmdp = ((struct cdrom_generic_command __user*) arg)->cmd;
|
||||
hdr.cmd_len = sizeof(cgc.cmd);
|
||||
|
||||
err = sg_io(q, bd_disk, &hdr, mode);
|
||||
if (err == -EFAULT)
|
||||
return -EFAULT;
|
||||
|
||||
if (hdr.status)
|
||||
return -EIO;
|
||||
|
||||
cgc.stat = err;
|
||||
cgc.buflen = hdr.resid;
|
||||
if (scsi_put_cdrom_generic_arg(&cgc, arg))
|
||||
return -EFAULT;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int scsi_cmd_ioctl(struct request_queue *q, struct gendisk *bd_disk, fmode_t mode,
|
||||
unsigned int cmd, void __user *arg)
|
||||
{
|
||||
@@ -716,60 +819,9 @@ int scsi_cmd_ioctl(struct request_queue *q, struct gendisk *bd_disk, fmode_t mod
|
||||
err = -EFAULT;
|
||||
break;
|
||||
}
|
||||
case CDROM_SEND_PACKET: {
|
||||
struct cdrom_generic_command cgc;
|
||||
struct sg_io_hdr hdr;
|
||||
|
||||
err = -EFAULT;
|
||||
if (copy_from_user(&cgc, arg, sizeof(cgc)))
|
||||
break;
|
||||
cgc.timeout = clock_t_to_jiffies(cgc.timeout);
|
||||
memset(&hdr, 0, sizeof(hdr));
|
||||
hdr.interface_id = 'S';
|
||||
hdr.cmd_len = sizeof(cgc.cmd);
|
||||
hdr.dxfer_len = cgc.buflen;
|
||||
err = 0;
|
||||
switch (cgc.data_direction) {
|
||||
case CGC_DATA_UNKNOWN:
|
||||
hdr.dxfer_direction = SG_DXFER_UNKNOWN;
|
||||
break;
|
||||
case CGC_DATA_WRITE:
|
||||
hdr.dxfer_direction = SG_DXFER_TO_DEV;
|
||||
break;
|
||||
case CGC_DATA_READ:
|
||||
hdr.dxfer_direction = SG_DXFER_FROM_DEV;
|
||||
break;
|
||||
case CGC_DATA_NONE:
|
||||
hdr.dxfer_direction = SG_DXFER_NONE;
|
||||
break;
|
||||
default:
|
||||
err = -EINVAL;
|
||||
}
|
||||
if (err)
|
||||
break;
|
||||
|
||||
hdr.dxferp = cgc.buffer;
|
||||
hdr.sbp = cgc.sense;
|
||||
if (hdr.sbp)
|
||||
hdr.mx_sb_len = sizeof(struct request_sense);
|
||||
hdr.timeout = jiffies_to_msecs(cgc.timeout);
|
||||
hdr.cmdp = ((struct cdrom_generic_command __user*) arg)->cmd;
|
||||
hdr.cmd_len = sizeof(cgc.cmd);
|
||||
|
||||
err = sg_io(q, bd_disk, &hdr, mode);
|
||||
if (err == -EFAULT)
|
||||
break;
|
||||
|
||||
if (hdr.status)
|
||||
err = -EIO;
|
||||
|
||||
cgc.stat = err;
|
||||
cgc.buflen = hdr.resid;
|
||||
if (copy_to_user(arg, &cgc, sizeof(cgc)))
|
||||
err = -EFAULT;
|
||||
|
||||
case CDROM_SEND_PACKET:
|
||||
err = scsi_cdrom_send_packet(q, bd_disk, mode, arg);
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* old junk scsi send command ioctl
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
* - http://www.t13.org/
|
||||
*/
|
||||
|
||||
#include <linux/compat.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/blkdev.h>
|
||||
@@ -761,6 +762,10 @@ static int ata_ioc32(struct ata_port *ap)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* This handles both native and compat commands, so anything added
|
||||
* here must have a compatible argument, or check in_compat_syscall()
|
||||
*/
|
||||
int ata_sas_scsi_ioctl(struct ata_port *ap, struct scsi_device *scsidev,
|
||||
unsigned int cmd, void __user *arg)
|
||||
{
|
||||
@@ -773,6 +778,10 @@ int ata_sas_scsi_ioctl(struct ata_port *ap, struct scsi_device *scsidev,
|
||||
spin_lock_irqsave(ap->lock, flags);
|
||||
val = ata_ioc32(ap);
|
||||
spin_unlock_irqrestore(ap->lock, flags);
|
||||
#ifdef CONFIG_COMPAT
|
||||
if (in_compat_syscall())
|
||||
return put_user(val, (compat_ulong_t __user *)arg);
|
||||
#endif
|
||||
return put_user(val, (unsigned long __user *)arg);
|
||||
|
||||
case HDIO_SET_32BIT:
|
||||
|
||||
@@ -236,6 +236,109 @@ attribute_container_remove_device(struct device *dev,
|
||||
mutex_unlock(&attribute_container_mutex);
|
||||
}
|
||||
|
||||
static int
|
||||
do_attribute_container_device_trigger_safe(struct device *dev,
|
||||
struct attribute_container *cont,
|
||||
int (*fn)(struct attribute_container *,
|
||||
struct device *, struct device *),
|
||||
int (*undo)(struct attribute_container *,
|
||||
struct device *, struct device *))
|
||||
{
|
||||
int ret;
|
||||
struct internal_container *ic, *failed;
|
||||
struct klist_iter iter;
|
||||
|
||||
if (attribute_container_no_classdevs(cont))
|
||||
return fn(cont, dev, NULL);
|
||||
|
||||
klist_for_each_entry(ic, &cont->containers, node, &iter) {
|
||||
if (dev == ic->classdev.parent) {
|
||||
ret = fn(cont, dev, &ic->classdev);
|
||||
if (ret) {
|
||||
failed = ic;
|
||||
klist_iter_exit(&iter);
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
if (!undo)
|
||||
return ret;
|
||||
|
||||
/* Attempt to undo the work partially done. */
|
||||
klist_for_each_entry(ic, &cont->containers, node, &iter) {
|
||||
if (ic == failed) {
|
||||
klist_iter_exit(&iter);
|
||||
break;
|
||||
}
|
||||
if (dev == ic->classdev.parent)
|
||||
undo(cont, dev, &ic->classdev);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* attribute_container_device_trigger_safe - execute a trigger for each
|
||||
* matching classdev or fail all of them.
|
||||
*
|
||||
* @dev: The generic device to run the trigger for
|
||||
* @fn the function to execute for each classdev.
|
||||
* @undo A function to undo the work previously done in case of error
|
||||
*
|
||||
* This function is a safe version of
|
||||
* attribute_container_device_trigger. It stops on the first error and
|
||||
* undo the partial work that has been done, on previous classdev. It
|
||||
* is guaranteed that either they all succeeded, or none of them
|
||||
* succeeded.
|
||||
*/
|
||||
int
|
||||
attribute_container_device_trigger_safe(struct device *dev,
|
||||
int (*fn)(struct attribute_container *,
|
||||
struct device *,
|
||||
struct device *),
|
||||
int (*undo)(struct attribute_container *,
|
||||
struct device *,
|
||||
struct device *))
|
||||
{
|
||||
struct attribute_container *cont, *failed = NULL;
|
||||
int ret = 0;
|
||||
|
||||
mutex_lock(&attribute_container_mutex);
|
||||
|
||||
list_for_each_entry(cont, &attribute_container_list, node) {
|
||||
|
||||
if (!cont->match(cont, dev))
|
||||
continue;
|
||||
|
||||
ret = do_attribute_container_device_trigger_safe(dev, cont,
|
||||
fn, undo);
|
||||
if (ret) {
|
||||
failed = cont;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (ret && !WARN_ON(!undo)) {
|
||||
list_for_each_entry(cont, &attribute_container_list, node) {
|
||||
|
||||
if (failed == cont)
|
||||
break;
|
||||
|
||||
if (!cont->match(cont, dev))
|
||||
continue;
|
||||
|
||||
do_attribute_container_device_trigger_safe(dev, cont,
|
||||
undo, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
mutex_unlock(&attribute_container_mutex);
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* attribute_container_device_trigger - execute a trigger for each matching classdev
|
||||
*
|
||||
|
||||
@@ -30,6 +30,10 @@
|
||||
#include <linux/attribute_container.h>
|
||||
#include <linux/transport_class.h>
|
||||
|
||||
static int transport_remove_classdev(struct attribute_container *cont,
|
||||
struct device *dev,
|
||||
struct device *classdev);
|
||||
|
||||
/**
|
||||
* transport_class_register - register an initial transport class
|
||||
*
|
||||
@@ -172,10 +176,11 @@ static int transport_add_class_device(struct attribute_container *cont,
|
||||
* routine is simply a trigger point used to add the device to the
|
||||
* system and register attributes for it.
|
||||
*/
|
||||
|
||||
void transport_add_device(struct device *dev)
|
||||
int transport_add_device(struct device *dev)
|
||||
{
|
||||
attribute_container_device_trigger(dev, transport_add_class_device);
|
||||
return attribute_container_device_trigger_safe(dev,
|
||||
transport_add_class_device,
|
||||
transport_remove_classdev);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(transport_add_device);
|
||||
|
||||
|
||||
@@ -329,6 +329,7 @@ static const struct block_device_operations aoe_bdops = {
|
||||
.open = aoeblk_open,
|
||||
.release = aoeblk_release,
|
||||
.ioctl = aoeblk_ioctl,
|
||||
.compat_ioctl = blkdev_compat_ptr_ioctl,
|
||||
.getgeo = aoeblk_getgeo,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
@@ -3879,6 +3879,9 @@ static int fd_compat_ioctl(struct block_device *bdev, fmode_t mode, unsigned int
|
||||
{
|
||||
int drive = (long)bdev->bd_disk->private_data;
|
||||
switch (cmd) {
|
||||
case CDROMEJECT: /* CD-ROM eject */
|
||||
case 0x6470: /* SunOS floppy eject */
|
||||
|
||||
case FDMSGON:
|
||||
case FDMSGOFF:
|
||||
case FDSETEMSGTRESH:
|
||||
|
||||
@@ -275,6 +275,9 @@ static const struct block_device_operations pcd_bdops = {
|
||||
.open = pcd_block_open,
|
||||
.release = pcd_block_release,
|
||||
.ioctl = pcd_block_ioctl,
|
||||
#ifdef CONFIG_COMPAT
|
||||
.ioctl = blkdev_compat_ptr_ioctl,
|
||||
#endif
|
||||
.check_events = pcd_block_check_events,
|
||||
};
|
||||
|
||||
|
||||
@@ -874,6 +874,7 @@ static const struct block_device_operations pd_fops = {
|
||||
.open = pd_open,
|
||||
.release = pd_release,
|
||||
.ioctl = pd_ioctl,
|
||||
.compat_ioctl = pd_ioctl,
|
||||
.getgeo = pd_getgeo,
|
||||
.check_events = pd_check_events,
|
||||
.revalidate_disk= pd_revalidate
|
||||
|
||||
@@ -276,6 +276,7 @@ static const struct block_device_operations pf_fops = {
|
||||
.open = pf_open,
|
||||
.release = pf_release,
|
||||
.ioctl = pf_ioctl,
|
||||
.compat_ioctl = pf_ioctl,
|
||||
.getgeo = pf_getgeo,
|
||||
.check_events = pf_check_events,
|
||||
};
|
||||
|
||||
@@ -2663,28 +2663,6 @@ static int pkt_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd,
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_COMPAT
|
||||
static int pkt_compat_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
switch (cmd) {
|
||||
/* compatible */
|
||||
case CDROMEJECT:
|
||||
case CDROMMULTISESSION:
|
||||
case CDROMREADTOCENTRY:
|
||||
case SCSI_IOCTL_SEND_COMMAND:
|
||||
return pkt_ioctl(bdev, mode, cmd, (unsigned long)compat_ptr(arg));
|
||||
|
||||
|
||||
/* FIXME: no handler so far */
|
||||
case CDROM_LAST_WRITTEN:
|
||||
/* handled in compat_blkdev_driver_ioctl */
|
||||
case CDROM_SEND_PACKET:
|
||||
default:
|
||||
return -ENOIOCTLCMD;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static unsigned int pkt_check_events(struct gendisk *disk,
|
||||
unsigned int clearing)
|
||||
{
|
||||
@@ -2706,9 +2684,7 @@ static const struct block_device_operations pktcdvd_ops = {
|
||||
.open = pkt_open,
|
||||
.release = pkt_close,
|
||||
.ioctl = pkt_ioctl,
|
||||
#ifdef CONFIG_COMPAT
|
||||
.compat_ioctl = pkt_compat_ioctl,
|
||||
#endif
|
||||
.compat_ioctl = blkdev_compat_ptr_ioctl,
|
||||
.check_events = pkt_check_events,
|
||||
};
|
||||
|
||||
|
||||
@@ -171,6 +171,7 @@ static const struct block_device_operations vdc_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.getgeo = vdc_getgeo,
|
||||
.ioctl = vdc_ioctl,
|
||||
.compat_ioctl = blkdev_compat_ptr_ioctl,
|
||||
};
|
||||
|
||||
static void vdc_blk_queue_start(struct vdc_port *port)
|
||||
|
||||
@@ -405,6 +405,9 @@ static int virtblk_getgeo(struct block_device *bd, struct hd_geometry *geo)
|
||||
|
||||
static const struct block_device_operations virtblk_fops = {
|
||||
.ioctl = virtblk_ioctl,
|
||||
#ifdef CONFIG_COMPAT
|
||||
.compat_ioctl = blkdev_compat_ptr_ioctl,
|
||||
#endif
|
||||
.owner = THIS_MODULE,
|
||||
.getgeo = virtblk_getgeo,
|
||||
};
|
||||
|
||||
@@ -2632,6 +2632,7 @@ static const struct block_device_operations xlvbd_block_fops =
|
||||
.release = blkif_release,
|
||||
.getgeo = blkif_getgeo,
|
||||
.ioctl = blkif_ioctl,
|
||||
.compat_ioctl = blkdev_compat_ptr_ioctl,
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -3017,9 +3017,31 @@ static noinline int mmc_ioctl_cdrom_read_audio(struct cdrom_device_info *cdi,
|
||||
struct cdrom_read_audio ra;
|
||||
int lba;
|
||||
|
||||
if (copy_from_user(&ra, (struct cdrom_read_audio __user *)arg,
|
||||
sizeof(ra)))
|
||||
return -EFAULT;
|
||||
#ifdef CONFIG_COMPAT
|
||||
if (in_compat_syscall()) {
|
||||
struct compat_cdrom_read_audio {
|
||||
union cdrom_addr addr;
|
||||
u8 addr_format;
|
||||
compat_int_t nframes;
|
||||
compat_caddr_t buf;
|
||||
} ra32;
|
||||
|
||||
if (copy_from_user(&ra32, arg, sizeof(ra32)))
|
||||
return -EFAULT;
|
||||
|
||||
ra = (struct cdrom_read_audio) {
|
||||
.addr = ra32.addr,
|
||||
.addr_format = ra32.addr_format,
|
||||
.nframes = ra32.nframes,
|
||||
.buf = compat_ptr(ra32.buf),
|
||||
};
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
if (copy_from_user(&ra, (struct cdrom_read_audio __user *)arg,
|
||||
sizeof(ra)))
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
if (ra.addr_format == CDROM_MSF)
|
||||
lba = msf_to_lba(ra.addr.msf.minute,
|
||||
@@ -3271,9 +3293,10 @@ static noinline int mmc_ioctl_cdrom_last_written(struct cdrom_device_info *cdi,
|
||||
ret = cdrom_get_last_written(cdi, &last);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (copy_to_user((long __user *)arg, &last, sizeof(last)))
|
||||
return -EFAULT;
|
||||
return 0;
|
||||
if (in_compat_syscall())
|
||||
return put_user(last, (__s32 __user *)arg);
|
||||
|
||||
return put_user(last, (long __user *)arg);
|
||||
}
|
||||
|
||||
static int mmc_ioctl(struct cdrom_device_info *cdi, unsigned int cmd,
|
||||
|
||||
@@ -518,6 +518,9 @@ static const struct block_device_operations gdrom_bdops = {
|
||||
.release = gdrom_bdops_release,
|
||||
.check_events = gdrom_bdops_check_events,
|
||||
.ioctl = gdrom_bdops_ioctl,
|
||||
#ifdef CONFIG_COMPAT
|
||||
.ioctl = blkdev_compat_ptr_ioctl,
|
||||
#endif
|
||||
};
|
||||
|
||||
static irqreturn_t gdrom_command_interrupt(int irq, void *dev_id)
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
|
||||
#define IDECD_VERSION "5.00"
|
||||
|
||||
#include <linux/compat.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/kernel.h>
|
||||
@@ -1710,6 +1711,41 @@ static int idecd_ioctl(struct block_device *bdev, fmode_t mode,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int idecd_locked_compat_ioctl(struct block_device *bdev, fmode_t mode,
|
||||
unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
struct cdrom_info *info = ide_drv_g(bdev->bd_disk, cdrom_info);
|
||||
void __user *argp = compat_ptr(arg);
|
||||
int err;
|
||||
|
||||
switch (cmd) {
|
||||
case CDROMSETSPINDOWN:
|
||||
return idecd_set_spindown(&info->devinfo, (unsigned long)argp);
|
||||
case CDROMGETSPINDOWN:
|
||||
return idecd_get_spindown(&info->devinfo, (unsigned long)argp);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
err = generic_ide_ioctl(info->drive, bdev, cmd, arg);
|
||||
if (err == -EINVAL)
|
||||
err = cdrom_ioctl(&info->devinfo, bdev, mode, cmd,
|
||||
(unsigned long)argp);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int idecd_compat_ioctl(struct block_device *bdev, fmode_t mode,
|
||||
unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
int ret;
|
||||
|
||||
mutex_lock(&ide_cd_mutex);
|
||||
ret = idecd_locked_compat_ioctl(bdev, mode, cmd, arg);
|
||||
mutex_unlock(&ide_cd_mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static unsigned int idecd_check_events(struct gendisk *disk,
|
||||
unsigned int clearing)
|
||||
@@ -1732,6 +1768,8 @@ static const struct block_device_operations idecd_ops = {
|
||||
.open = idecd_open,
|
||||
.release = idecd_release,
|
||||
.ioctl = idecd_ioctl,
|
||||
.compat_ioctl = IS_ENABLED(CONFIG_COMPAT) ?
|
||||
idecd_compat_ioctl : NULL,
|
||||
.check_events = idecd_check_events,
|
||||
.revalidate_disk = idecd_revalidate_disk
|
||||
};
|
||||
|
||||
@@ -794,4 +794,5 @@ const struct ide_disk_ops ide_ata_disk_ops = {
|
||||
.set_doorlock = ide_disk_set_doorlock,
|
||||
.do_request = ide_do_rw_disk,
|
||||
.ioctl = ide_disk_ioctl,
|
||||
.compat_ioctl = ide_disk_ioctl,
|
||||
};
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include <linux/types.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/compat.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/mm.h>
|
||||
@@ -546,4 +547,7 @@ const struct ide_disk_ops ide_atapi_disk_ops = {
|
||||
.set_doorlock = ide_set_media_lock,
|
||||
.do_request = ide_floppy_do_request,
|
||||
.ioctl = ide_floppy_ioctl,
|
||||
#ifdef CONFIG_COMPAT
|
||||
.compat_ioctl = ide_floppy_compat_ioctl,
|
||||
#endif
|
||||
};
|
||||
|
||||
@@ -26,6 +26,8 @@ void ide_floppy_create_read_capacity_cmd(struct ide_atapi_pc *);
|
||||
/* ide-floppy_ioctl.c */
|
||||
int ide_floppy_ioctl(ide_drive_t *, struct block_device *, fmode_t,
|
||||
unsigned int, unsigned long);
|
||||
int ide_floppy_compat_ioctl(ide_drive_t *, struct block_device *, fmode_t,
|
||||
unsigned int, unsigned long);
|
||||
|
||||
#ifdef CONFIG_IDE_PROC_FS
|
||||
/* ide-floppy_proc.c */
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/ide.h>
|
||||
#include <linux/compat.h>
|
||||
#include <linux/cdrom.h>
|
||||
#include <linux/mutex.h>
|
||||
|
||||
@@ -302,3 +303,37 @@ out:
|
||||
mutex_unlock(&ide_floppy_ioctl_mutex);
|
||||
return err;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_COMPAT
|
||||
int ide_floppy_compat_ioctl(ide_drive_t *drive, struct block_device *bdev,
|
||||
fmode_t mode, unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
struct ide_atapi_pc pc;
|
||||
void __user *argp = compat_ptr(arg);
|
||||
int err;
|
||||
|
||||
mutex_lock(&ide_floppy_ioctl_mutex);
|
||||
if (cmd == CDROMEJECT || cmd == CDROM_LOCKDOOR) {
|
||||
err = ide_floppy_lockdoor(drive, &pc, arg, cmd);
|
||||
goto out;
|
||||
}
|
||||
|
||||
err = ide_floppy_format_ioctl(drive, &pc, mode, cmd, argp);
|
||||
if (err != -ENOTTY)
|
||||
goto out;
|
||||
|
||||
/*
|
||||
* skip SCSI_IOCTL_SEND_COMMAND (deprecated)
|
||||
* and CDROM_SEND_PACKET (legacy) ioctls
|
||||
*/
|
||||
if (cmd != CDROM_SEND_PACKET && cmd != SCSI_IOCTL_SEND_COMMAND)
|
||||
err = scsi_cmd_blk_ioctl(bdev, mode, cmd, argp);
|
||||
|
||||
if (err == -ENOTTY)
|
||||
err = generic_ide_ioctl(drive, bdev, cmd, arg);
|
||||
|
||||
out:
|
||||
mutex_unlock(&ide_floppy_ioctl_mutex);
|
||||
return err;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -341,11 +341,28 @@ static int ide_gd_ioctl(struct block_device *bdev, fmode_t mode,
|
||||
return drive->disk_ops->ioctl(drive, bdev, mode, cmd, arg);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_COMPAT
|
||||
static int ide_gd_compat_ioctl(struct block_device *bdev, fmode_t mode,
|
||||
unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
struct ide_disk_obj *idkp = ide_drv_g(bdev->bd_disk, ide_disk_obj);
|
||||
ide_drive_t *drive = idkp->drive;
|
||||
|
||||
if (!drive->disk_ops->compat_ioctl)
|
||||
return -ENOIOCTLCMD;
|
||||
|
||||
return drive->disk_ops->compat_ioctl(drive, bdev, mode, cmd, arg);
|
||||
}
|
||||
#endif
|
||||
|
||||
static const struct block_device_operations ide_gd_ops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = ide_gd_unlocked_open,
|
||||
.release = ide_gd_release,
|
||||
.ioctl = ide_gd_ioctl,
|
||||
#ifdef CONFIG_COMPAT
|
||||
.ioctl = ide_gd_compat_ioctl,
|
||||
#endif
|
||||
.getgeo = ide_gd_getgeo,
|
||||
.check_events = ide_gd_check_events,
|
||||
.unlock_native_capacity = ide_gd_unlock_native_capacity,
|
||||
|
||||
@@ -3,11 +3,20 @@
|
||||
* IDE ioctls handling.
|
||||
*/
|
||||
|
||||
#include <linux/compat.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/hdreg.h>
|
||||
#include <linux/ide.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
static int put_user_long(long val, unsigned long arg)
|
||||
{
|
||||
if (in_compat_syscall())
|
||||
return put_user(val, (compat_long_t __user *)compat_ptr(arg));
|
||||
|
||||
return put_user(val, (long __user *)arg);
|
||||
}
|
||||
|
||||
static const struct ide_ioctl_devset ide_ioctl_settings[] = {
|
||||
{ HDIO_GET_32BIT, HDIO_SET_32BIT, &ide_devset_io_32bit },
|
||||
{ HDIO_GET_KEEPSETTINGS, HDIO_SET_KEEPSETTINGS, &ide_devset_keepsettings },
|
||||
@@ -37,7 +46,7 @@ read_val:
|
||||
mutex_lock(&ide_setting_mtx);
|
||||
err = ds->get(drive);
|
||||
mutex_unlock(&ide_setting_mtx);
|
||||
return err >= 0 ? put_user(err, (long __user *)arg) : err;
|
||||
return err >= 0 ? put_user_long(err, arg) : err;
|
||||
|
||||
set_val:
|
||||
if (bdev != bdev->bd_contains)
|
||||
@@ -56,7 +65,7 @@ set_val:
|
||||
EXPORT_SYMBOL_GPL(ide_setting_ioctl);
|
||||
|
||||
static int ide_get_identity_ioctl(ide_drive_t *drive, unsigned int cmd,
|
||||
unsigned long arg)
|
||||
void __user *argp)
|
||||
{
|
||||
u16 *id = NULL;
|
||||
int size = (cmd == HDIO_GET_IDENTITY) ? (ATA_ID_WORDS * 2) : 142;
|
||||
@@ -77,7 +86,7 @@ static int ide_get_identity_ioctl(ide_drive_t *drive, unsigned int cmd,
|
||||
memcpy(id, drive->id, size);
|
||||
ata_id_to_hd_driveid(id);
|
||||
|
||||
if (copy_to_user((void __user *)arg, id, size))
|
||||
if (copy_to_user(argp, id, size))
|
||||
rc = -EFAULT;
|
||||
|
||||
kfree(id);
|
||||
@@ -87,10 +96,10 @@ out:
|
||||
|
||||
static int ide_get_nice_ioctl(ide_drive_t *drive, unsigned long arg)
|
||||
{
|
||||
return put_user((!!(drive->dev_flags & IDE_DFLAG_DSC_OVERLAP)
|
||||
return put_user_long((!!(drive->dev_flags & IDE_DFLAG_DSC_OVERLAP)
|
||||
<< IDE_NICE_DSC_OVERLAP) |
|
||||
(!!(drive->dev_flags & IDE_DFLAG_NICE1)
|
||||
<< IDE_NICE_1), (long __user *)arg);
|
||||
<< IDE_NICE_1), arg);
|
||||
}
|
||||
|
||||
static int ide_set_nice_ioctl(ide_drive_t *drive, unsigned long arg)
|
||||
@@ -115,7 +124,7 @@ static int ide_set_nice_ioctl(ide_drive_t *drive, unsigned long arg)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ide_cmd_ioctl(ide_drive_t *drive, unsigned long arg)
|
||||
static int ide_cmd_ioctl(ide_drive_t *drive, void __user *argp)
|
||||
{
|
||||
u8 *buf = NULL;
|
||||
int bufsize = 0, err = 0;
|
||||
@@ -123,7 +132,7 @@ static int ide_cmd_ioctl(ide_drive_t *drive, unsigned long arg)
|
||||
struct ide_cmd cmd;
|
||||
struct ide_taskfile *tf = &cmd.tf;
|
||||
|
||||
if (NULL == (void *) arg) {
|
||||
if (NULL == argp) {
|
||||
struct request *rq;
|
||||
|
||||
rq = blk_get_request(drive->queue, REQ_OP_DRV_IN, 0);
|
||||
@@ -135,7 +144,7 @@ static int ide_cmd_ioctl(ide_drive_t *drive, unsigned long arg)
|
||||
return err;
|
||||
}
|
||||
|
||||
if (copy_from_user(args, (void __user *)arg, 4))
|
||||
if (copy_from_user(args, argp, 4))
|
||||
return -EFAULT;
|
||||
|
||||
memset(&cmd, 0, sizeof(cmd));
|
||||
@@ -181,19 +190,18 @@ static int ide_cmd_ioctl(ide_drive_t *drive, unsigned long arg)
|
||||
args[1] = tf->error;
|
||||
args[2] = tf->nsect;
|
||||
abort:
|
||||
if (copy_to_user((void __user *)arg, &args, 4))
|
||||
if (copy_to_user(argp, &args, 4))
|
||||
err = -EFAULT;
|
||||
if (buf) {
|
||||
if (copy_to_user((void __user *)(arg + 4), buf, bufsize))
|
||||
if (copy_to_user((argp + 4), buf, bufsize))
|
||||
err = -EFAULT;
|
||||
kfree(buf);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
static int ide_task_ioctl(ide_drive_t *drive, unsigned long arg)
|
||||
static int ide_task_ioctl(ide_drive_t *drive, void __user *p)
|
||||
{
|
||||
void __user *p = (void __user *)arg;
|
||||
int err = 0;
|
||||
u8 args[7];
|
||||
struct ide_cmd cmd;
|
||||
@@ -237,6 +245,10 @@ int generic_ide_ioctl(ide_drive_t *drive, struct block_device *bdev,
|
||||
unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
int err;
|
||||
void __user *argp = (void __user *)arg;
|
||||
|
||||
if (in_compat_syscall())
|
||||
argp = compat_ptr(arg);
|
||||
|
||||
err = ide_setting_ioctl(drive, bdev, cmd, arg, ide_ioctl_settings);
|
||||
if (err != -EOPNOTSUPP)
|
||||
@@ -247,7 +259,7 @@ int generic_ide_ioctl(ide_drive_t *drive, struct block_device *bdev,
|
||||
case HDIO_GET_IDENTITY:
|
||||
if (bdev != bdev->bd_contains)
|
||||
return -EINVAL;
|
||||
return ide_get_identity_ioctl(drive, cmd, arg);
|
||||
return ide_get_identity_ioctl(drive, cmd, argp);
|
||||
case HDIO_GET_NICE:
|
||||
return ide_get_nice_ioctl(drive, arg);
|
||||
case HDIO_SET_NICE:
|
||||
@@ -258,6 +270,9 @@ int generic_ide_ioctl(ide_drive_t *drive, struct block_device *bdev,
|
||||
case HDIO_DRIVE_TASKFILE:
|
||||
if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
|
||||
return -EACCES;
|
||||
/* missing compat handler for HDIO_DRIVE_TASKFILE */
|
||||
if (in_compat_syscall())
|
||||
return -ENOTTY;
|
||||
if (drive->media == ide_disk)
|
||||
return ide_taskfile_ioctl(drive, arg);
|
||||
return -ENOMSG;
|
||||
@@ -265,11 +280,11 @@ int generic_ide_ioctl(ide_drive_t *drive, struct block_device *bdev,
|
||||
case HDIO_DRIVE_CMD:
|
||||
if (!capable(CAP_SYS_RAWIO))
|
||||
return -EACCES;
|
||||
return ide_cmd_ioctl(drive, arg);
|
||||
return ide_cmd_ioctl(drive, argp);
|
||||
case HDIO_DRIVE_TASK:
|
||||
if (!capable(CAP_SYS_RAWIO))
|
||||
return -EACCES;
|
||||
return ide_task_ioctl(drive, arg);
|
||||
return ide_task_ioctl(drive, argp);
|
||||
case HDIO_DRIVE_RESET:
|
||||
if (!capable(CAP_SYS_ADMIN))
|
||||
return -EACCES;
|
||||
@@ -277,7 +292,7 @@ int generic_ide_ioctl(ide_drive_t *drive, struct block_device *bdev,
|
||||
case HDIO_GET_BUSSTATE:
|
||||
if (!capable(CAP_SYS_ADMIN))
|
||||
return -EACCES;
|
||||
if (put_user(BUSSTATE_ON, (long __user *)arg))
|
||||
if (put_user_long(BUSSTATE_ON, arg))
|
||||
return -EFAULT;
|
||||
return 0;
|
||||
case HDIO_SET_BUSSTATE:
|
||||
|
||||
@@ -1945,11 +1945,22 @@ static int idetape_ioctl(struct block_device *bdev, fmode_t mode,
|
||||
return err;
|
||||
}
|
||||
|
||||
static int idetape_compat_ioctl(struct block_device *bdev, fmode_t mode,
|
||||
unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
if (cmd == 0x0340 || cmd == 0x350)
|
||||
arg = (unsigned long)compat_ptr(arg);
|
||||
|
||||
return idetape_ioctl(bdev, mode, cmd, arg);
|
||||
}
|
||||
|
||||
static const struct block_device_operations idetape_block_ops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = idetape_open,
|
||||
.release = idetape_release,
|
||||
.ioctl = idetape_ioctl,
|
||||
.compat_ioctl = IS_ENABLED(CONFIG_COMPAT) ?
|
||||
idetape_compat_ioctl : NULL,
|
||||
};
|
||||
|
||||
static int ide_tape_probe(ide_drive_t *drive)
|
||||
|
||||
@@ -134,7 +134,7 @@ static char *blogic_cmd_failure_reason;
|
||||
static void blogic_announce_drvr(struct blogic_adapter *adapter)
|
||||
{
|
||||
blogic_announce("***** BusLogic SCSI Driver Version " blogic_drvr_version " of " blogic_drvr_date " *****\n", adapter);
|
||||
blogic_announce("Copyright 1995-1998 by Leonard N. Zubkoff " "<lnz@dandelion.com>\n", adapter);
|
||||
blogic_announce("Copyright 1995-1998 by Leonard N. Zubkoff <lnz@dandelion.com>\n", adapter);
|
||||
}
|
||||
|
||||
|
||||
@@ -440,7 +440,7 @@ static int blogic_cmd(struct blogic_adapter *adapter, enum blogic_opcode opcode,
|
||||
goto done;
|
||||
}
|
||||
if (blogic_global_options.trace_config)
|
||||
blogic_notice("blogic_cmd(%02X) Status = %02X: " "(Modify I/O Address)\n", adapter, opcode, statusreg.all);
|
||||
blogic_notice("blogic_cmd(%02X) Status = %02X: (Modify I/O Address)\n", adapter, opcode, statusreg.all);
|
||||
result = 0;
|
||||
goto done;
|
||||
}
|
||||
@@ -716,23 +716,23 @@ static int __init blogic_init_mm_probeinfo(struct blogic_adapter *adapter)
|
||||
pci_addr = base_addr1 = pci_resource_start(pci_device, 1);
|
||||
|
||||
if (pci_resource_flags(pci_device, 0) & IORESOURCE_MEM) {
|
||||
blogic_err("BusLogic: Base Address0 0x%X not I/O for " "MultiMaster Host Adapter\n", NULL, base_addr0);
|
||||
blogic_err("at PCI Bus %d Device %d I/O Address 0x%X\n", NULL, bus, device, io_addr);
|
||||
blogic_err("BusLogic: Base Address0 0x%lX not I/O for MultiMaster Host Adapter\n", NULL, base_addr0);
|
||||
blogic_err("at PCI Bus %d Device %d I/O Address 0x%lX\n", NULL, bus, device, io_addr);
|
||||
continue;
|
||||
}
|
||||
if (pci_resource_flags(pci_device, 1) & IORESOURCE_IO) {
|
||||
blogic_err("BusLogic: Base Address1 0x%X not Memory for " "MultiMaster Host Adapter\n", NULL, base_addr1);
|
||||
blogic_err("at PCI Bus %d Device %d PCI Address 0x%X\n", NULL, bus, device, pci_addr);
|
||||
blogic_err("BusLogic: Base Address1 0x%lX not Memory for MultiMaster Host Adapter\n", NULL, base_addr1);
|
||||
blogic_err("at PCI Bus %d Device %d PCI Address 0x%lX\n", NULL, bus, device, pci_addr);
|
||||
continue;
|
||||
}
|
||||
if (irq_ch == 0) {
|
||||
blogic_err("BusLogic: IRQ Channel %d invalid for " "MultiMaster Host Adapter\n", NULL, irq_ch);
|
||||
blogic_err("at PCI Bus %d Device %d I/O Address 0x%X\n", NULL, bus, device, io_addr);
|
||||
blogic_err("BusLogic: IRQ Channel %d invalid for MultiMaster Host Adapter\n", NULL, irq_ch);
|
||||
blogic_err("at PCI Bus %d Device %d I/O Address 0x%lX\n", NULL, bus, device, io_addr);
|
||||
continue;
|
||||
}
|
||||
if (blogic_global_options.trace_probe) {
|
||||
blogic_notice("BusLogic: PCI MultiMaster Host Adapter " "detected at\n", NULL);
|
||||
blogic_notice("BusLogic: PCI Bus %d Device %d I/O Address " "0x%X PCI Address 0x%X\n", NULL, bus, device, io_addr, pci_addr);
|
||||
blogic_notice("BusLogic: PCI MultiMaster Host Adapter detected at\n", NULL);
|
||||
blogic_notice("BusLogic: PCI Bus %d Device %d I/O Address 0x%lX PCI Address 0x%lX\n", NULL, bus, device, io_addr, pci_addr);
|
||||
}
|
||||
/*
|
||||
Issue the Inquire PCI Host Adapter Information command to determine
|
||||
@@ -818,7 +818,7 @@ static int __init blogic_init_mm_probeinfo(struct blogic_adapter *adapter)
|
||||
nonpr_mmcount++;
|
||||
mmcount++;
|
||||
} else
|
||||
blogic_warn("BusLogic: Too many Host Adapters " "detected\n", NULL);
|
||||
blogic_warn("BusLogic: Too many Host Adapters detected\n", NULL);
|
||||
}
|
||||
/*
|
||||
If the AutoSCSI "Use Bus And Device # For PCI Scanning Seq."
|
||||
@@ -956,23 +956,23 @@ static int __init blogic_init_fp_probeinfo(struct blogic_adapter *adapter)
|
||||
pci_addr = base_addr1 = pci_resource_start(pci_device, 1);
|
||||
#ifdef CONFIG_SCSI_FLASHPOINT
|
||||
if (pci_resource_flags(pci_device, 0) & IORESOURCE_MEM) {
|
||||
blogic_err("BusLogic: Base Address0 0x%X not I/O for " "FlashPoint Host Adapter\n", NULL, base_addr0);
|
||||
blogic_err("at PCI Bus %d Device %d I/O Address 0x%X\n", NULL, bus, device, io_addr);
|
||||
blogic_err("BusLogic: Base Address0 0x%lX not I/O for FlashPoint Host Adapter\n", NULL, base_addr0);
|
||||
blogic_err("at PCI Bus %d Device %d I/O Address 0x%lX\n", NULL, bus, device, io_addr);
|
||||
continue;
|
||||
}
|
||||
if (pci_resource_flags(pci_device, 1) & IORESOURCE_IO) {
|
||||
blogic_err("BusLogic: Base Address1 0x%X not Memory for " "FlashPoint Host Adapter\n", NULL, base_addr1);
|
||||
blogic_err("at PCI Bus %d Device %d PCI Address 0x%X\n", NULL, bus, device, pci_addr);
|
||||
blogic_err("BusLogic: Base Address1 0x%lX not Memory for FlashPoint Host Adapter\n", NULL, base_addr1);
|
||||
blogic_err("at PCI Bus %d Device %d PCI Address 0x%lX\n", NULL, bus, device, pci_addr);
|
||||
continue;
|
||||
}
|
||||
if (irq_ch == 0) {
|
||||
blogic_err("BusLogic: IRQ Channel %d invalid for " "FlashPoint Host Adapter\n", NULL, irq_ch);
|
||||
blogic_err("at PCI Bus %d Device %d I/O Address 0x%X\n", NULL, bus, device, io_addr);
|
||||
blogic_err("BusLogic: IRQ Channel %d invalid for FlashPoint Host Adapter\n", NULL, irq_ch);
|
||||
blogic_err("at PCI Bus %d Device %d I/O Address 0x%lX\n", NULL, bus, device, io_addr);
|
||||
continue;
|
||||
}
|
||||
if (blogic_global_options.trace_probe) {
|
||||
blogic_notice("BusLogic: FlashPoint Host Adapter " "detected at\n", NULL);
|
||||
blogic_notice("BusLogic: PCI Bus %d Device %d I/O Address " "0x%X PCI Address 0x%X\n", NULL, bus, device, io_addr, pci_addr);
|
||||
blogic_notice("BusLogic: FlashPoint Host Adapter detected at\n", NULL);
|
||||
blogic_notice("BusLogic: PCI Bus %d Device %d I/O Address 0x%lX PCI Address 0x%lX\n", NULL, bus, device, io_addr, pci_addr);
|
||||
}
|
||||
if (blogic_probeinfo_count < BLOGIC_MAX_ADAPTERS) {
|
||||
struct blogic_probeinfo *probeinfo =
|
||||
@@ -987,11 +987,11 @@ static int __init blogic_init_fp_probeinfo(struct blogic_adapter *adapter)
|
||||
probeinfo->pci_device = pci_dev_get(pci_device);
|
||||
fpcount++;
|
||||
} else
|
||||
blogic_warn("BusLogic: Too many Host Adapters " "detected\n", NULL);
|
||||
blogic_warn("BusLogic: Too many Host Adapters detected\n", NULL);
|
||||
#else
|
||||
blogic_err("BusLogic: FlashPoint Host Adapter detected at " "PCI Bus %d Device %d\n", NULL, bus, device);
|
||||
blogic_err("BusLogic: I/O Address 0x%X PCI Address 0x%X, irq %d, " "but FlashPoint\n", NULL, io_addr, pci_addr, irq_ch);
|
||||
blogic_err("BusLogic: support was omitted in this kernel " "configuration.\n", NULL);
|
||||
blogic_err("BusLogic: FlashPoint Host Adapter detected at PCI Bus %d Device %d\n", NULL, bus, device);
|
||||
blogic_err("BusLogic: I/O Address 0x%lX PCI Address 0x%lX, irq %d, but FlashPoint\n", NULL, io_addr, pci_addr, irq_ch);
|
||||
blogic_err("BusLogic: support was omitted in this kernel configuration.\n", NULL);
|
||||
#endif
|
||||
}
|
||||
/*
|
||||
@@ -1099,9 +1099,9 @@ static bool blogic_failure(struct blogic_adapter *adapter, char *msg)
|
||||
if (adapter->adapter_bus_type == BLOGIC_PCI_BUS) {
|
||||
blogic_err("While configuring BusLogic PCI Host Adapter at\n",
|
||||
adapter);
|
||||
blogic_err("Bus %d Device %d I/O Address 0x%X PCI Address 0x%X:\n", adapter, adapter->bus, adapter->dev, adapter->io_addr, adapter->pci_addr);
|
||||
blogic_err("Bus %d Device %d I/O Address 0x%lX PCI Address 0x%lX:\n", adapter, adapter->bus, adapter->dev, adapter->io_addr, adapter->pci_addr);
|
||||
} else
|
||||
blogic_err("While configuring BusLogic Host Adapter at " "I/O Address 0x%X:\n", adapter, adapter->io_addr);
|
||||
blogic_err("While configuring BusLogic Host Adapter at I/O Address 0x%lX:\n", adapter, adapter->io_addr);
|
||||
blogic_err("%s FAILED - DETACHING\n", adapter, msg);
|
||||
if (blogic_cmd_failure_reason != NULL)
|
||||
blogic_err("ADDITIONAL FAILURE INFO - %s\n", adapter,
|
||||
@@ -1129,13 +1129,13 @@ static bool __init blogic_probe(struct blogic_adapter *adapter)
|
||||
fpinfo->present = false;
|
||||
if (!(FlashPoint_ProbeHostAdapter(fpinfo) == 0 &&
|
||||
fpinfo->present)) {
|
||||
blogic_err("BusLogic: FlashPoint Host Adapter detected at " "PCI Bus %d Device %d\n", adapter, adapter->bus, adapter->dev);
|
||||
blogic_err("BusLogic: I/O Address 0x%X PCI Address 0x%X, " "but FlashPoint\n", adapter, adapter->io_addr, adapter->pci_addr);
|
||||
blogic_err("BusLogic: FlashPoint Host Adapter detected at PCI Bus %d Device %d\n", adapter, adapter->bus, adapter->dev);
|
||||
blogic_err("BusLogic: I/O Address 0x%lX PCI Address 0x%lX, but FlashPoint\n", adapter, adapter->io_addr, adapter->pci_addr);
|
||||
blogic_err("BusLogic: Probe Function failed to validate it.\n", adapter);
|
||||
return false;
|
||||
}
|
||||
if (blogic_global_options.trace_probe)
|
||||
blogic_notice("BusLogic_Probe(0x%X): FlashPoint Found\n", adapter, adapter->io_addr);
|
||||
blogic_notice("BusLogic_Probe(0x%lX): FlashPoint Found\n", adapter, adapter->io_addr);
|
||||
/*
|
||||
Indicate the Host Adapter Probe completed successfully.
|
||||
*/
|
||||
@@ -1152,7 +1152,7 @@ static bool __init blogic_probe(struct blogic_adapter *adapter)
|
||||
intreg.all = blogic_rdint(adapter);
|
||||
georeg.all = blogic_rdgeom(adapter);
|
||||
if (blogic_global_options.trace_probe)
|
||||
blogic_notice("BusLogic_Probe(0x%X): Status 0x%02X, Interrupt 0x%02X, " "Geometry 0x%02X\n", adapter, adapter->io_addr, statusreg.all, intreg.all, georeg.all);
|
||||
blogic_notice("BusLogic_Probe(0x%lX): Status 0x%02X, Interrupt 0x%02X, Geometry 0x%02X\n", adapter, adapter->io_addr, statusreg.all, intreg.all, georeg.all);
|
||||
if (statusreg.all == 0 || statusreg.sr.diag_active ||
|
||||
statusreg.sr.cmd_param_busy || statusreg.sr.rsvd ||
|
||||
statusreg.sr.cmd_invalid || intreg.ir.rsvd != 0)
|
||||
@@ -1231,7 +1231,7 @@ static bool blogic_hwreset(struct blogic_adapter *adapter, bool hard_reset)
|
||||
udelay(100);
|
||||
}
|
||||
if (blogic_global_options.trace_hw_reset)
|
||||
blogic_notice("BusLogic_HardwareReset(0x%X): Diagnostic Active, " "Status 0x%02X\n", adapter, adapter->io_addr, statusreg.all);
|
||||
blogic_notice("BusLogic_HardwareReset(0x%lX): Diagnostic Active, Status 0x%02X\n", adapter, adapter->io_addr, statusreg.all);
|
||||
if (timeout < 0)
|
||||
return false;
|
||||
/*
|
||||
@@ -1251,7 +1251,7 @@ static bool blogic_hwreset(struct blogic_adapter *adapter, bool hard_reset)
|
||||
udelay(100);
|
||||
}
|
||||
if (blogic_global_options.trace_hw_reset)
|
||||
blogic_notice("BusLogic_HardwareReset(0x%X): Diagnostic Completed, " "Status 0x%02X\n", adapter, adapter->io_addr, statusreg.all);
|
||||
blogic_notice("BusLogic_HardwareReset(0x%lX): Diagnostic Completed, Status 0x%02X\n", adapter, adapter->io_addr, statusreg.all);
|
||||
if (timeout < 0)
|
||||
return false;
|
||||
/*
|
||||
@@ -1267,7 +1267,7 @@ static bool blogic_hwreset(struct blogic_adapter *adapter, bool hard_reset)
|
||||
udelay(100);
|
||||
}
|
||||
if (blogic_global_options.trace_hw_reset)
|
||||
blogic_notice("BusLogic_HardwareReset(0x%X): Host Adapter Ready, " "Status 0x%02X\n", adapter, adapter->io_addr, statusreg.all);
|
||||
blogic_notice("BusLogic_HardwareReset(0x%lX): Host Adapter Ready, Status 0x%02X\n", adapter, adapter->io_addr, statusreg.all);
|
||||
if (timeout < 0)
|
||||
return false;
|
||||
/*
|
||||
@@ -1323,7 +1323,7 @@ static bool __init blogic_checkadapter(struct blogic_adapter *adapter)
|
||||
Provide tracing information if requested and return.
|
||||
*/
|
||||
if (blogic_global_options.trace_probe)
|
||||
blogic_notice("BusLogic_Check(0x%X): MultiMaster %s\n", adapter,
|
||||
blogic_notice("BusLogic_Check(0x%lX): MultiMaster %s\n", adapter,
|
||||
adapter->io_addr,
|
||||
(result ? "Found" : "Not Found"));
|
||||
return result;
|
||||
@@ -1836,7 +1836,7 @@ static bool __init blogic_reportconfig(struct blogic_adapter *adapter)
|
||||
int tgt_id;
|
||||
|
||||
blogic_info("Configuring BusLogic Model %s %s%s%s%s SCSI Host Adapter\n", adapter, adapter->model, blogic_adapter_busnames[adapter->adapter_bus_type], (adapter->wide ? " Wide" : ""), (adapter->differential ? " Differential" : ""), (adapter->ultra ? " Ultra" : ""));
|
||||
blogic_info(" Firmware Version: %s, I/O Address: 0x%X, " "IRQ Channel: %d/%s\n", adapter, adapter->fw_ver, adapter->io_addr, adapter->irq_ch, (adapter->level_int ? "Level" : "Edge"));
|
||||
blogic_info(" Firmware Version: %s, I/O Address: 0x%lX, IRQ Channel: %d/%s\n", adapter, adapter->fw_ver, adapter->io_addr, adapter->irq_ch, (adapter->level_int ? "Level" : "Edge"));
|
||||
if (adapter->adapter_bus_type != BLOGIC_PCI_BUS) {
|
||||
blogic_info(" DMA Channel: ", adapter);
|
||||
if (adapter->dma_ch > 0)
|
||||
@@ -1844,7 +1844,7 @@ static bool __init blogic_reportconfig(struct blogic_adapter *adapter)
|
||||
else
|
||||
blogic_info("None, ", adapter);
|
||||
if (adapter->bios_addr > 0)
|
||||
blogic_info("BIOS Address: 0x%X, ", adapter,
|
||||
blogic_info("BIOS Address: 0x%lX, ", adapter,
|
||||
adapter->bios_addr);
|
||||
else
|
||||
blogic_info("BIOS Address: None, ", adapter);
|
||||
@@ -1852,7 +1852,7 @@ static bool __init blogic_reportconfig(struct blogic_adapter *adapter)
|
||||
blogic_info(" PCI Bus: %d, Device: %d, Address: ", adapter,
|
||||
adapter->bus, adapter->dev);
|
||||
if (adapter->pci_addr > 0)
|
||||
blogic_info("0x%X, ", adapter, adapter->pci_addr);
|
||||
blogic_info("0x%lX, ", adapter, adapter->pci_addr);
|
||||
else
|
||||
blogic_info("Unassigned, ", adapter);
|
||||
}
|
||||
@@ -1932,10 +1932,10 @@ static bool __init blogic_reportconfig(struct blogic_adapter *adapter)
|
||||
blogic_info(" Disconnect/Reconnect: %s, Tagged Queuing: %s\n", adapter,
|
||||
discon_msg, tagq_msg);
|
||||
if (blogic_multimaster_type(adapter)) {
|
||||
blogic_info(" Scatter/Gather Limit: %d of %d segments, " "Mailboxes: %d\n", adapter, adapter->drvr_sglimit, adapter->adapter_sglimit, adapter->mbox_count);
|
||||
blogic_info(" Driver Queue Depth: %d, " "Host Adapter Queue Depth: %d\n", adapter, adapter->drvr_qdepth, adapter->adapter_qdepth);
|
||||
blogic_info(" Scatter/Gather Limit: %d of %d segments, Mailboxes: %d\n", adapter, adapter->drvr_sglimit, adapter->adapter_sglimit, adapter->mbox_count);
|
||||
blogic_info(" Driver Queue Depth: %d, Host Adapter Queue Depth: %d\n", adapter, adapter->drvr_qdepth, adapter->adapter_qdepth);
|
||||
} else
|
||||
blogic_info(" Driver Queue Depth: %d, " "Scatter/Gather Limit: %d segments\n", adapter, adapter->drvr_qdepth, adapter->drvr_sglimit);
|
||||
blogic_info(" Driver Queue Depth: %d, Scatter/Gather Limit: %d segments\n", adapter, adapter->drvr_qdepth, adapter->drvr_sglimit);
|
||||
blogic_info(" Tagged Queue Depth: ", adapter);
|
||||
common_tagq_depth = true;
|
||||
for (tgt_id = 1; tgt_id < adapter->maxdev; tgt_id++)
|
||||
@@ -2717,7 +2717,7 @@ static void blogic_scan_inbox(struct blogic_adapter *adapter)
|
||||
then there is most likely a bug in
|
||||
the Host Adapter firmware.
|
||||
*/
|
||||
blogic_warn("Illegal CCB #%ld status %d in " "Incoming Mailbox\n", adapter, ccb->serial, ccb->status);
|
||||
blogic_warn("Illegal CCB #%ld status %d in Incoming Mailbox\n", adapter, ccb->serial, ccb->status);
|
||||
}
|
||||
}
|
||||
next_inbox->comp_code = BLOGIC_INBOX_FREE;
|
||||
@@ -2752,7 +2752,7 @@ static void blogic_process_ccbs(struct blogic_adapter *adapter)
|
||||
if (ccb->opcode == BLOGIC_BDR) {
|
||||
int tgt_id = ccb->tgt_id;
|
||||
|
||||
blogic_warn("Bus Device Reset CCB #%ld to Target " "%d Completed\n", adapter, ccb->serial, tgt_id);
|
||||
blogic_warn("Bus Device Reset CCB #%ld to Target %d Completed\n", adapter, ccb->serial, tgt_id);
|
||||
blogic_inc_count(&adapter->tgt_stats[tgt_id].bdr_done);
|
||||
adapter->tgt_flags[tgt_id].tagq_active = false;
|
||||
adapter->cmds_since_rst[tgt_id] = 0;
|
||||
@@ -2829,7 +2829,7 @@ static void blogic_process_ccbs(struct blogic_adapter *adapter)
|
||||
if (blogic_global_options.trace_err) {
|
||||
int i;
|
||||
blogic_notice("CCB #%ld Target %d: Result %X Host "
|
||||
"Adapter Status %02X " "Target Status %02X\n", adapter, ccb->serial, ccb->tgt_id, command->result, ccb->adapter_status, ccb->tgt_status);
|
||||
"Adapter Status %02X Target Status %02X\n", adapter, ccb->serial, ccb->tgt_id, command->result, ccb->adapter_status, ccb->tgt_status);
|
||||
blogic_notice("CDB ", adapter);
|
||||
for (i = 0; i < ccb->cdblen; i++)
|
||||
blogic_notice(" %02X", adapter, ccb->cdb[i]);
|
||||
@@ -3203,12 +3203,12 @@ static int blogic_qcmd_lck(struct scsi_cmnd *command,
|
||||
*/
|
||||
if (!blogic_write_outbox(adapter, BLOGIC_MBOX_START, ccb)) {
|
||||
spin_unlock_irq(adapter->scsi_host->host_lock);
|
||||
blogic_warn("Unable to write Outgoing Mailbox - " "Pausing for 1 second\n", adapter);
|
||||
blogic_warn("Unable to write Outgoing Mailbox - Pausing for 1 second\n", adapter);
|
||||
blogic_delay(1);
|
||||
spin_lock_irq(adapter->scsi_host->host_lock);
|
||||
if (!blogic_write_outbox(adapter, BLOGIC_MBOX_START,
|
||||
ccb)) {
|
||||
blogic_warn("Still unable to write Outgoing Mailbox - " "Host Adapter Dead?\n", adapter);
|
||||
blogic_warn("Still unable to write Outgoing Mailbox - Host Adapter Dead?\n", adapter);
|
||||
blogic_dealloc_ccb(ccb, 1);
|
||||
command->result = DID_ERROR << 16;
|
||||
command->scsi_done(command);
|
||||
@@ -3443,8 +3443,8 @@ static int blogic_diskparam(struct scsi_device *sdev, struct block_device *dev,
|
||||
if (diskparam->cylinders != saved_cyl)
|
||||
blogic_warn("Adopting Geometry %d/%d from Partition Table\n", adapter, diskparam->heads, diskparam->sectors);
|
||||
} else if (part_end_head > 0 || part_end_sector > 0) {
|
||||
blogic_warn("Warning: Partition Table appears to " "have Geometry %d/%d which is\n", adapter, part_end_head + 1, part_end_sector);
|
||||
blogic_warn("not compatible with current BusLogic " "Host Adapter Geometry %d/%d\n", adapter, diskparam->heads, diskparam->sectors);
|
||||
blogic_warn("Warning: Partition Table appears to have Geometry %d/%d which is\n", adapter, part_end_head + 1, part_end_sector);
|
||||
blogic_warn("not compatible with current BusLogic Host Adapter Geometry %d/%d\n", adapter, diskparam->heads, diskparam->sectors);
|
||||
}
|
||||
}
|
||||
kfree(buf);
|
||||
@@ -3689,7 +3689,7 @@ static int __init blogic_parseopts(char *options)
|
||||
blogic_probe_options.probe134 = true;
|
||||
break;
|
||||
default:
|
||||
blogic_err("BusLogic: Invalid Driver Options " "(invalid I/O Address 0x%X)\n", NULL, io_addr);
|
||||
blogic_err("BusLogic: Invalid Driver Options (invalid I/O Address 0x%lX)\n", NULL, io_addr);
|
||||
return 0;
|
||||
}
|
||||
} else if (blogic_parse(&options, "NoProbeISA"))
|
||||
@@ -3710,7 +3710,7 @@ static int __init blogic_parseopts(char *options)
|
||||
for (tgt_id = 0; tgt_id < BLOGIC_MAXDEV; tgt_id++) {
|
||||
unsigned short qdepth = simple_strtoul(options, &options, 0);
|
||||
if (qdepth > BLOGIC_MAX_TAG_DEPTH) {
|
||||
blogic_err("BusLogic: Invalid Driver Options " "(invalid Queue Depth %d)\n", NULL, qdepth);
|
||||
blogic_err("BusLogic: Invalid Driver Options (invalid Queue Depth %d)\n", NULL, qdepth);
|
||||
return 0;
|
||||
}
|
||||
drvr_opts->qdepth[tgt_id] = qdepth;
|
||||
@@ -3719,12 +3719,12 @@ static int __init blogic_parseopts(char *options)
|
||||
else if (*options == ']')
|
||||
break;
|
||||
else {
|
||||
blogic_err("BusLogic: Invalid Driver Options " "(',' or ']' expected at '%s')\n", NULL, options);
|
||||
blogic_err("BusLogic: Invalid Driver Options (',' or ']' expected at '%s')\n", NULL, options);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if (*options != ']') {
|
||||
blogic_err("BusLogic: Invalid Driver Options " "(']' expected at '%s')\n", NULL, options);
|
||||
blogic_err("BusLogic: Invalid Driver Options (']' expected at '%s')\n", NULL, options);
|
||||
return 0;
|
||||
} else
|
||||
options++;
|
||||
@@ -3732,7 +3732,7 @@ static int __init blogic_parseopts(char *options)
|
||||
unsigned short qdepth = simple_strtoul(options, &options, 0);
|
||||
if (qdepth == 0 ||
|
||||
qdepth > BLOGIC_MAX_TAG_DEPTH) {
|
||||
blogic_err("BusLogic: Invalid Driver Options " "(invalid Queue Depth %d)\n", NULL, qdepth);
|
||||
blogic_err("BusLogic: Invalid Driver Options (invalid Queue Depth %d)\n", NULL, qdepth);
|
||||
return 0;
|
||||
}
|
||||
drvr_opts->common_qdepth = qdepth;
|
||||
@@ -3778,7 +3778,7 @@ static int __init blogic_parseopts(char *options)
|
||||
unsigned short bus_settle_time =
|
||||
simple_strtoul(options, &options, 0);
|
||||
if (bus_settle_time > 5 * 60) {
|
||||
blogic_err("BusLogic: Invalid Driver Options " "(invalid Bus Settle Time %d)\n", NULL, bus_settle_time);
|
||||
blogic_err("BusLogic: Invalid Driver Options (invalid Bus Settle Time %d)\n", NULL, bus_settle_time);
|
||||
return 0;
|
||||
}
|
||||
drvr_opts->bus_settle_time = bus_settle_time;
|
||||
@@ -3803,14 +3803,14 @@ static int __init blogic_parseopts(char *options)
|
||||
if (*options == ',')
|
||||
options++;
|
||||
else if (*options != ';' && *options != '\0') {
|
||||
blogic_err("BusLogic: Unexpected Driver Option '%s' " "ignored\n", NULL, options);
|
||||
blogic_err("BusLogic: Unexpected Driver Option '%s' ignored\n", NULL, options);
|
||||
*options = '\0';
|
||||
}
|
||||
}
|
||||
if (!(blogic_drvr_options_count == 0 ||
|
||||
blogic_probeinfo_count == 0 ||
|
||||
blogic_drvr_options_count == blogic_probeinfo_count)) {
|
||||
blogic_err("BusLogic: Invalid Driver Options " "(all or no I/O Addresses must be specified)\n", NULL);
|
||||
blogic_err("BusLogic: Invalid Driver Options (all or no I/O Addresses must be specified)\n", NULL);
|
||||
return 0;
|
||||
}
|
||||
/*
|
||||
@@ -3864,7 +3864,7 @@ static int __init blogic_setup(char *str)
|
||||
(void) get_options(str, ARRAY_SIZE(ints), ints);
|
||||
|
||||
if (ints[0] != 0) {
|
||||
blogic_err("BusLogic: Obsolete Command Line Entry " "Format Ignored\n", NULL);
|
||||
blogic_err("BusLogic: Obsolete Command Line Entry Format Ignored\n", NULL);
|
||||
return 0;
|
||||
}
|
||||
if (str == NULL || *str == '\0')
|
||||
|
||||
@@ -2314,7 +2314,7 @@ ahc_find_syncrate(struct ahc_softc *ahc, u_int *period,
|
||||
* At some speeds, we only support
|
||||
* ST transfers.
|
||||
*/
|
||||
if ((syncrate->sxfr_u2 & ST_SXFR) != 0)
|
||||
if ((syncrate->sxfr_u2 & ST_SXFR) != 0)
|
||||
*ppr_options &= ~MSG_EXT_PPR_DT_REQ;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -54,6 +54,9 @@ static struct scsi_host_template aic94xx_sht = {
|
||||
.eh_target_reset_handler = sas_eh_target_reset_handler,
|
||||
.target_destroy = sas_target_destroy,
|
||||
.ioctl = sas_ioctl,
|
||||
#ifdef CONFIG_COMPAT
|
||||
.compat_ioctl = sas_ioctl,
|
||||
#endif
|
||||
.track_queue_depth = 1,
|
||||
};
|
||||
|
||||
|
||||
@@ -872,6 +872,10 @@ static long ch_ioctl_compat(struct file * file,
|
||||
unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
scsi_changer *ch = file->private_data;
|
||||
int retval = scsi_ioctl_block_when_processing_errors(ch->device, cmd,
|
||||
file->f_flags & O_NDELAY);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
switch (cmd) {
|
||||
case CHIOGPARAMS:
|
||||
@@ -883,7 +887,7 @@ static long ch_ioctl_compat(struct file * file,
|
||||
case CHIOINITELEM:
|
||||
case CHIOSVOLTAG:
|
||||
/* compatible */
|
||||
return ch_ioctl(file, cmd, arg);
|
||||
return ch_ioctl(file, cmd, (unsigned long)compat_ptr(arg));
|
||||
case CHIOGSTATUS32:
|
||||
{
|
||||
struct changer_element_status32 ces32;
|
||||
@@ -898,8 +902,7 @@ static long ch_ioctl_compat(struct file * file,
|
||||
return ch_gstatus(ch, ces32.ces_type, data);
|
||||
}
|
||||
default:
|
||||
// return scsi_ioctl_compat(ch->device, cmd, (void*)arg);
|
||||
return -ENOIOCTLCMD;
|
||||
return scsi_compat_ioctl(ch->device, cmd, compat_ptr(arg));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1383,7 +1383,7 @@ csio_device_reset(struct device *dev,
|
||||
return -EINVAL;
|
||||
|
||||
/* Delete NPIV lnodes */
|
||||
csio_lnodes_exit(hw, 1);
|
||||
csio_lnodes_exit(hw, 1);
|
||||
|
||||
/* Block upper IOs */
|
||||
csio_lnodes_block_request(hw);
|
||||
|
||||
@@ -243,8 +243,6 @@ static void esp_set_all_config3(struct esp *esp, u8 val)
|
||||
/* Reset the ESP chip, _not_ the SCSI bus. */
|
||||
static void esp_reset_esp(struct esp *esp)
|
||||
{
|
||||
u8 family_code, version;
|
||||
|
||||
/* Now reset the ESP chip */
|
||||
scsi_esp_cmd(esp, ESP_CMD_RC);
|
||||
scsi_esp_cmd(esp, ESP_CMD_NULL | ESP_CMD_DMA);
|
||||
@@ -257,14 +255,19 @@ static void esp_reset_esp(struct esp *esp)
|
||||
*/
|
||||
esp->max_period = ((35 * esp->ccycle) / 1000);
|
||||
if (esp->rev == FAST) {
|
||||
version = esp_read8(ESP_UID);
|
||||
family_code = (version & 0xf8) >> 3;
|
||||
if (family_code == 0x02)
|
||||
u8 family_code = ESP_FAMILY(esp_read8(ESP_UID));
|
||||
|
||||
if (family_code == ESP_UID_F236) {
|
||||
esp->rev = FAS236;
|
||||
else if (family_code == 0x0a)
|
||||
} else if (family_code == ESP_UID_HME) {
|
||||
esp->rev = FASHME; /* Version is usually '5'. */
|
||||
else
|
||||
} else if (family_code == ESP_UID_FSC) {
|
||||
esp->rev = FSC;
|
||||
/* Enable Active Negation */
|
||||
esp_write8(ESP_CONFIG4_RADE, ESP_CFG4);
|
||||
} else {
|
||||
esp->rev = FAS100A;
|
||||
}
|
||||
esp->min_period = ((4 * esp->ccycle) / 1000);
|
||||
} else {
|
||||
esp->min_period = ((5 * esp->ccycle) / 1000);
|
||||
@@ -308,7 +311,7 @@ static void esp_reset_esp(struct esp *esp)
|
||||
|
||||
case FAS236:
|
||||
case PCSCSI:
|
||||
/* Fast 236, AM53c974 or HME */
|
||||
case FSC:
|
||||
esp_write8(esp->config2, ESP_CFG2);
|
||||
if (esp->rev == FASHME) {
|
||||
u8 cfg3 = esp->target[0].esp_config3;
|
||||
@@ -2373,10 +2376,11 @@ static const char *esp_chip_names[] = {
|
||||
"ESP100A",
|
||||
"ESP236",
|
||||
"FAS236",
|
||||
"AM53C974",
|
||||
"53CF9x-2",
|
||||
"FAS100A",
|
||||
"FAST",
|
||||
"FASHME",
|
||||
"AM53C974",
|
||||
};
|
||||
|
||||
static struct scsi_transport_template *esp_transport_template;
|
||||
|
||||
@@ -78,12 +78,14 @@
|
||||
#define ESP_CONFIG3_IMS 0x80 /* ID msg chk'ng (esp/fas236) */
|
||||
#define ESP_CONFIG3_OBPUSH 0x80 /* Push odd-byte to dma (hme) */
|
||||
|
||||
/* ESP config register 4 read-write, found only on am53c974 chips */
|
||||
#define ESP_CONFIG4_RADE 0x04 /* Active negation */
|
||||
#define ESP_CONFIG4_RAE 0x08 /* Active negation on REQ and ACK */
|
||||
#define ESP_CONFIG4_PWD 0x20 /* Reduced power feature */
|
||||
#define ESP_CONFIG4_GE0 0x40 /* Glitch eater bit 0 */
|
||||
#define ESP_CONFIG4_GE1 0x80 /* Glitch eater bit 1 */
|
||||
/* ESP config register 4 read-write */
|
||||
#define ESP_CONFIG4_BBTE 0x01 /* Back-to-back transfers (fsc) */
|
||||
#define ESP_CONGIG4_TEST 0x02 /* Transfer counter test mode (fsc) */
|
||||
#define ESP_CONFIG4_RADE 0x04 /* Active negation (am53c974/fsc) */
|
||||
#define ESP_CONFIG4_RAE 0x08 /* Act. negation REQ/ACK (am53c974) */
|
||||
#define ESP_CONFIG4_PWD 0x20 /* Reduced power feature (am53c974) */
|
||||
#define ESP_CONFIG4_GE0 0x40 /* Glitch eater bit 0 (am53c974) */
|
||||
#define ESP_CONFIG4_GE1 0x80 /* Glitch eater bit 1 (am53c974) */
|
||||
|
||||
#define ESP_CONFIG_GE_12NS (0)
|
||||
#define ESP_CONFIG_GE_25NS (ESP_CONFIG_GE1)
|
||||
@@ -209,10 +211,15 @@
|
||||
#define ESP_TEST_TS 0x04 /* Tristate test mode */
|
||||
|
||||
/* ESP unique ID register read-only, found on fas236+fas100a only */
|
||||
#define ESP_UID_FAM 0xf8 /* ESP family bitmask */
|
||||
|
||||
#define ESP_FAMILY(uid) (((uid) & ESP_UID_FAM) >> 3)
|
||||
|
||||
/* Values for the ESP family bits */
|
||||
#define ESP_UID_F100A 0x00 /* ESP FAS100A */
|
||||
#define ESP_UID_F236 0x02 /* ESP FAS236 */
|
||||
#define ESP_UID_REV 0x07 /* ESP revision */
|
||||
#define ESP_UID_FAM 0xf8 /* ESP family */
|
||||
#define ESP_UID_HME 0x0a /* FAS HME */
|
||||
#define ESP_UID_FSC 0x14 /* NCR/Symbios Logic 53CF9x-2 */
|
||||
|
||||
/* ESP fifo flags register read-only */
|
||||
/* Note that the following implies a 16 byte FIFO on the ESP. */
|
||||
@@ -257,15 +264,17 @@ struct esp_cmd_priv {
|
||||
};
|
||||
#define ESP_CMD_PRIV(CMD) ((struct esp_cmd_priv *)(&(CMD)->SCp))
|
||||
|
||||
/* NOTE: this enum is ordered based on chip features! */
|
||||
enum esp_rev {
|
||||
ESP100 = 0x00, /* NCR53C90 - very broken */
|
||||
ESP100A = 0x01, /* NCR53C90A */
|
||||
ESP236 = 0x02,
|
||||
FAS236 = 0x03,
|
||||
FAS100A = 0x04,
|
||||
FAST = 0x05,
|
||||
FASHME = 0x06,
|
||||
PCSCSI = 0x07, /* AM53c974 */
|
||||
ESP100, /* NCR53C90 - very broken */
|
||||
ESP100A, /* NCR53C90A */
|
||||
ESP236,
|
||||
FAS236,
|
||||
PCSCSI, /* AM53c974 */
|
||||
FSC, /* NCR/Symbios Logic 53CF9x-2 */
|
||||
FAS100A,
|
||||
FAST,
|
||||
FASHME,
|
||||
};
|
||||
|
||||
struct esp_cmd_entry {
|
||||
|
||||
@@ -180,10 +180,10 @@ struct hisi_sas_port {
|
||||
|
||||
struct hisi_sas_cq {
|
||||
struct hisi_hba *hisi_hba;
|
||||
const struct cpumask *pci_irq_mask;
|
||||
struct tasklet_struct tasklet;
|
||||
const struct cpumask *irq_mask;
|
||||
int rd_point;
|
||||
int id;
|
||||
int irq_no;
|
||||
};
|
||||
|
||||
struct hisi_sas_dq {
|
||||
@@ -627,7 +627,7 @@ extern void hisi_sas_slot_task_free(struct hisi_hba *hisi_hba,
|
||||
extern void hisi_sas_init_mem(struct hisi_hba *hisi_hba);
|
||||
extern void hisi_sas_rst_work_handler(struct work_struct *work);
|
||||
extern void hisi_sas_sync_rst_work_handler(struct work_struct *work);
|
||||
extern void hisi_sas_kill_tasklets(struct hisi_hba *hisi_hba);
|
||||
extern void hisi_sas_sync_irqs(struct hisi_hba *hisi_hba);
|
||||
extern void hisi_sas_phy_oob_ready(struct hisi_hba *hisi_hba, int phy_no);
|
||||
extern bool hisi_sas_notify_phy_event(struct hisi_sas_phy *phy,
|
||||
enum hisi_sas_phy_event event);
|
||||
|
||||
@@ -163,13 +163,11 @@ static void hisi_sas_slot_index_clear(struct hisi_hba *hisi_hba, int slot_idx)
|
||||
|
||||
static void hisi_sas_slot_index_free(struct hisi_hba *hisi_hba, int slot_idx)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
if (hisi_hba->hw->slot_index_alloc ||
|
||||
slot_idx >= HISI_SAS_UNRESERVED_IPTT) {
|
||||
spin_lock_irqsave(&hisi_hba->lock, flags);
|
||||
spin_lock(&hisi_hba->lock);
|
||||
hisi_sas_slot_index_clear(hisi_hba, slot_idx);
|
||||
spin_unlock_irqrestore(&hisi_hba->lock, flags);
|
||||
spin_unlock(&hisi_hba->lock);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -185,12 +183,11 @@ static int hisi_sas_slot_index_alloc(struct hisi_hba *hisi_hba,
|
||||
{
|
||||
int index;
|
||||
void *bitmap = hisi_hba->slot_index_tags;
|
||||
unsigned long flags;
|
||||
|
||||
if (scsi_cmnd)
|
||||
return scsi_cmnd->request->tag;
|
||||
|
||||
spin_lock_irqsave(&hisi_hba->lock, flags);
|
||||
spin_lock(&hisi_hba->lock);
|
||||
index = find_next_zero_bit(bitmap, hisi_hba->slot_index_count,
|
||||
hisi_hba->last_slot_index + 1);
|
||||
if (index >= hisi_hba->slot_index_count) {
|
||||
@@ -198,13 +195,13 @@ static int hisi_sas_slot_index_alloc(struct hisi_hba *hisi_hba,
|
||||
hisi_hba->slot_index_count,
|
||||
HISI_SAS_UNRESERVED_IPTT);
|
||||
if (index >= hisi_hba->slot_index_count) {
|
||||
spin_unlock_irqrestore(&hisi_hba->lock, flags);
|
||||
spin_unlock(&hisi_hba->lock);
|
||||
return -SAS_QUEUE_FULL;
|
||||
}
|
||||
}
|
||||
hisi_sas_slot_index_set(hisi_hba, index);
|
||||
hisi_hba->last_slot_index = index;
|
||||
spin_unlock_irqrestore(&hisi_hba->lock, flags);
|
||||
spin_unlock(&hisi_hba->lock);
|
||||
|
||||
return index;
|
||||
}
|
||||
@@ -220,7 +217,6 @@ static void hisi_sas_slot_index_init(struct hisi_hba *hisi_hba)
|
||||
void hisi_sas_slot_task_free(struct hisi_hba *hisi_hba, struct sas_task *task,
|
||||
struct hisi_sas_slot *slot)
|
||||
{
|
||||
unsigned long flags;
|
||||
int device_id = slot->device_id;
|
||||
struct hisi_sas_device *sas_dev = &hisi_hba->devices[device_id];
|
||||
|
||||
@@ -247,9 +243,9 @@ void hisi_sas_slot_task_free(struct hisi_hba *hisi_hba, struct sas_task *task,
|
||||
}
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&sas_dev->lock, flags);
|
||||
spin_lock(&sas_dev->lock);
|
||||
list_del_init(&slot->entry);
|
||||
spin_unlock_irqrestore(&sas_dev->lock, flags);
|
||||
spin_unlock(&sas_dev->lock);
|
||||
|
||||
memset(slot, 0, offsetof(struct hisi_sas_slot, buf));
|
||||
|
||||
@@ -489,14 +485,14 @@ static int hisi_sas_task_prep(struct sas_task *task,
|
||||
slot_idx = rc;
|
||||
slot = &hisi_hba->slot_info[slot_idx];
|
||||
|
||||
spin_lock_irqsave(&dq->lock, flags);
|
||||
spin_lock(&dq->lock);
|
||||
wr_q_index = dq->wr_point;
|
||||
dq->wr_point = (dq->wr_point + 1) % HISI_SAS_QUEUE_SLOTS;
|
||||
list_add_tail(&slot->delivery, &dq->list);
|
||||
spin_unlock_irqrestore(&dq->lock, flags);
|
||||
spin_lock_irqsave(&sas_dev->lock, flags);
|
||||
spin_unlock(&dq->lock);
|
||||
spin_lock(&sas_dev->lock);
|
||||
list_add_tail(&slot->entry, &sas_dev->list);
|
||||
spin_unlock_irqrestore(&sas_dev->lock, flags);
|
||||
spin_unlock(&sas_dev->lock);
|
||||
|
||||
dlvry_queue = dq->id;
|
||||
dlvry_queue_slot = wr_q_index;
|
||||
@@ -562,7 +558,6 @@ static int hisi_sas_task_exec(struct sas_task *task, gfp_t gfp_flags,
|
||||
{
|
||||
u32 rc;
|
||||
u32 pass = 0;
|
||||
unsigned long flags;
|
||||
struct hisi_hba *hisi_hba;
|
||||
struct device *dev;
|
||||
struct domain_device *device = task->dev;
|
||||
@@ -606,9 +601,9 @@ static int hisi_sas_task_exec(struct sas_task *task, gfp_t gfp_flags,
|
||||
dev_err(dev, "task exec: failed[%d]!\n", rc);
|
||||
|
||||
if (likely(pass)) {
|
||||
spin_lock_irqsave(&dq->lock, flags);
|
||||
spin_lock(&dq->lock);
|
||||
hisi_hba->hw->start_delivery(dq);
|
||||
spin_unlock_irqrestore(&dq->lock, flags);
|
||||
spin_unlock(&dq->lock);
|
||||
}
|
||||
|
||||
return rc;
|
||||
@@ -659,12 +654,11 @@ static struct hisi_sas_device *hisi_sas_alloc_dev(struct domain_device *device)
|
||||
{
|
||||
struct hisi_hba *hisi_hba = dev_to_hisi_hba(device);
|
||||
struct hisi_sas_device *sas_dev = NULL;
|
||||
unsigned long flags;
|
||||
int last = hisi_hba->last_dev_id;
|
||||
int first = (hisi_hba->last_dev_id + 1) % HISI_SAS_MAX_DEVICES;
|
||||
int i;
|
||||
|
||||
spin_lock_irqsave(&hisi_hba->lock, flags);
|
||||
spin_lock(&hisi_hba->lock);
|
||||
for (i = first; i != last; i %= HISI_SAS_MAX_DEVICES) {
|
||||
if (hisi_hba->devices[i].dev_type == SAS_PHY_UNUSED) {
|
||||
int queue = i % hisi_hba->queue_count;
|
||||
@@ -684,7 +678,7 @@ static struct hisi_sas_device *hisi_sas_alloc_dev(struct domain_device *device)
|
||||
i++;
|
||||
}
|
||||
hisi_hba->last_dev_id = i;
|
||||
spin_unlock_irqrestore(&hisi_hba->lock, flags);
|
||||
spin_unlock(&hisi_hba->lock);
|
||||
|
||||
return sas_dev;
|
||||
}
|
||||
@@ -1233,10 +1227,10 @@ static int hisi_sas_exec_internal_tmf_task(struct domain_device *device,
|
||||
struct hisi_sas_cq *cq =
|
||||
&hisi_hba->cq[slot->dlvry_queue];
|
||||
/*
|
||||
* flush tasklet to avoid free'ing task
|
||||
* sync irq to avoid free'ing task
|
||||
* before using task in IO completion
|
||||
*/
|
||||
tasklet_kill(&cq->tasklet);
|
||||
synchronize_irq(cq->irq_no);
|
||||
slot->task = NULL;
|
||||
}
|
||||
|
||||
@@ -1626,11 +1620,11 @@ static int hisi_sas_abort_task(struct sas_task *task)
|
||||
|
||||
if (slot) {
|
||||
/*
|
||||
* flush tasklet to avoid free'ing task
|
||||
* sync irq to avoid free'ing task
|
||||
* before using task in IO completion
|
||||
*/
|
||||
cq = &hisi_hba->cq[slot->dlvry_queue];
|
||||
tasklet_kill(&cq->tasklet);
|
||||
synchronize_irq(cq->irq_no);
|
||||
}
|
||||
spin_unlock_irqrestore(&task->task_state_lock, flags);
|
||||
rc = TMF_RESP_FUNC_COMPLETE;
|
||||
@@ -1694,10 +1688,10 @@ static int hisi_sas_abort_task(struct sas_task *task)
|
||||
if (((rc < 0) || (rc == TMF_RESP_FUNC_FAILED)) &&
|
||||
task->lldd_task) {
|
||||
/*
|
||||
* flush tasklet to avoid free'ing task
|
||||
* sync irq to avoid free'ing task
|
||||
* before using task in IO completion
|
||||
*/
|
||||
tasklet_kill(&cq->tasklet);
|
||||
synchronize_irq(cq->irq_no);
|
||||
slot->task = NULL;
|
||||
}
|
||||
}
|
||||
@@ -1965,14 +1959,14 @@ hisi_sas_internal_abort_task_exec(struct hisi_hba *hisi_hba, int device_id,
|
||||
slot_idx = rc;
|
||||
slot = &hisi_hba->slot_info[slot_idx];
|
||||
|
||||
spin_lock_irqsave(&dq->lock, flags);
|
||||
spin_lock(&dq->lock);
|
||||
wr_q_index = dq->wr_point;
|
||||
dq->wr_point = (dq->wr_point + 1) % HISI_SAS_QUEUE_SLOTS;
|
||||
list_add_tail(&slot->delivery, &dq->list);
|
||||
spin_unlock_irqrestore(&dq->lock, flags);
|
||||
spin_lock_irqsave(&sas_dev->lock, flags);
|
||||
spin_unlock(&dq->lock);
|
||||
spin_lock(&sas_dev->lock);
|
||||
list_add_tail(&slot->entry, &sas_dev->list);
|
||||
spin_unlock_irqrestore(&sas_dev->lock, flags);
|
||||
spin_unlock(&sas_dev->lock);
|
||||
|
||||
dlvry_queue = dq->id;
|
||||
dlvry_queue_slot = wr_q_index;
|
||||
@@ -2001,9 +1995,9 @@ hisi_sas_internal_abort_task_exec(struct hisi_hba *hisi_hba, int device_id,
|
||||
spin_unlock_irqrestore(&task->task_state_lock, flags);
|
||||
WRITE_ONCE(slot->ready, 1);
|
||||
/* send abort command to the chip */
|
||||
spin_lock_irqsave(&dq->lock, flags);
|
||||
spin_lock(&dq->lock);
|
||||
hisi_hba->hw->start_delivery(dq);
|
||||
spin_unlock_irqrestore(&dq->lock, flags);
|
||||
spin_unlock(&dq->lock);
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -2076,10 +2070,10 @@ _hisi_sas_internal_task_abort(struct hisi_hba *hisi_hba,
|
||||
struct hisi_sas_cq *cq =
|
||||
&hisi_hba->cq[slot->dlvry_queue];
|
||||
/*
|
||||
* flush tasklet to avoid free'ing task
|
||||
* sync irq to avoid free'ing task
|
||||
* before using task in IO completion
|
||||
*/
|
||||
tasklet_kill(&cq->tasklet);
|
||||
synchronize_irq(cq->irq_no);
|
||||
slot->task = NULL;
|
||||
}
|
||||
dev_err(dev, "internal task abort: timeout and not done.\n");
|
||||
@@ -2131,7 +2125,7 @@ hisi_sas_internal_task_abort(struct hisi_hba *hisi_hba,
|
||||
case HISI_SAS_INT_ABT_DEV:
|
||||
for (i = 0; i < hisi_hba->cq_nvecs; i++) {
|
||||
struct hisi_sas_cq *cq = &hisi_hba->cq[i];
|
||||
const struct cpumask *mask = cq->pci_irq_mask;
|
||||
const struct cpumask *mask = cq->irq_mask;
|
||||
|
||||
if (mask && !cpumask_intersects(cpu_online_mask, mask))
|
||||
continue;
|
||||
@@ -2225,17 +2219,17 @@ void hisi_sas_phy_down(struct hisi_hba *hisi_hba, int phy_no, int rdy)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(hisi_sas_phy_down);
|
||||
|
||||
void hisi_sas_kill_tasklets(struct hisi_hba *hisi_hba)
|
||||
void hisi_sas_sync_irqs(struct hisi_hba *hisi_hba)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < hisi_hba->cq_nvecs; i++) {
|
||||
struct hisi_sas_cq *cq = &hisi_hba->cq[i];
|
||||
|
||||
tasklet_kill(&cq->tasklet);
|
||||
synchronize_irq(cq->irq_no);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(hisi_sas_kill_tasklets);
|
||||
EXPORT_SYMBOL_GPL(hisi_sas_sync_irqs);
|
||||
|
||||
int hisi_sas_host_reset(struct Scsi_Host *shost, int reset_type)
|
||||
{
|
||||
@@ -3936,7 +3930,7 @@ void hisi_sas_debugfs_init(struct hisi_hba *hisi_hba)
|
||||
|
||||
hisi_hba->debugfs_dir = debugfs_create_dir(dev_name(dev),
|
||||
hisi_sas_debugfs_dir);
|
||||
debugfs_create_file("trigger_dump", 0600,
|
||||
debugfs_create_file("trigger_dump", 0200,
|
||||
hisi_hba->debugfs_dir,
|
||||
hisi_hba,
|
||||
&hisi_sas_debugfs_trigger_dump_fops);
|
||||
|
||||
@@ -1772,6 +1772,9 @@ static struct scsi_host_template sht_v1_hw = {
|
||||
.eh_target_reset_handler = sas_eh_target_reset_handler,
|
||||
.target_destroy = sas_target_destroy,
|
||||
.ioctl = sas_ioctl,
|
||||
#ifdef CONFIG_COMPAT
|
||||
.compat_ioctl = sas_ioctl,
|
||||
#endif
|
||||
.shost_attrs = host_attrs_v1_hw,
|
||||
.host_reset = hisi_sas_host_reset,
|
||||
};
|
||||
|
||||
@@ -773,7 +773,6 @@ slot_index_alloc_quirk_v2_hw(struct hisi_hba *hisi_hba,
|
||||
struct hisi_sas_device *sas_dev = device->lldd_dev;
|
||||
int sata_idx = sas_dev->sata_idx;
|
||||
int start, end;
|
||||
unsigned long flags;
|
||||
|
||||
if (!sata_dev) {
|
||||
/*
|
||||
@@ -797,12 +796,12 @@ slot_index_alloc_quirk_v2_hw(struct hisi_hba *hisi_hba,
|
||||
end = 64 * (sata_idx + 2);
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&hisi_hba->lock, flags);
|
||||
spin_lock(&hisi_hba->lock);
|
||||
while (1) {
|
||||
start = find_next_zero_bit(bitmap,
|
||||
hisi_hba->slot_index_count, start);
|
||||
if (start >= end) {
|
||||
spin_unlock_irqrestore(&hisi_hba->lock, flags);
|
||||
spin_unlock(&hisi_hba->lock);
|
||||
return -SAS_QUEUE_FULL;
|
||||
}
|
||||
/*
|
||||
@@ -814,7 +813,7 @@ slot_index_alloc_quirk_v2_hw(struct hisi_hba *hisi_hba,
|
||||
}
|
||||
|
||||
set_bit(start, bitmap);
|
||||
spin_unlock_irqrestore(&hisi_hba->lock, flags);
|
||||
spin_unlock(&hisi_hba->lock);
|
||||
return start;
|
||||
}
|
||||
|
||||
@@ -843,9 +842,8 @@ hisi_sas_device *alloc_dev_quirk_v2_hw(struct domain_device *device)
|
||||
struct hisi_sas_device *sas_dev = NULL;
|
||||
int i, sata_dev = dev_is_sata(device);
|
||||
int sata_idx = -1;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&hisi_hba->lock, flags);
|
||||
spin_lock(&hisi_hba->lock);
|
||||
|
||||
if (sata_dev)
|
||||
if (!sata_index_alloc_v2_hw(hisi_hba, &sata_idx))
|
||||
@@ -876,7 +874,7 @@ hisi_sas_device *alloc_dev_quirk_v2_hw(struct domain_device *device)
|
||||
}
|
||||
|
||||
out:
|
||||
spin_unlock_irqrestore(&hisi_hba->lock, flags);
|
||||
spin_unlock(&hisi_hba->lock);
|
||||
|
||||
return sas_dev;
|
||||
}
|
||||
@@ -3111,9 +3109,9 @@ static irqreturn_t fatal_axi_int_v2_hw(int irq_no, void *p)
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static void cq_tasklet_v2_hw(unsigned long val)
|
||||
static irqreturn_t cq_thread_v2_hw(int irq_no, void *p)
|
||||
{
|
||||
struct hisi_sas_cq *cq = (struct hisi_sas_cq *)val;
|
||||
struct hisi_sas_cq *cq = p;
|
||||
struct hisi_hba *hisi_hba = cq->hisi_hba;
|
||||
struct hisi_sas_slot *slot;
|
||||
struct hisi_sas_itct *itct;
|
||||
@@ -3181,6 +3179,8 @@ static void cq_tasklet_v2_hw(unsigned long val)
|
||||
/* update rd_point */
|
||||
cq->rd_point = rd_point;
|
||||
hisi_sas_write32(hisi_hba, COMPL_Q_0_RD_PTR + (0x14 * queue), rd_point);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static irqreturn_t cq_interrupt_v2_hw(int irq_no, void *p)
|
||||
@@ -3191,9 +3191,7 @@ static irqreturn_t cq_interrupt_v2_hw(int irq_no, void *p)
|
||||
|
||||
hisi_sas_write32(hisi_hba, OQ_INT_SRC, 1 << queue);
|
||||
|
||||
tasklet_schedule(&cq->tasklet);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
return IRQ_WAKE_THREAD;
|
||||
}
|
||||
|
||||
static irqreturn_t sata_int_v2_hw(int irq_no, void *p)
|
||||
@@ -3360,18 +3358,18 @@ static int interrupt_init_v2_hw(struct hisi_hba *hisi_hba)
|
||||
|
||||
for (queue_no = 0; queue_no < hisi_hba->queue_count; queue_no++) {
|
||||
struct hisi_sas_cq *cq = &hisi_hba->cq[queue_no];
|
||||
struct tasklet_struct *t = &cq->tasklet;
|
||||
|
||||
irq = irq_map[queue_no + 96];
|
||||
rc = devm_request_irq(dev, irq, cq_interrupt_v2_hw, 0,
|
||||
DRV_NAME " cq", cq);
|
||||
cq->irq_no = irq_map[queue_no + 96];
|
||||
rc = devm_request_threaded_irq(dev, cq->irq_no,
|
||||
cq_interrupt_v2_hw,
|
||||
cq_thread_v2_hw, IRQF_ONESHOT,
|
||||
DRV_NAME " cq", cq);
|
||||
if (rc) {
|
||||
dev_err(dev, "irq init: could not request cq interrupt %d, rc=%d\n",
|
||||
irq, rc);
|
||||
rc = -ENOENT;
|
||||
goto err_out;
|
||||
}
|
||||
tasklet_init(t, cq_tasklet_v2_hw, (unsigned long)cq);
|
||||
}
|
||||
|
||||
hisi_hba->cq_nvecs = hisi_hba->queue_count;
|
||||
@@ -3432,7 +3430,6 @@ static int soft_reset_v2_hw(struct hisi_hba *hisi_hba)
|
||||
|
||||
interrupt_disable_v2_hw(hisi_hba);
|
||||
hisi_sas_write32(hisi_hba, DLVRY_QUEUE_ENABLE, 0x0);
|
||||
hisi_sas_kill_tasklets(hisi_hba);
|
||||
|
||||
hisi_sas_stop_phys(hisi_hba);
|
||||
|
||||
@@ -3551,6 +3548,9 @@ static struct scsi_host_template sht_v2_hw = {
|
||||
.eh_target_reset_handler = sas_eh_target_reset_handler,
|
||||
.target_destroy = sas_target_destroy,
|
||||
.ioctl = sas_ioctl,
|
||||
#ifdef CONFIG_COMPAT
|
||||
.compat_ioctl = sas_ioctl,
|
||||
#endif
|
||||
.shost_attrs = host_attrs_v2_hw,
|
||||
.host_reset = hisi_sas_host_reset,
|
||||
};
|
||||
@@ -3603,11 +3603,6 @@ static int hisi_sas_v2_probe(struct platform_device *pdev)
|
||||
|
||||
static int hisi_sas_v2_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct sas_ha_struct *sha = platform_get_drvdata(pdev);
|
||||
struct hisi_hba *hisi_hba = sha->lldd_ha;
|
||||
|
||||
hisi_sas_kill_tasklets(hisi_hba);
|
||||
|
||||
return hisi_sas_remove(pdev);
|
||||
}
|
||||
|
||||
|
||||
@@ -495,6 +495,13 @@ struct hisi_sas_err_record_v3 {
|
||||
#define BASE_VECTORS_V3_HW 16
|
||||
#define MIN_AFFINE_VECTORS_V3_HW (BASE_VECTORS_V3_HW + 1)
|
||||
|
||||
#define CHNL_INT_STS_MSK 0xeeeeeeee
|
||||
#define CHNL_INT_STS_PHY_MSK 0xe
|
||||
#define CHNL_INT_STS_INT0_MSK BIT(1)
|
||||
#define CHNL_INT_STS_INT1_MSK BIT(2)
|
||||
#define CHNL_INT_STS_INT2_MSK BIT(3)
|
||||
#define CHNL_WIDTH 4
|
||||
|
||||
enum {
|
||||
DSM_FUNC_ERR_HANDLE_MSI = 0,
|
||||
};
|
||||
@@ -1819,19 +1826,19 @@ static irqreturn_t int_chnl_int_v3_hw(int irq_no, void *p)
|
||||
int phy_no = 0;
|
||||
|
||||
irq_msk = hisi_sas_read32(hisi_hba, CHNL_INT_STATUS)
|
||||
& 0xeeeeeeee;
|
||||
& CHNL_INT_STS_MSK;
|
||||
|
||||
while (irq_msk) {
|
||||
if (irq_msk & (2 << (phy_no * 4)))
|
||||
if (irq_msk & (CHNL_INT_STS_INT0_MSK << (phy_no * CHNL_WIDTH)))
|
||||
handle_chl_int0_v3_hw(hisi_hba, phy_no);
|
||||
|
||||
if (irq_msk & (4 << (phy_no * 4)))
|
||||
if (irq_msk & (CHNL_INT_STS_INT1_MSK << (phy_no * CHNL_WIDTH)))
|
||||
handle_chl_int1_v3_hw(hisi_hba, phy_no);
|
||||
|
||||
if (irq_msk & (8 << (phy_no * 4)))
|
||||
if (irq_msk & (CHNL_INT_STS_INT2_MSK << (phy_no * CHNL_WIDTH)))
|
||||
handle_chl_int2_v3_hw(hisi_hba, phy_no);
|
||||
|
||||
irq_msk &= ~(0xe << (phy_no * 4));
|
||||
irq_msk &= ~(CHNL_INT_STS_PHY_MSK << (phy_no * CHNL_WIDTH));
|
||||
phy_no++;
|
||||
}
|
||||
|
||||
@@ -2299,9 +2306,9 @@ out:
|
||||
return sts;
|
||||
}
|
||||
|
||||
static void cq_tasklet_v3_hw(unsigned long val)
|
||||
static irqreturn_t cq_thread_v3_hw(int irq_no, void *p)
|
||||
{
|
||||
struct hisi_sas_cq *cq = (struct hisi_sas_cq *)val;
|
||||
struct hisi_sas_cq *cq = p;
|
||||
struct hisi_hba *hisi_hba = cq->hisi_hba;
|
||||
struct hisi_sas_slot *slot;
|
||||
struct hisi_sas_complete_v3_hdr *complete_queue;
|
||||
@@ -2338,6 +2345,8 @@ static void cq_tasklet_v3_hw(unsigned long val)
|
||||
/* update rd_point */
|
||||
cq->rd_point = rd_point;
|
||||
hisi_sas_write32(hisi_hba, COMPL_Q_0_RD_PTR + (0x14 * queue), rd_point);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static irqreturn_t cq_interrupt_v3_hw(int irq_no, void *p)
|
||||
@@ -2348,9 +2357,7 @@ static irqreturn_t cq_interrupt_v3_hw(int irq_no, void *p)
|
||||
|
||||
hisi_sas_write32(hisi_hba, OQ_INT_SRC, 1 << queue);
|
||||
|
||||
tasklet_schedule(&cq->tasklet);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
return IRQ_WAKE_THREAD;
|
||||
}
|
||||
|
||||
static void setup_reply_map_v3_hw(struct hisi_hba *hisi_hba, int nvecs)
|
||||
@@ -2365,7 +2372,7 @@ static void setup_reply_map_v3_hw(struct hisi_hba *hisi_hba, int nvecs)
|
||||
BASE_VECTORS_V3_HW);
|
||||
if (!mask)
|
||||
goto fallback;
|
||||
cq->pci_irq_mask = mask;
|
||||
cq->irq_mask = mask;
|
||||
for_each_cpu(cpu, mask)
|
||||
hisi_hba->reply_map[cpu] = queue;
|
||||
}
|
||||
@@ -2389,6 +2396,8 @@ static int interrupt_init_v3_hw(struct hisi_hba *hisi_hba)
|
||||
.pre_vectors = BASE_VECTORS_V3_HW,
|
||||
};
|
||||
|
||||
dev_info(dev, "Enable MSI auto-affinity\n");
|
||||
|
||||
min_msi = MIN_AFFINE_VECTORS_V3_HW;
|
||||
|
||||
hisi_hba->reply_map = devm_kcalloc(dev, nr_cpu_ids,
|
||||
@@ -2441,15 +2450,20 @@ static int interrupt_init_v3_hw(struct hisi_hba *hisi_hba)
|
||||
goto free_irq_vectors;
|
||||
}
|
||||
|
||||
/* Init tasklets for cq only */
|
||||
if (hisi_sas_intr_conv)
|
||||
dev_info(dev, "Enable interrupt converge\n");
|
||||
|
||||
for (i = 0; i < hisi_hba->cq_nvecs; i++) {
|
||||
struct hisi_sas_cq *cq = &hisi_hba->cq[i];
|
||||
struct tasklet_struct *t = &cq->tasklet;
|
||||
int nr = hisi_sas_intr_conv ? 16 : 16 + i;
|
||||
unsigned long irqflags = hisi_sas_intr_conv ? IRQF_SHARED : 0;
|
||||
unsigned long irqflags = hisi_sas_intr_conv ? IRQF_SHARED :
|
||||
IRQF_ONESHOT;
|
||||
|
||||
rc = devm_request_irq(dev, pci_irq_vector(pdev, nr),
|
||||
cq_interrupt_v3_hw, irqflags,
|
||||
cq->irq_no = pci_irq_vector(pdev, nr);
|
||||
rc = devm_request_threaded_irq(dev, cq->irq_no,
|
||||
cq_interrupt_v3_hw,
|
||||
cq_thread_v3_hw,
|
||||
irqflags,
|
||||
DRV_NAME " cq", cq);
|
||||
if (rc) {
|
||||
dev_err(dev, "could not request cq%d interrupt, rc=%d\n",
|
||||
@@ -2457,8 +2471,6 @@ static int interrupt_init_v3_hw(struct hisi_hba *hisi_hba)
|
||||
rc = -ENOENT;
|
||||
goto free_irq_vectors;
|
||||
}
|
||||
|
||||
tasklet_init(t, cq_tasklet_v3_hw, (unsigned long)cq);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -2534,7 +2546,6 @@ static int disable_host_v3_hw(struct hisi_hba *hisi_hba)
|
||||
|
||||
interrupt_disable_v3_hw(hisi_hba);
|
||||
hisi_sas_write32(hisi_hba, DLVRY_QUEUE_ENABLE, 0x0);
|
||||
hisi_sas_kill_tasklets(hisi_hba);
|
||||
|
||||
hisi_sas_stop_phys(hisi_hba);
|
||||
|
||||
@@ -2910,7 +2921,7 @@ static void debugfs_snapshot_prepare_v3_hw(struct hisi_hba *hisi_hba)
|
||||
|
||||
wait_cmds_complete_timeout_v3_hw(hisi_hba, 100, 5000);
|
||||
|
||||
hisi_sas_kill_tasklets(hisi_hba);
|
||||
hisi_sas_sync_irqs(hisi_hba);
|
||||
}
|
||||
|
||||
static void debugfs_snapshot_restore_v3_hw(struct hisi_hba *hisi_hba)
|
||||
@@ -3075,6 +3086,9 @@ static struct scsi_host_template sht_v3_hw = {
|
||||
.eh_target_reset_handler = sas_eh_target_reset_handler,
|
||||
.target_destroy = sas_target_destroy,
|
||||
.ioctl = sas_ioctl,
|
||||
#ifdef CONFIG_COMPAT
|
||||
.compat_ioctl = sas_ioctl,
|
||||
#endif
|
||||
.shost_attrs = host_attrs_v3_hw,
|
||||
.tag_alloc_policy = BLK_TAG_ALLOC_RR,
|
||||
.host_reset = hisi_sas_host_reset,
|
||||
@@ -3309,7 +3323,6 @@ static void hisi_sas_v3_remove(struct pci_dev *pdev)
|
||||
sas_remove_host(sha->core.shost);
|
||||
|
||||
hisi_sas_v3_destroy_irqs(pdev, hisi_hba);
|
||||
hisi_sas_kill_tasklets(hisi_hba);
|
||||
pci_release_regions(pdev);
|
||||
pci_disable_device(pdev);
|
||||
hisi_sas_free(hisi_hba);
|
||||
|
||||
@@ -1877,7 +1877,6 @@ static void ibmvscsis_send_messages(struct scsi_info *vscsi)
|
||||
*/
|
||||
struct viosrp_crq *crq = (struct viosrp_crq *)&msg_hi;
|
||||
struct ibmvscsis_cmd *cmd, *nxt;
|
||||
struct iu_entry *iue;
|
||||
long rc = ADAPT_SUCCESS;
|
||||
bool retry = false;
|
||||
|
||||
@@ -1931,8 +1930,6 @@ static void ibmvscsis_send_messages(struct scsi_info *vscsi)
|
||||
*/
|
||||
vscsi->credit += 1;
|
||||
} else {
|
||||
iue = cmd->iue;
|
||||
|
||||
crq->valid = VALID_CMD_RESP_EL;
|
||||
crq->format = cmd->rsp.format;
|
||||
|
||||
@@ -3796,7 +3793,6 @@ static int ibmvscsis_queue_data_in(struct se_cmd *se_cmd)
|
||||
se_cmd);
|
||||
struct iu_entry *iue = cmd->iue;
|
||||
struct scsi_info *vscsi = cmd->adapter;
|
||||
char *sd;
|
||||
uint len = 0;
|
||||
int rc;
|
||||
|
||||
@@ -3804,7 +3800,6 @@ static int ibmvscsis_queue_data_in(struct se_cmd *se_cmd)
|
||||
1);
|
||||
if (rc) {
|
||||
dev_err(&vscsi->dev, "srp_transfer_data failed: %d\n", rc);
|
||||
sd = se_cmd->sense_buffer;
|
||||
se_cmd->scsi_sense_length = 18;
|
||||
memset(se_cmd->sense_buffer, 0, se_cmd->scsi_sense_length);
|
||||
/* Logical Unit Communication Time-out asc/ascq = 0x0801 */
|
||||
|
||||
@@ -1640,7 +1640,7 @@ static int initio_state_6(struct initio_host * host)
|
||||
*
|
||||
*/
|
||||
|
||||
int initio_state_7(struct initio_host * host)
|
||||
static int initio_state_7(struct initio_host * host)
|
||||
{
|
||||
int cnt, i;
|
||||
|
||||
|
||||
@@ -6727,6 +6727,9 @@ static struct scsi_host_template driver_template = {
|
||||
.name = "IPR",
|
||||
.info = ipr_ioa_info,
|
||||
.ioctl = ipr_ioctl,
|
||||
#ifdef CONFIG_COMPAT
|
||||
.compat_ioctl = ipr_ioctl,
|
||||
#endif
|
||||
.queuecommand = ipr_queuecommand,
|
||||
.eh_abort_handler = ipr_eh_abort,
|
||||
.eh_device_reset_handler = ipr_eh_dev_reset,
|
||||
|
||||
@@ -168,6 +168,9 @@ static struct scsi_host_template isci_sht = {
|
||||
.eh_target_reset_handler = sas_eh_target_reset_handler,
|
||||
.target_destroy = sas_target_destroy,
|
||||
.ioctl = sas_ioctl,
|
||||
#ifdef CONFIG_COMPAT
|
||||
.compat_ioctl = sas_ioctl,
|
||||
#endif
|
||||
.shost_attrs = isci_host_attrs,
|
||||
.track_queue_depth = 1,
|
||||
};
|
||||
|
||||
@@ -887,6 +887,10 @@ free_host:
|
||||
static void iscsi_sw_tcp_session_destroy(struct iscsi_cls_session *cls_session)
|
||||
{
|
||||
struct Scsi_Host *shost = iscsi_session_to_shost(cls_session);
|
||||
struct iscsi_session *session = cls_session->dd_data;
|
||||
|
||||
if (WARN_ON_ONCE(session->leadconn))
|
||||
return;
|
||||
|
||||
iscsi_tcp_r2tpool_free(cls_session->dd_data);
|
||||
iscsi_session_teardown(cls_session);
|
||||
|
||||
@@ -137,7 +137,7 @@ static void sas_ata_task_done(struct sas_task *task)
|
||||
} else {
|
||||
ac = sas_to_ata_err(stat);
|
||||
if (ac) {
|
||||
pr_warn("%s: SAS error %x\n", __func__, stat->stat);
|
||||
pr_warn("%s: SAS error 0x%x\n", __func__, stat->stat);
|
||||
/* We saw a SAS error. Send a vague error. */
|
||||
if (!link->sactive) {
|
||||
qc->err_mask = ac;
|
||||
|
||||
@@ -179,7 +179,7 @@ int sas_notify_lldd_dev_found(struct domain_device *dev)
|
||||
|
||||
res = i->dft->lldd_dev_found(dev);
|
||||
if (res) {
|
||||
pr_warn("driver on host %s cannot handle device %llx, error:%d\n",
|
||||
pr_warn("driver on host %s cannot handle device %016llx, error:%d\n",
|
||||
dev_name(sas_ha->dev),
|
||||
SAS_ADDR(dev->sas_addr), res);
|
||||
}
|
||||
|
||||
@@ -500,7 +500,7 @@ static int sas_ex_general(struct domain_device *dev)
|
||||
ex_assign_report_general(dev, rg_resp);
|
||||
|
||||
if (dev->ex_dev.configuring) {
|
||||
pr_debug("RG: ex %llx self-configuring...\n",
|
||||
pr_debug("RG: ex %016llx self-configuring...\n",
|
||||
SAS_ADDR(dev->sas_addr));
|
||||
schedule_timeout_interruptible(5*HZ);
|
||||
} else
|
||||
@@ -881,7 +881,7 @@ static struct domain_device *sas_ex_discover_end_dev(
|
||||
|
||||
res = sas_discover_end_dev(child);
|
||||
if (res) {
|
||||
pr_notice("sas_discover_end_dev() for device %16llx at %016llx:%02d returned 0x%x\n",
|
||||
pr_notice("sas_discover_end_dev() for device %016llx at %016llx:%02d returned 0x%x\n",
|
||||
SAS_ADDR(child->sas_addr),
|
||||
SAS_ADDR(parent->sas_addr), phy_id, res);
|
||||
goto out_list_del;
|
||||
|
||||
@@ -107,7 +107,7 @@ static inline void sas_smp_host_handler(struct bsg_job *job,
|
||||
|
||||
static inline void sas_fail_probe(struct domain_device *dev, const char *func, int err)
|
||||
{
|
||||
pr_warn("%s: for %s device %16llx returned %d\n",
|
||||
pr_warn("%s: for %s device %016llx returned %d\n",
|
||||
func, dev->parent ? "exp-attached" :
|
||||
"direct-attached",
|
||||
SAS_ADDR(dev->sas_addr), err);
|
||||
|
||||
@@ -165,7 +165,7 @@ static void sas_form_port(struct asd_sas_phy *phy)
|
||||
}
|
||||
sas_port_add_phy(port->port, phy->phy);
|
||||
|
||||
pr_debug("%s added to %s, phy_mask:0x%x (%16llx)\n",
|
||||
pr_debug("%s added to %s, phy_mask:0x%x (%016llx)\n",
|
||||
dev_name(&phy->phy->dev), dev_name(&port->port->dev),
|
||||
port->phy_mask,
|
||||
SAS_ADDR(port->attached_sas_addr));
|
||||
|
||||
@@ -330,7 +330,7 @@ static int sas_recover_lu(struct domain_device *dev, struct scsi_cmnd *cmd)
|
||||
|
||||
int_to_scsilun(cmd->device->lun, &lun);
|
||||
|
||||
pr_notice("eh: device %llx LUN %llx has the task\n",
|
||||
pr_notice("eh: device %016llx LUN 0x%llx has the task\n",
|
||||
SAS_ADDR(dev->sas_addr),
|
||||
cmd->device->lun);
|
||||
|
||||
@@ -615,7 +615,7 @@ static void sas_eh_handle_sas_errors(struct Scsi_Host *shost, struct list_head *
|
||||
reset:
|
||||
tmf_resp = sas_recover_lu(task->dev, cmd);
|
||||
if (tmf_resp == TMF_RESP_FUNC_COMPLETE) {
|
||||
pr_notice("dev %016llx LU %llx is recovered\n",
|
||||
pr_notice("dev %016llx LU 0x%llx is recovered\n",
|
||||
SAS_ADDR(task->dev),
|
||||
cmd->device->lun);
|
||||
sas_eh_finish_cmd(cmd);
|
||||
@@ -666,7 +666,7 @@ static void sas_eh_handle_sas_errors(struct Scsi_Host *shost, struct list_head *
|
||||
* of effort could recover from errors. Quite
|
||||
* possibly the HA just disappeared.
|
||||
*/
|
||||
pr_err("error from device %llx, LUN %llx couldn't be recovered in any way\n",
|
||||
pr_err("error from device %016llx, LUN 0x%llx couldn't be recovered in any way\n",
|
||||
SAS_ADDR(task->dev->sas_addr),
|
||||
cmd->device->lun);
|
||||
|
||||
@@ -851,7 +851,7 @@ int sas_slave_configure(struct scsi_device *scsi_dev)
|
||||
if (scsi_dev->tagged_supported) {
|
||||
scsi_change_queue_depth(scsi_dev, SAS_DEF_QD);
|
||||
} else {
|
||||
pr_notice("device %llx, LUN %llx doesn't support TCQ\n",
|
||||
pr_notice("device %016llx, LUN 0x%llx doesn't support TCQ\n",
|
||||
SAS_ADDR(dev->sas_addr), scsi_dev->lun);
|
||||
scsi_change_queue_depth(scsi_dev, 1);
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ void sas_ssp_task_response(struct device *dev, struct sas_task *task,
|
||||
memcpy(tstat->buf, iu->sense_data, tstat->buf_valid_size);
|
||||
|
||||
if (iu->status != SAM_STAT_CHECK_CONDITION)
|
||||
dev_warn(dev, "dev %llx sent sense data, but stat(%x) is not CHECK CONDITION\n",
|
||||
dev_warn(dev, "dev %016llx sent sense data, but stat(0x%x) is not CHECK CONDITION\n",
|
||||
SAS_ADDR(task->dev->sas_addr), iu->status);
|
||||
}
|
||||
else
|
||||
|
||||
@@ -1223,6 +1223,8 @@ struct lpfc_hba {
|
||||
#define LPFC_POLL_HB 1 /* slowpath heartbeat */
|
||||
#define LPFC_POLL_FASTPATH 0 /* called from fastpath */
|
||||
#define LPFC_POLL_SLOWPATH 1 /* called from slowpath */
|
||||
|
||||
char os_host_name[MAXHOSTNAMELEN];
|
||||
};
|
||||
|
||||
static inline struct Scsi_Host *
|
||||
|
||||
@@ -4123,14 +4123,13 @@ lpfc_topology_store(struct device *dev, struct device_attribute *attr,
|
||||
/*
|
||||
* The 'topology' is not a configurable parameter if :
|
||||
* - persistent topology enabled
|
||||
* - G7 adapters
|
||||
* - G6 with no private loop support
|
||||
* - G7/G6 with no private loop support
|
||||
*/
|
||||
|
||||
if (((phba->hba_flag & HBA_PERSISTENT_TOPO) ||
|
||||
if ((phba->hba_flag & HBA_PERSISTENT_TOPO ||
|
||||
(!phba->sli4_hba.pc_sli4_params.pls &&
|
||||
phba->pcidev->device == PCI_DEVICE_ID_LANCER_G6_FC) ||
|
||||
phba->pcidev->device == PCI_DEVICE_ID_LANCER_G7_FC) &&
|
||||
(phba->pcidev->device == PCI_DEVICE_ID_LANCER_G6_FC ||
|
||||
phba->pcidev->device == PCI_DEVICE_ID_LANCER_G7_FC))) &&
|
||||
val == 4) {
|
||||
lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT,
|
||||
"3114 Loop mode not supported\n");
|
||||
|
||||
@@ -180,7 +180,7 @@ int lpfc_issue_gidft(struct lpfc_vport *vport);
|
||||
int lpfc_get_gidft_type(struct lpfc_vport *vport, struct lpfc_iocbq *iocbq);
|
||||
int lpfc_ns_cmd(struct lpfc_vport *, int, uint8_t, uint32_t);
|
||||
int lpfc_fdmi_cmd(struct lpfc_vport *, struct lpfc_nodelist *, int, uint32_t);
|
||||
void lpfc_fdmi_num_disc_check(struct lpfc_vport *);
|
||||
void lpfc_fdmi_change_check(struct lpfc_vport *vport);
|
||||
void lpfc_delayed_disc_tmo(struct timer_list *);
|
||||
void lpfc_delayed_disc_timeout_handler(struct lpfc_vport *);
|
||||
|
||||
|
||||
@@ -1493,33 +1493,35 @@ int
|
||||
lpfc_vport_symbolic_node_name(struct lpfc_vport *vport, char *symbol,
|
||||
size_t size)
|
||||
{
|
||||
char fwrev[FW_REV_STR_SIZE];
|
||||
int n;
|
||||
char fwrev[FW_REV_STR_SIZE] = {0};
|
||||
char tmp[MAXHOSTNAMELEN] = {0};
|
||||
|
||||
memset(symbol, 0, size);
|
||||
|
||||
scnprintf(tmp, sizeof(tmp), "Emulex %s", vport->phba->ModelName);
|
||||
if (strlcat(symbol, tmp, size) >= size)
|
||||
goto buffer_done;
|
||||
|
||||
lpfc_decode_firmware_rev(vport->phba, fwrev, 0);
|
||||
scnprintf(tmp, sizeof(tmp), " FV%s", fwrev);
|
||||
if (strlcat(symbol, tmp, size) >= size)
|
||||
goto buffer_done;
|
||||
|
||||
n = scnprintf(symbol, size, "Emulex %s", vport->phba->ModelName);
|
||||
if (size < n)
|
||||
return n;
|
||||
scnprintf(tmp, sizeof(tmp), " DV%s", lpfc_release_version);
|
||||
if (strlcat(symbol, tmp, size) >= size)
|
||||
goto buffer_done;
|
||||
|
||||
n += scnprintf(symbol + n, size - n, " FV%s", fwrev);
|
||||
if (size < n)
|
||||
return n;
|
||||
|
||||
n += scnprintf(symbol + n, size - n, " DV%s.",
|
||||
lpfc_release_version);
|
||||
if (size < n)
|
||||
return n;
|
||||
|
||||
n += scnprintf(symbol + n, size - n, " HN:%s.",
|
||||
init_utsname()->nodename);
|
||||
if (size < n)
|
||||
return n;
|
||||
scnprintf(tmp, sizeof(tmp), " HN:%s", vport->phba->os_host_name);
|
||||
if (strlcat(symbol, tmp, size) >= size)
|
||||
goto buffer_done;
|
||||
|
||||
/* Note :- OS name is "Linux" */
|
||||
n += scnprintf(symbol + n, size - n, " OS:%s",
|
||||
init_utsname()->sysname);
|
||||
return n;
|
||||
scnprintf(tmp, sizeof(tmp), " OS:%s", init_utsname()->sysname);
|
||||
strlcat(symbol, tmp, size);
|
||||
|
||||
buffer_done:
|
||||
return strnlen(symbol, size);
|
||||
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
@@ -1998,14 +2000,16 @@ lpfc_cmpl_ct_disc_fdmi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
|
||||
|
||||
|
||||
/**
|
||||
* lpfc_fdmi_num_disc_check - Check how many mapped NPorts we are connected to
|
||||
* lpfc_fdmi_change_check - Check for changed FDMI parameters
|
||||
* @vport: pointer to a host virtual N_Port data structure.
|
||||
*
|
||||
* Called from hbeat timeout routine to check if the number of discovered
|
||||
* ports has changed. If so, re-register thar port Attribute.
|
||||
* Check how many mapped NPorts we are connected to
|
||||
* Check if our hostname changed
|
||||
* Called from hbeat timeout routine to check if any FDMI parameters
|
||||
* changed. If so, re-register those Attributes.
|
||||
*/
|
||||
void
|
||||
lpfc_fdmi_num_disc_check(struct lpfc_vport *vport)
|
||||
lpfc_fdmi_change_check(struct lpfc_vport *vport)
|
||||
{
|
||||
struct lpfc_hba *phba = vport->phba;
|
||||
struct lpfc_nodelist *ndlp;
|
||||
@@ -2018,17 +2022,41 @@ lpfc_fdmi_num_disc_check(struct lpfc_vport *vport)
|
||||
if (!(vport->fc_flag & FC_FABRIC))
|
||||
return;
|
||||
|
||||
ndlp = lpfc_findnode_did(vport, FDMI_DID);
|
||||
if (!ndlp || !NLP_CHK_NODE_ACT(ndlp))
|
||||
return;
|
||||
|
||||
/* Check if system hostname changed */
|
||||
if (strcmp(phba->os_host_name, init_utsname()->nodename)) {
|
||||
memset(phba->os_host_name, 0, sizeof(phba->os_host_name));
|
||||
scnprintf(phba->os_host_name, sizeof(phba->os_host_name), "%s",
|
||||
init_utsname()->nodename);
|
||||
lpfc_ns_cmd(vport, SLI_CTNS_RSNN_NN, 0, 0);
|
||||
|
||||
/* Since this effects multiple HBA and PORT attributes, we need
|
||||
* de-register and go thru the whole FDMI registration cycle.
|
||||
* DHBA -> DPRT -> RHBA -> RPA (physical port)
|
||||
* DPRT -> RPRT (vports)
|
||||
*/
|
||||
if (vport->port_type == LPFC_PHYSICAL_PORT)
|
||||
lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_DHBA, 0);
|
||||
else
|
||||
lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_DPRT, 0);
|
||||
|
||||
/* Since this code path registers all the port attributes
|
||||
* we can just return without further checking.
|
||||
*/
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(vport->fdmi_port_mask & LPFC_FDMI_PORT_ATTR_num_disc))
|
||||
return;
|
||||
|
||||
/* Check if the number of mapped NPorts changed */
|
||||
cnt = lpfc_find_map_node(vport);
|
||||
if (cnt == vport->fdmi_num_disc)
|
||||
return;
|
||||
|
||||
ndlp = lpfc_findnode_did(vport, FDMI_DID);
|
||||
if (!ndlp || !NLP_CHK_NODE_ACT(ndlp))
|
||||
return;
|
||||
|
||||
if (vport->port_type == LPFC_PHYSICAL_PORT) {
|
||||
lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_RPA,
|
||||
LPFC_FDMI_PORT_ATTR_num_disc);
|
||||
@@ -2616,8 +2644,8 @@ lpfc_fdmi_port_attr_host_name(struct lpfc_vport *vport,
|
||||
ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
|
||||
memset(ae, 0, 256);
|
||||
|
||||
snprintf(ae->un.AttrString, sizeof(ae->un.AttrString), "%s",
|
||||
init_utsname()->nodename);
|
||||
scnprintf(ae->un.AttrString, sizeof(ae->un.AttrString), "%s",
|
||||
vport->phba->os_host_name);
|
||||
|
||||
len = strnlen(ae->un.AttrString, sizeof(ae->un.AttrString));
|
||||
len += (len & 3) ? (4 - (len & 3)) : 4;
|
||||
|
||||
@@ -2085,6 +2085,8 @@ static int lpfc_debugfs_ras_log_data(struct lpfc_hba *phba,
|
||||
int copied = 0;
|
||||
struct lpfc_dmabuf *dmabuf, *next;
|
||||
|
||||
memset(buffer, 0, size);
|
||||
|
||||
spin_lock_irq(&phba->hbalock);
|
||||
if (phba->ras_fwlog.state != ACTIVE) {
|
||||
spin_unlock_irq(&phba->hbalock);
|
||||
@@ -2094,10 +2096,15 @@ static int lpfc_debugfs_ras_log_data(struct lpfc_hba *phba,
|
||||
|
||||
list_for_each_entry_safe(dmabuf, next,
|
||||
&phba->ras_fwlog.fwlog_buff_list, list) {
|
||||
/* Check if copying will go over size and a '\0' char */
|
||||
if ((copied + LPFC_RAS_MAX_ENTRY_SIZE) >= (size - 1)) {
|
||||
memcpy(buffer + copied, dmabuf->virt,
|
||||
size - copied - 1);
|
||||
copied += size - copied - 1;
|
||||
break;
|
||||
}
|
||||
memcpy(buffer + copied, dmabuf->virt, LPFC_RAS_MAX_ENTRY_SIZE);
|
||||
copied += LPFC_RAS_MAX_ENTRY_SIZE;
|
||||
if (size > copied)
|
||||
break;
|
||||
}
|
||||
return copied;
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#include <linux/kthread.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/lockdep.h>
|
||||
#include <linux/utsname.h>
|
||||
|
||||
#include <scsi/scsi.h>
|
||||
#include <scsi/scsi_device.h>
|
||||
@@ -3315,6 +3316,10 @@ lpfc_mbx_process_link_up(struct lpfc_hba *phba, struct lpfc_mbx_read_top *la)
|
||||
lpfc_sli4_clear_fcf_rr_bmask(phba);
|
||||
}
|
||||
|
||||
/* Prepare for LINK up registrations */
|
||||
memset(phba->os_host_name, 0, sizeof(phba->os_host_name));
|
||||
scnprintf(phba->os_host_name, sizeof(phba->os_host_name), "%s",
|
||||
init_utsname()->nodename);
|
||||
return;
|
||||
out:
|
||||
lpfc_vport_set_state(vport, FC_VPORT_FAILED);
|
||||
|
||||
@@ -3925,6 +3925,9 @@ struct lpfc_mbx_wr_object {
|
||||
#define LPFC_CHANGE_STATUS_FW_RESET 0x02
|
||||
#define LPFC_CHANGE_STATUS_PORT_MIGRATION 0x04
|
||||
#define LPFC_CHANGE_STATUS_PCI_RESET 0x05
|
||||
#define lpfc_wr_object_csf_SHIFT 8
|
||||
#define lpfc_wr_object_csf_MASK 0x00000001
|
||||
#define lpfc_wr_object_csf_WORD word5
|
||||
} response;
|
||||
} u;
|
||||
};
|
||||
|
||||
@@ -1362,7 +1362,7 @@ lpfc_hb_timeout_handler(struct lpfc_hba *phba)
|
||||
if (vports != NULL)
|
||||
for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) {
|
||||
lpfc_rcv_seq_check_edtov(vports[i]);
|
||||
lpfc_fdmi_num_disc_check(vports[i]);
|
||||
lpfc_fdmi_change_check(vports[i]);
|
||||
}
|
||||
lpfc_destroy_vport_work_array(phba, vports);
|
||||
|
||||
@@ -8320,14 +8320,6 @@ lpfc_map_topology(struct lpfc_hba *phba, struct lpfc_mbx_read_config *rd_config)
|
||||
phba->hba_flag |= HBA_PERSISTENT_TOPO;
|
||||
switch (phba->pcidev->device) {
|
||||
case PCI_DEVICE_ID_LANCER_G7_FC:
|
||||
if (tf || (pt == LINK_FLAGS_LOOP)) {
|
||||
/* Invalid values from FW - use driver params */
|
||||
phba->hba_flag &= ~HBA_PERSISTENT_TOPO;
|
||||
} else {
|
||||
/* Prism only supports PT2PT topology */
|
||||
phba->cfg_topology = FLAGS_TOPOLOGY_MODE_PT_PT;
|
||||
}
|
||||
break;
|
||||
case PCI_DEVICE_ID_LANCER_G6_FC:
|
||||
if (!tf) {
|
||||
phba->cfg_topology = ((pt == LINK_FLAGS_LOOP)
|
||||
@@ -10449,6 +10441,8 @@ lpfc_sli4_pci_mem_unset(struct lpfc_hba *phba)
|
||||
case LPFC_SLI_INTF_IF_TYPE_6:
|
||||
iounmap(phba->sli4_hba.drbl_regs_memmap_p);
|
||||
iounmap(phba->sli4_hba.conf_regs_memmap_p);
|
||||
if (phba->sli4_hba.dpp_regs_memmap_p)
|
||||
iounmap(phba->sli4_hba.dpp_regs_memmap_p);
|
||||
break;
|
||||
case LPFC_SLI_INTF_IF_TYPE_1:
|
||||
default:
|
||||
|
||||
@@ -308,7 +308,7 @@ lpfc_defer_pt2pt_acc(struct lpfc_hba *phba, LPFC_MBOXQ_t *link_mbox)
|
||||
mb->mbxStatus);
|
||||
mempool_free(login_mbox, phba->mbox_mem_pool);
|
||||
mempool_free(link_mbox, phba->mbox_mem_pool);
|
||||
lpfc_sli_release_iocbq(phba, save_iocb);
|
||||
kfree(save_iocb);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -325,7 +325,61 @@ lpfc_defer_pt2pt_acc(struct lpfc_hba *phba, LPFC_MBOXQ_t *link_mbox)
|
||||
}
|
||||
|
||||
mempool_free(link_mbox, phba->mbox_mem_pool);
|
||||
lpfc_sli_release_iocbq(phba, save_iocb);
|
||||
kfree(save_iocb);
|
||||
}
|
||||
|
||||
/**
|
||||
* lpfc_defer_tgt_acc - Progress SLI4 target rcv PLOGI handler
|
||||
* @phba: Pointer to HBA context object.
|
||||
* @pmb: Pointer to mailbox object.
|
||||
*
|
||||
* This function provides the unreg rpi mailbox completion handler for a tgt.
|
||||
* The routine frees the memory resources associated with the completed
|
||||
* mailbox command and transmits the ELS ACC.
|
||||
*
|
||||
* This routine is only called if we are SLI4, acting in target
|
||||
* mode and the remote NPort issues the PLOGI after link up.
|
||||
**/
|
||||
static void
|
||||
lpfc_defer_acc_rsp(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
|
||||
{
|
||||
struct lpfc_vport *vport = pmb->vport;
|
||||
struct lpfc_nodelist *ndlp = pmb->ctx_ndlp;
|
||||
LPFC_MBOXQ_t *mbox = pmb->context3;
|
||||
struct lpfc_iocbq *piocb = NULL;
|
||||
int rc;
|
||||
|
||||
if (mbox) {
|
||||
pmb->context3 = NULL;
|
||||
piocb = mbox->context3;
|
||||
mbox->context3 = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Complete the unreg rpi mbx request, and update flags.
|
||||
* This will also restart any deferred events.
|
||||
*/
|
||||
lpfc_nlp_get(ndlp);
|
||||
lpfc_sli4_unreg_rpi_cmpl_clr(phba, pmb);
|
||||
|
||||
if (!piocb) {
|
||||
lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY | LOG_ELS,
|
||||
"4578 PLOGI ACC fail\n");
|
||||
if (mbox)
|
||||
mempool_free(mbox, phba->mbox_mem_pool);
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc = lpfc_els_rsp_acc(vport, ELS_CMD_PLOGI, piocb, ndlp, mbox);
|
||||
if (rc) {
|
||||
lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY | LOG_ELS,
|
||||
"4579 PLOGI ACC fail %x\n", rc);
|
||||
if (mbox)
|
||||
mempool_free(mbox, phba->mbox_mem_pool);
|
||||
}
|
||||
kfree(piocb);
|
||||
out:
|
||||
lpfc_nlp_put(ndlp);
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -345,6 +399,7 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
|
||||
struct lpfc_iocbq *save_iocb;
|
||||
struct ls_rjt stat;
|
||||
uint32_t vid, flag;
|
||||
u16 rpi;
|
||||
int rc, defer_acc;
|
||||
|
||||
memset(&stat, 0, sizeof (struct ls_rjt));
|
||||
@@ -488,7 +543,7 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
|
||||
link_mbox->vport = vport;
|
||||
link_mbox->ctx_ndlp = ndlp;
|
||||
|
||||
save_iocb = lpfc_sli_get_iocbq(phba);
|
||||
save_iocb = kzalloc(sizeof(*save_iocb), GFP_KERNEL);
|
||||
if (!save_iocb)
|
||||
goto out;
|
||||
/* Save info from cmd IOCB used in rsp */
|
||||
@@ -513,7 +568,36 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
|
||||
goto out;
|
||||
|
||||
/* Registering an existing RPI behaves differently for SLI3 vs SLI4 */
|
||||
if (phba->sli_rev == LPFC_SLI_REV4)
|
||||
if (phba->nvmet_support && !defer_acc) {
|
||||
link_mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
|
||||
if (!link_mbox)
|
||||
goto out;
|
||||
|
||||
/* As unique identifiers such as iotag would be overwritten
|
||||
* with those from the cmdiocb, allocate separate temporary
|
||||
* storage for the copy.
|
||||
*/
|
||||
save_iocb = kzalloc(sizeof(*save_iocb), GFP_KERNEL);
|
||||
if (!save_iocb)
|
||||
goto out;
|
||||
|
||||
/* Unreg RPI is required for SLI4. */
|
||||
rpi = phba->sli4_hba.rpi_ids[ndlp->nlp_rpi];
|
||||
lpfc_unreg_login(phba, vport->vpi, rpi, link_mbox);
|
||||
link_mbox->vport = vport;
|
||||
link_mbox->ctx_ndlp = ndlp;
|
||||
link_mbox->mbox_cmpl = lpfc_defer_acc_rsp;
|
||||
|
||||
if (((ndlp->nlp_DID & Fabric_DID_MASK) != Fabric_DID_MASK) &&
|
||||
(!(vport->fc_flag & FC_OFFLINE_MODE)))
|
||||
ndlp->nlp_flag |= NLP_UNREG_INP;
|
||||
|
||||
/* Save info from cmd IOCB used in rsp */
|
||||
memcpy(save_iocb, cmdiocb, sizeof(*save_iocb));
|
||||
|
||||
/* Delay sending ACC till unreg RPI completes. */
|
||||
defer_acc = 1;
|
||||
} else if (phba->sli_rev == LPFC_SLI_REV4)
|
||||
lpfc_unreg_rpi(vport, ndlp);
|
||||
|
||||
rc = lpfc_reg_rpi(phba, vport->vpi, icmd->un.rcvels.remoteID,
|
||||
@@ -553,6 +637,9 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
|
||||
if ((vport->port_type == LPFC_NPIV_PORT &&
|
||||
vport->cfg_restrict_login)) {
|
||||
|
||||
/* no deferred ACC */
|
||||
kfree(save_iocb);
|
||||
|
||||
/* In order to preserve RPIs, we want to cleanup
|
||||
* the default RPI the firmware created to rcv
|
||||
* this ELS request. The only way to do this is
|
||||
@@ -571,8 +658,12 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
|
||||
}
|
||||
if (defer_acc) {
|
||||
/* So the order here should be:
|
||||
* Issue CONFIG_LINK mbox
|
||||
* CONFIG_LINK cmpl
|
||||
* SLI3 pt2pt
|
||||
* Issue CONFIG_LINK mbox
|
||||
* CONFIG_LINK cmpl
|
||||
* SLI4 tgt
|
||||
* Issue UNREG RPI mbx
|
||||
* UNREG RPI cmpl
|
||||
* Issue PLOGI ACC
|
||||
* PLOGI ACC cmpl
|
||||
* Issue REG_LOGIN mbox
|
||||
@@ -596,10 +687,9 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
|
||||
out:
|
||||
if (defer_acc)
|
||||
lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
|
||||
"4577 pt2pt discovery failure: %p %p %p\n",
|
||||
"4577 discovery failure: %p %p %p\n",
|
||||
save_iocb, link_mbox, login_mbox);
|
||||
if (save_iocb)
|
||||
lpfc_sli_release_iocbq(phba, save_iocb);
|
||||
kfree(save_iocb);
|
||||
if (link_mbox)
|
||||
mempool_free(link_mbox, phba->mbox_mem_pool);
|
||||
if (login_mbox)
|
||||
|
||||
@@ -481,7 +481,7 @@ lpfc_sli4_vport_delete_fcp_xri_aborted(struct lpfc_vport *vport)
|
||||
spin_lock(&qp->abts_io_buf_list_lock);
|
||||
list_for_each_entry_safe(psb, next_psb,
|
||||
&qp->lpfc_abts_io_buf_list, list) {
|
||||
if (psb->cur_iocbq.iocb_flag == LPFC_IO_NVME)
|
||||
if (psb->cur_iocbq.iocb_flag & LPFC_IO_NVME)
|
||||
continue;
|
||||
|
||||
if (psb->rdata && psb->rdata->pnode &&
|
||||
@@ -528,7 +528,7 @@ lpfc_sli4_io_xri_aborted(struct lpfc_hba *phba,
|
||||
list_del_init(&psb->list);
|
||||
psb->flags &= ~LPFC_SBUF_XBUSY;
|
||||
psb->status = IOSTAT_SUCCESS;
|
||||
if (psb->cur_iocbq.iocb_flag == LPFC_IO_NVME) {
|
||||
if (psb->cur_iocbq.iocb_flag & LPFC_IO_NVME) {
|
||||
qp->abts_nvme_io_bufs--;
|
||||
spin_unlock(&qp->abts_io_buf_list_lock);
|
||||
spin_unlock_irqrestore(&phba->hbalock, iflag);
|
||||
|
||||
@@ -4918,8 +4918,17 @@ static int
|
||||
lpfc_sli4_rb_setup(struct lpfc_hba *phba)
|
||||
{
|
||||
phba->hbq_in_use = 1;
|
||||
phba->hbqs[LPFC_ELS_HBQ].entry_count =
|
||||
lpfc_hbq_defs[LPFC_ELS_HBQ]->entry_count;
|
||||
/**
|
||||
* Specific case when the MDS diagnostics is enabled and supported.
|
||||
* The receive buffer count is truncated to manage the incoming
|
||||
* traffic.
|
||||
**/
|
||||
if (phba->cfg_enable_mds_diags && phba->mds_diags_support)
|
||||
phba->hbqs[LPFC_ELS_HBQ].entry_count =
|
||||
lpfc_hbq_defs[LPFC_ELS_HBQ]->entry_count >> 1;
|
||||
else
|
||||
phba->hbqs[LPFC_ELS_HBQ].entry_count =
|
||||
lpfc_hbq_defs[LPFC_ELS_HBQ]->entry_count;
|
||||
phba->hbq_count = 1;
|
||||
lpfc_sli_hbqbuf_init_hbqs(phba, LPFC_ELS_HBQ);
|
||||
/* Initially populate or replenish the HBQs */
|
||||
@@ -19449,7 +19458,7 @@ lpfc_wr_object(struct lpfc_hba *phba, struct list_head *dmabuf_list,
|
||||
struct lpfc_mbx_wr_object *wr_object;
|
||||
LPFC_MBOXQ_t *mbox;
|
||||
int rc = 0, i = 0;
|
||||
uint32_t shdr_status, shdr_add_status, shdr_change_status;
|
||||
uint32_t shdr_status, shdr_add_status, shdr_change_status, shdr_csf;
|
||||
uint32_t mbox_tmo;
|
||||
struct lpfc_dmabuf *dmabuf;
|
||||
uint32_t written = 0;
|
||||
@@ -19506,6 +19515,16 @@ lpfc_wr_object(struct lpfc_hba *phba, struct list_head *dmabuf_list,
|
||||
if (check_change_status) {
|
||||
shdr_change_status = bf_get(lpfc_wr_object_change_status,
|
||||
&wr_object->u.response);
|
||||
|
||||
if (shdr_change_status == LPFC_CHANGE_STATUS_FW_RESET ||
|
||||
shdr_change_status == LPFC_CHANGE_STATUS_PORT_MIGRATION) {
|
||||
shdr_csf = bf_get(lpfc_wr_object_csf,
|
||||
&wr_object->u.response);
|
||||
if (shdr_csf)
|
||||
shdr_change_status =
|
||||
LPFC_CHANGE_STATUS_PCI_RESET;
|
||||
}
|
||||
|
||||
switch (shdr_change_status) {
|
||||
case (LPFC_CHANGE_STATUS_PHYS_DEV_RESET):
|
||||
lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
* included with this package. *
|
||||
*******************************************************************/
|
||||
|
||||
#define LPFC_DRIVER_VERSION "12.6.0.2"
|
||||
#define LPFC_DRIVER_VERSION "12.6.0.3"
|
||||
#define LPFC_DRIVER_NAME "lpfc"
|
||||
|
||||
/* Used for SLI 2/3 */
|
||||
|
||||
@@ -21,8 +21,8 @@
|
||||
/*
|
||||
* MegaRAID SAS Driver meta data
|
||||
*/
|
||||
#define MEGASAS_VERSION "07.710.50.00-rc1"
|
||||
#define MEGASAS_RELDATE "June 28, 2019"
|
||||
#define MEGASAS_VERSION "07.713.01.00-rc1"
|
||||
#define MEGASAS_RELDATE "Dec 27, 2019"
|
||||
|
||||
#define MEGASAS_MSIX_NAME_LEN 32
|
||||
|
||||
@@ -2233,9 +2233,9 @@ enum MR_PD_TYPE {
|
||||
|
||||
/* JBOD Queue depth definitions */
|
||||
#define MEGASAS_SATA_QD 32
|
||||
#define MEGASAS_SAS_QD 64
|
||||
#define MEGASAS_SAS_QD 256
|
||||
#define MEGASAS_DEFAULT_PD_QD 64
|
||||
#define MEGASAS_NVME_QD 32
|
||||
#define MEGASAS_NVME_QD 64
|
||||
|
||||
#define MR_DEFAULT_NVME_PAGE_SIZE 4096
|
||||
#define MR_DEFAULT_NVME_PAGE_SHIFT 12
|
||||
@@ -2640,10 +2640,11 @@ enum MEGASAS_OCR_CAUSE {
|
||||
};
|
||||
|
||||
enum DCMD_RETURN_STATUS {
|
||||
DCMD_SUCCESS = 0,
|
||||
DCMD_TIMEOUT = 1,
|
||||
DCMD_FAILED = 2,
|
||||
DCMD_NOT_FIRED = 3,
|
||||
DCMD_SUCCESS = 0x00,
|
||||
DCMD_TIMEOUT = 0x01,
|
||||
DCMD_FAILED = 0x02,
|
||||
DCMD_BUSY = 0x03,
|
||||
DCMD_INIT = 0xff,
|
||||
};
|
||||
|
||||
u8
|
||||
|
||||
@@ -1099,7 +1099,7 @@ megasas_issue_polled(struct megasas_instance *instance, struct megasas_cmd *cmd)
|
||||
if (atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR) {
|
||||
dev_err(&instance->pdev->dev, "Failed from %s %d\n",
|
||||
__func__, __LINE__);
|
||||
return DCMD_NOT_FIRED;
|
||||
return DCMD_INIT;
|
||||
}
|
||||
|
||||
instance->instancet->issue_dcmd(instance, cmd);
|
||||
@@ -1123,19 +1123,19 @@ megasas_issue_blocked_cmd(struct megasas_instance *instance,
|
||||
struct megasas_cmd *cmd, int timeout)
|
||||
{
|
||||
int ret = 0;
|
||||
cmd->cmd_status_drv = MFI_STAT_INVALID_STATUS;
|
||||
cmd->cmd_status_drv = DCMD_INIT;
|
||||
|
||||
if (atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR) {
|
||||
dev_err(&instance->pdev->dev, "Failed from %s %d\n",
|
||||
__func__, __LINE__);
|
||||
return DCMD_NOT_FIRED;
|
||||
return DCMD_INIT;
|
||||
}
|
||||
|
||||
instance->instancet->issue_dcmd(instance, cmd);
|
||||
|
||||
if (timeout) {
|
||||
ret = wait_event_timeout(instance->int_cmd_wait_q,
|
||||
cmd->cmd_status_drv != MFI_STAT_INVALID_STATUS, timeout * HZ);
|
||||
cmd->cmd_status_drv != DCMD_INIT, timeout * HZ);
|
||||
if (!ret) {
|
||||
dev_err(&instance->pdev->dev,
|
||||
"DCMD(opcode: 0x%x) is timed out, func:%s\n",
|
||||
@@ -1144,10 +1144,9 @@ megasas_issue_blocked_cmd(struct megasas_instance *instance,
|
||||
}
|
||||
} else
|
||||
wait_event(instance->int_cmd_wait_q,
|
||||
cmd->cmd_status_drv != MFI_STAT_INVALID_STATUS);
|
||||
cmd->cmd_status_drv != DCMD_INIT);
|
||||
|
||||
return (cmd->cmd_status_drv == MFI_STAT_OK) ?
|
||||
DCMD_SUCCESS : DCMD_FAILED;
|
||||
return cmd->cmd_status_drv;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1190,19 +1189,19 @@ megasas_issue_blocked_abort_cmd(struct megasas_instance *instance,
|
||||
cpu_to_le32(upper_32_bits(cmd_to_abort->frame_phys_addr));
|
||||
|
||||
cmd->sync_cmd = 1;
|
||||
cmd->cmd_status_drv = MFI_STAT_INVALID_STATUS;
|
||||
cmd->cmd_status_drv = DCMD_INIT;
|
||||
|
||||
if (atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR) {
|
||||
dev_err(&instance->pdev->dev, "Failed from %s %d\n",
|
||||
__func__, __LINE__);
|
||||
return DCMD_NOT_FIRED;
|
||||
return DCMD_INIT;
|
||||
}
|
||||
|
||||
instance->instancet->issue_dcmd(instance, cmd);
|
||||
|
||||
if (timeout) {
|
||||
ret = wait_event_timeout(instance->abort_cmd_wait_q,
|
||||
cmd->cmd_status_drv != MFI_STAT_INVALID_STATUS, timeout * HZ);
|
||||
cmd->cmd_status_drv != DCMD_INIT, timeout * HZ);
|
||||
if (!ret) {
|
||||
opcode = cmd_to_abort->frame->dcmd.opcode;
|
||||
dev_err(&instance->pdev->dev,
|
||||
@@ -1212,13 +1211,12 @@ megasas_issue_blocked_abort_cmd(struct megasas_instance *instance,
|
||||
}
|
||||
} else
|
||||
wait_event(instance->abort_cmd_wait_q,
|
||||
cmd->cmd_status_drv != MFI_STAT_INVALID_STATUS);
|
||||
cmd->cmd_status_drv != DCMD_INIT);
|
||||
|
||||
cmd->sync_cmd = 0;
|
||||
|
||||
megasas_return_cmd(instance, cmd);
|
||||
return (cmd->cmd_status_drv == MFI_STAT_OK) ?
|
||||
DCMD_SUCCESS : DCMD_FAILED;
|
||||
return cmd->cmd_status_drv;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1887,6 +1885,10 @@ void megasas_set_dynamic_target_properties(struct scsi_device *sdev,
|
||||
|
||||
mr_device_priv_data->is_tm_capable =
|
||||
raid->capability.tmCapable;
|
||||
|
||||
if (!raid->flags.isEPD)
|
||||
sdev->no_write_same = 1;
|
||||
|
||||
} else if (instance->use_seqnum_jbod_fp) {
|
||||
pd_index = (sdev->channel * MEGASAS_MAX_DEV_PER_CHANNEL) +
|
||||
sdev->id;
|
||||
@@ -2150,6 +2152,12 @@ static void megasas_complete_outstanding_ioctls(struct megasas_instance *instanc
|
||||
|
||||
void megaraid_sas_kill_hba(struct megasas_instance *instance)
|
||||
{
|
||||
if (atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR) {
|
||||
dev_warn(&instance->pdev->dev,
|
||||
"Adapter already dead, skipping kill HBA\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Set critical error to block I/O & ioctls in case caller didn't */
|
||||
atomic_set(&instance->adprecovery, MEGASAS_HW_CRITICAL_ERROR);
|
||||
/* Wait 1 second to ensure IO or ioctls in build have posted */
|
||||
@@ -2726,7 +2734,7 @@ static int megasas_wait_for_outstanding(struct megasas_instance *instance)
|
||||
"reset queue\n",
|
||||
reset_cmd);
|
||||
|
||||
reset_cmd->cmd_status_drv = MFI_STAT_INVALID_STATUS;
|
||||
reset_cmd->cmd_status_drv = DCMD_INIT;
|
||||
instance->instancet->fire_cmd(instance,
|
||||
reset_cmd->frame_phys_addr,
|
||||
0, instance->reg_set);
|
||||
@@ -3416,7 +3424,6 @@ static struct scsi_host_template megasas_template = {
|
||||
.bios_param = megasas_bios_param,
|
||||
.change_queue_depth = scsi_change_queue_depth,
|
||||
.max_segment_size = 0xffffffff,
|
||||
.no_write_same = 1,
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -3432,7 +3439,11 @@ static void
|
||||
megasas_complete_int_cmd(struct megasas_instance *instance,
|
||||
struct megasas_cmd *cmd)
|
||||
{
|
||||
cmd->cmd_status_drv = cmd->frame->io.cmd_status;
|
||||
if (cmd->cmd_status_drv == DCMD_INIT)
|
||||
cmd->cmd_status_drv =
|
||||
(cmd->frame->io.cmd_status == MFI_STAT_OK) ?
|
||||
DCMD_SUCCESS : DCMD_FAILED;
|
||||
|
||||
wake_up(&instance->int_cmd_wait_q);
|
||||
}
|
||||
|
||||
@@ -3451,7 +3462,7 @@ megasas_complete_abort(struct megasas_instance *instance,
|
||||
{
|
||||
if (cmd->sync_cmd) {
|
||||
cmd->sync_cmd = 0;
|
||||
cmd->cmd_status_drv = 0;
|
||||
cmd->cmd_status_drv = DCMD_SUCCESS;
|
||||
wake_up(&instance->abort_cmd_wait_q);
|
||||
}
|
||||
}
|
||||
@@ -3727,7 +3738,7 @@ megasas_issue_pending_cmds_again(struct megasas_instance *instance)
|
||||
dev_notice(&instance->pdev->dev, "%p synchronous cmd"
|
||||
"on the internal reset queue,"
|
||||
"issue it again.\n", cmd);
|
||||
cmd->cmd_status_drv = MFI_STAT_INVALID_STATUS;
|
||||
cmd->cmd_status_drv = DCMD_INIT;
|
||||
instance->instancet->fire_cmd(instance,
|
||||
cmd->frame_phys_addr,
|
||||
0, instance->reg_set);
|
||||
@@ -4392,7 +4403,8 @@ dcmd_timeout_ocr_possible(struct megasas_instance *instance) {
|
||||
if (instance->adapter_type == MFI_SERIES)
|
||||
return KILL_ADAPTER;
|
||||
else if (instance->unload ||
|
||||
test_bit(MEGASAS_FUSION_IN_RESET, &instance->reset_flags))
|
||||
test_bit(MEGASAS_FUSION_OCR_NOT_POSSIBLE,
|
||||
&instance->reset_flags))
|
||||
return IGNORE_TIMEOUT;
|
||||
else
|
||||
return INITIATE_OCR;
|
||||
@@ -7593,6 +7605,7 @@ megasas_resume(struct pci_dev *pdev)
|
||||
struct Scsi_Host *host;
|
||||
struct megasas_instance *instance;
|
||||
int irq_flags = PCI_IRQ_LEGACY;
|
||||
u32 status_reg;
|
||||
|
||||
instance = pci_get_drvdata(pdev);
|
||||
|
||||
@@ -7620,9 +7633,35 @@ megasas_resume(struct pci_dev *pdev)
|
||||
/*
|
||||
* We expect the FW state to be READY
|
||||
*/
|
||||
if (megasas_transition_to_ready(instance, 0))
|
||||
goto fail_ready_state;
|
||||
|
||||
if (megasas_transition_to_ready(instance, 0)) {
|
||||
dev_info(&instance->pdev->dev,
|
||||
"Failed to transition controller to ready from %s!\n",
|
||||
__func__);
|
||||
if (instance->adapter_type != MFI_SERIES) {
|
||||
status_reg =
|
||||
instance->instancet->read_fw_status_reg(instance);
|
||||
if (!(status_reg & MFI_RESET_ADAPTER) ||
|
||||
((megasas_adp_reset_wait_for_ready
|
||||
(instance, true, 0)) == FAILED))
|
||||
goto fail_ready_state;
|
||||
} else {
|
||||
atomic_set(&instance->fw_reset_no_pci_access, 1);
|
||||
instance->instancet->adp_reset
|
||||
(instance, instance->reg_set);
|
||||
atomic_set(&instance->fw_reset_no_pci_access, 0);
|
||||
|
||||
/* waiting for about 30 seconds before retry */
|
||||
ssleep(30);
|
||||
|
||||
if (megasas_transition_to_ready(instance, 0))
|
||||
goto fail_ready_state;
|
||||
}
|
||||
|
||||
dev_info(&instance->pdev->dev,
|
||||
"FW restarted successfully from %s!\n",
|
||||
__func__);
|
||||
}
|
||||
if (megasas_set_dma_mask(instance))
|
||||
goto fail_set_dma_mask;
|
||||
|
||||
@@ -8036,6 +8075,7 @@ megasas_mgmt_fw_ioctl(struct megasas_instance *instance,
|
||||
dma_addr_t sense_handle;
|
||||
unsigned long *sense_ptr;
|
||||
u32 opcode = 0;
|
||||
int ret = DCMD_SUCCESS;
|
||||
|
||||
memset(kbuff_arr, 0, sizeof(kbuff_arr));
|
||||
|
||||
@@ -8176,13 +8216,18 @@ megasas_mgmt_fw_ioctl(struct megasas_instance *instance,
|
||||
* cmd to the SCSI mid-layer
|
||||
*/
|
||||
cmd->sync_cmd = 1;
|
||||
if (megasas_issue_blocked_cmd(instance, cmd, 0) == DCMD_NOT_FIRED) {
|
||||
|
||||
ret = megasas_issue_blocked_cmd(instance, cmd, 0);
|
||||
switch (ret) {
|
||||
case DCMD_INIT:
|
||||
case DCMD_BUSY:
|
||||
cmd->sync_cmd = 0;
|
||||
dev_err(&instance->pdev->dev,
|
||||
"return -EBUSY from %s %d cmd 0x%x opcode 0x%x cmd->cmd_status_drv 0x%x\n",
|
||||
__func__, __LINE__, cmd->frame->hdr.cmd, opcode,
|
||||
cmd->cmd_status_drv);
|
||||
return -EBUSY;
|
||||
__func__, __LINE__, cmd->frame->hdr.cmd, opcode,
|
||||
cmd->cmd_status_drv);
|
||||
error = -EBUSY;
|
||||
goto out;
|
||||
}
|
||||
|
||||
cmd->sync_cmd = 0;
|
||||
|
||||
@@ -364,6 +364,35 @@ megasas_fusion_update_can_queue(struct megasas_instance *instance, int fw_boot_c
|
||||
instance->max_fw_cmds = instance->max_fw_cmds-1;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
megasas_get_msix_index(struct megasas_instance *instance,
|
||||
struct scsi_cmnd *scmd,
|
||||
struct megasas_cmd_fusion *cmd,
|
||||
u8 data_arms)
|
||||
{
|
||||
int sdev_busy;
|
||||
|
||||
/* nr_hw_queue = 1 for MegaRAID */
|
||||
struct blk_mq_hw_ctx *hctx =
|
||||
scmd->device->request_queue->queue_hw_ctx[0];
|
||||
|
||||
sdev_busy = atomic_read(&hctx->nr_active);
|
||||
|
||||
if (instance->perf_mode == MR_BALANCED_PERF_MODE &&
|
||||
sdev_busy > (data_arms * MR_DEVICE_HIGH_IOPS_DEPTH))
|
||||
cmd->request_desc->SCSIIO.MSIxIndex =
|
||||
mega_mod64((atomic64_add_return(1, &instance->high_iops_outstanding) /
|
||||
MR_HIGH_IOPS_BATCH_COUNT), instance->low_latency_index_start);
|
||||
else if (instance->msix_load_balance)
|
||||
cmd->request_desc->SCSIIO.MSIxIndex =
|
||||
(mega_mod64(atomic64_add_return(1, &instance->total_io_count),
|
||||
instance->msix_vectors));
|
||||
else
|
||||
cmd->request_desc->SCSIIO.MSIxIndex =
|
||||
instance->reply_map[raw_smp_processor_id()];
|
||||
}
|
||||
|
||||
/**
|
||||
* megasas_free_cmds_fusion - Free all the cmds in the free cmd pool
|
||||
* @instance: Adapter soft state
|
||||
@@ -1312,7 +1341,9 @@ megasas_sync_pd_seq_num(struct megasas_instance *instance, bool pend) {
|
||||
}
|
||||
|
||||
if (ret == DCMD_TIMEOUT)
|
||||
megaraid_sas_kill_hba(instance);
|
||||
dev_warn(&instance->pdev->dev,
|
||||
"%s DCMD timed out, continue without JBOD sequence map\n",
|
||||
__func__);
|
||||
|
||||
if (ret == DCMD_SUCCESS)
|
||||
instance->pd_seq_map_id++;
|
||||
@@ -1394,7 +1425,9 @@ megasas_get_ld_map_info(struct megasas_instance *instance)
|
||||
ret = megasas_issue_polled(instance, cmd);
|
||||
|
||||
if (ret == DCMD_TIMEOUT)
|
||||
megaraid_sas_kill_hba(instance);
|
||||
dev_warn(&instance->pdev->dev,
|
||||
"%s DCMD timed out, RAID map is disabled\n",
|
||||
__func__);
|
||||
|
||||
megasas_return_cmd(instance, cmd);
|
||||
|
||||
@@ -2825,19 +2858,7 @@ megasas_build_ldio_fusion(struct megasas_instance *instance,
|
||||
fp_possible = (io_info.fpOkForIo > 0) ? true : false;
|
||||
}
|
||||
|
||||
if ((instance->perf_mode == MR_BALANCED_PERF_MODE) &&
|
||||
atomic_read(&scp->device->device_busy) >
|
||||
(io_info.data_arms * MR_DEVICE_HIGH_IOPS_DEPTH))
|
||||
cmd->request_desc->SCSIIO.MSIxIndex =
|
||||
mega_mod64((atomic64_add_return(1, &instance->high_iops_outstanding) /
|
||||
MR_HIGH_IOPS_BATCH_COUNT), instance->low_latency_index_start);
|
||||
else if (instance->msix_load_balance)
|
||||
cmd->request_desc->SCSIIO.MSIxIndex =
|
||||
(mega_mod64(atomic64_add_return(1, &instance->total_io_count),
|
||||
instance->msix_vectors));
|
||||
else
|
||||
cmd->request_desc->SCSIIO.MSIxIndex =
|
||||
instance->reply_map[raw_smp_processor_id()];
|
||||
megasas_get_msix_index(instance, scp, cmd, io_info.data_arms);
|
||||
|
||||
if (instance->adapter_type >= VENTURA_SERIES) {
|
||||
/* FP for Optimal raid level 1.
|
||||
@@ -3158,18 +3179,7 @@ megasas_build_syspd_fusion(struct megasas_instance *instance,
|
||||
|
||||
cmd->request_desc->SCSIIO.DevHandle = io_request->DevHandle;
|
||||
|
||||
if ((instance->perf_mode == MR_BALANCED_PERF_MODE) &&
|
||||
atomic_read(&scmd->device->device_busy) > MR_DEVICE_HIGH_IOPS_DEPTH)
|
||||
cmd->request_desc->SCSIIO.MSIxIndex =
|
||||
mega_mod64((atomic64_add_return(1, &instance->high_iops_outstanding) /
|
||||
MR_HIGH_IOPS_BATCH_COUNT), instance->low_latency_index_start);
|
||||
else if (instance->msix_load_balance)
|
||||
cmd->request_desc->SCSIIO.MSIxIndex =
|
||||
(mega_mod64(atomic64_add_return(1, &instance->total_io_count),
|
||||
instance->msix_vectors));
|
||||
else
|
||||
cmd->request_desc->SCSIIO.MSIxIndex =
|
||||
instance->reply_map[raw_smp_processor_id()];
|
||||
megasas_get_msix_index(instance, scmd, cmd, 1);
|
||||
|
||||
if (!fp_possible) {
|
||||
/* system pd firmware path */
|
||||
@@ -4219,7 +4229,8 @@ void megasas_reset_reply_desc(struct megasas_instance *instance)
|
||||
* megasas_refire_mgmt_cmd : Re-fire management commands
|
||||
* @instance: Controller's soft instance
|
||||
*/
|
||||
static void megasas_refire_mgmt_cmd(struct megasas_instance *instance)
|
||||
void megasas_refire_mgmt_cmd(struct megasas_instance *instance,
|
||||
bool return_ioctl)
|
||||
{
|
||||
int j;
|
||||
struct megasas_cmd_fusion *cmd_fusion;
|
||||
@@ -4283,6 +4294,16 @@ static void megasas_refire_mgmt_cmd(struct megasas_instance *instance)
|
||||
break;
|
||||
}
|
||||
|
||||
if (return_ioctl && cmd_mfi->sync_cmd &&
|
||||
cmd_mfi->frame->hdr.cmd != MFI_CMD_ABORT) {
|
||||
dev_err(&instance->pdev->dev,
|
||||
"return -EBUSY from %s %d cmd 0x%x opcode 0x%x\n",
|
||||
__func__, __LINE__, cmd_mfi->frame->hdr.cmd,
|
||||
le32_to_cpu(cmd_mfi->frame->dcmd.opcode));
|
||||
cmd_mfi->cmd_status_drv = DCMD_BUSY;
|
||||
result = COMPLETE_CMD;
|
||||
}
|
||||
|
||||
switch (result) {
|
||||
case REFIRE_CMD:
|
||||
megasas_fire_cmd_fusion(instance, req_desc);
|
||||
@@ -4297,6 +4318,37 @@ static void megasas_refire_mgmt_cmd(struct megasas_instance *instance)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* megasas_return_polled_cmds: Return polled mode commands back to the pool
|
||||
* before initiating an OCR.
|
||||
* @instance: Controller's soft instance
|
||||
*/
|
||||
static void
|
||||
megasas_return_polled_cmds(struct megasas_instance *instance)
|
||||
{
|
||||
int i;
|
||||
struct megasas_cmd_fusion *cmd_fusion;
|
||||
struct fusion_context *fusion;
|
||||
struct megasas_cmd *cmd_mfi;
|
||||
|
||||
fusion = instance->ctrl_context;
|
||||
|
||||
for (i = instance->max_scsi_cmds; i < instance->max_fw_cmds; i++) {
|
||||
cmd_fusion = fusion->cmd_list[i];
|
||||
cmd_mfi = instance->cmd_list[cmd_fusion->sync_cmd_idx];
|
||||
|
||||
if (cmd_mfi->flags & DRV_DCMD_POLLED_MODE) {
|
||||
if (megasas_dbg_lvl & OCR_DEBUG)
|
||||
dev_info(&instance->pdev->dev,
|
||||
"%s %d return cmd 0x%x opcode 0x%x\n",
|
||||
__func__, __LINE__, cmd_mfi->frame->hdr.cmd,
|
||||
le32_to_cpu(cmd_mfi->frame->dcmd.opcode));
|
||||
cmd_mfi->flags &= ~DRV_DCMD_POLLED_MODE;
|
||||
megasas_return_cmd(instance, cmd_mfi);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* megasas_track_scsiio : Track SCSI IOs outstanding to a SCSI device
|
||||
* @instance: per adapter struct
|
||||
@@ -4847,6 +4899,7 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int reason)
|
||||
if (instance->requestorId && !instance->skip_heartbeat_timer_del)
|
||||
del_timer_sync(&instance->sriov_heartbeat_timer);
|
||||
set_bit(MEGASAS_FUSION_IN_RESET, &instance->reset_flags);
|
||||
set_bit(MEGASAS_FUSION_OCR_NOT_POSSIBLE, &instance->reset_flags);
|
||||
atomic_set(&instance->adprecovery, MEGASAS_ADPRESET_SM_POLLING);
|
||||
instance->instancet->disable_intr(instance);
|
||||
megasas_sync_irqs((unsigned long)instance);
|
||||
@@ -4951,7 +5004,9 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int reason)
|
||||
goto kill_hba;
|
||||
}
|
||||
|
||||
megasas_refire_mgmt_cmd(instance);
|
||||
megasas_refire_mgmt_cmd(instance,
|
||||
(i == (MEGASAS_FUSION_MAX_RESET_TRIES - 1)
|
||||
? 1 : 0));
|
||||
|
||||
/* Reset load balance info */
|
||||
if (fusion->load_balance_info)
|
||||
@@ -4959,8 +5014,16 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int reason)
|
||||
(sizeof(struct LD_LOAD_BALANCE_INFO) *
|
||||
MAX_LOGICAL_DRIVES_EXT));
|
||||
|
||||
if (!megasas_get_map_info(instance))
|
||||
if (!megasas_get_map_info(instance)) {
|
||||
megasas_sync_map_info(instance);
|
||||
} else {
|
||||
/*
|
||||
* Return pending polled mode cmds before
|
||||
* retrying OCR
|
||||
*/
|
||||
megasas_return_polled_cmds(instance);
|
||||
continue;
|
||||
}
|
||||
|
||||
megasas_setup_jbod_map(instance);
|
||||
|
||||
@@ -4987,6 +5050,15 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int reason)
|
||||
megasas_set_dynamic_target_properties(sdev, is_target_prop);
|
||||
}
|
||||
|
||||
status_reg = instance->instancet->read_fw_status_reg
|
||||
(instance);
|
||||
abs_state = status_reg & MFI_STATE_MASK;
|
||||
if (abs_state != MFI_STATE_OPERATIONAL) {
|
||||
dev_info(&instance->pdev->dev,
|
||||
"Adapter is not OPERATIONAL, state 0x%x for scsi:%d\n",
|
||||
abs_state, instance->host->host_no);
|
||||
goto out;
|
||||
}
|
||||
atomic_set(&instance->adprecovery, MEGASAS_HBA_OPERATIONAL);
|
||||
|
||||
dev_info(&instance->pdev->dev,
|
||||
@@ -5046,7 +5118,7 @@ kill_hba:
|
||||
instance->skip_heartbeat_timer_del = 1;
|
||||
retval = FAILED;
|
||||
out:
|
||||
clear_bit(MEGASAS_FUSION_IN_RESET, &instance->reset_flags);
|
||||
clear_bit(MEGASAS_FUSION_OCR_NOT_POSSIBLE, &instance->reset_flags);
|
||||
mutex_unlock(&instance->reset_mutex);
|
||||
return retval;
|
||||
}
|
||||
|
||||
@@ -89,6 +89,7 @@ enum MR_RAID_FLAGS_IO_SUB_TYPE {
|
||||
|
||||
#define MEGASAS_FP_CMD_LEN 16
|
||||
#define MEGASAS_FUSION_IN_RESET 0
|
||||
#define MEGASAS_FUSION_OCR_NOT_POSSIBLE 1
|
||||
#define RAID_1_PEER_CMDS 2
|
||||
#define JBOD_MAPS_COUNT 2
|
||||
#define MEGASAS_REDUCE_QD_COUNT 64
|
||||
@@ -864,9 +865,20 @@ struct MR_LD_RAID {
|
||||
u8 regTypeReqOnRead;
|
||||
__le16 seqNum;
|
||||
|
||||
struct {
|
||||
u32 ldSyncRequired:1;
|
||||
u32 reserved:31;
|
||||
struct {
|
||||
#ifndef MFI_BIG_ENDIAN
|
||||
u32 ldSyncRequired:1;
|
||||
u32 regTypeReqOnReadIsValid:1;
|
||||
u32 isEPD:1;
|
||||
u32 enableSLDOnAllRWIOs:1;
|
||||
u32 reserved:28;
|
||||
#else
|
||||
u32 reserved:28;
|
||||
u32 enableSLDOnAllRWIOs:1;
|
||||
u32 isEPD:1;
|
||||
u32 regTypeReqOnReadIsValid:1;
|
||||
u32 ldSyncRequired:1;
|
||||
#endif
|
||||
} flags;
|
||||
|
||||
u8 LUN[8]; /* 0x24 8 byte LUN field used for SCSI IO's */
|
||||
|
||||
@@ -122,6 +122,9 @@
|
||||
* 08-28-18 02.00.53 Bumped MPI2_HEADER_VERSION_UNIT.
|
||||
* Added MPI2_IOCSTATUS_FAILURE
|
||||
* 12-17-18 02.00.54 Bumped MPI2_HEADER_VERSION_UNIT
|
||||
* 06-24-19 02.00.55 Bumped MPI2_HEADER_VERSION_UNIT
|
||||
* 08-01-19 02.00.56 Bumped MPI2_HEADER_VERSION_UNIT
|
||||
* 10-02-19 02.00.57 Bumped MPI2_HEADER_VERSION_UNIT
|
||||
* --------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
@@ -162,7 +165,7 @@
|
||||
|
||||
|
||||
/* Unit and Dev versioning for this MPI header set */
|
||||
#define MPI2_HEADER_VERSION_UNIT (0x36)
|
||||
#define MPI2_HEADER_VERSION_UNIT (0x39)
|
||||
#define MPI2_HEADER_VERSION_DEV (0x00)
|
||||
#define MPI2_HEADER_VERSION_UNIT_MASK (0xFF00)
|
||||
#define MPI2_HEADER_VERSION_UNIT_SHIFT (8)
|
||||
@@ -181,6 +184,7 @@
|
||||
#define MPI2_IOC_STATE_READY (0x10000000)
|
||||
#define MPI2_IOC_STATE_OPERATIONAL (0x20000000)
|
||||
#define MPI2_IOC_STATE_FAULT (0x40000000)
|
||||
#define MPI2_IOC_STATE_COREDUMP (0x50000000)
|
||||
|
||||
#define MPI2_IOC_STATE_MASK (0xF0000000)
|
||||
#define MPI2_IOC_STATE_SHIFT (28)
|
||||
|
||||
@@ -249,6 +249,8 @@
|
||||
* 08-28-18 02.00.46 Added NVMs Write Cache flag to IOUnitPage1
|
||||
* Added DMDReport Delay Time defines to PCIeIOUnitPage1
|
||||
* 12-17-18 02.00.47 Swap locations of Slotx2 and Slotx4 in ManPage 7.
|
||||
* 08-01-19 02.00.49 Add MPI26_MANPAGE7_FLAG_X2_X4_SLOT_INFO_VALID
|
||||
* Add MPI26_IOUNITPAGE1_NVME_WRCACHE_SHIFT
|
||||
*/
|
||||
|
||||
#ifndef MPI2_CNFG_H
|
||||
@@ -891,6 +893,8 @@ typedef struct _MPI2_CONFIG_PAGE_MAN_7 {
|
||||
#define MPI2_MANPAGE7_FLAG_EVENTREPLAY_SLOT_ORDER (0x00000002)
|
||||
#define MPI2_MANPAGE7_FLAG_USE_SLOT_INFO (0x00000001)
|
||||
|
||||
#define MPI26_MANPAGE7_FLAG_CONN_LANE_USE_PINOUT (0x00000020)
|
||||
#define MPI26_MANPAGE7_FLAG_X2_X4_SLOT_INFO_VALID (0x00000010)
|
||||
|
||||
/*
|
||||
*Generic structure to use for product-specific manufacturing pages
|
||||
@@ -962,9 +966,10 @@ typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_1 {
|
||||
|
||||
/* IO Unit Page 1 Flags defines */
|
||||
#define MPI26_IOUNITPAGE1_NVME_WRCACHE_MASK (0x00030000)
|
||||
#define MPI26_IOUNITPAGE1_NVME_WRCACHE_ENABLE (0x00000000)
|
||||
#define MPI26_IOUNITPAGE1_NVME_WRCACHE_DISABLE (0x00010000)
|
||||
#define MPI26_IOUNITPAGE1_NVME_WRCACHE_NO_CHANGE (0x00020000)
|
||||
#define MPI26_IOUNITPAGE1_NVME_WRCACHE_SHIFT (16)
|
||||
#define MPI26_IOUNITPAGE1_NVME_WRCACHE_NO_CHANGE (0x00000000)
|
||||
#define MPI26_IOUNITPAGE1_NVME_WRCACHE_ENABLE (0x00010000)
|
||||
#define MPI26_IOUNITPAGE1_NVME_WRCACHE_DISABLE (0x00020000)
|
||||
#define MPI2_IOUNITPAGE1_ATA_SECURITY_FREEZE_LOCK (0x00004000)
|
||||
#define MPI25_IOUNITPAGE1_NEW_DEVICE_FAST_PATH_DISABLE (0x00002000)
|
||||
#define MPI25_IOUNITPAGE1_DISABLE_FAST_PATH (0x00001000)
|
||||
@@ -3931,7 +3936,13 @@ typedef struct _MPI26_CONFIG_PAGE_PCIEDEV_2 {
|
||||
U32 MaximumDataTransferSize; /*0x0C */
|
||||
U32 Capabilities; /*0x10 */
|
||||
U16 NOIOB; /* 0x14 */
|
||||
U16 Reserved2; /* 0x16 */
|
||||
U16 ShutdownLatency; /* 0x16 */
|
||||
U16 VendorID; /* 0x18 */
|
||||
U16 DeviceID; /* 0x1A */
|
||||
U16 SubsystemVendorID; /* 0x1C */
|
||||
U16 SubsystemID; /* 0x1E */
|
||||
U8 RevisionID; /* 0x20 */
|
||||
U8 Reserved21[3]; /* 0x21 */
|
||||
} MPI26_CONFIG_PAGE_PCIEDEV_2, *PTR_MPI26_CONFIG_PAGE_PCIEDEV_2,
|
||||
Mpi26PCIeDevicePage2_t, *pMpi26PCIeDevicePage2_t;
|
||||
|
||||
|
||||
@@ -19,6 +19,10 @@
|
||||
* 09-07-18 02.06.03 Added MPI26_EVENT_PCIE_TOPO_PI_16_LANES
|
||||
* 12-17-18 02.06.04 Addd MPI2_EXT_IMAGE_TYPE_PBLP
|
||||
* Shorten some defines to be compatible with DOS
|
||||
* 06-24-19 02.06.05 Whitespace adjustments to help with identifier
|
||||
* checking tool.
|
||||
* 10-02-19 02.06.06 Added MPI26_IMAGE_HEADER_SIG1_COREDUMP
|
||||
* Added MPI2_FLASH_REGION_COREDUMP
|
||||
*/
|
||||
#ifndef MPI2_IMAGE_H
|
||||
#define MPI2_IMAGE_H
|
||||
@@ -213,6 +217,8 @@ typedef struct _MPI26_COMPONENT_IMAGE_HEADER {
|
||||
#define MPI26_IMAGE_HEADER_SIG1_NVDATA (0x5444564E)
|
||||
#define MPI26_IMAGE_HEADER_SIG1_GAS_GAUGE (0x20534147)
|
||||
#define MPI26_IMAGE_HEADER_SIG1_PBLP (0x504C4250)
|
||||
/* little-endian "DUMP" */
|
||||
#define MPI26_IMAGE_HEADER_SIG1_COREDUMP (0x504D5544)
|
||||
|
||||
/**** Definitions for Signature2 field ****/
|
||||
#define MPI26_IMAGE_HEADER_SIGNATURE2_VALUE (0x50584546)
|
||||
@@ -359,6 +365,7 @@ typedef struct _MPI2_FLASH_LAYOUT_DATA {
|
||||
#define MPI2_FLASH_REGION_MR_NVDATA (0x14)
|
||||
#define MPI2_FLASH_REGION_CPLD (0x15)
|
||||
#define MPI2_FLASH_REGION_PSOC (0x16)
|
||||
#define MPI2_FLASH_REGION_COREDUMP (0x17)
|
||||
|
||||
/*ImageRevision */
|
||||
#define MPI2_FLASH_LAYOUT_IMAGE_REVISION (0x00)
|
||||
|
||||
@@ -175,6 +175,10 @@
|
||||
* Moved FW image definitions ionto new mpi2_image,h
|
||||
* 08-14-18 02.00.36 Fixed definition of MPI2_FW_DOWNLOAD_ITYPE_PSOC (0x16)
|
||||
* 09-07-18 02.00.37 Added MPI26_EVENT_PCIE_TOPO_PI_16_LANES
|
||||
* 10-02-19 02.00.38 Added MPI26_IOCINIT_CFGFLAGS_COREDUMP_ENABLE
|
||||
* Added MPI26_IOCFACTS_CAPABILITY_COREDUMP_ENABLED
|
||||
* Added MPI2_FW_DOWNLOAD_ITYPE_COREDUMP
|
||||
* Added MPI2_FW_UPLOAD_ITYPE_COREDUMP
|
||||
* --------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
@@ -248,6 +252,7 @@ typedef struct _MPI2_IOC_INIT_REQUEST {
|
||||
|
||||
/*ConfigurationFlags */
|
||||
#define MPI26_IOCINIT_CFGFLAGS_NVME_SGL_FORMAT (0x0001)
|
||||
#define MPI26_IOCINIT_CFGFLAGS_COREDUMP_ENABLE (0x0002)
|
||||
|
||||
/*minimum depth for a Reply Descriptor Post Queue */
|
||||
#define MPI2_RDPQ_DEPTH_MIN (16)
|
||||
@@ -377,6 +382,7 @@ typedef struct _MPI2_IOC_FACTS_REPLY {
|
||||
/*ProductID field uses MPI2_FW_HEADER_PID_ */
|
||||
|
||||
/*IOCCapabilities */
|
||||
#define MPI26_IOCFACTS_CAPABILITY_COREDUMP_ENABLED (0x00200000)
|
||||
#define MPI26_IOCFACTS_CAPABILITY_PCIE_SRIOV (0x00100000)
|
||||
#define MPI26_IOCFACTS_CAPABILITY_ATOMIC_REQ (0x00080000)
|
||||
#define MPI2_IOCFACTS_CAPABILITY_RDPQ_ARRAY_CAPABLE (0x00040000)
|
||||
@@ -1458,8 +1464,8 @@ typedef struct _MPI2_FW_DOWNLOAD_REQUEST {
|
||||
/*MPI v2.6 and newer */
|
||||
#define MPI2_FW_DOWNLOAD_ITYPE_CPLD (0x15)
|
||||
#define MPI2_FW_DOWNLOAD_ITYPE_PSOC (0x16)
|
||||
#define MPI2_FW_DOWNLOAD_ITYPE_COREDUMP (0x17)
|
||||
#define MPI2_FW_DOWNLOAD_ITYPE_MIN_PRODUCT_SPECIFIC (0xF0)
|
||||
#define MPI2_FW_DOWNLOAD_ITYPE_TERMINATE (0xFF)
|
||||
|
||||
/*MPI v2.0 FWDownload TransactionContext Element */
|
||||
typedef struct _MPI2_FW_DOWNLOAD_TCSGE {
|
||||
|
||||
@@ -123,8 +123,15 @@ enum mpt3sas_perf_mode {
|
||||
MPT_PERF_MODE_LATENCY = 2,
|
||||
};
|
||||
|
||||
static int
|
||||
_base_wait_on_iocstate(struct MPT3SAS_ADAPTER *ioc,
|
||||
u32 ioc_state, int timeout);
|
||||
static int
|
||||
_base_get_ioc_facts(struct MPT3SAS_ADAPTER *ioc);
|
||||
static void
|
||||
_base_mask_interrupts(struct MPT3SAS_ADAPTER *ioc);
|
||||
static void
|
||||
_base_clear_outstanding_commands(struct MPT3SAS_ADAPTER *ioc);
|
||||
|
||||
/**
|
||||
* mpt3sas_base_check_cmd_timeout - Function
|
||||
@@ -609,7 +616,8 @@ _base_fault_reset_work(struct work_struct *work)
|
||||
|
||||
|
||||
spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags);
|
||||
if (ioc->shost_recovery || ioc->pci_error_recovery)
|
||||
if ((ioc->shost_recovery && (ioc->ioc_coredump_loop == 0)) ||
|
||||
ioc->pci_error_recovery)
|
||||
goto rearm_timer;
|
||||
spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags);
|
||||
|
||||
@@ -656,20 +664,64 @@ _base_fault_reset_work(struct work_struct *work)
|
||||
return; /* don't rearm timer */
|
||||
}
|
||||
|
||||
ioc->non_operational_loop = 0;
|
||||
if ((doorbell & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_COREDUMP) {
|
||||
u8 timeout = (ioc->manu_pg11.CoreDumpTOSec) ?
|
||||
ioc->manu_pg11.CoreDumpTOSec :
|
||||
MPT3SAS_DEFAULT_COREDUMP_TIMEOUT_SECONDS;
|
||||
|
||||
timeout /= (FAULT_POLLING_INTERVAL/1000);
|
||||
|
||||
if (ioc->ioc_coredump_loop == 0) {
|
||||
mpt3sas_print_coredump_info(ioc,
|
||||
doorbell & MPI2_DOORBELL_DATA_MASK);
|
||||
/* do not accept any IOs and disable the interrupts */
|
||||
spin_lock_irqsave(
|
||||
&ioc->ioc_reset_in_progress_lock, flags);
|
||||
ioc->shost_recovery = 1;
|
||||
spin_unlock_irqrestore(
|
||||
&ioc->ioc_reset_in_progress_lock, flags);
|
||||
_base_mask_interrupts(ioc);
|
||||
_base_clear_outstanding_commands(ioc);
|
||||
}
|
||||
|
||||
ioc_info(ioc, "%s: CoreDump loop %d.",
|
||||
__func__, ioc->ioc_coredump_loop);
|
||||
|
||||
/* Wait until CoreDump completes or times out */
|
||||
if (ioc->ioc_coredump_loop++ < timeout) {
|
||||
spin_lock_irqsave(
|
||||
&ioc->ioc_reset_in_progress_lock, flags);
|
||||
goto rearm_timer;
|
||||
}
|
||||
}
|
||||
|
||||
if (ioc->ioc_coredump_loop) {
|
||||
if ((doorbell & MPI2_IOC_STATE_MASK) != MPI2_IOC_STATE_COREDUMP)
|
||||
ioc_err(ioc, "%s: CoreDump completed. LoopCount: %d",
|
||||
__func__, ioc->ioc_coredump_loop);
|
||||
else
|
||||
ioc_err(ioc, "%s: CoreDump Timed out. LoopCount: %d",
|
||||
__func__, ioc->ioc_coredump_loop);
|
||||
ioc->ioc_coredump_loop = MPT3SAS_COREDUMP_LOOP_DONE;
|
||||
}
|
||||
ioc->non_operational_loop = 0;
|
||||
if ((doorbell & MPI2_IOC_STATE_MASK) != MPI2_IOC_STATE_OPERATIONAL) {
|
||||
rc = mpt3sas_base_hard_reset_handler(ioc, FORCE_BIG_HAMMER);
|
||||
ioc_warn(ioc, "%s: hard reset: %s\n",
|
||||
__func__, rc == 0 ? "success" : "failed");
|
||||
doorbell = mpt3sas_base_get_iocstate(ioc, 0);
|
||||
if ((doorbell & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_FAULT)
|
||||
mpt3sas_base_fault_info(ioc, doorbell &
|
||||
if ((doorbell & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_FAULT) {
|
||||
mpt3sas_print_fault_code(ioc, doorbell &
|
||||
MPI2_DOORBELL_DATA_MASK);
|
||||
} else if ((doorbell & MPI2_IOC_STATE_MASK) ==
|
||||
MPI2_IOC_STATE_COREDUMP)
|
||||
mpt3sas_print_coredump_info(ioc, doorbell &
|
||||
MPI2_DOORBELL_DATA_MASK);
|
||||
if (rc && (doorbell & MPI2_IOC_STATE_MASK) !=
|
||||
MPI2_IOC_STATE_OPERATIONAL)
|
||||
return; /* don't rearm timer */
|
||||
}
|
||||
ioc->ioc_coredump_loop = 0;
|
||||
|
||||
spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags);
|
||||
rearm_timer:
|
||||
@@ -748,6 +800,49 @@ mpt3sas_base_fault_info(struct MPT3SAS_ADAPTER *ioc , u16 fault_code)
|
||||
ioc_err(ioc, "fault_state(0x%04x)!\n", fault_code);
|
||||
}
|
||||
|
||||
/**
|
||||
* mpt3sas_base_coredump_info - verbose translation of firmware CoreDump state
|
||||
* @ioc: per adapter object
|
||||
* @fault_code: fault code
|
||||
*
|
||||
* Return nothing.
|
||||
*/
|
||||
void
|
||||
mpt3sas_base_coredump_info(struct MPT3SAS_ADAPTER *ioc, u16 fault_code)
|
||||
{
|
||||
ioc_err(ioc, "coredump_state(0x%04x)!\n", fault_code);
|
||||
}
|
||||
|
||||
/**
|
||||
* mpt3sas_base_wait_for_coredump_completion - Wait until coredump
|
||||
* completes or times out
|
||||
* @ioc: per adapter object
|
||||
*
|
||||
* Returns 0 for success, non-zero for failure.
|
||||
*/
|
||||
int
|
||||
mpt3sas_base_wait_for_coredump_completion(struct MPT3SAS_ADAPTER *ioc,
|
||||
const char *caller)
|
||||
{
|
||||
u8 timeout = (ioc->manu_pg11.CoreDumpTOSec) ?
|
||||
ioc->manu_pg11.CoreDumpTOSec :
|
||||
MPT3SAS_DEFAULT_COREDUMP_TIMEOUT_SECONDS;
|
||||
|
||||
int ioc_state = _base_wait_on_iocstate(ioc, MPI2_IOC_STATE_FAULT,
|
||||
timeout);
|
||||
|
||||
if (ioc_state)
|
||||
ioc_err(ioc,
|
||||
"%s: CoreDump timed out. (ioc_state=0x%x)\n",
|
||||
caller, ioc_state);
|
||||
else
|
||||
ioc_info(ioc,
|
||||
"%s: CoreDump completed. (ioc_state=0x%x)\n",
|
||||
caller, ioc_state);
|
||||
|
||||
return ioc_state;
|
||||
}
|
||||
|
||||
/**
|
||||
* mpt3sas_halt_firmware - halt's mpt controller firmware
|
||||
* @ioc: per adapter object
|
||||
@@ -768,9 +863,14 @@ mpt3sas_halt_firmware(struct MPT3SAS_ADAPTER *ioc)
|
||||
dump_stack();
|
||||
|
||||
doorbell = ioc->base_readl(&ioc->chip->Doorbell);
|
||||
if ((doorbell & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_FAULT)
|
||||
mpt3sas_base_fault_info(ioc , doorbell);
|
||||
else {
|
||||
if ((doorbell & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_FAULT) {
|
||||
mpt3sas_print_fault_code(ioc, doorbell &
|
||||
MPI2_DOORBELL_DATA_MASK);
|
||||
} else if ((doorbell & MPI2_IOC_STATE_MASK) ==
|
||||
MPI2_IOC_STATE_COREDUMP) {
|
||||
mpt3sas_print_coredump_info(ioc, doorbell &
|
||||
MPI2_DOORBELL_DATA_MASK);
|
||||
} else {
|
||||
writel(0xC0FFEE00, &ioc->chip->Doorbell);
|
||||
ioc_err(ioc, "Firmware is halted due to command timeout\n");
|
||||
}
|
||||
@@ -3103,6 +3203,8 @@ _base_enable_msix(struct MPT3SAS_ADAPTER *ioc)
|
||||
*/
|
||||
if (!ioc->combined_reply_queue &&
|
||||
ioc->hba_mpi_version_belonged != MPI2_VERSION) {
|
||||
ioc_info(ioc,
|
||||
"combined ReplyQueue is off, Enabling msix load balance\n");
|
||||
ioc->msix_load_balance = true;
|
||||
}
|
||||
|
||||
@@ -3115,9 +3217,7 @@ _base_enable_msix(struct MPT3SAS_ADAPTER *ioc)
|
||||
|
||||
r = _base_alloc_irq_vectors(ioc);
|
||||
if (r < 0) {
|
||||
dfailprintk(ioc,
|
||||
ioc_info(ioc, "pci_alloc_irq_vectors failed (r=%d) !!!\n",
|
||||
r));
|
||||
ioc_info(ioc, "pci_alloc_irq_vectors failed (r=%d) !!!\n", r);
|
||||
goto try_ioapic;
|
||||
}
|
||||
|
||||
@@ -3206,9 +3306,15 @@ _base_check_for_fault_and_issue_reset(struct MPT3SAS_ADAPTER *ioc)
|
||||
dhsprintk(ioc, pr_info("%s: ioc_state(0x%08x)\n", __func__, ioc_state));
|
||||
|
||||
if ((ioc_state & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_FAULT) {
|
||||
mpt3sas_base_fault_info(ioc, ioc_state &
|
||||
mpt3sas_print_fault_code(ioc, ioc_state &
|
||||
MPI2_DOORBELL_DATA_MASK);
|
||||
rc = _base_diag_reset(ioc);
|
||||
} else if ((ioc_state & MPI2_IOC_STATE_MASK) ==
|
||||
MPI2_IOC_STATE_COREDUMP) {
|
||||
mpt3sas_print_coredump_info(ioc, ioc_state &
|
||||
MPI2_DOORBELL_DATA_MASK);
|
||||
mpt3sas_base_wait_for_coredump_completion(ioc, __func__);
|
||||
rc = _base_diag_reset(ioc);
|
||||
}
|
||||
|
||||
return rc;
|
||||
@@ -3279,7 +3385,8 @@ mpt3sas_base_map_resources(struct MPT3SAS_ADAPTER *ioc)
|
||||
}
|
||||
|
||||
if (ioc->chip == NULL) {
|
||||
ioc_err(ioc, "unable to map adapter memory! or resource not found\n");
|
||||
ioc_err(ioc,
|
||||
"unable to map adapter memory! or resource not found\n");
|
||||
r = -EINVAL;
|
||||
goto out_fail;
|
||||
}
|
||||
@@ -3318,8 +3425,8 @@ mpt3sas_base_map_resources(struct MPT3SAS_ADAPTER *ioc)
|
||||
ioc->combined_reply_index_count,
|
||||
sizeof(resource_size_t *), GFP_KERNEL);
|
||||
if (!ioc->replyPostRegisterIndex) {
|
||||
dfailprintk(ioc,
|
||||
ioc_warn(ioc, "allocation for reply Post Register Index failed!!!\n"));
|
||||
ioc_err(ioc,
|
||||
"allocation for replyPostRegisterIndex failed!\n");
|
||||
r = -ENOMEM;
|
||||
goto out_fail;
|
||||
}
|
||||
@@ -3466,6 +3573,22 @@ _base_get_msix_index(struct MPT3SAS_ADAPTER *ioc,
|
||||
return ioc->cpu_msix_table[raw_smp_processor_id()];
|
||||
}
|
||||
|
||||
/**
|
||||
* _base_sdev_nr_inflight_request -get number of inflight requests
|
||||
* of a request queue.
|
||||
* @q: request_queue object
|
||||
*
|
||||
* returns number of inflight request of a request queue.
|
||||
*/
|
||||
inline unsigned long
|
||||
_base_sdev_nr_inflight_request(struct request_queue *q)
|
||||
{
|
||||
struct blk_mq_hw_ctx *hctx = q->queue_hw_ctx[0];
|
||||
|
||||
return atomic_read(&hctx->nr_active);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* _base_get_high_iops_msix_index - get the msix index of
|
||||
* high iops queues
|
||||
@@ -3485,7 +3608,7 @@ _base_get_high_iops_msix_index(struct MPT3SAS_ADAPTER *ioc,
|
||||
* reply queues in terms of batch count 16 when outstanding
|
||||
* IOs on the target device is >=8.
|
||||
*/
|
||||
if (atomic_read(&scmd->device->device_busy) >
|
||||
if (_base_sdev_nr_inflight_request(scmd->device->request_queue) >
|
||||
MPT3SAS_DEVICE_HIGH_IOPS_DEPTH)
|
||||
return base_mod64((
|
||||
atomic64_add_return(1, &ioc->high_iops_outstanding) /
|
||||
@@ -4264,7 +4387,8 @@ _base_display_fwpkg_version(struct MPT3SAS_ADAPTER *ioc)
|
||||
fwpkg_data = dma_alloc_coherent(&ioc->pdev->dev, data_length,
|
||||
&fwpkg_data_dma, GFP_KERNEL);
|
||||
if (!fwpkg_data) {
|
||||
ioc_err(ioc, "failure at %s:%d/%s()!\n",
|
||||
ioc_err(ioc,
|
||||
"Memory allocation for fwpkg data failed at %s:%d/%s()!\n",
|
||||
__FILE__, __LINE__, __func__);
|
||||
return -ENOMEM;
|
||||
}
|
||||
@@ -4994,12 +5118,13 @@ _base_allocate_memory_pools(struct MPT3SAS_ADAPTER *ioc)
|
||||
ioc->reply_free_queue_depth = ioc->hba_queue_depth + 64;
|
||||
}
|
||||
|
||||
dinitprintk(ioc,
|
||||
ioc_info(ioc, "scatter gather: sge_in_main_msg(%d), sge_per_chain(%d), sge_per_io(%d), chains_per_io(%d)\n",
|
||||
ioc->max_sges_in_main_message,
|
||||
ioc->max_sges_in_chain_message,
|
||||
ioc->shost->sg_tablesize,
|
||||
ioc->chains_needed_per_io));
|
||||
ioc_info(ioc,
|
||||
"scatter gather: sge_in_main_msg(%d), sge_per_chain(%d), "
|
||||
"sge_per_io(%d), chains_per_io(%d)\n",
|
||||
ioc->max_sges_in_main_message,
|
||||
ioc->max_sges_in_chain_message,
|
||||
ioc->shost->sg_tablesize,
|
||||
ioc->chains_needed_per_io);
|
||||
|
||||
/* reply post queue, 16 byte align */
|
||||
reply_post_free_sz = ioc->reply_post_queue_depth *
|
||||
@@ -5109,15 +5234,13 @@ _base_allocate_memory_pools(struct MPT3SAS_ADAPTER *ioc)
|
||||
ioc->internal_dma = ioc->hi_priority_dma + (ioc->hi_priority_depth *
|
||||
ioc->request_sz);
|
||||
|
||||
dinitprintk(ioc,
|
||||
ioc_info(ioc, "request pool(0x%p): depth(%d), frame_size(%d), pool_size(%d kB)\n",
|
||||
ioc->request, ioc->hba_queue_depth,
|
||||
ioc->request_sz,
|
||||
(ioc->hba_queue_depth * ioc->request_sz) / 1024));
|
||||
ioc_info(ioc,
|
||||
"request pool(0x%p) - dma(0x%llx): "
|
||||
"depth(%d), frame_size(%d), pool_size(%d kB)\n",
|
||||
ioc->request, (unsigned long long) ioc->request_dma,
|
||||
ioc->hba_queue_depth, ioc->request_sz,
|
||||
(ioc->hba_queue_depth * ioc->request_sz) / 1024);
|
||||
|
||||
dinitprintk(ioc,
|
||||
ioc_info(ioc, "request pool: dma(0x%llx)\n",
|
||||
(unsigned long long)ioc->request_dma));
|
||||
total_sz += sz;
|
||||
|
||||
dinitprintk(ioc,
|
||||
@@ -5302,13 +5425,12 @@ _base_allocate_memory_pools(struct MPT3SAS_ADAPTER *ioc)
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
dinitprintk(ioc,
|
||||
ioc_info(ioc, "sense pool(0x%p): depth(%d), element_size(%d), pool_size(%d kB)\n",
|
||||
ioc->sense, ioc->scsiio_depth,
|
||||
SCSI_SENSE_BUFFERSIZE, sz / 1024));
|
||||
dinitprintk(ioc,
|
||||
ioc_info(ioc, "sense_dma(0x%llx)\n",
|
||||
(unsigned long long)ioc->sense_dma));
|
||||
ioc_info(ioc,
|
||||
"sense pool(0x%p)- dma(0x%llx): depth(%d),"
|
||||
"element_size(%d), pool_size(%d kB)\n",
|
||||
ioc->sense, (unsigned long long)ioc->sense_dma, ioc->scsiio_depth,
|
||||
SCSI_SENSE_BUFFERSIZE, sz / 1024);
|
||||
|
||||
total_sz += sz;
|
||||
|
||||
/* reply pool, 4 byte align */
|
||||
@@ -5386,12 +5508,10 @@ _base_allocate_memory_pools(struct MPT3SAS_ADAPTER *ioc)
|
||||
ioc_err(ioc, "config page: dma_pool_alloc failed\n");
|
||||
goto out;
|
||||
}
|
||||
dinitprintk(ioc,
|
||||
ioc_info(ioc, "config page(0x%p): size(%d)\n",
|
||||
ioc->config_page, ioc->config_page_sz));
|
||||
dinitprintk(ioc,
|
||||
ioc_info(ioc, "config_page_dma(0x%llx)\n",
|
||||
(unsigned long long)ioc->config_page_dma));
|
||||
|
||||
ioc_info(ioc, "config page(0x%p) - dma(0x%llx): size(%d)\n",
|
||||
ioc->config_page, (unsigned long long)ioc->config_page_dma,
|
||||
ioc->config_page_sz);
|
||||
total_sz += ioc->config_page_sz;
|
||||
|
||||
ioc_info(ioc, "Allocated physical memory: size(%d kB)\n",
|
||||
@@ -5446,6 +5566,8 @@ _base_wait_on_iocstate(struct MPT3SAS_ADAPTER *ioc, u32 ioc_state, int timeout)
|
||||
return 0;
|
||||
if (count && current_state == MPI2_IOC_STATE_FAULT)
|
||||
break;
|
||||
if (count && current_state == MPI2_IOC_STATE_COREDUMP)
|
||||
break;
|
||||
|
||||
usleep_range(1000, 1500);
|
||||
count++;
|
||||
@@ -5547,7 +5669,12 @@ _base_wait_for_doorbell_ack(struct MPT3SAS_ADAPTER *ioc, int timeout)
|
||||
doorbell = ioc->base_readl(&ioc->chip->Doorbell);
|
||||
if ((doorbell & MPI2_IOC_STATE_MASK) ==
|
||||
MPI2_IOC_STATE_FAULT) {
|
||||
mpt3sas_base_fault_info(ioc , doorbell);
|
||||
mpt3sas_print_fault_code(ioc, doorbell);
|
||||
return -EFAULT;
|
||||
}
|
||||
if ((doorbell & MPI2_IOC_STATE_MASK) ==
|
||||
MPI2_IOC_STATE_COREDUMP) {
|
||||
mpt3sas_print_coredump_info(ioc, doorbell);
|
||||
return -EFAULT;
|
||||
}
|
||||
} else if (int_status == 0xFFFFFFFF)
|
||||
@@ -5609,6 +5736,7 @@ _base_send_ioc_reset(struct MPT3SAS_ADAPTER *ioc, u8 reset_type, int timeout)
|
||||
{
|
||||
u32 ioc_state;
|
||||
int r = 0;
|
||||
unsigned long flags;
|
||||
|
||||
if (reset_type != MPI2_FUNCTION_IOC_MESSAGE_UNIT_RESET) {
|
||||
ioc_err(ioc, "%s: unknown reset_type\n", __func__);
|
||||
@@ -5627,6 +5755,7 @@ _base_send_ioc_reset(struct MPT3SAS_ADAPTER *ioc, u8 reset_type, int timeout)
|
||||
r = -EFAULT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ioc_state = _base_wait_on_iocstate(ioc, MPI2_IOC_STATE_READY, timeout);
|
||||
if (ioc_state) {
|
||||
ioc_err(ioc, "%s: failed going to ready state (ioc_state=0x%x)\n",
|
||||
@@ -5635,6 +5764,26 @@ _base_send_ioc_reset(struct MPT3SAS_ADAPTER *ioc, u8 reset_type, int timeout)
|
||||
goto out;
|
||||
}
|
||||
out:
|
||||
if (r != 0) {
|
||||
ioc_state = mpt3sas_base_get_iocstate(ioc, 0);
|
||||
spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags);
|
||||
/*
|
||||
* Wait for IOC state CoreDump to clear only during
|
||||
* HBA initialization & release time.
|
||||
*/
|
||||
if ((ioc_state & MPI2_IOC_STATE_MASK) ==
|
||||
MPI2_IOC_STATE_COREDUMP && (ioc->is_driver_loading == 1 ||
|
||||
ioc->fault_reset_work_q == NULL)) {
|
||||
spin_unlock_irqrestore(
|
||||
&ioc->ioc_reset_in_progress_lock, flags);
|
||||
mpt3sas_print_coredump_info(ioc, ioc_state);
|
||||
mpt3sas_base_wait_for_coredump_completion(ioc,
|
||||
__func__);
|
||||
spin_lock_irqsave(
|
||||
&ioc->ioc_reset_in_progress_lock, flags);
|
||||
}
|
||||
spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags);
|
||||
}
|
||||
ioc_info(ioc, "message unit reset: %s\n",
|
||||
r == 0 ? "SUCCESS" : "FAILED");
|
||||
return r;
|
||||
@@ -5782,7 +5931,7 @@ _base_handshake_req_reply_wait(struct MPT3SAS_ADAPTER *ioc, int request_bytes,
|
||||
mfp = (__le32 *)reply;
|
||||
pr_info("\toffset:data\n");
|
||||
for (i = 0; i < reply_bytes/4; i++)
|
||||
pr_info("\t[0x%02x]:%08x\n", i*4,
|
||||
ioc_info(ioc, "\t[0x%02x]:%08x\n", i*4,
|
||||
le32_to_cpu(mfp[i]));
|
||||
}
|
||||
return 0;
|
||||
@@ -5850,10 +5999,9 @@ mpt3sas_base_sas_iounit_control(struct MPT3SAS_ADAPTER *ioc,
|
||||
ioc->ioc_link_reset_in_progress)
|
||||
ioc->ioc_link_reset_in_progress = 0;
|
||||
if (!(ioc->base_cmds.status & MPT3_CMD_COMPLETE)) {
|
||||
issue_reset =
|
||||
mpt3sas_base_check_cmd_timeout(ioc,
|
||||
ioc->base_cmds.status, mpi_request,
|
||||
sizeof(Mpi2SasIoUnitControlRequest_t)/4);
|
||||
mpt3sas_check_cmd_timeout(ioc, ioc->base_cmds.status,
|
||||
mpi_request, sizeof(Mpi2SasIoUnitControlRequest_t)/4,
|
||||
issue_reset);
|
||||
goto issue_host_reset;
|
||||
}
|
||||
if (ioc->base_cmds.status & MPT3_CMD_REPLY_VALID)
|
||||
@@ -5926,10 +6074,9 @@ mpt3sas_base_scsi_enclosure_processor(struct MPT3SAS_ADAPTER *ioc,
|
||||
wait_for_completion_timeout(&ioc->base_cmds.done,
|
||||
msecs_to_jiffies(10000));
|
||||
if (!(ioc->base_cmds.status & MPT3_CMD_COMPLETE)) {
|
||||
issue_reset =
|
||||
mpt3sas_base_check_cmd_timeout(ioc,
|
||||
ioc->base_cmds.status, mpi_request,
|
||||
sizeof(Mpi2SepRequest_t)/4);
|
||||
mpt3sas_check_cmd_timeout(ioc,
|
||||
ioc->base_cmds.status, mpi_request,
|
||||
sizeof(Mpi2SepRequest_t)/4, issue_reset);
|
||||
goto issue_host_reset;
|
||||
}
|
||||
if (ioc->base_cmds.status & MPT3_CMD_REPLY_VALID)
|
||||
@@ -6028,9 +6175,15 @@ _base_wait_for_iocstate(struct MPT3SAS_ADAPTER *ioc, int timeout)
|
||||
}
|
||||
|
||||
if ((ioc_state & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_FAULT) {
|
||||
mpt3sas_base_fault_info(ioc, ioc_state &
|
||||
mpt3sas_print_fault_code(ioc, ioc_state &
|
||||
MPI2_DOORBELL_DATA_MASK);
|
||||
goto issue_diag_reset;
|
||||
} else if ((ioc_state & MPI2_IOC_STATE_MASK) ==
|
||||
MPI2_IOC_STATE_COREDUMP) {
|
||||
ioc_info(ioc,
|
||||
"%s: Skipping the diag reset here. (ioc_state=0x%x)\n",
|
||||
__func__, ioc_state);
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
ioc_state = _base_wait_on_iocstate(ioc, MPI2_IOC_STATE_READY, timeout);
|
||||
@@ -6209,6 +6362,12 @@ _base_send_ioc_init(struct MPT3SAS_ADAPTER *ioc)
|
||||
cpu_to_le64((u64)ioc->reply_post[0].reply_post_free_dma);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the flag to enable CoreDump state feature in IOC firmware.
|
||||
*/
|
||||
mpi_request.ConfigurationFlags |=
|
||||
cpu_to_le16(MPI26_IOCINIT_CFGFLAGS_COREDUMP_ENABLE);
|
||||
|
||||
/* This time stamp specifies number of milliseconds
|
||||
* since epoch ~ midnight January 1, 1970.
|
||||
*/
|
||||
@@ -6220,9 +6379,9 @@ _base_send_ioc_init(struct MPT3SAS_ADAPTER *ioc)
|
||||
int i;
|
||||
|
||||
mfp = (__le32 *)&mpi_request;
|
||||
pr_info("\toffset:data\n");
|
||||
ioc_info(ioc, "\toffset:data\n");
|
||||
for (i = 0; i < sizeof(Mpi2IOCInitRequest_t)/4; i++)
|
||||
pr_info("\t[0x%02x]:%08x\n", i*4,
|
||||
ioc_info(ioc, "\t[0x%02x]:%08x\n", i*4,
|
||||
le32_to_cpu(mfp[i]));
|
||||
}
|
||||
|
||||
@@ -6592,8 +6751,11 @@ _base_diag_reset(struct MPT3SAS_ADAPTER *ioc)
|
||||
/* wait 100 msec */
|
||||
msleep(100);
|
||||
|
||||
if (count++ > 20)
|
||||
if (count++ > 20) {
|
||||
ioc_info(ioc,
|
||||
"Stop writing magic sequence after 20 retries\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
host_diagnostic = ioc->base_readl(&ioc->chip->HostDiagnostic);
|
||||
drsprintk(ioc,
|
||||
@@ -6617,8 +6779,11 @@ _base_diag_reset(struct MPT3SAS_ADAPTER *ioc)
|
||||
|
||||
host_diagnostic = ioc->base_readl(&ioc->chip->HostDiagnostic);
|
||||
|
||||
if (host_diagnostic == 0xFFFFFFFF)
|
||||
if (host_diagnostic == 0xFFFFFFFF) {
|
||||
ioc_info(ioc,
|
||||
"Invalid host diagnostic register value\n");
|
||||
goto out;
|
||||
}
|
||||
if (!(host_diagnostic & MPI2_DIAG_RESET_ADAPTER))
|
||||
break;
|
||||
|
||||
@@ -6705,16 +6870,33 @@ _base_make_ioc_ready(struct MPT3SAS_ADAPTER *ioc, enum reset_type type)
|
||||
return 0;
|
||||
|
||||
if (ioc_state & MPI2_DOORBELL_USED) {
|
||||
dhsprintk(ioc, ioc_info(ioc, "unexpected doorbell active!\n"));
|
||||
ioc_info(ioc, "unexpected doorbell active!\n");
|
||||
goto issue_diag_reset;
|
||||
}
|
||||
|
||||
if ((ioc_state & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_FAULT) {
|
||||
mpt3sas_base_fault_info(ioc, ioc_state &
|
||||
mpt3sas_print_fault_code(ioc, ioc_state &
|
||||
MPI2_DOORBELL_DATA_MASK);
|
||||
goto issue_diag_reset;
|
||||
}
|
||||
|
||||
if ((ioc_state & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_COREDUMP) {
|
||||
/*
|
||||
* if host reset is invoked while watch dog thread is waiting
|
||||
* for IOC state to be changed to Fault state then driver has
|
||||
* to wait here for CoreDump state to clear otherwise reset
|
||||
* will be issued to the FW and FW move the IOC state to
|
||||
* reset state without copying the FW logs to coredump region.
|
||||
*/
|
||||
if (ioc->ioc_coredump_loop != MPT3SAS_COREDUMP_LOOP_DONE) {
|
||||
mpt3sas_print_coredump_info(ioc, ioc_state &
|
||||
MPI2_DOORBELL_DATA_MASK);
|
||||
mpt3sas_base_wait_for_coredump_completion(ioc,
|
||||
__func__);
|
||||
}
|
||||
goto issue_diag_reset;
|
||||
}
|
||||
|
||||
if (type == FORCE_BIG_HAMMER)
|
||||
goto issue_diag_reset;
|
||||
|
||||
@@ -6958,8 +7140,7 @@ mpt3sas_base_attach(struct MPT3SAS_ADAPTER *ioc)
|
||||
ioc->cpu_msix_table = kzalloc(ioc->cpu_msix_table_sz, GFP_KERNEL);
|
||||
ioc->reply_queue_count = 1;
|
||||
if (!ioc->cpu_msix_table) {
|
||||
dfailprintk(ioc,
|
||||
ioc_info(ioc, "allocation for cpu_msix_table failed!!!\n"));
|
||||
ioc_info(ioc, "Allocation for cpu_msix_table failed!!!\n");
|
||||
r = -ENOMEM;
|
||||
goto out_free_resources;
|
||||
}
|
||||
@@ -6968,8 +7149,7 @@ mpt3sas_base_attach(struct MPT3SAS_ADAPTER *ioc)
|
||||
ioc->reply_post_host_index = kcalloc(ioc->cpu_msix_table_sz,
|
||||
sizeof(resource_size_t *), GFP_KERNEL);
|
||||
if (!ioc->reply_post_host_index) {
|
||||
dfailprintk(ioc,
|
||||
ioc_info(ioc, "allocation for reply_post_host_index failed!!!\n"));
|
||||
ioc_info(ioc, "Allocation for reply_post_host_index failed!!!\n");
|
||||
r = -ENOMEM;
|
||||
goto out_free_resources;
|
||||
}
|
||||
@@ -7195,6 +7375,7 @@ mpt3sas_base_attach(struct MPT3SAS_ADAPTER *ioc)
|
||||
sizeof(struct mpt3sas_facts));
|
||||
|
||||
ioc->non_operational_loop = 0;
|
||||
ioc->ioc_coredump_loop = 0;
|
||||
ioc->got_task_abort_from_ioctl = 0;
|
||||
return 0;
|
||||
|
||||
@@ -7276,14 +7457,14 @@ static void _base_pre_reset_handler(struct MPT3SAS_ADAPTER *ioc)
|
||||
}
|
||||
|
||||
/**
|
||||
* _base_after_reset_handler - after reset handler
|
||||
* _base_clear_outstanding_mpt_commands - clears outstanding mpt commands
|
||||
* @ioc: per adapter object
|
||||
*/
|
||||
static void _base_after_reset_handler(struct MPT3SAS_ADAPTER *ioc)
|
||||
static void
|
||||
_base_clear_outstanding_mpt_commands(struct MPT3SAS_ADAPTER *ioc)
|
||||
{
|
||||
mpt3sas_scsih_after_reset_handler(ioc);
|
||||
mpt3sas_ctl_after_reset_handler(ioc);
|
||||
dtmprintk(ioc, ioc_info(ioc, "%s: MPT3_IOC_AFTER_RESET\n", __func__));
|
||||
dtmprintk(ioc,
|
||||
ioc_info(ioc, "%s: clear outstanding mpt cmds\n", __func__));
|
||||
if (ioc->transport_cmds.status & MPT3_CMD_PENDING) {
|
||||
ioc->transport_cmds.status |= MPT3_CMD_RESET;
|
||||
mpt3sas_base_free_smid(ioc, ioc->transport_cmds.smid);
|
||||
@@ -7316,6 +7497,17 @@ static void _base_after_reset_handler(struct MPT3SAS_ADAPTER *ioc)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* _base_clear_outstanding_commands - clear all outstanding commands
|
||||
* @ioc: per adapter object
|
||||
*/
|
||||
static void _base_clear_outstanding_commands(struct MPT3SAS_ADAPTER *ioc)
|
||||
{
|
||||
mpt3sas_scsih_clear_outstanding_scsi_tm_commands(ioc);
|
||||
mpt3sas_ctl_clear_outstanding_ioctls(ioc);
|
||||
_base_clear_outstanding_mpt_commands(ioc);
|
||||
}
|
||||
|
||||
/**
|
||||
* _base_reset_done_handler - reset done handler
|
||||
* @ioc: per adapter object
|
||||
@@ -7474,7 +7666,9 @@ mpt3sas_base_hard_reset_handler(struct MPT3SAS_ADAPTER *ioc,
|
||||
MPT3_DIAG_BUFFER_IS_RELEASED))) {
|
||||
is_trigger = 1;
|
||||
ioc_state = mpt3sas_base_get_iocstate(ioc, 0);
|
||||
if ((ioc_state & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_FAULT)
|
||||
if ((ioc_state & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_FAULT ||
|
||||
(ioc_state & MPI2_IOC_STATE_MASK) ==
|
||||
MPI2_IOC_STATE_COREDUMP)
|
||||
is_fault = 1;
|
||||
}
|
||||
_base_pre_reset_handler(ioc);
|
||||
@@ -7483,7 +7677,7 @@ mpt3sas_base_hard_reset_handler(struct MPT3SAS_ADAPTER *ioc,
|
||||
r = _base_make_ioc_ready(ioc, type);
|
||||
if (r)
|
||||
goto out;
|
||||
_base_after_reset_handler(ioc);
|
||||
_base_clear_outstanding_commands(ioc);
|
||||
|
||||
/* If this hard reset is called while port enable is active, then
|
||||
* there is no reason to call make_ioc_operational
|
||||
@@ -7514,9 +7708,7 @@ mpt3sas_base_hard_reset_handler(struct MPT3SAS_ADAPTER *ioc,
|
||||
_base_reset_done_handler(ioc);
|
||||
|
||||
out:
|
||||
dtmprintk(ioc,
|
||||
ioc_info(ioc, "%s: %s\n",
|
||||
__func__, r == 0 ? "SUCCESS" : "FAILED"));
|
||||
ioc_info(ioc, "%s: %s\n", __func__, r == 0 ? "SUCCESS" : "FAILED");
|
||||
|
||||
spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags);
|
||||
ioc->shost_recovery = 0;
|
||||
|
||||
@@ -76,8 +76,8 @@
|
||||
#define MPT3SAS_DRIVER_NAME "mpt3sas"
|
||||
#define MPT3SAS_AUTHOR "Avago Technologies <MPT-FusionLinux.pdl@avagotech.com>"
|
||||
#define MPT3SAS_DESCRIPTION "LSI MPT Fusion SAS 3.0 Device Driver"
|
||||
#define MPT3SAS_DRIVER_VERSION "32.100.00.00"
|
||||
#define MPT3SAS_MAJOR_VERSION 32
|
||||
#define MPT3SAS_DRIVER_VERSION "33.100.00.00"
|
||||
#define MPT3SAS_MAJOR_VERSION 33
|
||||
#define MPT3SAS_MINOR_VERSION 100
|
||||
#define MPT3SAS_BUILD_VERSION 0
|
||||
#define MPT3SAS_RELEASE_VERSION 00
|
||||
@@ -90,6 +90,10 @@
|
||||
#define MPT2SAS_BUILD_VERSION 0
|
||||
#define MPT2SAS_RELEASE_VERSION 00
|
||||
|
||||
/* CoreDump: Default timeout */
|
||||
#define MPT3SAS_DEFAULT_COREDUMP_TIMEOUT_SECONDS (15) /*15 seconds*/
|
||||
#define MPT3SAS_COREDUMP_LOOP_DONE (0xFF)
|
||||
|
||||
/*
|
||||
* Set MPT3SAS_SG_DEPTH value based on user input.
|
||||
*/
|
||||
@@ -140,6 +144,7 @@
|
||||
#define MAX_CHAIN_ELEMT_SZ 16
|
||||
#define DEFAULT_NUM_FWCHAIN_ELEMTS 8
|
||||
|
||||
#define IO_UNIT_CONTROL_SHUTDOWN_TIMEOUT 6
|
||||
#define FW_IMG_HDR_READ_TIMEOUT 15
|
||||
|
||||
#define IOC_OPERATIONAL_WAIT_COUNT 10
|
||||
@@ -398,7 +403,10 @@ struct Mpi2ManufacturingPage11_t {
|
||||
u8 HostTraceBufferFlags; /* 4Fh */
|
||||
u16 HostTraceBufferMaxSizeKB; /* 50h */
|
||||
u16 HostTraceBufferMinSizeKB; /* 52h */
|
||||
__le32 Reserved10[2]; /* 54h - 5Bh */
|
||||
u8 CoreDumpTOSec; /* 54h */
|
||||
u8 Reserved8; /* 55h */
|
||||
u16 Reserved9; /* 56h */
|
||||
__le32 Reserved10; /* 58h */
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -589,6 +597,7 @@ static inline void sas_device_put(struct _sas_device *s)
|
||||
* @connector_name: ASCII value of the Connector's name
|
||||
* @serial_number: pointer of serial number string allocated runtime
|
||||
* @access_status: Device's Access Status
|
||||
* @shutdown_latency: NVMe device's RTD3 Entry Latency
|
||||
* @refcount: reference count for deletion
|
||||
*/
|
||||
struct _pcie_device {
|
||||
@@ -611,6 +620,7 @@ struct _pcie_device {
|
||||
u8 *serial_number;
|
||||
u8 reset_timeout;
|
||||
u8 access_status;
|
||||
u16 shutdown_latency;
|
||||
struct kref refcount;
|
||||
};
|
||||
/**
|
||||
@@ -1045,6 +1055,7 @@ typedef void (*MPT3SAS_FLUSH_RUNNING_CMDS)(struct MPT3SAS_ADAPTER *ioc);
|
||||
* @cpu_msix_table: table for mapping cpus to msix index
|
||||
* @cpu_msix_table_sz: table size
|
||||
* @total_io_cnt: Gives total IO count, used to load balance the interrupts
|
||||
* @ioc_coredump_loop: will have non-zero value when FW is in CoreDump state
|
||||
* @high_iops_outstanding: used to load balance the interrupts
|
||||
* within high iops reply queues
|
||||
* @msix_load_balance: Enables load balancing of interrupts across
|
||||
@@ -1073,6 +1084,10 @@ typedef void (*MPT3SAS_FLUSH_RUNNING_CMDS)(struct MPT3SAS_ADAPTER *ioc);
|
||||
* @event_context: unique id for each logged event
|
||||
* @event_log: event log pointer
|
||||
* @event_masks: events that are masked
|
||||
* @max_shutdown_latency: timeout value for NVMe shutdown operation,
|
||||
* which is equal that NVMe drive's RTD3 Entry Latency
|
||||
* which has reported maximum RTD3 Entry Latency value
|
||||
* among attached NVMe drives.
|
||||
* @facts: static facts data
|
||||
* @prev_fw_facts: previous fw facts data
|
||||
* @pfacts: static port facts data
|
||||
@@ -1231,6 +1246,7 @@ struct MPT3SAS_ADAPTER {
|
||||
u32 ioc_reset_count;
|
||||
MPT3SAS_FLUSH_RUNNING_CMDS schedule_dead_ioc_flush_running_cmds;
|
||||
u32 non_operational_loop;
|
||||
u8 ioc_coredump_loop;
|
||||
atomic64_t total_io_cnt;
|
||||
atomic64_t high_iops_outstanding;
|
||||
bool msix_load_balance;
|
||||
@@ -1283,7 +1299,7 @@ struct MPT3SAS_ADAPTER {
|
||||
|
||||
u8 tm_custom_handling;
|
||||
u8 nvme_abort_timeout;
|
||||
|
||||
u16 max_shutdown_latency;
|
||||
|
||||
/* static config pages */
|
||||
struct mpt3sas_facts facts;
|
||||
@@ -1531,6 +1547,17 @@ void *mpt3sas_base_get_reply_virt_addr(struct MPT3SAS_ADAPTER *ioc,
|
||||
u32 mpt3sas_base_get_iocstate(struct MPT3SAS_ADAPTER *ioc, int cooked);
|
||||
|
||||
void mpt3sas_base_fault_info(struct MPT3SAS_ADAPTER *ioc , u16 fault_code);
|
||||
#define mpt3sas_print_fault_code(ioc, fault_code) \
|
||||
do { pr_err("%s fault info from func: %s\n", ioc->name, __func__); \
|
||||
mpt3sas_base_fault_info(ioc, fault_code); } while (0)
|
||||
|
||||
void mpt3sas_base_coredump_info(struct MPT3SAS_ADAPTER *ioc, u16 fault_code);
|
||||
#define mpt3sas_print_coredump_info(ioc, fault_code) \
|
||||
do { pr_err("%s fault info from func: %s\n", ioc->name, __func__); \
|
||||
mpt3sas_base_coredump_info(ioc, fault_code); } while (0)
|
||||
|
||||
int mpt3sas_base_wait_for_coredump_completion(struct MPT3SAS_ADAPTER *ioc,
|
||||
const char *caller);
|
||||
int mpt3sas_base_sas_iounit_control(struct MPT3SAS_ADAPTER *ioc,
|
||||
Mpi2SasIoUnitControlReply_t *mpi_reply,
|
||||
Mpi2SasIoUnitControlRequest_t *mpi_request);
|
||||
@@ -1552,6 +1579,11 @@ mpt3sas_wait_for_commands_to_complete(struct MPT3SAS_ADAPTER *ioc);
|
||||
|
||||
u8 mpt3sas_base_check_cmd_timeout(struct MPT3SAS_ADAPTER *ioc,
|
||||
u8 status, void *mpi_request, int sz);
|
||||
#define mpt3sas_check_cmd_timeout(ioc, status, mpi_request, sz, issue_reset) \
|
||||
do { ioc_err(ioc, "In func: %s\n", __func__); \
|
||||
issue_reset = mpt3sas_base_check_cmd_timeout(ioc, \
|
||||
status, mpi_request, sz); } while (0)
|
||||
|
||||
int mpt3sas_wait_for_ioc(struct MPT3SAS_ADAPTER *ioc, int wait_count);
|
||||
|
||||
/* scsih shared API */
|
||||
@@ -1560,7 +1592,8 @@ struct scsi_cmnd *mpt3sas_scsih_scsi_lookup_get(struct MPT3SAS_ADAPTER *ioc,
|
||||
u8 mpt3sas_scsih_event_callback(struct MPT3SAS_ADAPTER *ioc, u8 msix_index,
|
||||
u32 reply);
|
||||
void mpt3sas_scsih_pre_reset_handler(struct MPT3SAS_ADAPTER *ioc);
|
||||
void mpt3sas_scsih_after_reset_handler(struct MPT3SAS_ADAPTER *ioc);
|
||||
void mpt3sas_scsih_clear_outstanding_scsi_tm_commands(
|
||||
struct MPT3SAS_ADAPTER *ioc);
|
||||
void mpt3sas_scsih_reset_done_handler(struct MPT3SAS_ADAPTER *ioc);
|
||||
|
||||
int mpt3sas_scsih_issue_tm(struct MPT3SAS_ADAPTER *ioc, u16 handle, u64 lun,
|
||||
@@ -1694,7 +1727,7 @@ void mpt3sas_ctl_exit(ushort hbas_to_enumerate);
|
||||
u8 mpt3sas_ctl_done(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index,
|
||||
u32 reply);
|
||||
void mpt3sas_ctl_pre_reset_handler(struct MPT3SAS_ADAPTER *ioc);
|
||||
void mpt3sas_ctl_after_reset_handler(struct MPT3SAS_ADAPTER *ioc);
|
||||
void mpt3sas_ctl_clear_outstanding_ioctls(struct MPT3SAS_ADAPTER *ioc);
|
||||
void mpt3sas_ctl_reset_done_handler(struct MPT3SAS_ADAPTER *ioc);
|
||||
u8 mpt3sas_ctl_event_callback(struct MPT3SAS_ADAPTER *ioc,
|
||||
u8 msix_index, u32 reply);
|
||||
|
||||
@@ -101,9 +101,6 @@ _config_display_some_debug(struct MPT3SAS_ADAPTER *ioc, u16 smid,
|
||||
Mpi2ConfigRequest_t *mpi_request;
|
||||
char *desc = NULL;
|
||||
|
||||
if (!(ioc->logging_level & MPT_DEBUG_CONFIG))
|
||||
return;
|
||||
|
||||
mpi_request = mpt3sas_base_get_msg_frame(ioc, smid);
|
||||
switch (mpi_request->Header.PageType & MPI2_CONFIG_PAGETYPE_MASK) {
|
||||
case MPI2_CONFIG_PAGETYPE_IO_UNIT:
|
||||
@@ -269,7 +266,8 @@ mpt3sas_config_done(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index,
|
||||
mpi_reply->MsgLength*4);
|
||||
}
|
||||
ioc->config_cmds.status &= ~MPT3_CMD_PENDING;
|
||||
_config_display_some_debug(ioc, smid, "config_done", mpi_reply);
|
||||
if (ioc->logging_level & MPT_DEBUG_CONFIG)
|
||||
_config_display_some_debug(ioc, smid, "config_done", mpi_reply);
|
||||
ioc->config_cmds.smid = USHRT_MAX;
|
||||
complete(&ioc->config_cmds.done);
|
||||
return 1;
|
||||
@@ -305,6 +303,7 @@ _config_request(struct MPT3SAS_ADAPTER *ioc, Mpi2ConfigRequest_t
|
||||
u8 retry_count, issue_host_reset = 0;
|
||||
struct config_request mem;
|
||||
u32 ioc_status = UINT_MAX;
|
||||
u8 issue_reset = 0;
|
||||
|
||||
mutex_lock(&ioc->config_cmds.mutex);
|
||||
if (ioc->config_cmds.status != MPT3_CMD_NOT_USED) {
|
||||
@@ -378,14 +377,18 @@ _config_request(struct MPT3SAS_ADAPTER *ioc, Mpi2ConfigRequest_t
|
||||
config_request = mpt3sas_base_get_msg_frame(ioc, smid);
|
||||
ioc->config_cmds.smid = smid;
|
||||
memcpy(config_request, mpi_request, sizeof(Mpi2ConfigRequest_t));
|
||||
_config_display_some_debug(ioc, smid, "config_request", NULL);
|
||||
if (ioc->logging_level & MPT_DEBUG_CONFIG)
|
||||
_config_display_some_debug(ioc, smid, "config_request", NULL);
|
||||
init_completion(&ioc->config_cmds.done);
|
||||
ioc->put_smid_default(ioc, smid);
|
||||
wait_for_completion_timeout(&ioc->config_cmds.done, timeout*HZ);
|
||||
if (!(ioc->config_cmds.status & MPT3_CMD_COMPLETE)) {
|
||||
mpt3sas_base_check_cmd_timeout(ioc,
|
||||
ioc->config_cmds.status, mpi_request,
|
||||
sizeof(Mpi2ConfigRequest_t)/4);
|
||||
if (!(ioc->logging_level & MPT_DEBUG_CONFIG))
|
||||
_config_display_some_debug(ioc,
|
||||
smid, "config_request", NULL);
|
||||
mpt3sas_check_cmd_timeout(ioc,
|
||||
ioc->config_cmds.status, mpi_request,
|
||||
sizeof(Mpi2ConfigRequest_t)/4, issue_reset);
|
||||
retry_count++;
|
||||
if (ioc->config_cmds.smid == smid)
|
||||
mpt3sas_base_free_smid(ioc, smid);
|
||||
@@ -404,8 +407,11 @@ _config_request(struct MPT3SAS_ADAPTER *ioc, Mpi2ConfigRequest_t
|
||||
/* Reply Frame Sanity Checks to workaround FW issues */
|
||||
if ((mpi_request->Header.PageType & 0xF) !=
|
||||
(mpi_reply->Header.PageType & 0xF)) {
|
||||
if (!(ioc->logging_level & MPT_DEBUG_CONFIG))
|
||||
_config_display_some_debug(ioc,
|
||||
smid, "config_request", NULL);
|
||||
_debug_dump_mf(mpi_request, ioc->request_sz/4);
|
||||
_debug_dump_reply(mpi_reply, ioc->request_sz/4);
|
||||
_debug_dump_reply(mpi_reply, ioc->reply_sz/4);
|
||||
panic("%s: %s: Firmware BUG: mpi_reply mismatch: Requested PageType(0x%02x) Reply PageType(0x%02x)\n",
|
||||
ioc->name, __func__,
|
||||
mpi_request->Header.PageType & 0xF,
|
||||
@@ -415,8 +421,11 @@ _config_request(struct MPT3SAS_ADAPTER *ioc, Mpi2ConfigRequest_t
|
||||
if (((mpi_request->Header.PageType & 0xF) ==
|
||||
MPI2_CONFIG_PAGETYPE_EXTENDED) &&
|
||||
mpi_request->ExtPageType != mpi_reply->ExtPageType) {
|
||||
if (!(ioc->logging_level & MPT_DEBUG_CONFIG))
|
||||
_config_display_some_debug(ioc,
|
||||
smid, "config_request", NULL);
|
||||
_debug_dump_mf(mpi_request, ioc->request_sz/4);
|
||||
_debug_dump_reply(mpi_reply, ioc->request_sz/4);
|
||||
_debug_dump_reply(mpi_reply, ioc->reply_sz/4);
|
||||
panic("%s: %s: Firmware BUG: mpi_reply mismatch: Requested ExtPageType(0x%02x) Reply ExtPageType(0x%02x)\n",
|
||||
ioc->name, __func__,
|
||||
mpi_request->ExtPageType,
|
||||
@@ -439,8 +448,11 @@ _config_request(struct MPT3SAS_ADAPTER *ioc, Mpi2ConfigRequest_t
|
||||
if (p) {
|
||||
if ((mpi_request->Header.PageType & 0xF) !=
|
||||
(p[3] & 0xF)) {
|
||||
if (!(ioc->logging_level & MPT_DEBUG_CONFIG))
|
||||
_config_display_some_debug(ioc,
|
||||
smid, "config_request", NULL);
|
||||
_debug_dump_mf(mpi_request, ioc->request_sz/4);
|
||||
_debug_dump_reply(mpi_reply, ioc->request_sz/4);
|
||||
_debug_dump_reply(mpi_reply, ioc->reply_sz/4);
|
||||
_debug_dump_config(p, min_t(u16, mem.sz,
|
||||
config_page_sz)/4);
|
||||
panic("%s: %s: Firmware BUG: config page mismatch: Requested PageType(0x%02x) Reply PageType(0x%02x)\n",
|
||||
@@ -452,8 +464,11 @@ _config_request(struct MPT3SAS_ADAPTER *ioc, Mpi2ConfigRequest_t
|
||||
if (((mpi_request->Header.PageType & 0xF) ==
|
||||
MPI2_CONFIG_PAGETYPE_EXTENDED) &&
|
||||
(mpi_request->ExtPageType != p[6])) {
|
||||
if (!(ioc->logging_level & MPT_DEBUG_CONFIG))
|
||||
_config_display_some_debug(ioc,
|
||||
smid, "config_request", NULL);
|
||||
_debug_dump_mf(mpi_request, ioc->request_sz/4);
|
||||
_debug_dump_reply(mpi_reply, ioc->request_sz/4);
|
||||
_debug_dump_reply(mpi_reply, ioc->reply_sz/4);
|
||||
_debug_dump_config(p, min_t(u16, mem.sz,
|
||||
config_page_sz)/4);
|
||||
panic("%s: %s: Firmware BUG: config page mismatch: Requested ExtPageType(0x%02x) Reply ExtPageType(0x%02x)\n",
|
||||
|
||||
@@ -180,6 +180,12 @@ _ctl_display_some_debug(struct MPT3SAS_ADAPTER *ioc, u16 smid,
|
||||
case MPI2_FUNCTION_SMP_PASSTHROUGH:
|
||||
desc = "smp_passthrough";
|
||||
break;
|
||||
case MPI2_FUNCTION_TOOLBOX:
|
||||
desc = "toolbox";
|
||||
break;
|
||||
case MPI2_FUNCTION_NVME_ENCAPSULATED:
|
||||
desc = "nvme_encapsulated";
|
||||
break;
|
||||
}
|
||||
|
||||
if (!desc)
|
||||
@@ -478,14 +484,15 @@ void mpt3sas_ctl_pre_reset_handler(struct MPT3SAS_ADAPTER *ioc)
|
||||
}
|
||||
|
||||
/**
|
||||
* mpt3sas_ctl_reset_handler - reset callback handler (for ctl)
|
||||
* mpt3sas_ctl_reset_handler - clears outstanding ioctl cmd.
|
||||
* @ioc: per adapter object
|
||||
*
|
||||
* The handler for doing any required cleanup or initialization.
|
||||
*/
|
||||
void mpt3sas_ctl_after_reset_handler(struct MPT3SAS_ADAPTER *ioc)
|
||||
void mpt3sas_ctl_clear_outstanding_ioctls(struct MPT3SAS_ADAPTER *ioc)
|
||||
{
|
||||
dtmprintk(ioc, ioc_info(ioc, "%s: MPT3_IOC_AFTER_RESET\n", __func__));
|
||||
dtmprintk(ioc,
|
||||
ioc_info(ioc, "%s: clear outstanding ioctl cmd\n", __func__));
|
||||
if (ioc->ctl_cmds.status & MPT3_CMD_PENDING) {
|
||||
ioc->ctl_cmds.status |= MPT3_CMD_RESET;
|
||||
mpt3sas_base_free_smid(ioc, ioc->ctl_cmds.smid);
|
||||
@@ -1021,10 +1028,9 @@ _ctl_do_mpt_command(struct MPT3SAS_ADAPTER *ioc, struct mpt3_ioctl_command karg,
|
||||
ioc->ignore_loginfos = 0;
|
||||
}
|
||||
if (!(ioc->ctl_cmds.status & MPT3_CMD_COMPLETE)) {
|
||||
issue_reset =
|
||||
mpt3sas_base_check_cmd_timeout(ioc,
|
||||
ioc->ctl_cmds.status, mpi_request,
|
||||
karg.data_sge_offset);
|
||||
mpt3sas_check_cmd_timeout(ioc,
|
||||
ioc->ctl_cmds.status, mpi_request,
|
||||
karg.data_sge_offset, issue_reset);
|
||||
goto issue_host_reset;
|
||||
}
|
||||
|
||||
@@ -1325,7 +1331,8 @@ _ctl_do_reset(struct MPT3SAS_ADAPTER *ioc, void __user *arg)
|
||||
__func__));
|
||||
|
||||
retval = mpt3sas_base_hard_reset_handler(ioc, FORCE_BIG_HAMMER);
|
||||
ioc_info(ioc, "host reset: %s\n", ((!retval) ? "SUCCESS" : "FAILED"));
|
||||
ioc_info(ioc,
|
||||
"Ioctl: host reset: %s\n", ((!retval) ? "SUCCESS" : "FAILED"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1733,10 +1740,9 @@ _ctl_diag_register_2(struct MPT3SAS_ADAPTER *ioc,
|
||||
MPT3_IOCTL_DEFAULT_TIMEOUT*HZ);
|
||||
|
||||
if (!(ioc->ctl_cmds.status & MPT3_CMD_COMPLETE)) {
|
||||
issue_reset =
|
||||
mpt3sas_base_check_cmd_timeout(ioc,
|
||||
ioc->ctl_cmds.status, mpi_request,
|
||||
sizeof(Mpi2DiagBufferPostRequest_t)/4);
|
||||
mpt3sas_check_cmd_timeout(ioc,
|
||||
ioc->ctl_cmds.status, mpi_request,
|
||||
sizeof(Mpi2DiagBufferPostRequest_t)/4, issue_reset);
|
||||
goto issue_host_reset;
|
||||
}
|
||||
|
||||
@@ -2108,6 +2114,7 @@ mpt3sas_send_diag_release(struct MPT3SAS_ADAPTER *ioc, u8 buffer_type,
|
||||
u16 ioc_status;
|
||||
u32 ioc_state;
|
||||
int rc;
|
||||
u8 reset_needed = 0;
|
||||
|
||||
dctlprintk(ioc, ioc_info(ioc, "%s\n",
|
||||
__func__));
|
||||
@@ -2115,6 +2122,7 @@ mpt3sas_send_diag_release(struct MPT3SAS_ADAPTER *ioc, u8 buffer_type,
|
||||
rc = 0;
|
||||
*issue_reset = 0;
|
||||
|
||||
|
||||
ioc_state = mpt3sas_base_get_iocstate(ioc, 1);
|
||||
if (ioc_state != MPI2_IOC_STATE_OPERATIONAL) {
|
||||
if (ioc->diag_buffer_status[buffer_type] &
|
||||
@@ -2157,9 +2165,10 @@ mpt3sas_send_diag_release(struct MPT3SAS_ADAPTER *ioc, u8 buffer_type,
|
||||
MPT3_IOCTL_DEFAULT_TIMEOUT*HZ);
|
||||
|
||||
if (!(ioc->ctl_cmds.status & MPT3_CMD_COMPLETE)) {
|
||||
*issue_reset = mpt3sas_base_check_cmd_timeout(ioc,
|
||||
ioc->ctl_cmds.status, mpi_request,
|
||||
sizeof(Mpi2DiagReleaseRequest_t)/4);
|
||||
mpt3sas_check_cmd_timeout(ioc,
|
||||
ioc->ctl_cmds.status, mpi_request,
|
||||
sizeof(Mpi2DiagReleaseRequest_t)/4, reset_needed);
|
||||
*issue_reset = reset_needed;
|
||||
rc = -EFAULT;
|
||||
goto out;
|
||||
}
|
||||
@@ -2417,10 +2426,9 @@ _ctl_diag_read_buffer(struct MPT3SAS_ADAPTER *ioc, void __user *arg)
|
||||
MPT3_IOCTL_DEFAULT_TIMEOUT*HZ);
|
||||
|
||||
if (!(ioc->ctl_cmds.status & MPT3_CMD_COMPLETE)) {
|
||||
issue_reset =
|
||||
mpt3sas_base_check_cmd_timeout(ioc,
|
||||
ioc->ctl_cmds.status, mpi_request,
|
||||
sizeof(Mpi2DiagBufferPostRequest_t)/4);
|
||||
mpt3sas_check_cmd_timeout(ioc,
|
||||
ioc->ctl_cmds.status, mpi_request,
|
||||
sizeof(Mpi2DiagBufferPostRequest_t)/4, issue_reset);
|
||||
goto issue_host_reset;
|
||||
}
|
||||
|
||||
|
||||
@@ -1049,6 +1049,34 @@ mpt3sas_get_pdev_by_handle(struct MPT3SAS_ADAPTER *ioc, u16 handle)
|
||||
return pcie_device;
|
||||
}
|
||||
|
||||
/**
|
||||
* _scsih_set_nvme_max_shutdown_latency - Update max_shutdown_latency.
|
||||
* @ioc: per adapter object
|
||||
* Context: This function will acquire ioc->pcie_device_lock
|
||||
*
|
||||
* Update ioc->max_shutdown_latency to that NVMe drives RTD3 Entry Latency
|
||||
* which has reported maximum among all available NVMe drives.
|
||||
* Minimum max_shutdown_latency will be six seconds.
|
||||
*/
|
||||
static void
|
||||
_scsih_set_nvme_max_shutdown_latency(struct MPT3SAS_ADAPTER *ioc)
|
||||
{
|
||||
struct _pcie_device *pcie_device;
|
||||
unsigned long flags;
|
||||
u16 shutdown_latency = IO_UNIT_CONTROL_SHUTDOWN_TIMEOUT;
|
||||
|
||||
spin_lock_irqsave(&ioc->pcie_device_lock, flags);
|
||||
list_for_each_entry(pcie_device, &ioc->pcie_device_list, list) {
|
||||
if (pcie_device->shutdown_latency) {
|
||||
if (shutdown_latency < pcie_device->shutdown_latency)
|
||||
shutdown_latency =
|
||||
pcie_device->shutdown_latency;
|
||||
}
|
||||
}
|
||||
ioc->max_shutdown_latency = shutdown_latency;
|
||||
spin_unlock_irqrestore(&ioc->pcie_device_lock, flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* _scsih_pcie_device_remove - remove pcie_device from list.
|
||||
* @ioc: per adapter object
|
||||
@@ -1063,6 +1091,7 @@ _scsih_pcie_device_remove(struct MPT3SAS_ADAPTER *ioc,
|
||||
{
|
||||
unsigned long flags;
|
||||
int was_on_pcie_device_list = 0;
|
||||
u8 update_latency = 0;
|
||||
|
||||
if (!pcie_device)
|
||||
return;
|
||||
@@ -1082,11 +1111,21 @@ _scsih_pcie_device_remove(struct MPT3SAS_ADAPTER *ioc,
|
||||
list_del_init(&pcie_device->list);
|
||||
was_on_pcie_device_list = 1;
|
||||
}
|
||||
if (pcie_device->shutdown_latency == ioc->max_shutdown_latency)
|
||||
update_latency = 1;
|
||||
spin_unlock_irqrestore(&ioc->pcie_device_lock, flags);
|
||||
if (was_on_pcie_device_list) {
|
||||
kfree(pcie_device->serial_number);
|
||||
pcie_device_put(pcie_device);
|
||||
}
|
||||
|
||||
/*
|
||||
* This device's RTD3 Entry Latency matches IOC's
|
||||
* max_shutdown_latency. Recalculate IOC's max_shutdown_latency
|
||||
* from the available drives as current drive is getting removed.
|
||||
*/
|
||||
if (update_latency)
|
||||
_scsih_set_nvme_max_shutdown_latency(ioc);
|
||||
}
|
||||
|
||||
|
||||
@@ -1101,6 +1140,7 @@ _scsih_pcie_device_remove_by_handle(struct MPT3SAS_ADAPTER *ioc, u16 handle)
|
||||
struct _pcie_device *pcie_device;
|
||||
unsigned long flags;
|
||||
int was_on_pcie_device_list = 0;
|
||||
u8 update_latency = 0;
|
||||
|
||||
if (ioc->shost_recovery)
|
||||
return;
|
||||
@@ -1113,12 +1153,22 @@ _scsih_pcie_device_remove_by_handle(struct MPT3SAS_ADAPTER *ioc, u16 handle)
|
||||
was_on_pcie_device_list = 1;
|
||||
pcie_device_put(pcie_device);
|
||||
}
|
||||
if (pcie_device->shutdown_latency == ioc->max_shutdown_latency)
|
||||
update_latency = 1;
|
||||
}
|
||||
spin_unlock_irqrestore(&ioc->pcie_device_lock, flags);
|
||||
if (was_on_pcie_device_list) {
|
||||
_scsih_pcie_device_remove_from_sml(ioc, pcie_device);
|
||||
pcie_device_put(pcie_device);
|
||||
}
|
||||
|
||||
/*
|
||||
* This device's RTD3 Entry Latency matches IOC's
|
||||
* max_shutdown_latency. Recalculate IOC's max_shutdown_latency
|
||||
* from the available drives as current drive is getting removed.
|
||||
*/
|
||||
if (update_latency)
|
||||
_scsih_set_nvme_max_shutdown_latency(ioc);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1554,7 +1604,12 @@ scsih_change_queue_depth(struct scsi_device *sdev, int qdepth)
|
||||
max_depth = 1;
|
||||
if (qdepth > max_depth)
|
||||
qdepth = max_depth;
|
||||
return scsi_change_queue_depth(sdev, qdepth);
|
||||
scsi_change_queue_depth(sdev, qdepth);
|
||||
sdev_printk(KERN_INFO, sdev,
|
||||
"qdepth(%d), tagged(%d), scsi_level(%d), cmd_que(%d)\n",
|
||||
sdev->queue_depth, sdev->tagged_supported,
|
||||
sdev->scsi_level, ((sdev->inquiry[7] & 2) >> 1));
|
||||
return sdev->queue_depth;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2673,6 +2728,7 @@ mpt3sas_scsih_issue_tm(struct MPT3SAS_ADAPTER *ioc, u16 handle, u64 lun,
|
||||
u16 smid = 0;
|
||||
u32 ioc_state;
|
||||
int rc;
|
||||
u8 issue_reset = 0;
|
||||
|
||||
lockdep_assert_held(&ioc->tm_cmds.mutex);
|
||||
|
||||
@@ -2695,7 +2751,13 @@ mpt3sas_scsih_issue_tm(struct MPT3SAS_ADAPTER *ioc, u16 handle, u64 lun,
|
||||
}
|
||||
|
||||
if ((ioc_state & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_FAULT) {
|
||||
mpt3sas_base_fault_info(ioc, ioc_state &
|
||||
mpt3sas_print_fault_code(ioc, ioc_state &
|
||||
MPI2_DOORBELL_DATA_MASK);
|
||||
rc = mpt3sas_base_hard_reset_handler(ioc, FORCE_BIG_HAMMER);
|
||||
return (!rc) ? SUCCESS : FAILED;
|
||||
} else if ((ioc_state & MPI2_IOC_STATE_MASK) ==
|
||||
MPI2_IOC_STATE_COREDUMP) {
|
||||
mpt3sas_print_coredump_info(ioc, ioc_state &
|
||||
MPI2_DOORBELL_DATA_MASK);
|
||||
rc = mpt3sas_base_hard_reset_handler(ioc, FORCE_BIG_HAMMER);
|
||||
return (!rc) ? SUCCESS : FAILED;
|
||||
@@ -2726,9 +2788,10 @@ mpt3sas_scsih_issue_tm(struct MPT3SAS_ADAPTER *ioc, u16 handle, u64 lun,
|
||||
ioc->put_smid_hi_priority(ioc, smid, msix_task);
|
||||
wait_for_completion_timeout(&ioc->tm_cmds.done, timeout*HZ);
|
||||
if (!(ioc->tm_cmds.status & MPT3_CMD_COMPLETE)) {
|
||||
if (mpt3sas_base_check_cmd_timeout(ioc,
|
||||
ioc->tm_cmds.status, mpi_request,
|
||||
sizeof(Mpi2SCSITaskManagementRequest_t)/4)) {
|
||||
mpt3sas_check_cmd_timeout(ioc,
|
||||
ioc->tm_cmds.status, mpi_request,
|
||||
sizeof(Mpi2SCSITaskManagementRequest_t)/4, issue_reset);
|
||||
if (issue_reset) {
|
||||
rc = mpt3sas_base_hard_reset_handler(ioc,
|
||||
FORCE_BIG_HAMMER);
|
||||
rc = (!rc) ? SUCCESS : FAILED;
|
||||
@@ -2875,15 +2938,17 @@ scsih_abort(struct scsi_cmnd *scmd)
|
||||
|
||||
u8 timeout = 30;
|
||||
struct _pcie_device *pcie_device = NULL;
|
||||
sdev_printk(KERN_INFO, scmd->device,
|
||||
"attempting task abort! scmd(%p)\n", scmd);
|
||||
sdev_printk(KERN_INFO, scmd->device, "attempting task abort!"
|
||||
"scmd(0x%p), outstanding for %u ms & timeout %u ms\n",
|
||||
scmd, jiffies_to_msecs(jiffies - scmd->jiffies_at_alloc),
|
||||
(scmd->request->timeout / HZ) * 1000);
|
||||
_scsih_tm_display_info(ioc, scmd);
|
||||
|
||||
sas_device_priv_data = scmd->device->hostdata;
|
||||
if (!sas_device_priv_data || !sas_device_priv_data->sas_target ||
|
||||
ioc->remove_host) {
|
||||
sdev_printk(KERN_INFO, scmd->device,
|
||||
"device been deleted! scmd(%p)\n", scmd);
|
||||
"device been deleted! scmd(0x%p)\n", scmd);
|
||||
scmd->result = DID_NO_CONNECT << 16;
|
||||
scmd->scsi_done(scmd);
|
||||
r = SUCCESS;
|
||||
@@ -2892,6 +2957,8 @@ scsih_abort(struct scsi_cmnd *scmd)
|
||||
|
||||
/* check for completed command */
|
||||
if (st == NULL || st->cb_idx == 0xFF) {
|
||||
sdev_printk(KERN_INFO, scmd->device, "No reference found at "
|
||||
"driver, assuming scmd(0x%p) might have completed\n", scmd);
|
||||
scmd->result = DID_RESET << 16;
|
||||
r = SUCCESS;
|
||||
goto out;
|
||||
@@ -2920,7 +2987,7 @@ scsih_abort(struct scsi_cmnd *scmd)
|
||||
if (r == SUCCESS && st->cb_idx != 0xFF)
|
||||
r = FAILED;
|
||||
out:
|
||||
sdev_printk(KERN_INFO, scmd->device, "task abort: %s scmd(%p)\n",
|
||||
sdev_printk(KERN_INFO, scmd->device, "task abort: %s scmd(0x%p)\n",
|
||||
((r == SUCCESS) ? "SUCCESS" : "FAILED"), scmd);
|
||||
if (pcie_device)
|
||||
pcie_device_put(pcie_device);
|
||||
@@ -2949,14 +3016,14 @@ scsih_dev_reset(struct scsi_cmnd *scmd)
|
||||
struct MPT3SAS_TARGET *target_priv_data = starget->hostdata;
|
||||
|
||||
sdev_printk(KERN_INFO, scmd->device,
|
||||
"attempting device reset! scmd(%p)\n", scmd);
|
||||
"attempting device reset! scmd(0x%p)\n", scmd);
|
||||
_scsih_tm_display_info(ioc, scmd);
|
||||
|
||||
sas_device_priv_data = scmd->device->hostdata;
|
||||
if (!sas_device_priv_data || !sas_device_priv_data->sas_target ||
|
||||
ioc->remove_host) {
|
||||
sdev_printk(KERN_INFO, scmd->device,
|
||||
"device been deleted! scmd(%p)\n", scmd);
|
||||
"device been deleted! scmd(0x%p)\n", scmd);
|
||||
scmd->result = DID_NO_CONNECT << 16;
|
||||
scmd->scsi_done(scmd);
|
||||
r = SUCCESS;
|
||||
@@ -2996,7 +3063,7 @@ scsih_dev_reset(struct scsi_cmnd *scmd)
|
||||
if (r == SUCCESS && atomic_read(&scmd->device->device_busy))
|
||||
r = FAILED;
|
||||
out:
|
||||
sdev_printk(KERN_INFO, scmd->device, "device reset: %s scmd(%p)\n",
|
||||
sdev_printk(KERN_INFO, scmd->device, "device reset: %s scmd(0x%p)\n",
|
||||
((r == SUCCESS) ? "SUCCESS" : "FAILED"), scmd);
|
||||
|
||||
if (sas_device)
|
||||
@@ -3027,15 +3094,15 @@ scsih_target_reset(struct scsi_cmnd *scmd)
|
||||
struct scsi_target *starget = scmd->device->sdev_target;
|
||||
struct MPT3SAS_TARGET *target_priv_data = starget->hostdata;
|
||||
|
||||
starget_printk(KERN_INFO, starget, "attempting target reset! scmd(%p)\n",
|
||||
scmd);
|
||||
starget_printk(KERN_INFO, starget,
|
||||
"attempting target reset! scmd(0x%p)\n", scmd);
|
||||
_scsih_tm_display_info(ioc, scmd);
|
||||
|
||||
sas_device_priv_data = scmd->device->hostdata;
|
||||
if (!sas_device_priv_data || !sas_device_priv_data->sas_target ||
|
||||
ioc->remove_host) {
|
||||
starget_printk(KERN_INFO, starget, "target been deleted! scmd(%p)\n",
|
||||
scmd);
|
||||
starget_printk(KERN_INFO, starget,
|
||||
"target been deleted! scmd(0x%p)\n", scmd);
|
||||
scmd->result = DID_NO_CONNECT << 16;
|
||||
scmd->scsi_done(scmd);
|
||||
r = SUCCESS;
|
||||
@@ -3074,7 +3141,7 @@ scsih_target_reset(struct scsi_cmnd *scmd)
|
||||
if (r == SUCCESS && atomic_read(&starget->target_busy))
|
||||
r = FAILED;
|
||||
out:
|
||||
starget_printk(KERN_INFO, starget, "target reset: %s scmd(%p)\n",
|
||||
starget_printk(KERN_INFO, starget, "target reset: %s scmd(0x%p)\n",
|
||||
((r == SUCCESS) ? "SUCCESS" : "FAILED"), scmd);
|
||||
|
||||
if (sas_device)
|
||||
@@ -3097,7 +3164,7 @@ scsih_host_reset(struct scsi_cmnd *scmd)
|
||||
struct MPT3SAS_ADAPTER *ioc = shost_priv(scmd->device->host);
|
||||
int r, retval;
|
||||
|
||||
ioc_info(ioc, "attempting host reset! scmd(%p)\n", scmd);
|
||||
ioc_info(ioc, "attempting host reset! scmd(0x%p)\n", scmd);
|
||||
scsi_print_command(scmd);
|
||||
|
||||
if (ioc->is_driver_loading || ioc->remove_host) {
|
||||
@@ -3109,7 +3176,7 @@ scsih_host_reset(struct scsi_cmnd *scmd)
|
||||
retval = mpt3sas_base_hard_reset_handler(ioc, FORCE_BIG_HAMMER);
|
||||
r = (retval < 0) ? FAILED : SUCCESS;
|
||||
out:
|
||||
ioc_info(ioc, "host reset: %s scmd(%p)\n",
|
||||
ioc_info(ioc, "host reset: %s scmd(0x%p)\n",
|
||||
r == SUCCESS ? "SUCCESS" : "FAILED", scmd);
|
||||
|
||||
return r;
|
||||
@@ -4475,6 +4542,7 @@ static void
|
||||
_scsih_temp_threshold_events(struct MPT3SAS_ADAPTER *ioc,
|
||||
Mpi2EventDataTemperature_t *event_data)
|
||||
{
|
||||
u32 doorbell;
|
||||
if (ioc->temp_sensors_count >= event_data->SensorNum) {
|
||||
ioc_err(ioc, "Temperature Threshold flags %s%s%s%s exceeded for Sensor: %d !!!\n",
|
||||
le16_to_cpu(event_data->Status) & 0x1 ? "0 " : " ",
|
||||
@@ -4484,6 +4552,18 @@ _scsih_temp_threshold_events(struct MPT3SAS_ADAPTER *ioc,
|
||||
event_data->SensorNum);
|
||||
ioc_err(ioc, "Current Temp In Celsius: %d\n",
|
||||
event_data->CurrentTemperature);
|
||||
if (ioc->hba_mpi_version_belonged != MPI2_VERSION) {
|
||||
doorbell = mpt3sas_base_get_iocstate(ioc, 0);
|
||||
if ((doorbell & MPI2_IOC_STATE_MASK) ==
|
||||
MPI2_IOC_STATE_FAULT) {
|
||||
mpt3sas_print_fault_code(ioc,
|
||||
doorbell & MPI2_DOORBELL_DATA_MASK);
|
||||
} else if ((doorbell & MPI2_IOC_STATE_MASK) ==
|
||||
MPI2_IOC_STATE_COREDUMP) {
|
||||
mpt3sas_print_coredump_info(ioc,
|
||||
doorbell & MPI2_DOORBELL_DATA_MASK);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6933,6 +7013,16 @@ _scsih_pcie_add_device(struct MPT3SAS_ADAPTER *ioc, u16 handle)
|
||||
le32_to_cpu(pcie_device_pg0.DeviceInfo)))) {
|
||||
pcie_device->nvme_mdts =
|
||||
le32_to_cpu(pcie_device_pg2.MaximumDataTransferSize);
|
||||
pcie_device->shutdown_latency =
|
||||
le16_to_cpu(pcie_device_pg2.ShutdownLatency);
|
||||
/*
|
||||
* Set IOC's max_shutdown_latency to drive's RTD3 Entry Latency
|
||||
* if drive's RTD3 Entry Latency is greater then IOC's
|
||||
* max_shutdown_latency.
|
||||
*/
|
||||
if (pcie_device->shutdown_latency > ioc->max_shutdown_latency)
|
||||
ioc->max_shutdown_latency =
|
||||
pcie_device->shutdown_latency;
|
||||
if (pcie_device_pg2.ControllerResetTO)
|
||||
pcie_device->reset_timeout =
|
||||
pcie_device_pg2.ControllerResetTO;
|
||||
@@ -7669,10 +7759,9 @@ _scsih_ir_fastpath(struct MPT3SAS_ADAPTER *ioc, u16 handle, u8 phys_disk_num)
|
||||
wait_for_completion_timeout(&ioc->scsih_cmds.done, 10*HZ);
|
||||
|
||||
if (!(ioc->scsih_cmds.status & MPT3_CMD_COMPLETE)) {
|
||||
issue_reset =
|
||||
mpt3sas_base_check_cmd_timeout(ioc,
|
||||
ioc->scsih_cmds.status, mpi_request,
|
||||
sizeof(Mpi2RaidActionRequest_t)/4);
|
||||
mpt3sas_check_cmd_timeout(ioc,
|
||||
ioc->scsih_cmds.status, mpi_request,
|
||||
sizeof(Mpi2RaidActionRequest_t)/4, issue_reset);
|
||||
rc = -EFAULT;
|
||||
goto out;
|
||||
}
|
||||
@@ -9272,15 +9361,17 @@ void mpt3sas_scsih_pre_reset_handler(struct MPT3SAS_ADAPTER *ioc)
|
||||
}
|
||||
|
||||
/**
|
||||
* mpt3sas_scsih_after_reset_handler - reset callback handler (for scsih)
|
||||
* mpt3sas_scsih_clear_outstanding_scsi_tm_commands - clears outstanding
|
||||
* scsi & tm cmds.
|
||||
* @ioc: per adapter object
|
||||
*
|
||||
* The handler for doing any required cleanup or initialization.
|
||||
*/
|
||||
void
|
||||
mpt3sas_scsih_after_reset_handler(struct MPT3SAS_ADAPTER *ioc)
|
||||
mpt3sas_scsih_clear_outstanding_scsi_tm_commands(struct MPT3SAS_ADAPTER *ioc)
|
||||
{
|
||||
dtmprintk(ioc, ioc_info(ioc, "%s: MPT3_IOC_AFTER_RESET\n", __func__));
|
||||
dtmprintk(ioc,
|
||||
ioc_info(ioc, "%s: clear outstanding scsi & tm cmds\n", __func__));
|
||||
if (ioc->scsih_cmds.status & MPT3_CMD_PENDING) {
|
||||
ioc->scsih_cmds.status |= MPT3_CMD_RESET;
|
||||
mpt3sas_base_free_smid(ioc, ioc->scsih_cmds.smid);
|
||||
@@ -9357,6 +9448,7 @@ _mpt3sas_fw_work(struct MPT3SAS_ADAPTER *ioc, struct fw_event_work *fw_event)
|
||||
}
|
||||
_scsih_remove_unresponding_devices(ioc);
|
||||
_scsih_scan_for_devices_after_reset(ioc);
|
||||
_scsih_set_nvme_max_shutdown_latency(ioc);
|
||||
break;
|
||||
case MPT3SAS_PORT_ENABLE_COMPLETE:
|
||||
ioc->start_scan = 0;
|
||||
@@ -9659,6 +9751,75 @@ _scsih_expander_node_remove(struct MPT3SAS_ADAPTER *ioc,
|
||||
kfree(sas_expander);
|
||||
}
|
||||
|
||||
/**
|
||||
* _scsih_nvme_shutdown - NVMe shutdown notification
|
||||
* @ioc: per adapter object
|
||||
*
|
||||
* Sending IoUnitControl request with shutdown operation code to alert IOC that
|
||||
* the host system is shutting down so that IOC can issue NVMe shutdown to
|
||||
* NVMe drives attached to it.
|
||||
*/
|
||||
static void
|
||||
_scsih_nvme_shutdown(struct MPT3SAS_ADAPTER *ioc)
|
||||
{
|
||||
Mpi26IoUnitControlRequest_t *mpi_request;
|
||||
Mpi26IoUnitControlReply_t *mpi_reply;
|
||||
u16 smid;
|
||||
|
||||
/* are there any NVMe devices ? */
|
||||
if (list_empty(&ioc->pcie_device_list))
|
||||
return;
|
||||
|
||||
mutex_lock(&ioc->scsih_cmds.mutex);
|
||||
|
||||
if (ioc->scsih_cmds.status != MPT3_CMD_NOT_USED) {
|
||||
ioc_err(ioc, "%s: scsih_cmd in use\n", __func__);
|
||||
goto out;
|
||||
}
|
||||
|
||||
ioc->scsih_cmds.status = MPT3_CMD_PENDING;
|
||||
|
||||
smid = mpt3sas_base_get_smid(ioc, ioc->scsih_cb_idx);
|
||||
if (!smid) {
|
||||
ioc_err(ioc,
|
||||
"%s: failed obtaining a smid\n", __func__);
|
||||
ioc->scsih_cmds.status = MPT3_CMD_NOT_USED;
|
||||
goto out;
|
||||
}
|
||||
|
||||
mpi_request = mpt3sas_base_get_msg_frame(ioc, smid);
|
||||
ioc->scsih_cmds.smid = smid;
|
||||
memset(mpi_request, 0, sizeof(Mpi26IoUnitControlRequest_t));
|
||||
mpi_request->Function = MPI2_FUNCTION_IO_UNIT_CONTROL;
|
||||
mpi_request->Operation = MPI26_CTRL_OP_SHUTDOWN;
|
||||
|
||||
init_completion(&ioc->scsih_cmds.done);
|
||||
ioc->put_smid_default(ioc, smid);
|
||||
/* Wait for max_shutdown_latency seconds */
|
||||
ioc_info(ioc,
|
||||
"Io Unit Control shutdown (sending), Shutdown latency %d sec\n",
|
||||
ioc->max_shutdown_latency);
|
||||
wait_for_completion_timeout(&ioc->scsih_cmds.done,
|
||||
ioc->max_shutdown_latency*HZ);
|
||||
|
||||
if (!(ioc->scsih_cmds.status & MPT3_CMD_COMPLETE)) {
|
||||
ioc_err(ioc, "%s: timeout\n", __func__);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (ioc->scsih_cmds.status & MPT3_CMD_REPLY_VALID) {
|
||||
mpi_reply = ioc->scsih_cmds.reply;
|
||||
ioc_info(ioc, "Io Unit Control shutdown (complete):"
|
||||
"ioc_status(0x%04x), loginfo(0x%08x)\n",
|
||||
le16_to_cpu(mpi_reply->IOCStatus),
|
||||
le32_to_cpu(mpi_reply->IOCLogInfo));
|
||||
}
|
||||
out:
|
||||
ioc->scsih_cmds.status = MPT3_CMD_NOT_USED;
|
||||
mutex_unlock(&ioc->scsih_cmds.mutex);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* _scsih_ir_shutdown - IR shutdown notification
|
||||
* @ioc: per adapter object
|
||||
@@ -9851,6 +10012,7 @@ scsih_shutdown(struct pci_dev *pdev)
|
||||
&ioc->ioc_pg1_copy);
|
||||
|
||||
_scsih_ir_shutdown(ioc);
|
||||
_scsih_nvme_shutdown(ioc);
|
||||
mpt3sas_base_detach(ioc);
|
||||
}
|
||||
|
||||
@@ -10533,6 +10695,8 @@ _scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
||||
ioc->tm_sas_control_cb_idx = tm_sas_control_cb_idx;
|
||||
ioc->logging_level = logging_level;
|
||||
ioc->schedule_dead_ioc_flush_running_cmds = &_scsih_flush_running_cmds;
|
||||
/* Host waits for minimum of six seconds */
|
||||
ioc->max_shutdown_latency = IO_UNIT_CONTROL_SHUTDOWN_TIMEOUT;
|
||||
/*
|
||||
* Enable MEMORY MOVE support flag.
|
||||
*/
|
||||
@@ -10681,6 +10845,7 @@ scsih_suspend(struct pci_dev *pdev, pm_message_t state)
|
||||
mpt3sas_base_stop_watchdog(ioc);
|
||||
flush_scheduled_work();
|
||||
scsi_block_requests(shost);
|
||||
_scsih_nvme_shutdown(ioc);
|
||||
device_state = pci_choose_state(pdev, state);
|
||||
ioc_info(ioc, "pdev=0x%p, slot=%s, entering operating state [D%d]\n",
|
||||
pdev, pci_name(pdev), device_state);
|
||||
@@ -10715,7 +10880,7 @@ scsih_resume(struct pci_dev *pdev)
|
||||
r = mpt3sas_base_map_resources(ioc);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
ioc_info(ioc, "Issuing Hard Reset as part of OS Resume\n");
|
||||
mpt3sas_base_hard_reset_handler(ioc, SOFT_RESET);
|
||||
scsi_unblock_requests(shost);
|
||||
mpt3sas_base_start_watchdog(ioc);
|
||||
@@ -10784,6 +10949,7 @@ scsih_pci_slot_reset(struct pci_dev *pdev)
|
||||
if (rc)
|
||||
return PCI_ERS_RESULT_DISCONNECT;
|
||||
|
||||
ioc_info(ioc, "Issuing Hard Reset as part of PCI Slot Reset\n");
|
||||
rc = mpt3sas_base_hard_reset_handler(ioc, FORCE_BIG_HAMMER);
|
||||
|
||||
ioc_warn(ioc, "hard reset: %s\n",
|
||||
|
||||
@@ -719,11 +719,10 @@ mpt3sas_transport_port_add(struct MPT3SAS_ADAPTER *ioc, u16 handle,
|
||||
sas_device_put(sas_device);
|
||||
}
|
||||
|
||||
if ((ioc->logging_level & MPT_DEBUG_TRANSPORT))
|
||||
dev_printk(KERN_INFO, &rphy->dev,
|
||||
"add: handle(0x%04x), sas_addr(0x%016llx)\n",
|
||||
handle, (unsigned long long)
|
||||
mpt3sas_port->remote_identify.sas_address);
|
||||
dev_info(&rphy->dev,
|
||||
"add: handle(0x%04x), sas_addr(0x%016llx)\n", handle,
|
||||
(unsigned long long)mpt3sas_port->remote_identify.sas_address);
|
||||
|
||||
mpt3sas_port->rphy = rphy;
|
||||
spin_lock_irqsave(&ioc->sas_node_lock, flags);
|
||||
list_add_tail(&mpt3sas_port->port_list, &sas_node->sas_port_list);
|
||||
@@ -813,6 +812,8 @@ mpt3sas_transport_port_remove(struct MPT3SAS_ADAPTER *ioc, u64 sas_address,
|
||||
}
|
||||
if (!ioc->remove_host)
|
||||
sas_port_delete(mpt3sas_port->port);
|
||||
ioc_info(ioc, "%s: removed: sas_addr(0x%016llx)\n",
|
||||
__func__, (unsigned long long)sas_address);
|
||||
kfree(mpt3sas_port);
|
||||
}
|
||||
|
||||
|
||||
@@ -47,6 +47,9 @@ static struct scsi_host_template mvs_sht = {
|
||||
.eh_target_reset_handler = sas_eh_target_reset_handler,
|
||||
.target_destroy = sas_target_destroy,
|
||||
.ioctl = sas_ioctl,
|
||||
#ifdef CONFIG_COMPAT
|
||||
.compat_ioctl = sas_ioctl,
|
||||
#endif
|
||||
.shost_attrs = mvst_host_attrs,
|
||||
.track_queue_depth = 1,
|
||||
};
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0
|
||||
*
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Linux Driver for Mylex DAC960/AcceleRAID/eXtremeRAID PCI RAID Controllers
|
||||
*
|
||||
* Copyright 2017 Hannes Reinecke, SUSE Linux GmbH <hare@suse.com>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0
|
||||
*
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Linux Driver for Mylex DAC960/AcceleRAID/eXtremeRAID PCI RAID Controllers
|
||||
*
|
||||
* This driver supports the newer, SCSI-based firmware interface only.
|
||||
|
||||
@@ -101,6 +101,9 @@ static struct scsi_host_template pm8001_sht = {
|
||||
.eh_target_reset_handler = sas_eh_target_reset_handler,
|
||||
.target_destroy = sas_target_destroy,
|
||||
.ioctl = sas_ioctl,
|
||||
#ifdef CONFIG_COMPAT
|
||||
.compat_ioctl = sas_ioctl,
|
||||
#endif
|
||||
.shost_attrs = pm8001_host_attrs,
|
||||
.track_queue_depth = 1,
|
||||
};
|
||||
|
||||
@@ -1699,6 +1699,16 @@ qla1280_load_firmware_pio(struct scsi_qla_host *ha)
|
||||
return err;
|
||||
}
|
||||
|
||||
#ifdef QLA_64BIT_PTR
|
||||
#define LOAD_CMD MBC_LOAD_RAM_A64_ROM
|
||||
#define DUMP_CMD MBC_DUMP_RAM_A64_ROM
|
||||
#define CMD_ARGS (BIT_7 | BIT_6 | BIT_4 | BIT_3 | BIT_2 | BIT_1 | BIT_0)
|
||||
#else
|
||||
#define LOAD_CMD MBC_LOAD_RAM
|
||||
#define DUMP_CMD MBC_DUMP_RAM
|
||||
#define CMD_ARGS (BIT_4 | BIT_3 | BIT_2 | BIT_1 | BIT_0)
|
||||
#endif
|
||||
|
||||
#define DUMP_IT_BACK 0 /* for debug of RISC loading */
|
||||
static int
|
||||
qla1280_load_firmware_dma(struct scsi_qla_host *ha)
|
||||
@@ -1748,7 +1758,7 @@ qla1280_load_firmware_dma(struct scsi_qla_host *ha)
|
||||
for(i = 0; i < cnt; i++)
|
||||
((__le16 *)ha->request_ring)[i] = fw_data[i];
|
||||
|
||||
mb[0] = MBC_LOAD_RAM;
|
||||
mb[0] = LOAD_CMD;
|
||||
mb[1] = risc_address;
|
||||
mb[4] = cnt;
|
||||
mb[3] = ha->request_dma & 0xffff;
|
||||
@@ -1759,8 +1769,7 @@ qla1280_load_firmware_dma(struct scsi_qla_host *ha)
|
||||
__func__, mb[0],
|
||||
(void *)(long)ha->request_dma,
|
||||
mb[6], mb[7], mb[2], mb[3]);
|
||||
err = qla1280_mailbox_command(ha, BIT_4 | BIT_3 | BIT_2 |
|
||||
BIT_1 | BIT_0, mb);
|
||||
err = qla1280_mailbox_command(ha, CMD_ARGS, mb);
|
||||
if (err) {
|
||||
printk(KERN_ERR "scsi(%li): Failed to load partial "
|
||||
"segment of f\n", ha->host_no);
|
||||
@@ -1768,7 +1777,7 @@ qla1280_load_firmware_dma(struct scsi_qla_host *ha)
|
||||
}
|
||||
|
||||
#if DUMP_IT_BACK
|
||||
mb[0] = MBC_DUMP_RAM;
|
||||
mb[0] = DUMP_CMD;
|
||||
mb[1] = risc_address;
|
||||
mb[4] = cnt;
|
||||
mb[3] = p_tbuf & 0xffff;
|
||||
@@ -1776,8 +1785,7 @@ qla1280_load_firmware_dma(struct scsi_qla_host *ha)
|
||||
mb[7] = upper_32_bits(p_tbuf) & 0xffff;
|
||||
mb[6] = upper_32_bits(p_tbuf) >> 16;
|
||||
|
||||
err = qla1280_mailbox_command(ha, BIT_4 | BIT_3 | BIT_2 |
|
||||
BIT_1 | BIT_0, mb);
|
||||
err = qla1280_mailbox_command(ha, CMD_ARGS, mb);
|
||||
if (err) {
|
||||
printk(KERN_ERR
|
||||
"Failed to dump partial segment of f/w\n");
|
||||
|
||||
@@ -277,6 +277,8 @@ struct device_reg {
|
||||
#define MBC_MAILBOX_REGISTER_TEST 6 /* Wrap incoming mailboxes */
|
||||
#define MBC_VERIFY_CHECKSUM 7 /* Verify checksum */
|
||||
#define MBC_ABOUT_FIRMWARE 8 /* Get firmware revision */
|
||||
#define MBC_LOAD_RAM_A64_ROM 9 /* Load RAM 64bit ROM version */
|
||||
#define MBC_DUMP_RAM_A64_ROM 0x0a /* Dump RAM 64bit ROM version */
|
||||
#define MBC_INIT_REQUEST_QUEUE 0x10 /* Initialize request queue */
|
||||
#define MBC_INIT_RESPONSE_QUEUE 0x11 /* Initialize response queue */
|
||||
#define MBC_EXECUTE_IOCB 0x12 /* Execute IOCB command */
|
||||
|
||||
@@ -54,7 +54,8 @@ void qla2x00_bsg_sp_free(srb_t *sp)
|
||||
if (sp->type == SRB_CT_CMD ||
|
||||
sp->type == SRB_FXIOCB_BCMD ||
|
||||
sp->type == SRB_ELS_CMD_HST)
|
||||
kfree(sp->fcport);
|
||||
qla2x00_free_fcport(sp->fcport);
|
||||
|
||||
qla2x00_rel_sp(sp);
|
||||
}
|
||||
|
||||
@@ -405,7 +406,7 @@ done_unmap_sg:
|
||||
|
||||
done_free_fcport:
|
||||
if (bsg_request->msgcode == FC_BSG_RPT_ELS)
|
||||
kfree(fcport);
|
||||
qla2x00_free_fcport(fcport);
|
||||
done:
|
||||
return rval;
|
||||
}
|
||||
@@ -545,7 +546,7 @@ qla2x00_process_ct(struct bsg_job *bsg_job)
|
||||
return rval;
|
||||
|
||||
done_free_fcport:
|
||||
kfree(fcport);
|
||||
qla2x00_free_fcport(fcport);
|
||||
done_unmap_sg:
|
||||
dma_unmap_sg(&ha->pdev->dev, bsg_job->request_payload.sg_list,
|
||||
bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE);
|
||||
@@ -796,7 +797,7 @@ qla2x00_process_loopback(struct bsg_job *bsg_job)
|
||||
|
||||
if (atomic_read(&vha->loop_state) == LOOP_READY &&
|
||||
(ha->current_topology == ISP_CFG_F ||
|
||||
(le32_to_cpu(*(uint32_t *)req_data) == ELS_OPCODE_BYTE &&
|
||||
(get_unaligned_le32(req_data) == ELS_OPCODE_BYTE &&
|
||||
req_data_len == MAX_ELS_FRAME_PAYLOAD)) &&
|
||||
elreq.options == EXTERNAL_LOOPBACK) {
|
||||
type = "FC_BSG_HST_VENDOR_ECHO_DIAG";
|
||||
@@ -2049,7 +2050,7 @@ qlafx00_mgmt_cmd(struct bsg_job *bsg_job)
|
||||
return rval;
|
||||
|
||||
done_free_fcport:
|
||||
kfree(fcport);
|
||||
qla2x00_free_fcport(fcport);
|
||||
|
||||
done_unmap_rsp_sg:
|
||||
if (piocb_rqst->flags & SRB_FXDISC_RESP_DMA_VALID)
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
* | Device Discovery | 0x2134 | 0x210e-0x2116 |
|
||||
* | | | 0x211a |
|
||||
* | | | 0x211c-0x2128 |
|
||||
* | | | 0x212a-0x2130 |
|
||||
* | | | 0x212a-0x2134 |
|
||||
* | Queue Command and IO tracing | 0x3074 | 0x300b |
|
||||
* | | | 0x3027-0x3028 |
|
||||
* | | | 0x303d-0x3041 |
|
||||
|
||||
@@ -2402,6 +2402,7 @@ typedef struct fc_port {
|
||||
unsigned int scan_needed:1;
|
||||
unsigned int n2n_flag:1;
|
||||
unsigned int explicit_logout:1;
|
||||
unsigned int prli_pend_timer:1;
|
||||
|
||||
struct completion nvme_del_done;
|
||||
uint32_t nvme_prli_service_param;
|
||||
@@ -2428,6 +2429,7 @@ typedef struct fc_port {
|
||||
struct work_struct free_work;
|
||||
struct work_struct reg_work;
|
||||
uint64_t jiffies_at_registration;
|
||||
unsigned long prli_expired;
|
||||
struct qlt_plogi_ack_t *plogi_link[QLT_PLOGI_LINK_MAX];
|
||||
|
||||
uint16_t tgt_id;
|
||||
@@ -2464,6 +2466,7 @@ typedef struct fc_port {
|
||||
struct qla_tgt_sess *tgt_session;
|
||||
struct ct_sns_desc ct_desc;
|
||||
enum discovery_state disc_state;
|
||||
atomic_t shadow_disc_state;
|
||||
enum discovery_state next_disc_state;
|
||||
enum login_state fw_login_state;
|
||||
unsigned long dm_login_expire;
|
||||
@@ -2510,6 +2513,19 @@ struct event_arg {
|
||||
|
||||
extern const char *const port_state_str[5];
|
||||
|
||||
static const char * const port_dstate_str[] = {
|
||||
"DELETED",
|
||||
"GNN_ID",
|
||||
"GNL",
|
||||
"LOGIN_PEND",
|
||||
"LOGIN_FAILED",
|
||||
"GPDB",
|
||||
"UPD_FCPORT",
|
||||
"LOGIN_COMPLETE",
|
||||
"ADISC",
|
||||
"DELETE_PEND"
|
||||
};
|
||||
|
||||
/*
|
||||
* FC port flags.
|
||||
*/
|
||||
@@ -3263,7 +3279,6 @@ enum qla_work_type {
|
||||
QLA_EVT_IDC_ACK,
|
||||
QLA_EVT_ASYNC_LOGIN,
|
||||
QLA_EVT_ASYNC_LOGOUT,
|
||||
QLA_EVT_ASYNC_LOGOUT_DONE,
|
||||
QLA_EVT_ASYNC_ADISC,
|
||||
QLA_EVT_UEVENT,
|
||||
QLA_EVT_AENFX,
|
||||
@@ -3953,7 +3968,7 @@ struct qla_hw_data {
|
||||
void *sfp_data;
|
||||
dma_addr_t sfp_data_dma;
|
||||
|
||||
void *flt;
|
||||
struct qla_flt_header *flt;
|
||||
dma_addr_t flt_dma;
|
||||
|
||||
#define XGMAC_DATA_SIZE 4096
|
||||
@@ -4845,6 +4860,9 @@ struct sff_8247_a0 {
|
||||
(ha->fc4_type_priority == FC4_PRIORITY_NVME)) || \
|
||||
NVME_ONLY_TARGET(fcport)) \
|
||||
|
||||
#define PRLI_PHASE(_cls) \
|
||||
((_cls == DSC_LS_PRLI_PEND) || (_cls == DSC_LS_PRLI_COMP))
|
||||
|
||||
#include "qla_target.h"
|
||||
#include "qla_gbl.h"
|
||||
#include "qla_dbg.h"
|
||||
|
||||
@@ -1354,12 +1354,12 @@ struct vp_rpt_id_entry_24xx {
|
||||
uint8_t port_id[3];
|
||||
uint8_t format;
|
||||
union {
|
||||
struct {
|
||||
struct _f0 {
|
||||
/* format 0 loop */
|
||||
uint8_t vp_idx_map[16];
|
||||
uint8_t reserved_4[32];
|
||||
} f0;
|
||||
struct {
|
||||
struct _f1 {
|
||||
/* format 1 fabric */
|
||||
uint8_t vpstat1_subcode; /* vp_status=1 subcode */
|
||||
uint8_t flags;
|
||||
@@ -1381,21 +1381,22 @@ struct vp_rpt_id_entry_24xx {
|
||||
uint16_t bbcr;
|
||||
uint8_t reserved_5[6];
|
||||
} f1;
|
||||
struct { /* format 2: N2N direct connect */
|
||||
uint8_t vpstat1_subcode;
|
||||
uint8_t flags;
|
||||
uint16_t rsv6;
|
||||
uint8_t rsv2[12];
|
||||
struct _f2 { /* format 2: N2N direct connect */
|
||||
uint8_t vpstat1_subcode;
|
||||
uint8_t flags;
|
||||
uint16_t fip_flags;
|
||||
uint8_t rsv2[12];
|
||||
|
||||
uint8_t ls_rjt_vendor;
|
||||
uint8_t ls_rjt_explanation;
|
||||
uint8_t ls_rjt_reason;
|
||||
uint8_t rsv3[5];
|
||||
uint8_t ls_rjt_vendor;
|
||||
uint8_t ls_rjt_explanation;
|
||||
uint8_t ls_rjt_reason;
|
||||
uint8_t rsv3[5];
|
||||
|
||||
uint8_t port_name[8];
|
||||
uint8_t node_name[8];
|
||||
uint8_t remote_nport_id[4];
|
||||
uint32_t reserved_5;
|
||||
uint8_t port_name[8];
|
||||
uint8_t node_name[8];
|
||||
uint16_t bbcr;
|
||||
uint8_t reserved_5[2];
|
||||
uint8_t remote_nport_id[4];
|
||||
} f2;
|
||||
} u;
|
||||
};
|
||||
@@ -1470,13 +1471,6 @@ struct qla_flt_location {
|
||||
uint16_t checksum;
|
||||
};
|
||||
|
||||
struct qla_flt_header {
|
||||
uint16_t version;
|
||||
uint16_t length;
|
||||
uint16_t checksum;
|
||||
uint16_t unused;
|
||||
};
|
||||
|
||||
#define FLT_REG_FW 0x01
|
||||
#define FLT_REG_BOOT_CODE 0x07
|
||||
#define FLT_REG_VPD_0 0x14
|
||||
@@ -1537,6 +1531,14 @@ struct qla_flt_region {
|
||||
uint32_t end;
|
||||
};
|
||||
|
||||
struct qla_flt_header {
|
||||
uint16_t version;
|
||||
uint16_t length;
|
||||
uint16_t checksum;
|
||||
uint16_t unused;
|
||||
struct qla_flt_region region[0];
|
||||
};
|
||||
|
||||
#define FLT_REGION_SIZE 16
|
||||
#define FLT_MAX_REGIONS 0xFF
|
||||
#define FLT_REGIONS_SIZE (FLT_REGION_SIZE * FLT_MAX_REGIONS)
|
||||
|
||||
@@ -72,14 +72,13 @@ extern int qla2x00_async_adisc(struct scsi_qla_host *, fc_port_t *,
|
||||
extern int qla2x00_async_tm_cmd(fc_port_t *, uint32_t, uint32_t, uint32_t);
|
||||
extern void qla2x00_async_login_done(struct scsi_qla_host *, fc_port_t *,
|
||||
uint16_t *);
|
||||
extern void qla2x00_async_logout_done(struct scsi_qla_host *, fc_port_t *,
|
||||
uint16_t *);
|
||||
struct qla_work_evt *qla2x00_alloc_work(struct scsi_qla_host *,
|
||||
enum qla_work_type);
|
||||
extern int qla24xx_async_gnl(struct scsi_qla_host *, fc_port_t *);
|
||||
int qla2x00_post_work(struct scsi_qla_host *vha, struct qla_work_evt *e);
|
||||
extern void *qla2x00_alloc_iocbs_ready(struct qla_qpair *, srb_t *);
|
||||
extern int qla24xx_update_fcport_fcp_prio(scsi_qla_host_t *, fc_port_t *);
|
||||
extern int qla24xx_async_abort_cmd(srb_t *, bool);
|
||||
|
||||
extern void qla2x00_set_fcport_state(fc_port_t *fcport, int state);
|
||||
extern fc_port_t *
|
||||
@@ -182,8 +181,6 @@ extern int qla2x00_post_async_login_work(struct scsi_qla_host *, fc_port_t *,
|
||||
uint16_t *);
|
||||
extern int qla2x00_post_async_logout_work(struct scsi_qla_host *, fc_port_t *,
|
||||
uint16_t *);
|
||||
extern int qla2x00_post_async_logout_done_work(struct scsi_qla_host *,
|
||||
fc_port_t *, uint16_t *);
|
||||
extern int qla2x00_post_async_adisc_work(struct scsi_qla_host *, fc_port_t *,
|
||||
uint16_t *);
|
||||
extern int qla2x00_post_async_adisc_done_work(struct scsi_qla_host *,
|
||||
@@ -201,6 +198,7 @@ extern void qla2x00_free_host(struct scsi_qla_host *);
|
||||
extern void qla2x00_relogin(struct scsi_qla_host *);
|
||||
extern void qla2x00_do_work(struct scsi_qla_host *);
|
||||
extern void qla2x00_free_fcports(struct scsi_qla_host *);
|
||||
extern void qla2x00_free_fcport(fc_port_t *);
|
||||
|
||||
extern void qla83xx_schedule_work(scsi_qla_host_t *, int);
|
||||
extern void qla83xx_service_idc_aen(struct work_struct *);
|
||||
@@ -253,8 +251,9 @@ extern scsi_qla_host_t *qla24xx_create_vhost(struct fc_vport *);
|
||||
extern void qla2x00_sp_free_dma(srb_t *sp);
|
||||
extern char *qla2x00_get_fw_version_str(struct scsi_qla_host *, char *);
|
||||
|
||||
extern void qla2x00_mark_device_lost(scsi_qla_host_t *, fc_port_t *, int, int);
|
||||
extern void qla2x00_mark_all_devices_lost(scsi_qla_host_t *, int);
|
||||
extern void qla2x00_mark_device_lost(scsi_qla_host_t *, fc_port_t *, int);
|
||||
extern void qla2x00_mark_all_devices_lost(scsi_qla_host_t *);
|
||||
extern int qla24xx_async_abort_cmd(srb_t *, bool);
|
||||
|
||||
extern struct fw_blob *qla2x00_request_firmware(scsi_qla_host_t *);
|
||||
|
||||
|
||||
@@ -2963,7 +2963,6 @@ int qla24xx_post_gpsc_work(struct scsi_qla_host *vha, fc_port_t *fcport)
|
||||
return QLA_FUNCTION_FAILED;
|
||||
|
||||
e->u.fcport.fcport = fcport;
|
||||
fcport->flags |= FCF_ASYNC_ACTIVE;
|
||||
return qla2x00_post_work(vha, e);
|
||||
}
|
||||
|
||||
@@ -3097,9 +3096,7 @@ int qla24xx_async_gpsc(scsi_qla_host_t *vha, fc_port_t *fcport)
|
||||
|
||||
done_free_sp:
|
||||
sp->free(sp);
|
||||
fcport->flags &= ~FCF_ASYNC_SENT;
|
||||
done:
|
||||
fcport->flags &= ~FCF_ASYNC_ACTIVE;
|
||||
return rval;
|
||||
}
|
||||
|
||||
@@ -4290,7 +4287,7 @@ int qla24xx_async_gnnid(scsi_qla_host_t *vha, fc_port_t *fcport)
|
||||
if (!vha->flags.online || (fcport->flags & FCF_ASYNC_SENT))
|
||||
return rval;
|
||||
|
||||
fcport->disc_state = DSC_GNN_ID;
|
||||
qla2x00_set_fcport_disc_state(fcport, DSC_GNN_ID);
|
||||
sp = qla2x00_get_sp(vha, fcport, GFP_ATOMIC);
|
||||
if (!sp)
|
||||
goto done;
|
||||
@@ -4464,7 +4461,6 @@ int qla24xx_async_gfpnid(scsi_qla_host_t *vha, fc_port_t *fcport)
|
||||
|
||||
done_free_sp:
|
||||
sp->free(sp);
|
||||
fcport->flags &= ~FCF_ASYNC_SENT;
|
||||
done:
|
||||
return rval;
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user