mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-06 02:50:49 +09:00
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
|
gcc-plugins
|
||||||
symbol-namespaces
|
symbol-namespaces
|
||||||
padata
|
padata
|
||||||
|
ioctl
|
||||||
|
|
||||||
|
|
||||||
Interfaces for kernel debugging
|
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
|
#ifndef __ASM_COMPAT_H
|
||||||
#define __ASM_COMPAT_H
|
#define __ASM_COMPAT_H
|
||||||
|
|
||||||
|
#include <asm-generic/compat.h>
|
||||||
|
|
||||||
#ifdef CONFIG_COMPAT
|
#ifdef CONFIG_COMPAT
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -13,8 +16,6 @@
|
|||||||
#include <linux/sched.h>
|
#include <linux/sched.h>
|
||||||
#include <linux/sched/task_stack.h>
|
#include <linux/sched/task_stack.h>
|
||||||
|
|
||||||
#include <asm-generic/compat.h>
|
|
||||||
|
|
||||||
#define COMPAT_USER_HZ 100
|
#define COMPAT_USER_HZ 100
|
||||||
#ifdef __AARCH64EB__
|
#ifdef __AARCH64EB__
|
||||||
#define COMPAT_UTS_MACHINE "armv8b\0\0"
|
#define COMPAT_UTS_MACHINE "armv8b\0\0"
|
||||||
@@ -113,23 +114,6 @@ typedef u32 compat_sigset_word;
|
|||||||
|
|
||||||
#define COMPAT_OFF_T_MAX 0x7fffffff
|
#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_user_stack_pointer() (user_stack_pointer(task_pt_regs(current)))
|
||||||
#define COMPAT_MINSIGSTKSZ 2048
|
#define COMPAT_MINSIGSTKSZ 2048
|
||||||
|
|
||||||
|
|||||||
@@ -100,24 +100,6 @@ typedef u32 compat_sigset_word;
|
|||||||
|
|
||||||
#define COMPAT_OFF_T_MAX 0x7fffffff
|
#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)
|
static inline void __user *arch_compat_alloc_user_space(long len)
|
||||||
{
|
{
|
||||||
struct pt_regs *regs = (struct pt_regs *)
|
struct pt_regs *regs = (struct pt_regs *)
|
||||||
|
|||||||
@@ -173,23 +173,6 @@ struct compat_shmid64_ds {
|
|||||||
#define COMPAT_ELF_NGREG 80
|
#define COMPAT_ELF_NGREG 80
|
||||||
typedef compat_ulong_t compat_elf_gregset_t[COMPAT_ELF_NGREG];
|
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)
|
static __inline__ void __user *arch_compat_alloc_user_space(long len)
|
||||||
{
|
{
|
||||||
struct pt_regs *regs = ¤t->thread.regs;
|
struct pt_regs *regs = ¤t->thread.regs;
|
||||||
|
|||||||
@@ -96,23 +96,6 @@ typedef u32 compat_sigset_word;
|
|||||||
|
|
||||||
#define COMPAT_OFF_T_MAX 0x7fffffff
|
#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)
|
static inline void __user *arch_compat_alloc_user_space(long len)
|
||||||
{
|
{
|
||||||
struct pt_regs *regs = current->thread.regs;
|
struct pt_regs *regs = current->thread.regs;
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
#include <linux/sched.h>
|
#include <linux/sched.h>
|
||||||
#include <asm/processor.h>
|
#include <asm/processor.h>
|
||||||
#include <linux/uaccess.h>
|
#include <linux/uaccess.h>
|
||||||
#include <asm/compat.h>
|
#include <linux/compat.h>
|
||||||
#include <asm/oprofile_impl.h>
|
#include <asm/oprofile_impl.h>
|
||||||
|
|
||||||
#define STACK_SP(STACK) *(STACK)
|
#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);
|
return (void __user *)(unsigned long)(uptr & 0x7fffffffUL);
|
||||||
}
|
}
|
||||||
|
#define compat_ptr(uptr) compat_ptr(uptr)
|
||||||
static inline compat_uptr_t ptr_to_compat(void __user *uptr)
|
|
||||||
{
|
|
||||||
return (u32)(unsigned long)uptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef CONFIG_COMPAT
|
#ifdef CONFIG_COMPAT
|
||||||
|
|
||||||
|
|||||||
@@ -125,23 +125,6 @@ typedef u32 compat_sigset_word;
|
|||||||
|
|
||||||
#define COMPAT_OFF_T_MAX 0x7fffffff
|
#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
|
#ifdef CONFIG_COMPAT
|
||||||
static inline void __user *arch_compat_alloc_user_space(long len)
|
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,
|
.open = ubd_open,
|
||||||
.release = ubd_release,
|
.release = ubd_release,
|
||||||
.ioctl = ubd_ioctl,
|
.ioctl = ubd_ioctl,
|
||||||
|
.compat_ioctl = blkdev_compat_ptr_ioctl,
|
||||||
.getgeo = ubd_getgeo,
|
.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))
|
(!!(task_pt_regs(current)->orig_ax & __X32_SYSCALL_BIT))
|
||||||
#endif
|
#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)
|
static inline void __user *arch_compat_alloc_user_space(long len)
|
||||||
{
|
{
|
||||||
compat_uptr_t sp;
|
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
|
bfq-y := bfq-iosched.o bfq-wf2q.o bfq-cgroup.o
|
||||||
obj-$(CONFIG_IOSCHED_BFQ) += bfq.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_CMDLINE_PARSER) += cmdline-parser.o
|
||||||
obj-$(CONFIG_BLK_DEV_INTEGRITY) += bio-integrity.o blk-integrity.o
|
obj-$(CONFIG_BLK_DEV_INTEGRITY) += bio-integrity.o blk-integrity.o
|
||||||
obj-$(CONFIG_BLK_DEV_INTEGRITY_T10) += t10-pi.o
|
obj-$(CONFIG_BLK_DEV_INTEGRITY_T10) += t10-pi.o
|
||||||
|
|||||||
@@ -382,6 +382,7 @@ static const struct file_operations bsg_fops = {
|
|||||||
.open = bsg_open,
|
.open = bsg_open,
|
||||||
.release = bsg_release,
|
.release = bsg_release,
|
||||||
.unlocked_ioctl = bsg_ioctl,
|
.unlocked_ioctl = bsg_ioctl,
|
||||||
|
.compat_ioctl = compat_ptr_ioctl,
|
||||||
.owner = THIS_MODULE,
|
.owner = THIS_MODULE,
|
||||||
.llseek = default_llseek,
|
.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
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
#include <linux/capability.h>
|
#include <linux/capability.h>
|
||||||
|
#include <linux/compat.h>
|
||||||
#include <linux/blkdev.h>
|
#include <linux/blkdev.h>
|
||||||
#include <linux/export.h>
|
#include <linux/export.h>
|
||||||
#include <linux/gfp.h>
|
#include <linux/gfp.h>
|
||||||
@@ -11,12 +12,12 @@
|
|||||||
#include <linux/pr.h>
|
#include <linux/pr.h>
|
||||||
#include <linux/uaccess.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 block_device *bdevp;
|
||||||
struct gendisk *disk;
|
struct gendisk *disk;
|
||||||
struct hd_struct *part, *lpart;
|
struct hd_struct *part, *lpart;
|
||||||
struct blkpg_ioctl_arg a;
|
|
||||||
struct blkpg_partition p;
|
struct blkpg_partition p;
|
||||||
struct disk_part_iter piter;
|
struct disk_part_iter piter;
|
||||||
long long start, length;
|
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))
|
if (!capable(CAP_SYS_ADMIN))
|
||||||
return -EACCES;
|
return -EACCES;
|
||||||
if (copy_from_user(&a, arg, sizeof(struct blkpg_ioctl_arg)))
|
if (copy_from_user(&p, upart, sizeof(struct blkpg_partition)))
|
||||||
return -EFAULT;
|
|
||||||
if (copy_from_user(&p, a.data, sizeof(struct blkpg_partition)))
|
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
disk = bdev->bd_disk;
|
disk = bdev->bd_disk;
|
||||||
if (bdev != bdev->bd_contains)
|
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;
|
partno = p.pno;
|
||||||
if (partno <= 0)
|
if (partno <= 0)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
switch (a.op) {
|
switch (op) {
|
||||||
case BLKPG_ADD_PARTITION:
|
case BLKPG_ADD_PARTITION:
|
||||||
start = p.start >> 9;
|
start = p.start >> 9;
|
||||||
length = p.length >> 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)
|
static int blkdev_reread_part(struct block_device *bdev)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
@@ -238,36 +270,48 @@ static int blk_ioctl_zeroout(struct block_device *bdev, fmode_t mode,
|
|||||||
BLKDEV_ZERO_NOUNMAP);
|
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,
|
int __blkdev_driver_ioctl(struct block_device *bdev, fmode_t mode,
|
||||||
unsigned cmd, unsigned long arg)
|
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);
|
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,
|
static int blkdev_pr_register(struct block_device *bdev,
|
||||||
struct pr_registration __user *arg)
|
struct pr_registration __user *arg)
|
||||||
{
|
{
|
||||||
@@ -455,6 +519,45 @@ static int blkdev_getgeo(struct block_device *bdev,
|
|||||||
return 0;
|
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 */
|
/* set the logical block size */
|
||||||
static int blkdev_bszset(struct block_device *bdev, fmode_t mode,
|
static int blkdev_bszset(struct block_device *bdev, fmode_t mode,
|
||||||
int __user *argp)
|
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,
|
static int blkdev_common_ioctl(struct block_device *bdev, fmode_t mode,
|
||||||
unsigned long arg)
|
unsigned cmd, unsigned long arg, void __user *argp)
|
||||||
{
|
{
|
||||||
void __user *argp = (void __user *)arg;
|
|
||||||
loff_t size;
|
|
||||||
unsigned int max_sectors;
|
unsigned int max_sectors;
|
||||||
|
|
||||||
switch (cmd) {
|
switch (cmd) {
|
||||||
@@ -510,60 +613,39 @@ int blkdev_ioctl(struct block_device *bdev, fmode_t mode, unsigned cmd,
|
|||||||
case BLKFINISHZONE:
|
case BLKFINISHZONE:
|
||||||
return blkdev_zone_mgmt_ioctl(bdev, mode, cmd, arg);
|
return blkdev_zone_mgmt_ioctl(bdev, mode, cmd, arg);
|
||||||
case BLKGETZONESZ:
|
case BLKGETZONESZ:
|
||||||
return put_uint(arg, bdev_zone_sectors(bdev));
|
return put_uint(argp, bdev_zone_sectors(bdev));
|
||||||
case BLKGETNRZONES:
|
case BLKGETNRZONES:
|
||||||
return put_uint(arg, blkdev_nr_zones(bdev->bd_disk));
|
return put_uint(argp, 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);
|
|
||||||
case BLKROGET:
|
case BLKROGET:
|
||||||
return put_int(arg, bdev_read_only(bdev) != 0);
|
return put_int(argp, bdev_read_only(bdev) != 0);
|
||||||
case BLKBSZGET: /* get block device soft block size (cf. BLKSSZGET) */
|
|
||||||
return put_int(arg, block_size(bdev));
|
|
||||||
case BLKSSZGET: /* get block device logical block size */
|
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 */
|
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:
|
case BLKIOMIN:
|
||||||
return put_uint(arg, bdev_io_min(bdev));
|
return put_uint(argp, bdev_io_min(bdev));
|
||||||
case BLKIOOPT:
|
case BLKIOOPT:
|
||||||
return put_uint(arg, bdev_io_opt(bdev));
|
return put_uint(argp, bdev_io_opt(bdev));
|
||||||
case BLKALIGNOFF:
|
case BLKALIGNOFF:
|
||||||
return put_int(arg, bdev_alignment_offset(bdev));
|
return put_int(argp, bdev_alignment_offset(bdev));
|
||||||
case BLKDISCARDZEROES:
|
case BLKDISCARDZEROES:
|
||||||
return put_uint(arg, 0);
|
return put_uint(argp, 0);
|
||||||
case BLKSECTGET:
|
case BLKSECTGET:
|
||||||
max_sectors = min_t(unsigned int, USHRT_MAX,
|
max_sectors = min_t(unsigned int, USHRT_MAX,
|
||||||
queue_max_sectors(bdev_get_queue(bdev)));
|
queue_max_sectors(bdev_get_queue(bdev)));
|
||||||
return put_ushort(arg, max_sectors);
|
return put_ushort(argp, max_sectors);
|
||||||
case BLKROTATIONAL:
|
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 BLKRASET:
|
||||||
case BLKFRASET:
|
case BLKFRASET:
|
||||||
if(!capable(CAP_SYS_ADMIN))
|
if(!capable(CAP_SYS_ADMIN))
|
||||||
return -EACCES;
|
return -EACCES;
|
||||||
bdev->bd_bdi->ra_pages = (arg * 512) / PAGE_SIZE;
|
bdev->bd_bdi->ra_pages = (arg * 512) / PAGE_SIZE;
|
||||||
return 0;
|
return 0;
|
||||||
case BLKBSZSET:
|
|
||||||
return blkdev_bszset(bdev, mode, argp);
|
|
||||||
case BLKPG:
|
|
||||||
return blkpg_ioctl(bdev, argp);
|
|
||||||
case BLKRRPART:
|
case BLKRRPART:
|
||||||
return blkdev_reread_part(bdev);
|
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 BLKTRACESTART:
|
||||||
case BLKTRACESTOP:
|
case BLKTRACESTOP:
|
||||||
case BLKTRACESETUP:
|
|
||||||
case BLKTRACETEARDOWN:
|
case BLKTRACETEARDOWN:
|
||||||
return blk_trace_ioctl(bdev, cmd, argp);
|
return blk_trace_ioctl(bdev, cmd, argp);
|
||||||
case IOC_PR_REGISTER:
|
case IOC_PR_REGISTER:
|
||||||
@@ -579,7 +661,132 @@ int blkdev_ioctl(struct block_device *bdev, fmode_t mode, unsigned cmd,
|
|||||||
case IOC_PR_CLEAR:
|
case IOC_PR_CLEAR:
|
||||||
return blkdev_pr_clear(bdev, argp);
|
return blkdev_pr_clear(bdev, argp);
|
||||||
default:
|
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.h>
|
||||||
#include <scsi/scsi_ioctl.h>
|
#include <scsi/scsi_ioctl.h>
|
||||||
#include <scsi/scsi_cmnd.h>
|
#include <scsi/scsi_cmnd.h>
|
||||||
|
#include <scsi/sg.h>
|
||||||
|
|
||||||
struct blk_cmd_filter {
|
struct blk_cmd_filter {
|
||||||
unsigned long read_ok[BLK_SCSI_CMD_PER_LONG];
|
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);
|
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)
|
int put_sg_io_hdr(const struct sg_io_hdr *hdr, void __user *argp)
|
||||||
{
|
{
|
||||||
#ifdef CONFIG_COMPAT
|
#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);
|
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,
|
int scsi_cmd_ioctl(struct request_queue *q, struct gendisk *bd_disk, fmode_t mode,
|
||||||
unsigned int cmd, void __user *arg)
|
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;
|
err = -EFAULT;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case CDROM_SEND_PACKET: {
|
case CDROM_SEND_PACKET:
|
||||||
struct cdrom_generic_command cgc;
|
err = scsi_cdrom_send_packet(q, bd_disk, mode, arg);
|
||||||
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;
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* old junk scsi send command ioctl
|
* old junk scsi send command ioctl
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
* - http://www.t13.org/
|
* - http://www.t13.org/
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <linux/compat.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
#include <linux/blkdev.h>
|
#include <linux/blkdev.h>
|
||||||
@@ -761,6 +762,10 @@ static int ata_ioc32(struct ata_port *ap)
|
|||||||
return 0;
|
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,
|
int ata_sas_scsi_ioctl(struct ata_port *ap, struct scsi_device *scsidev,
|
||||||
unsigned int cmd, void __user *arg)
|
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);
|
spin_lock_irqsave(ap->lock, flags);
|
||||||
val = ata_ioc32(ap);
|
val = ata_ioc32(ap);
|
||||||
spin_unlock_irqrestore(ap->lock, flags);
|
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);
|
return put_user(val, (unsigned long __user *)arg);
|
||||||
|
|
||||||
case HDIO_SET_32BIT:
|
case HDIO_SET_32BIT:
|
||||||
|
|||||||
@@ -236,6 +236,109 @@ attribute_container_remove_device(struct device *dev,
|
|||||||
mutex_unlock(&attribute_container_mutex);
|
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
|
* attribute_container_device_trigger - execute a trigger for each matching classdev
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -30,6 +30,10 @@
|
|||||||
#include <linux/attribute_container.h>
|
#include <linux/attribute_container.h>
|
||||||
#include <linux/transport_class.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
|
* 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
|
* routine is simply a trigger point used to add the device to the
|
||||||
* system and register attributes for it.
|
* system and register attributes for it.
|
||||||
*/
|
*/
|
||||||
|
int transport_add_device(struct device *dev)
|
||||||
void 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);
|
EXPORT_SYMBOL_GPL(transport_add_device);
|
||||||
|
|
||||||
|
|||||||
@@ -329,6 +329,7 @@ static const struct block_device_operations aoe_bdops = {
|
|||||||
.open = aoeblk_open,
|
.open = aoeblk_open,
|
||||||
.release = aoeblk_release,
|
.release = aoeblk_release,
|
||||||
.ioctl = aoeblk_ioctl,
|
.ioctl = aoeblk_ioctl,
|
||||||
|
.compat_ioctl = blkdev_compat_ptr_ioctl,
|
||||||
.getgeo = aoeblk_getgeo,
|
.getgeo = aoeblk_getgeo,
|
||||||
.owner = THIS_MODULE,
|
.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;
|
int drive = (long)bdev->bd_disk->private_data;
|
||||||
switch (cmd) {
|
switch (cmd) {
|
||||||
|
case CDROMEJECT: /* CD-ROM eject */
|
||||||
|
case 0x6470: /* SunOS floppy eject */
|
||||||
|
|
||||||
case FDMSGON:
|
case FDMSGON:
|
||||||
case FDMSGOFF:
|
case FDMSGOFF:
|
||||||
case FDSETEMSGTRESH:
|
case FDSETEMSGTRESH:
|
||||||
|
|||||||
@@ -275,6 +275,9 @@ static const struct block_device_operations pcd_bdops = {
|
|||||||
.open = pcd_block_open,
|
.open = pcd_block_open,
|
||||||
.release = pcd_block_release,
|
.release = pcd_block_release,
|
||||||
.ioctl = pcd_block_ioctl,
|
.ioctl = pcd_block_ioctl,
|
||||||
|
#ifdef CONFIG_COMPAT
|
||||||
|
.ioctl = blkdev_compat_ptr_ioctl,
|
||||||
|
#endif
|
||||||
.check_events = pcd_block_check_events,
|
.check_events = pcd_block_check_events,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -874,6 +874,7 @@ static const struct block_device_operations pd_fops = {
|
|||||||
.open = pd_open,
|
.open = pd_open,
|
||||||
.release = pd_release,
|
.release = pd_release,
|
||||||
.ioctl = pd_ioctl,
|
.ioctl = pd_ioctl,
|
||||||
|
.compat_ioctl = pd_ioctl,
|
||||||
.getgeo = pd_getgeo,
|
.getgeo = pd_getgeo,
|
||||||
.check_events = pd_check_events,
|
.check_events = pd_check_events,
|
||||||
.revalidate_disk= pd_revalidate
|
.revalidate_disk= pd_revalidate
|
||||||
|
|||||||
@@ -276,6 +276,7 @@ static const struct block_device_operations pf_fops = {
|
|||||||
.open = pf_open,
|
.open = pf_open,
|
||||||
.release = pf_release,
|
.release = pf_release,
|
||||||
.ioctl = pf_ioctl,
|
.ioctl = pf_ioctl,
|
||||||
|
.compat_ioctl = pf_ioctl,
|
||||||
.getgeo = pf_getgeo,
|
.getgeo = pf_getgeo,
|
||||||
.check_events = pf_check_events,
|
.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;
|
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,
|
static unsigned int pkt_check_events(struct gendisk *disk,
|
||||||
unsigned int clearing)
|
unsigned int clearing)
|
||||||
{
|
{
|
||||||
@@ -2706,9 +2684,7 @@ static const struct block_device_operations pktcdvd_ops = {
|
|||||||
.open = pkt_open,
|
.open = pkt_open,
|
||||||
.release = pkt_close,
|
.release = pkt_close,
|
||||||
.ioctl = pkt_ioctl,
|
.ioctl = pkt_ioctl,
|
||||||
#ifdef CONFIG_COMPAT
|
.compat_ioctl = blkdev_compat_ptr_ioctl,
|
||||||
.compat_ioctl = pkt_compat_ioctl,
|
|
||||||
#endif
|
|
||||||
.check_events = pkt_check_events,
|
.check_events = pkt_check_events,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -171,6 +171,7 @@ static const struct block_device_operations vdc_fops = {
|
|||||||
.owner = THIS_MODULE,
|
.owner = THIS_MODULE,
|
||||||
.getgeo = vdc_getgeo,
|
.getgeo = vdc_getgeo,
|
||||||
.ioctl = vdc_ioctl,
|
.ioctl = vdc_ioctl,
|
||||||
|
.compat_ioctl = blkdev_compat_ptr_ioctl,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void vdc_blk_queue_start(struct vdc_port *port)
|
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 = {
|
static const struct block_device_operations virtblk_fops = {
|
||||||
.ioctl = virtblk_ioctl,
|
.ioctl = virtblk_ioctl,
|
||||||
|
#ifdef CONFIG_COMPAT
|
||||||
|
.compat_ioctl = blkdev_compat_ptr_ioctl,
|
||||||
|
#endif
|
||||||
.owner = THIS_MODULE,
|
.owner = THIS_MODULE,
|
||||||
.getgeo = virtblk_getgeo,
|
.getgeo = virtblk_getgeo,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -2632,6 +2632,7 @@ static const struct block_device_operations xlvbd_block_fops =
|
|||||||
.release = blkif_release,
|
.release = blkif_release,
|
||||||
.getgeo = blkif_getgeo,
|
.getgeo = blkif_getgeo,
|
||||||
.ioctl = blkif_ioctl,
|
.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;
|
struct cdrom_read_audio ra;
|
||||||
int lba;
|
int lba;
|
||||||
|
|
||||||
if (copy_from_user(&ra, (struct cdrom_read_audio __user *)arg,
|
#ifdef CONFIG_COMPAT
|
||||||
sizeof(ra)))
|
if (in_compat_syscall()) {
|
||||||
return -EFAULT;
|
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)
|
if (ra.addr_format == CDROM_MSF)
|
||||||
lba = msf_to_lba(ra.addr.msf.minute,
|
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);
|
ret = cdrom_get_last_written(cdi, &last);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
if (copy_to_user((long __user *)arg, &last, sizeof(last)))
|
if (in_compat_syscall())
|
||||||
return -EFAULT;
|
return put_user(last, (__s32 __user *)arg);
|
||||||
return 0;
|
|
||||||
|
return put_user(last, (long __user *)arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int mmc_ioctl(struct cdrom_device_info *cdi, unsigned int cmd,
|
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,
|
.release = gdrom_bdops_release,
|
||||||
.check_events = gdrom_bdops_check_events,
|
.check_events = gdrom_bdops_check_events,
|
||||||
.ioctl = gdrom_bdops_ioctl,
|
.ioctl = gdrom_bdops_ioctl,
|
||||||
|
#ifdef CONFIG_COMPAT
|
||||||
|
.ioctl = blkdev_compat_ptr_ioctl,
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
static irqreturn_t gdrom_command_interrupt(int irq, void *dev_id)
|
static irqreturn_t gdrom_command_interrupt(int irq, void *dev_id)
|
||||||
|
|||||||
@@ -25,6 +25,7 @@
|
|||||||
|
|
||||||
#define IDECD_VERSION "5.00"
|
#define IDECD_VERSION "5.00"
|
||||||
|
|
||||||
|
#include <linux/compat.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/types.h>
|
#include <linux/types.h>
|
||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
@@ -1710,6 +1711,41 @@ static int idecd_ioctl(struct block_device *bdev, fmode_t mode,
|
|||||||
return ret;
|
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,
|
static unsigned int idecd_check_events(struct gendisk *disk,
|
||||||
unsigned int clearing)
|
unsigned int clearing)
|
||||||
@@ -1732,6 +1768,8 @@ static const struct block_device_operations idecd_ops = {
|
|||||||
.open = idecd_open,
|
.open = idecd_open,
|
||||||
.release = idecd_release,
|
.release = idecd_release,
|
||||||
.ioctl = idecd_ioctl,
|
.ioctl = idecd_ioctl,
|
||||||
|
.compat_ioctl = IS_ENABLED(CONFIG_COMPAT) ?
|
||||||
|
idecd_compat_ioctl : NULL,
|
||||||
.check_events = idecd_check_events,
|
.check_events = idecd_check_events,
|
||||||
.revalidate_disk = idecd_revalidate_disk
|
.revalidate_disk = idecd_revalidate_disk
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -794,4 +794,5 @@ const struct ide_disk_ops ide_ata_disk_ops = {
|
|||||||
.set_doorlock = ide_disk_set_doorlock,
|
.set_doorlock = ide_disk_set_doorlock,
|
||||||
.do_request = ide_do_rw_disk,
|
.do_request = ide_do_rw_disk,
|
||||||
.ioctl = ide_disk_ioctl,
|
.ioctl = ide_disk_ioctl,
|
||||||
|
.compat_ioctl = ide_disk_ioctl,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
#include <linux/types.h>
|
#include <linux/types.h>
|
||||||
#include <linux/string.h>
|
#include <linux/string.h>
|
||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/compat.h>
|
||||||
#include <linux/delay.h>
|
#include <linux/delay.h>
|
||||||
#include <linux/timer.h>
|
#include <linux/timer.h>
|
||||||
#include <linux/mm.h>
|
#include <linux/mm.h>
|
||||||
@@ -546,4 +547,7 @@ const struct ide_disk_ops ide_atapi_disk_ops = {
|
|||||||
.set_doorlock = ide_set_media_lock,
|
.set_doorlock = ide_set_media_lock,
|
||||||
.do_request = ide_floppy_do_request,
|
.do_request = ide_floppy_do_request,
|
||||||
.ioctl = ide_floppy_ioctl,
|
.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 */
|
/* ide-floppy_ioctl.c */
|
||||||
int ide_floppy_ioctl(ide_drive_t *, struct block_device *, fmode_t,
|
int ide_floppy_ioctl(ide_drive_t *, struct block_device *, fmode_t,
|
||||||
unsigned int, unsigned long);
|
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
|
#ifdef CONFIG_IDE_PROC_FS
|
||||||
/* ide-floppy_proc.c */
|
/* ide-floppy_proc.c */
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
#include <linux/ide.h>
|
#include <linux/ide.h>
|
||||||
|
#include <linux/compat.h>
|
||||||
#include <linux/cdrom.h>
|
#include <linux/cdrom.h>
|
||||||
#include <linux/mutex.h>
|
#include <linux/mutex.h>
|
||||||
|
|
||||||
@@ -302,3 +303,37 @@ out:
|
|||||||
mutex_unlock(&ide_floppy_ioctl_mutex);
|
mutex_unlock(&ide_floppy_ioctl_mutex);
|
||||||
return err;
|
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);
|
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 = {
|
static const struct block_device_operations ide_gd_ops = {
|
||||||
.owner = THIS_MODULE,
|
.owner = THIS_MODULE,
|
||||||
.open = ide_gd_unlocked_open,
|
.open = ide_gd_unlocked_open,
|
||||||
.release = ide_gd_release,
|
.release = ide_gd_release,
|
||||||
.ioctl = ide_gd_ioctl,
|
.ioctl = ide_gd_ioctl,
|
||||||
|
#ifdef CONFIG_COMPAT
|
||||||
|
.ioctl = ide_gd_compat_ioctl,
|
||||||
|
#endif
|
||||||
.getgeo = ide_gd_getgeo,
|
.getgeo = ide_gd_getgeo,
|
||||||
.check_events = ide_gd_check_events,
|
.check_events = ide_gd_check_events,
|
||||||
.unlock_native_capacity = ide_gd_unlock_native_capacity,
|
.unlock_native_capacity = ide_gd_unlock_native_capacity,
|
||||||
|
|||||||
@@ -3,11 +3,20 @@
|
|||||||
* IDE ioctls handling.
|
* IDE ioctls handling.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <linux/compat.h>
|
||||||
#include <linux/export.h>
|
#include <linux/export.h>
|
||||||
#include <linux/hdreg.h>
|
#include <linux/hdreg.h>
|
||||||
#include <linux/ide.h>
|
#include <linux/ide.h>
|
||||||
#include <linux/slab.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[] = {
|
static const struct ide_ioctl_devset ide_ioctl_settings[] = {
|
||||||
{ HDIO_GET_32BIT, HDIO_SET_32BIT, &ide_devset_io_32bit },
|
{ HDIO_GET_32BIT, HDIO_SET_32BIT, &ide_devset_io_32bit },
|
||||||
{ HDIO_GET_KEEPSETTINGS, HDIO_SET_KEEPSETTINGS, &ide_devset_keepsettings },
|
{ HDIO_GET_KEEPSETTINGS, HDIO_SET_KEEPSETTINGS, &ide_devset_keepsettings },
|
||||||
@@ -37,7 +46,7 @@ read_val:
|
|||||||
mutex_lock(&ide_setting_mtx);
|
mutex_lock(&ide_setting_mtx);
|
||||||
err = ds->get(drive);
|
err = ds->get(drive);
|
||||||
mutex_unlock(&ide_setting_mtx);
|
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:
|
set_val:
|
||||||
if (bdev != bdev->bd_contains)
|
if (bdev != bdev->bd_contains)
|
||||||
@@ -56,7 +65,7 @@ set_val:
|
|||||||
EXPORT_SYMBOL_GPL(ide_setting_ioctl);
|
EXPORT_SYMBOL_GPL(ide_setting_ioctl);
|
||||||
|
|
||||||
static int ide_get_identity_ioctl(ide_drive_t *drive, unsigned int cmd,
|
static int ide_get_identity_ioctl(ide_drive_t *drive, unsigned int cmd,
|
||||||
unsigned long arg)
|
void __user *argp)
|
||||||
{
|
{
|
||||||
u16 *id = NULL;
|
u16 *id = NULL;
|
||||||
int size = (cmd == HDIO_GET_IDENTITY) ? (ATA_ID_WORDS * 2) : 142;
|
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);
|
memcpy(id, drive->id, size);
|
||||||
ata_id_to_hd_driveid(id);
|
ata_id_to_hd_driveid(id);
|
||||||
|
|
||||||
if (copy_to_user((void __user *)arg, id, size))
|
if (copy_to_user(argp, id, size))
|
||||||
rc = -EFAULT;
|
rc = -EFAULT;
|
||||||
|
|
||||||
kfree(id);
|
kfree(id);
|
||||||
@@ -87,10 +96,10 @@ out:
|
|||||||
|
|
||||||
static int ide_get_nice_ioctl(ide_drive_t *drive, unsigned long arg)
|
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) |
|
<< IDE_NICE_DSC_OVERLAP) |
|
||||||
(!!(drive->dev_flags & IDE_DFLAG_NICE1)
|
(!!(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)
|
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;
|
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;
|
u8 *buf = NULL;
|
||||||
int bufsize = 0, err = 0;
|
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_cmd cmd;
|
||||||
struct ide_taskfile *tf = &cmd.tf;
|
struct ide_taskfile *tf = &cmd.tf;
|
||||||
|
|
||||||
if (NULL == (void *) arg) {
|
if (NULL == argp) {
|
||||||
struct request *rq;
|
struct request *rq;
|
||||||
|
|
||||||
rq = blk_get_request(drive->queue, REQ_OP_DRV_IN, 0);
|
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;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (copy_from_user(args, (void __user *)arg, 4))
|
if (copy_from_user(args, argp, 4))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
|
|
||||||
memset(&cmd, 0, sizeof(cmd));
|
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[1] = tf->error;
|
||||||
args[2] = tf->nsect;
|
args[2] = tf->nsect;
|
||||||
abort:
|
abort:
|
||||||
if (copy_to_user((void __user *)arg, &args, 4))
|
if (copy_to_user(argp, &args, 4))
|
||||||
err = -EFAULT;
|
err = -EFAULT;
|
||||||
if (buf) {
|
if (buf) {
|
||||||
if (copy_to_user((void __user *)(arg + 4), buf, bufsize))
|
if (copy_to_user((argp + 4), buf, bufsize))
|
||||||
err = -EFAULT;
|
err = -EFAULT;
|
||||||
kfree(buf);
|
kfree(buf);
|
||||||
}
|
}
|
||||||
return err;
|
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;
|
int err = 0;
|
||||||
u8 args[7];
|
u8 args[7];
|
||||||
struct ide_cmd cmd;
|
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)
|
unsigned int cmd, unsigned long arg)
|
||||||
{
|
{
|
||||||
int err;
|
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);
|
err = ide_setting_ioctl(drive, bdev, cmd, arg, ide_ioctl_settings);
|
||||||
if (err != -EOPNOTSUPP)
|
if (err != -EOPNOTSUPP)
|
||||||
@@ -247,7 +259,7 @@ int generic_ide_ioctl(ide_drive_t *drive, struct block_device *bdev,
|
|||||||
case HDIO_GET_IDENTITY:
|
case HDIO_GET_IDENTITY:
|
||||||
if (bdev != bdev->bd_contains)
|
if (bdev != bdev->bd_contains)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
return ide_get_identity_ioctl(drive, cmd, arg);
|
return ide_get_identity_ioctl(drive, cmd, argp);
|
||||||
case HDIO_GET_NICE:
|
case HDIO_GET_NICE:
|
||||||
return ide_get_nice_ioctl(drive, arg);
|
return ide_get_nice_ioctl(drive, arg);
|
||||||
case HDIO_SET_NICE:
|
case HDIO_SET_NICE:
|
||||||
@@ -258,6 +270,9 @@ int generic_ide_ioctl(ide_drive_t *drive, struct block_device *bdev,
|
|||||||
case HDIO_DRIVE_TASKFILE:
|
case HDIO_DRIVE_TASKFILE:
|
||||||
if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
|
if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
|
||||||
return -EACCES;
|
return -EACCES;
|
||||||
|
/* missing compat handler for HDIO_DRIVE_TASKFILE */
|
||||||
|
if (in_compat_syscall())
|
||||||
|
return -ENOTTY;
|
||||||
if (drive->media == ide_disk)
|
if (drive->media == ide_disk)
|
||||||
return ide_taskfile_ioctl(drive, arg);
|
return ide_taskfile_ioctl(drive, arg);
|
||||||
return -ENOMSG;
|
return -ENOMSG;
|
||||||
@@ -265,11 +280,11 @@ int generic_ide_ioctl(ide_drive_t *drive, struct block_device *bdev,
|
|||||||
case HDIO_DRIVE_CMD:
|
case HDIO_DRIVE_CMD:
|
||||||
if (!capable(CAP_SYS_RAWIO))
|
if (!capable(CAP_SYS_RAWIO))
|
||||||
return -EACCES;
|
return -EACCES;
|
||||||
return ide_cmd_ioctl(drive, arg);
|
return ide_cmd_ioctl(drive, argp);
|
||||||
case HDIO_DRIVE_TASK:
|
case HDIO_DRIVE_TASK:
|
||||||
if (!capable(CAP_SYS_RAWIO))
|
if (!capable(CAP_SYS_RAWIO))
|
||||||
return -EACCES;
|
return -EACCES;
|
||||||
return ide_task_ioctl(drive, arg);
|
return ide_task_ioctl(drive, argp);
|
||||||
case HDIO_DRIVE_RESET:
|
case HDIO_DRIVE_RESET:
|
||||||
if (!capable(CAP_SYS_ADMIN))
|
if (!capable(CAP_SYS_ADMIN))
|
||||||
return -EACCES;
|
return -EACCES;
|
||||||
@@ -277,7 +292,7 @@ int generic_ide_ioctl(ide_drive_t *drive, struct block_device *bdev,
|
|||||||
case HDIO_GET_BUSSTATE:
|
case HDIO_GET_BUSSTATE:
|
||||||
if (!capable(CAP_SYS_ADMIN))
|
if (!capable(CAP_SYS_ADMIN))
|
||||||
return -EACCES;
|
return -EACCES;
|
||||||
if (put_user(BUSSTATE_ON, (long __user *)arg))
|
if (put_user_long(BUSSTATE_ON, arg))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
return 0;
|
return 0;
|
||||||
case HDIO_SET_BUSSTATE:
|
case HDIO_SET_BUSSTATE:
|
||||||
|
|||||||
@@ -1945,11 +1945,22 @@ static int idetape_ioctl(struct block_device *bdev, fmode_t mode,
|
|||||||
return err;
|
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 = {
|
static const struct block_device_operations idetape_block_ops = {
|
||||||
.owner = THIS_MODULE,
|
.owner = THIS_MODULE,
|
||||||
.open = idetape_open,
|
.open = idetape_open,
|
||||||
.release = idetape_release,
|
.release = idetape_release,
|
||||||
.ioctl = idetape_ioctl,
|
.ioctl = idetape_ioctl,
|
||||||
|
.compat_ioctl = IS_ENABLED(CONFIG_COMPAT) ?
|
||||||
|
idetape_compat_ioctl : NULL,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int ide_tape_probe(ide_drive_t *drive)
|
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)
|
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("***** 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;
|
goto done;
|
||||||
}
|
}
|
||||||
if (blogic_global_options.trace_config)
|
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;
|
result = 0;
|
||||||
goto done;
|
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);
|
pci_addr = base_addr1 = pci_resource_start(pci_device, 1);
|
||||||
|
|
||||||
if (pci_resource_flags(pci_device, 0) & IORESOURCE_MEM) {
|
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("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%X\n", NULL, bus, device, io_addr);
|
blogic_err("at PCI Bus %d Device %d I/O Address 0x%lX\n", NULL, bus, device, io_addr);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (pci_resource_flags(pci_device, 1) & IORESOURCE_IO) {
|
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("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%X\n", NULL, bus, device, pci_addr);
|
blogic_err("at PCI Bus %d Device %d PCI Address 0x%lX\n", NULL, bus, device, pci_addr);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (irq_ch == 0) {
|
if (irq_ch == 0) {
|
||||||
blogic_err("BusLogic: IRQ Channel %d invalid for " "MultiMaster Host Adapter\n", NULL, irq_ch);
|
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("at PCI Bus %d Device %d I/O Address 0x%lX\n", NULL, bus, device, io_addr);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (blogic_global_options.trace_probe) {
|
if (blogic_global_options.trace_probe) {
|
||||||
blogic_notice("BusLogic: PCI MultiMaster Host Adapter " "detected at\n", NULL);
|
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 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
|
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++;
|
nonpr_mmcount++;
|
||||||
mmcount++;
|
mmcount++;
|
||||||
} else
|
} 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."
|
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);
|
pci_addr = base_addr1 = pci_resource_start(pci_device, 1);
|
||||||
#ifdef CONFIG_SCSI_FLASHPOINT
|
#ifdef CONFIG_SCSI_FLASHPOINT
|
||||||
if (pci_resource_flags(pci_device, 0) & IORESOURCE_MEM) {
|
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("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%X\n", NULL, bus, device, io_addr);
|
blogic_err("at PCI Bus %d Device %d I/O Address 0x%lX\n", NULL, bus, device, io_addr);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (pci_resource_flags(pci_device, 1) & IORESOURCE_IO) {
|
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("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%X\n", NULL, bus, device, pci_addr);
|
blogic_err("at PCI Bus %d Device %d PCI Address 0x%lX\n", NULL, bus, device, pci_addr);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (irq_ch == 0) {
|
if (irq_ch == 0) {
|
||||||
blogic_err("BusLogic: IRQ Channel %d invalid for " "FlashPoint Host Adapter\n", NULL, irq_ch);
|
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("at PCI Bus %d Device %d I/O Address 0x%lX\n", NULL, bus, device, io_addr);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (blogic_global_options.trace_probe) {
|
if (blogic_global_options.trace_probe) {
|
||||||
blogic_notice("BusLogic: FlashPoint Host Adapter " "detected at\n", NULL);
|
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: 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) {
|
if (blogic_probeinfo_count < BLOGIC_MAX_ADAPTERS) {
|
||||||
struct blogic_probeinfo *probeinfo =
|
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);
|
probeinfo->pci_device = pci_dev_get(pci_device);
|
||||||
fpcount++;
|
fpcount++;
|
||||||
} else
|
} else
|
||||||
blogic_warn("BusLogic: Too many Host Adapters " "detected\n", NULL);
|
blogic_warn("BusLogic: Too many Host Adapters detected\n", NULL);
|
||||||
#else
|
#else
|
||||||
blogic_err("BusLogic: FlashPoint Host Adapter detected at " "PCI Bus %d Device %d\n", NULL, bus, device);
|
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: 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);
|
blogic_err("BusLogic: support was omitted in this kernel configuration.\n", NULL);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
@@ -1099,9 +1099,9 @@ static bool blogic_failure(struct blogic_adapter *adapter, char *msg)
|
|||||||
if (adapter->adapter_bus_type == BLOGIC_PCI_BUS) {
|
if (adapter->adapter_bus_type == BLOGIC_PCI_BUS) {
|
||||||
blogic_err("While configuring BusLogic PCI Host Adapter at\n",
|
blogic_err("While configuring BusLogic PCI Host Adapter at\n",
|
||||||
adapter);
|
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
|
} 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);
|
blogic_err("%s FAILED - DETACHING\n", adapter, msg);
|
||||||
if (blogic_cmd_failure_reason != NULL)
|
if (blogic_cmd_failure_reason != NULL)
|
||||||
blogic_err("ADDITIONAL FAILURE INFO - %s\n", adapter,
|
blogic_err("ADDITIONAL FAILURE INFO - %s\n", adapter,
|
||||||
@@ -1129,13 +1129,13 @@ static bool __init blogic_probe(struct blogic_adapter *adapter)
|
|||||||
fpinfo->present = false;
|
fpinfo->present = false;
|
||||||
if (!(FlashPoint_ProbeHostAdapter(fpinfo) == 0 &&
|
if (!(FlashPoint_ProbeHostAdapter(fpinfo) == 0 &&
|
||||||
fpinfo->present)) {
|
fpinfo->present)) {
|
||||||
blogic_err("BusLogic: FlashPoint Host Adapter detected at " "PCI Bus %d Device %d\n", adapter, adapter->bus, adapter->dev);
|
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: 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);
|
blogic_err("BusLogic: Probe Function failed to validate it.\n", adapter);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (blogic_global_options.trace_probe)
|
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.
|
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);
|
intreg.all = blogic_rdint(adapter);
|
||||||
georeg.all = blogic_rdgeom(adapter);
|
georeg.all = blogic_rdgeom(adapter);
|
||||||
if (blogic_global_options.trace_probe)
|
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 ||
|
if (statusreg.all == 0 || statusreg.sr.diag_active ||
|
||||||
statusreg.sr.cmd_param_busy || statusreg.sr.rsvd ||
|
statusreg.sr.cmd_param_busy || statusreg.sr.rsvd ||
|
||||||
statusreg.sr.cmd_invalid || intreg.ir.rsvd != 0)
|
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);
|
udelay(100);
|
||||||
}
|
}
|
||||||
if (blogic_global_options.trace_hw_reset)
|
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)
|
if (timeout < 0)
|
||||||
return false;
|
return false;
|
||||||
/*
|
/*
|
||||||
@@ -1251,7 +1251,7 @@ static bool blogic_hwreset(struct blogic_adapter *adapter, bool hard_reset)
|
|||||||
udelay(100);
|
udelay(100);
|
||||||
}
|
}
|
||||||
if (blogic_global_options.trace_hw_reset)
|
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)
|
if (timeout < 0)
|
||||||
return false;
|
return false;
|
||||||
/*
|
/*
|
||||||
@@ -1267,7 +1267,7 @@ static bool blogic_hwreset(struct blogic_adapter *adapter, bool hard_reset)
|
|||||||
udelay(100);
|
udelay(100);
|
||||||
}
|
}
|
||||||
if (blogic_global_options.trace_hw_reset)
|
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)
|
if (timeout < 0)
|
||||||
return false;
|
return false;
|
||||||
/*
|
/*
|
||||||
@@ -1323,7 +1323,7 @@ static bool __init blogic_checkadapter(struct blogic_adapter *adapter)
|
|||||||
Provide tracing information if requested and return.
|
Provide tracing information if requested and return.
|
||||||
*/
|
*/
|
||||||
if (blogic_global_options.trace_probe)
|
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,
|
adapter->io_addr,
|
||||||
(result ? "Found" : "Not Found"));
|
(result ? "Found" : "Not Found"));
|
||||||
return result;
|
return result;
|
||||||
@@ -1836,7 +1836,7 @@ static bool __init blogic_reportconfig(struct blogic_adapter *adapter)
|
|||||||
int tgt_id;
|
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("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) {
|
if (adapter->adapter_bus_type != BLOGIC_PCI_BUS) {
|
||||||
blogic_info(" DMA Channel: ", adapter);
|
blogic_info(" DMA Channel: ", adapter);
|
||||||
if (adapter->dma_ch > 0)
|
if (adapter->dma_ch > 0)
|
||||||
@@ -1844,7 +1844,7 @@ static bool __init blogic_reportconfig(struct blogic_adapter *adapter)
|
|||||||
else
|
else
|
||||||
blogic_info("None, ", adapter);
|
blogic_info("None, ", adapter);
|
||||||
if (adapter->bios_addr > 0)
|
if (adapter->bios_addr > 0)
|
||||||
blogic_info("BIOS Address: 0x%X, ", adapter,
|
blogic_info("BIOS Address: 0x%lX, ", adapter,
|
||||||
adapter->bios_addr);
|
adapter->bios_addr);
|
||||||
else
|
else
|
||||||
blogic_info("BIOS Address: None, ", adapter);
|
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,
|
blogic_info(" PCI Bus: %d, Device: %d, Address: ", adapter,
|
||||||
adapter->bus, adapter->dev);
|
adapter->bus, adapter->dev);
|
||||||
if (adapter->pci_addr > 0)
|
if (adapter->pci_addr > 0)
|
||||||
blogic_info("0x%X, ", adapter, adapter->pci_addr);
|
blogic_info("0x%lX, ", adapter, adapter->pci_addr);
|
||||||
else
|
else
|
||||||
blogic_info("Unassigned, ", adapter);
|
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,
|
blogic_info(" Disconnect/Reconnect: %s, Tagged Queuing: %s\n", adapter,
|
||||||
discon_msg, tagq_msg);
|
discon_msg, tagq_msg);
|
||||||
if (blogic_multimaster_type(adapter)) {
|
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(" 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(" Driver Queue Depth: %d, Host Adapter Queue Depth: %d\n", adapter, adapter->drvr_qdepth, adapter->adapter_qdepth);
|
||||||
} else
|
} 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);
|
blogic_info(" Tagged Queue Depth: ", adapter);
|
||||||
common_tagq_depth = true;
|
common_tagq_depth = true;
|
||||||
for (tgt_id = 1; tgt_id < adapter->maxdev; tgt_id++)
|
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
|
then there is most likely a bug in
|
||||||
the Host Adapter firmware.
|
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;
|
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) {
|
if (ccb->opcode == BLOGIC_BDR) {
|
||||||
int tgt_id = ccb->tgt_id;
|
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);
|
blogic_inc_count(&adapter->tgt_stats[tgt_id].bdr_done);
|
||||||
adapter->tgt_flags[tgt_id].tagq_active = false;
|
adapter->tgt_flags[tgt_id].tagq_active = false;
|
||||||
adapter->cmds_since_rst[tgt_id] = 0;
|
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) {
|
if (blogic_global_options.trace_err) {
|
||||||
int i;
|
int i;
|
||||||
blogic_notice("CCB #%ld Target %d: Result %X Host "
|
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);
|
blogic_notice("CDB ", adapter);
|
||||||
for (i = 0; i < ccb->cdblen; i++)
|
for (i = 0; i < ccb->cdblen; i++)
|
||||||
blogic_notice(" %02X", adapter, ccb->cdb[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)) {
|
if (!blogic_write_outbox(adapter, BLOGIC_MBOX_START, ccb)) {
|
||||||
spin_unlock_irq(adapter->scsi_host->host_lock);
|
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);
|
blogic_delay(1);
|
||||||
spin_lock_irq(adapter->scsi_host->host_lock);
|
spin_lock_irq(adapter->scsi_host->host_lock);
|
||||||
if (!blogic_write_outbox(adapter, BLOGIC_MBOX_START,
|
if (!blogic_write_outbox(adapter, BLOGIC_MBOX_START,
|
||||||
ccb)) {
|
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);
|
blogic_dealloc_ccb(ccb, 1);
|
||||||
command->result = DID_ERROR << 16;
|
command->result = DID_ERROR << 16;
|
||||||
command->scsi_done(command);
|
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)
|
if (diskparam->cylinders != saved_cyl)
|
||||||
blogic_warn("Adopting Geometry %d/%d from Partition Table\n", adapter, diskparam->heads, diskparam->sectors);
|
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) {
|
} 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("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("not compatible with current BusLogic Host Adapter Geometry %d/%d\n", adapter, diskparam->heads, diskparam->sectors);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
kfree(buf);
|
kfree(buf);
|
||||||
@@ -3689,7 +3689,7 @@ static int __init blogic_parseopts(char *options)
|
|||||||
blogic_probe_options.probe134 = true;
|
blogic_probe_options.probe134 = true;
|
||||||
break;
|
break;
|
||||||
default:
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
} else if (blogic_parse(&options, "NoProbeISA"))
|
} 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++) {
|
for (tgt_id = 0; tgt_id < BLOGIC_MAXDEV; tgt_id++) {
|
||||||
unsigned short qdepth = simple_strtoul(options, &options, 0);
|
unsigned short qdepth = simple_strtoul(options, &options, 0);
|
||||||
if (qdepth > BLOGIC_MAX_TAG_DEPTH) {
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
drvr_opts->qdepth[tgt_id] = qdepth;
|
drvr_opts->qdepth[tgt_id] = qdepth;
|
||||||
@@ -3719,12 +3719,12 @@ static int __init blogic_parseopts(char *options)
|
|||||||
else if (*options == ']')
|
else if (*options == ']')
|
||||||
break;
|
break;
|
||||||
else {
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (*options != ']') {
|
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;
|
return 0;
|
||||||
} else
|
} else
|
||||||
options++;
|
options++;
|
||||||
@@ -3732,7 +3732,7 @@ static int __init blogic_parseopts(char *options)
|
|||||||
unsigned short qdepth = simple_strtoul(options, &options, 0);
|
unsigned short qdepth = simple_strtoul(options, &options, 0);
|
||||||
if (qdepth == 0 ||
|
if (qdepth == 0 ||
|
||||||
qdepth > BLOGIC_MAX_TAG_DEPTH) {
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
drvr_opts->common_qdepth = qdepth;
|
drvr_opts->common_qdepth = qdepth;
|
||||||
@@ -3778,7 +3778,7 @@ static int __init blogic_parseopts(char *options)
|
|||||||
unsigned short bus_settle_time =
|
unsigned short bus_settle_time =
|
||||||
simple_strtoul(options, &options, 0);
|
simple_strtoul(options, &options, 0);
|
||||||
if (bus_settle_time > 5 * 60) {
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
drvr_opts->bus_settle_time = bus_settle_time;
|
drvr_opts->bus_settle_time = bus_settle_time;
|
||||||
@@ -3803,14 +3803,14 @@ static int __init blogic_parseopts(char *options)
|
|||||||
if (*options == ',')
|
if (*options == ',')
|
||||||
options++;
|
options++;
|
||||||
else if (*options != ';' && *options != '\0') {
|
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';
|
*options = '\0';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!(blogic_drvr_options_count == 0 ||
|
if (!(blogic_drvr_options_count == 0 ||
|
||||||
blogic_probeinfo_count == 0 ||
|
blogic_probeinfo_count == 0 ||
|
||||||
blogic_drvr_options_count == blogic_probeinfo_count)) {
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
@@ -3864,7 +3864,7 @@ static int __init blogic_setup(char *str)
|
|||||||
(void) get_options(str, ARRAY_SIZE(ints), ints);
|
(void) get_options(str, ARRAY_SIZE(ints), ints);
|
||||||
|
|
||||||
if (ints[0] != 0) {
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
if (str == NULL || *str == '\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
|
* At some speeds, we only support
|
||||||
* ST transfers.
|
* ST transfers.
|
||||||
*/
|
*/
|
||||||
if ((syncrate->sxfr_u2 & ST_SXFR) != 0)
|
if ((syncrate->sxfr_u2 & ST_SXFR) != 0)
|
||||||
*ppr_options &= ~MSG_EXT_PPR_DT_REQ;
|
*ppr_options &= ~MSG_EXT_PPR_DT_REQ;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -54,6 +54,9 @@ static struct scsi_host_template aic94xx_sht = {
|
|||||||
.eh_target_reset_handler = sas_eh_target_reset_handler,
|
.eh_target_reset_handler = sas_eh_target_reset_handler,
|
||||||
.target_destroy = sas_target_destroy,
|
.target_destroy = sas_target_destroy,
|
||||||
.ioctl = sas_ioctl,
|
.ioctl = sas_ioctl,
|
||||||
|
#ifdef CONFIG_COMPAT
|
||||||
|
.compat_ioctl = sas_ioctl,
|
||||||
|
#endif
|
||||||
.track_queue_depth = 1,
|
.track_queue_depth = 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -872,6 +872,10 @@ static long ch_ioctl_compat(struct file * file,
|
|||||||
unsigned int cmd, unsigned long arg)
|
unsigned int cmd, unsigned long arg)
|
||||||
{
|
{
|
||||||
scsi_changer *ch = file->private_data;
|
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) {
|
switch (cmd) {
|
||||||
case CHIOGPARAMS:
|
case CHIOGPARAMS:
|
||||||
@@ -883,7 +887,7 @@ static long ch_ioctl_compat(struct file * file,
|
|||||||
case CHIOINITELEM:
|
case CHIOINITELEM:
|
||||||
case CHIOSVOLTAG:
|
case CHIOSVOLTAG:
|
||||||
/* compatible */
|
/* compatible */
|
||||||
return ch_ioctl(file, cmd, arg);
|
return ch_ioctl(file, cmd, (unsigned long)compat_ptr(arg));
|
||||||
case CHIOGSTATUS32:
|
case CHIOGSTATUS32:
|
||||||
{
|
{
|
||||||
struct changer_element_status32 ces32;
|
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);
|
return ch_gstatus(ch, ces32.ces_type, data);
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
// return scsi_ioctl_compat(ch->device, cmd, (void*)arg);
|
return scsi_compat_ioctl(ch->device, cmd, compat_ptr(arg));
|
||||||
return -ENOIOCTLCMD;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1383,7 +1383,7 @@ csio_device_reset(struct device *dev,
|
|||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
/* Delete NPIV lnodes */
|
/* Delete NPIV lnodes */
|
||||||
csio_lnodes_exit(hw, 1);
|
csio_lnodes_exit(hw, 1);
|
||||||
|
|
||||||
/* Block upper IOs */
|
/* Block upper IOs */
|
||||||
csio_lnodes_block_request(hw);
|
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. */
|
/* Reset the ESP chip, _not_ the SCSI bus. */
|
||||||
static void esp_reset_esp(struct esp *esp)
|
static void esp_reset_esp(struct esp *esp)
|
||||||
{
|
{
|
||||||
u8 family_code, version;
|
|
||||||
|
|
||||||
/* Now reset the ESP chip */
|
/* Now reset the ESP chip */
|
||||||
scsi_esp_cmd(esp, ESP_CMD_RC);
|
scsi_esp_cmd(esp, ESP_CMD_RC);
|
||||||
scsi_esp_cmd(esp, ESP_CMD_NULL | ESP_CMD_DMA);
|
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);
|
esp->max_period = ((35 * esp->ccycle) / 1000);
|
||||||
if (esp->rev == FAST) {
|
if (esp->rev == FAST) {
|
||||||
version = esp_read8(ESP_UID);
|
u8 family_code = ESP_FAMILY(esp_read8(ESP_UID));
|
||||||
family_code = (version & 0xf8) >> 3;
|
|
||||||
if (family_code == 0x02)
|
if (family_code == ESP_UID_F236) {
|
||||||
esp->rev = FAS236;
|
esp->rev = FAS236;
|
||||||
else if (family_code == 0x0a)
|
} else if (family_code == ESP_UID_HME) {
|
||||||
esp->rev = FASHME; /* Version is usually '5'. */
|
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->rev = FAS100A;
|
||||||
|
}
|
||||||
esp->min_period = ((4 * esp->ccycle) / 1000);
|
esp->min_period = ((4 * esp->ccycle) / 1000);
|
||||||
} else {
|
} else {
|
||||||
esp->min_period = ((5 * esp->ccycle) / 1000);
|
esp->min_period = ((5 * esp->ccycle) / 1000);
|
||||||
@@ -308,7 +311,7 @@ static void esp_reset_esp(struct esp *esp)
|
|||||||
|
|
||||||
case FAS236:
|
case FAS236:
|
||||||
case PCSCSI:
|
case PCSCSI:
|
||||||
/* Fast 236, AM53c974 or HME */
|
case FSC:
|
||||||
esp_write8(esp->config2, ESP_CFG2);
|
esp_write8(esp->config2, ESP_CFG2);
|
||||||
if (esp->rev == FASHME) {
|
if (esp->rev == FASHME) {
|
||||||
u8 cfg3 = esp->target[0].esp_config3;
|
u8 cfg3 = esp->target[0].esp_config3;
|
||||||
@@ -2373,10 +2376,11 @@ static const char *esp_chip_names[] = {
|
|||||||
"ESP100A",
|
"ESP100A",
|
||||||
"ESP236",
|
"ESP236",
|
||||||
"FAS236",
|
"FAS236",
|
||||||
|
"AM53C974",
|
||||||
|
"53CF9x-2",
|
||||||
"FAS100A",
|
"FAS100A",
|
||||||
"FAST",
|
"FAST",
|
||||||
"FASHME",
|
"FASHME",
|
||||||
"AM53C974",
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct scsi_transport_template *esp_transport_template;
|
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_IMS 0x80 /* ID msg chk'ng (esp/fas236) */
|
||||||
#define ESP_CONFIG3_OBPUSH 0x80 /* Push odd-byte to dma (hme) */
|
#define ESP_CONFIG3_OBPUSH 0x80 /* Push odd-byte to dma (hme) */
|
||||||
|
|
||||||
/* ESP config register 4 read-write, found only on am53c974 chips */
|
/* ESP config register 4 read-write */
|
||||||
#define ESP_CONFIG4_RADE 0x04 /* Active negation */
|
#define ESP_CONFIG4_BBTE 0x01 /* Back-to-back transfers (fsc) */
|
||||||
#define ESP_CONFIG4_RAE 0x08 /* Active negation on REQ and ACK */
|
#define ESP_CONGIG4_TEST 0x02 /* Transfer counter test mode (fsc) */
|
||||||
#define ESP_CONFIG4_PWD 0x20 /* Reduced power feature */
|
#define ESP_CONFIG4_RADE 0x04 /* Active negation (am53c974/fsc) */
|
||||||
#define ESP_CONFIG4_GE0 0x40 /* Glitch eater bit 0 */
|
#define ESP_CONFIG4_RAE 0x08 /* Act. negation REQ/ACK (am53c974) */
|
||||||
#define ESP_CONFIG4_GE1 0x80 /* Glitch eater bit 1 */
|
#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_12NS (0)
|
||||||
#define ESP_CONFIG_GE_25NS (ESP_CONFIG_GE1)
|
#define ESP_CONFIG_GE_25NS (ESP_CONFIG_GE1)
|
||||||
@@ -209,10 +211,15 @@
|
|||||||
#define ESP_TEST_TS 0x04 /* Tristate test mode */
|
#define ESP_TEST_TS 0x04 /* Tristate test mode */
|
||||||
|
|
||||||
/* ESP unique ID register read-only, found on fas236+fas100a only */
|
/* 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_F100A 0x00 /* ESP FAS100A */
|
||||||
#define ESP_UID_F236 0x02 /* ESP FAS236 */
|
#define ESP_UID_F236 0x02 /* ESP FAS236 */
|
||||||
#define ESP_UID_REV 0x07 /* ESP revision */
|
#define ESP_UID_HME 0x0a /* FAS HME */
|
||||||
#define ESP_UID_FAM 0xf8 /* ESP family */
|
#define ESP_UID_FSC 0x14 /* NCR/Symbios Logic 53CF9x-2 */
|
||||||
|
|
||||||
/* ESP fifo flags register read-only */
|
/* ESP fifo flags register read-only */
|
||||||
/* Note that the following implies a 16 byte FIFO on the ESP. */
|
/* 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))
|
#define ESP_CMD_PRIV(CMD) ((struct esp_cmd_priv *)(&(CMD)->SCp))
|
||||||
|
|
||||||
|
/* NOTE: this enum is ordered based on chip features! */
|
||||||
enum esp_rev {
|
enum esp_rev {
|
||||||
ESP100 = 0x00, /* NCR53C90 - very broken */
|
ESP100, /* NCR53C90 - very broken */
|
||||||
ESP100A = 0x01, /* NCR53C90A */
|
ESP100A, /* NCR53C90A */
|
||||||
ESP236 = 0x02,
|
ESP236,
|
||||||
FAS236 = 0x03,
|
FAS236,
|
||||||
FAS100A = 0x04,
|
PCSCSI, /* AM53c974 */
|
||||||
FAST = 0x05,
|
FSC, /* NCR/Symbios Logic 53CF9x-2 */
|
||||||
FASHME = 0x06,
|
FAS100A,
|
||||||
PCSCSI = 0x07, /* AM53c974 */
|
FAST,
|
||||||
|
FASHME,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct esp_cmd_entry {
|
struct esp_cmd_entry {
|
||||||
|
|||||||
@@ -180,10 +180,10 @@ struct hisi_sas_port {
|
|||||||
|
|
||||||
struct hisi_sas_cq {
|
struct hisi_sas_cq {
|
||||||
struct hisi_hba *hisi_hba;
|
struct hisi_hba *hisi_hba;
|
||||||
const struct cpumask *pci_irq_mask;
|
const struct cpumask *irq_mask;
|
||||||
struct tasklet_struct tasklet;
|
|
||||||
int rd_point;
|
int rd_point;
|
||||||
int id;
|
int id;
|
||||||
|
int irq_no;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct hisi_sas_dq {
|
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_init_mem(struct hisi_hba *hisi_hba);
|
||||||
extern void hisi_sas_rst_work_handler(struct work_struct *work);
|
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_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 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,
|
extern bool hisi_sas_notify_phy_event(struct hisi_sas_phy *phy,
|
||||||
enum hisi_sas_phy_event event);
|
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)
|
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 ||
|
if (hisi_hba->hw->slot_index_alloc ||
|
||||||
slot_idx >= HISI_SAS_UNRESERVED_IPTT) {
|
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);
|
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;
|
int index;
|
||||||
void *bitmap = hisi_hba->slot_index_tags;
|
void *bitmap = hisi_hba->slot_index_tags;
|
||||||
unsigned long flags;
|
|
||||||
|
|
||||||
if (scsi_cmnd)
|
if (scsi_cmnd)
|
||||||
return scsi_cmnd->request->tag;
|
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,
|
index = find_next_zero_bit(bitmap, hisi_hba->slot_index_count,
|
||||||
hisi_hba->last_slot_index + 1);
|
hisi_hba->last_slot_index + 1);
|
||||||
if (index >= hisi_hba->slot_index_count) {
|
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_hba->slot_index_count,
|
||||||
HISI_SAS_UNRESERVED_IPTT);
|
HISI_SAS_UNRESERVED_IPTT);
|
||||||
if (index >= hisi_hba->slot_index_count) {
|
if (index >= hisi_hba->slot_index_count) {
|
||||||
spin_unlock_irqrestore(&hisi_hba->lock, flags);
|
spin_unlock(&hisi_hba->lock);
|
||||||
return -SAS_QUEUE_FULL;
|
return -SAS_QUEUE_FULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
hisi_sas_slot_index_set(hisi_hba, index);
|
hisi_sas_slot_index_set(hisi_hba, index);
|
||||||
hisi_hba->last_slot_index = index;
|
hisi_hba->last_slot_index = index;
|
||||||
spin_unlock_irqrestore(&hisi_hba->lock, flags);
|
spin_unlock(&hisi_hba->lock);
|
||||||
|
|
||||||
return index;
|
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,
|
void hisi_sas_slot_task_free(struct hisi_hba *hisi_hba, struct sas_task *task,
|
||||||
struct hisi_sas_slot *slot)
|
struct hisi_sas_slot *slot)
|
||||||
{
|
{
|
||||||
unsigned long flags;
|
|
||||||
int device_id = slot->device_id;
|
int device_id = slot->device_id;
|
||||||
struct hisi_sas_device *sas_dev = &hisi_hba->devices[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);
|
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));
|
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_idx = rc;
|
||||||
slot = &hisi_hba->slot_info[slot_idx];
|
slot = &hisi_hba->slot_info[slot_idx];
|
||||||
|
|
||||||
spin_lock_irqsave(&dq->lock, flags);
|
spin_lock(&dq->lock);
|
||||||
wr_q_index = dq->wr_point;
|
wr_q_index = dq->wr_point;
|
||||||
dq->wr_point = (dq->wr_point + 1) % HISI_SAS_QUEUE_SLOTS;
|
dq->wr_point = (dq->wr_point + 1) % HISI_SAS_QUEUE_SLOTS;
|
||||||
list_add_tail(&slot->delivery, &dq->list);
|
list_add_tail(&slot->delivery, &dq->list);
|
||||||
spin_unlock_irqrestore(&dq->lock, flags);
|
spin_unlock(&dq->lock);
|
||||||
spin_lock_irqsave(&sas_dev->lock, flags);
|
spin_lock(&sas_dev->lock);
|
||||||
list_add_tail(&slot->entry, &sas_dev->list);
|
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 = dq->id;
|
||||||
dlvry_queue_slot = wr_q_index;
|
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 rc;
|
||||||
u32 pass = 0;
|
u32 pass = 0;
|
||||||
unsigned long flags;
|
|
||||||
struct hisi_hba *hisi_hba;
|
struct hisi_hba *hisi_hba;
|
||||||
struct device *dev;
|
struct device *dev;
|
||||||
struct domain_device *device = task->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);
|
dev_err(dev, "task exec: failed[%d]!\n", rc);
|
||||||
|
|
||||||
if (likely(pass)) {
|
if (likely(pass)) {
|
||||||
spin_lock_irqsave(&dq->lock, flags);
|
spin_lock(&dq->lock);
|
||||||
hisi_hba->hw->start_delivery(dq);
|
hisi_hba->hw->start_delivery(dq);
|
||||||
spin_unlock_irqrestore(&dq->lock, flags);
|
spin_unlock(&dq->lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
return rc;
|
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_hba *hisi_hba = dev_to_hisi_hba(device);
|
||||||
struct hisi_sas_device *sas_dev = NULL;
|
struct hisi_sas_device *sas_dev = NULL;
|
||||||
unsigned long flags;
|
|
||||||
int last = hisi_hba->last_dev_id;
|
int last = hisi_hba->last_dev_id;
|
||||||
int first = (hisi_hba->last_dev_id + 1) % HISI_SAS_MAX_DEVICES;
|
int first = (hisi_hba->last_dev_id + 1) % HISI_SAS_MAX_DEVICES;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
spin_lock_irqsave(&hisi_hba->lock, flags);
|
spin_lock(&hisi_hba->lock);
|
||||||
for (i = first; i != last; i %= HISI_SAS_MAX_DEVICES) {
|
for (i = first; i != last; i %= HISI_SAS_MAX_DEVICES) {
|
||||||
if (hisi_hba->devices[i].dev_type == SAS_PHY_UNUSED) {
|
if (hisi_hba->devices[i].dev_type == SAS_PHY_UNUSED) {
|
||||||
int queue = i % hisi_hba->queue_count;
|
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++;
|
i++;
|
||||||
}
|
}
|
||||||
hisi_hba->last_dev_id = i;
|
hisi_hba->last_dev_id = i;
|
||||||
spin_unlock_irqrestore(&hisi_hba->lock, flags);
|
spin_unlock(&hisi_hba->lock);
|
||||||
|
|
||||||
return sas_dev;
|
return sas_dev;
|
||||||
}
|
}
|
||||||
@@ -1233,10 +1227,10 @@ static int hisi_sas_exec_internal_tmf_task(struct domain_device *device,
|
|||||||
struct hisi_sas_cq *cq =
|
struct hisi_sas_cq *cq =
|
||||||
&hisi_hba->cq[slot->dlvry_queue];
|
&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
|
* before using task in IO completion
|
||||||
*/
|
*/
|
||||||
tasklet_kill(&cq->tasklet);
|
synchronize_irq(cq->irq_no);
|
||||||
slot->task = NULL;
|
slot->task = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1626,11 +1620,11 @@ static int hisi_sas_abort_task(struct sas_task *task)
|
|||||||
|
|
||||||
if (slot) {
|
if (slot) {
|
||||||
/*
|
/*
|
||||||
* flush tasklet to avoid free'ing task
|
* sync irq to avoid free'ing task
|
||||||
* before using task in IO completion
|
* before using task in IO completion
|
||||||
*/
|
*/
|
||||||
cq = &hisi_hba->cq[slot->dlvry_queue];
|
cq = &hisi_hba->cq[slot->dlvry_queue];
|
||||||
tasklet_kill(&cq->tasklet);
|
synchronize_irq(cq->irq_no);
|
||||||
}
|
}
|
||||||
spin_unlock_irqrestore(&task->task_state_lock, flags);
|
spin_unlock_irqrestore(&task->task_state_lock, flags);
|
||||||
rc = TMF_RESP_FUNC_COMPLETE;
|
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)) &&
|
if (((rc < 0) || (rc == TMF_RESP_FUNC_FAILED)) &&
|
||||||
task->lldd_task) {
|
task->lldd_task) {
|
||||||
/*
|
/*
|
||||||
* flush tasklet to avoid free'ing task
|
* sync irq to avoid free'ing task
|
||||||
* before using task in IO completion
|
* before using task in IO completion
|
||||||
*/
|
*/
|
||||||
tasklet_kill(&cq->tasklet);
|
synchronize_irq(cq->irq_no);
|
||||||
slot->task = NULL;
|
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_idx = rc;
|
||||||
slot = &hisi_hba->slot_info[slot_idx];
|
slot = &hisi_hba->slot_info[slot_idx];
|
||||||
|
|
||||||
spin_lock_irqsave(&dq->lock, flags);
|
spin_lock(&dq->lock);
|
||||||
wr_q_index = dq->wr_point;
|
wr_q_index = dq->wr_point;
|
||||||
dq->wr_point = (dq->wr_point + 1) % HISI_SAS_QUEUE_SLOTS;
|
dq->wr_point = (dq->wr_point + 1) % HISI_SAS_QUEUE_SLOTS;
|
||||||
list_add_tail(&slot->delivery, &dq->list);
|
list_add_tail(&slot->delivery, &dq->list);
|
||||||
spin_unlock_irqrestore(&dq->lock, flags);
|
spin_unlock(&dq->lock);
|
||||||
spin_lock_irqsave(&sas_dev->lock, flags);
|
spin_lock(&sas_dev->lock);
|
||||||
list_add_tail(&slot->entry, &sas_dev->list);
|
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 = dq->id;
|
||||||
dlvry_queue_slot = wr_q_index;
|
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);
|
spin_unlock_irqrestore(&task->task_state_lock, flags);
|
||||||
WRITE_ONCE(slot->ready, 1);
|
WRITE_ONCE(slot->ready, 1);
|
||||||
/* send abort command to the chip */
|
/* send abort command to the chip */
|
||||||
spin_lock_irqsave(&dq->lock, flags);
|
spin_lock(&dq->lock);
|
||||||
hisi_hba->hw->start_delivery(dq);
|
hisi_hba->hw->start_delivery(dq);
|
||||||
spin_unlock_irqrestore(&dq->lock, flags);
|
spin_unlock(&dq->lock);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
@@ -2076,10 +2070,10 @@ _hisi_sas_internal_task_abort(struct hisi_hba *hisi_hba,
|
|||||||
struct hisi_sas_cq *cq =
|
struct hisi_sas_cq *cq =
|
||||||
&hisi_hba->cq[slot->dlvry_queue];
|
&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
|
* before using task in IO completion
|
||||||
*/
|
*/
|
||||||
tasklet_kill(&cq->tasklet);
|
synchronize_irq(cq->irq_no);
|
||||||
slot->task = NULL;
|
slot->task = NULL;
|
||||||
}
|
}
|
||||||
dev_err(dev, "internal task abort: timeout and not done.\n");
|
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:
|
case HISI_SAS_INT_ABT_DEV:
|
||||||
for (i = 0; i < hisi_hba->cq_nvecs; i++) {
|
for (i = 0; i < hisi_hba->cq_nvecs; i++) {
|
||||||
struct hisi_sas_cq *cq = &hisi_hba->cq[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))
|
if (mask && !cpumask_intersects(cpu_online_mask, mask))
|
||||||
continue;
|
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);
|
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;
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < hisi_hba->cq_nvecs; i++) {
|
for (i = 0; i < hisi_hba->cq_nvecs; i++) {
|
||||||
struct hisi_sas_cq *cq = &hisi_hba->cq[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)
|
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_hba->debugfs_dir = debugfs_create_dir(dev_name(dev),
|
||||||
hisi_sas_debugfs_dir);
|
hisi_sas_debugfs_dir);
|
||||||
debugfs_create_file("trigger_dump", 0600,
|
debugfs_create_file("trigger_dump", 0200,
|
||||||
hisi_hba->debugfs_dir,
|
hisi_hba->debugfs_dir,
|
||||||
hisi_hba,
|
hisi_hba,
|
||||||
&hisi_sas_debugfs_trigger_dump_fops);
|
&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,
|
.eh_target_reset_handler = sas_eh_target_reset_handler,
|
||||||
.target_destroy = sas_target_destroy,
|
.target_destroy = sas_target_destroy,
|
||||||
.ioctl = sas_ioctl,
|
.ioctl = sas_ioctl,
|
||||||
|
#ifdef CONFIG_COMPAT
|
||||||
|
.compat_ioctl = sas_ioctl,
|
||||||
|
#endif
|
||||||
.shost_attrs = host_attrs_v1_hw,
|
.shost_attrs = host_attrs_v1_hw,
|
||||||
.host_reset = hisi_sas_host_reset,
|
.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;
|
struct hisi_sas_device *sas_dev = device->lldd_dev;
|
||||||
int sata_idx = sas_dev->sata_idx;
|
int sata_idx = sas_dev->sata_idx;
|
||||||
int start, end;
|
int start, end;
|
||||||
unsigned long flags;
|
|
||||||
|
|
||||||
if (!sata_dev) {
|
if (!sata_dev) {
|
||||||
/*
|
/*
|
||||||
@@ -797,12 +796,12 @@ slot_index_alloc_quirk_v2_hw(struct hisi_hba *hisi_hba,
|
|||||||
end = 64 * (sata_idx + 2);
|
end = 64 * (sata_idx + 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
spin_lock_irqsave(&hisi_hba->lock, flags);
|
spin_lock(&hisi_hba->lock);
|
||||||
while (1) {
|
while (1) {
|
||||||
start = find_next_zero_bit(bitmap,
|
start = find_next_zero_bit(bitmap,
|
||||||
hisi_hba->slot_index_count, start);
|
hisi_hba->slot_index_count, start);
|
||||||
if (start >= end) {
|
if (start >= end) {
|
||||||
spin_unlock_irqrestore(&hisi_hba->lock, flags);
|
spin_unlock(&hisi_hba->lock);
|
||||||
return -SAS_QUEUE_FULL;
|
return -SAS_QUEUE_FULL;
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
@@ -814,7 +813,7 @@ slot_index_alloc_quirk_v2_hw(struct hisi_hba *hisi_hba,
|
|||||||
}
|
}
|
||||||
|
|
||||||
set_bit(start, bitmap);
|
set_bit(start, bitmap);
|
||||||
spin_unlock_irqrestore(&hisi_hba->lock, flags);
|
spin_unlock(&hisi_hba->lock);
|
||||||
return start;
|
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;
|
struct hisi_sas_device *sas_dev = NULL;
|
||||||
int i, sata_dev = dev_is_sata(device);
|
int i, sata_dev = dev_is_sata(device);
|
||||||
int sata_idx = -1;
|
int sata_idx = -1;
|
||||||
unsigned long flags;
|
|
||||||
|
|
||||||
spin_lock_irqsave(&hisi_hba->lock, flags);
|
spin_lock(&hisi_hba->lock);
|
||||||
|
|
||||||
if (sata_dev)
|
if (sata_dev)
|
||||||
if (!sata_index_alloc_v2_hw(hisi_hba, &sata_idx))
|
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:
|
out:
|
||||||
spin_unlock_irqrestore(&hisi_hba->lock, flags);
|
spin_unlock(&hisi_hba->lock);
|
||||||
|
|
||||||
return sas_dev;
|
return sas_dev;
|
||||||
}
|
}
|
||||||
@@ -3111,9 +3109,9 @@ static irqreturn_t fatal_axi_int_v2_hw(int irq_no, void *p)
|
|||||||
return IRQ_HANDLED;
|
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_hba *hisi_hba = cq->hisi_hba;
|
||||||
struct hisi_sas_slot *slot;
|
struct hisi_sas_slot *slot;
|
||||||
struct hisi_sas_itct *itct;
|
struct hisi_sas_itct *itct;
|
||||||
@@ -3181,6 +3179,8 @@ static void cq_tasklet_v2_hw(unsigned long val)
|
|||||||
/* update rd_point */
|
/* update rd_point */
|
||||||
cq->rd_point = rd_point;
|
cq->rd_point = rd_point;
|
||||||
hisi_sas_write32(hisi_hba, COMPL_Q_0_RD_PTR + (0x14 * queue), 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)
|
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);
|
hisi_sas_write32(hisi_hba, OQ_INT_SRC, 1 << queue);
|
||||||
|
|
||||||
tasklet_schedule(&cq->tasklet);
|
return IRQ_WAKE_THREAD;
|
||||||
|
|
||||||
return IRQ_HANDLED;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static irqreturn_t sata_int_v2_hw(int irq_no, void *p)
|
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++) {
|
for (queue_no = 0; queue_no < hisi_hba->queue_count; queue_no++) {
|
||||||
struct hisi_sas_cq *cq = &hisi_hba->cq[queue_no];
|
struct hisi_sas_cq *cq = &hisi_hba->cq[queue_no];
|
||||||
struct tasklet_struct *t = &cq->tasklet;
|
|
||||||
|
|
||||||
irq = irq_map[queue_no + 96];
|
cq->irq_no = irq_map[queue_no + 96];
|
||||||
rc = devm_request_irq(dev, irq, cq_interrupt_v2_hw, 0,
|
rc = devm_request_threaded_irq(dev, cq->irq_no,
|
||||||
DRV_NAME " cq", cq);
|
cq_interrupt_v2_hw,
|
||||||
|
cq_thread_v2_hw, IRQF_ONESHOT,
|
||||||
|
DRV_NAME " cq", cq);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
dev_err(dev, "irq init: could not request cq interrupt %d, rc=%d\n",
|
dev_err(dev, "irq init: could not request cq interrupt %d, rc=%d\n",
|
||||||
irq, rc);
|
irq, rc);
|
||||||
rc = -ENOENT;
|
rc = -ENOENT;
|
||||||
goto err_out;
|
goto err_out;
|
||||||
}
|
}
|
||||||
tasklet_init(t, cq_tasklet_v2_hw, (unsigned long)cq);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
hisi_hba->cq_nvecs = hisi_hba->queue_count;
|
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);
|
interrupt_disable_v2_hw(hisi_hba);
|
||||||
hisi_sas_write32(hisi_hba, DLVRY_QUEUE_ENABLE, 0x0);
|
hisi_sas_write32(hisi_hba, DLVRY_QUEUE_ENABLE, 0x0);
|
||||||
hisi_sas_kill_tasklets(hisi_hba);
|
|
||||||
|
|
||||||
hisi_sas_stop_phys(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,
|
.eh_target_reset_handler = sas_eh_target_reset_handler,
|
||||||
.target_destroy = sas_target_destroy,
|
.target_destroy = sas_target_destroy,
|
||||||
.ioctl = sas_ioctl,
|
.ioctl = sas_ioctl,
|
||||||
|
#ifdef CONFIG_COMPAT
|
||||||
|
.compat_ioctl = sas_ioctl,
|
||||||
|
#endif
|
||||||
.shost_attrs = host_attrs_v2_hw,
|
.shost_attrs = host_attrs_v2_hw,
|
||||||
.host_reset = hisi_sas_host_reset,
|
.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)
|
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);
|
return hisi_sas_remove(pdev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -495,6 +495,13 @@ struct hisi_sas_err_record_v3 {
|
|||||||
#define BASE_VECTORS_V3_HW 16
|
#define BASE_VECTORS_V3_HW 16
|
||||||
#define MIN_AFFINE_VECTORS_V3_HW (BASE_VECTORS_V3_HW + 1)
|
#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 {
|
enum {
|
||||||
DSM_FUNC_ERR_HANDLE_MSI = 0,
|
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;
|
int phy_no = 0;
|
||||||
|
|
||||||
irq_msk = hisi_sas_read32(hisi_hba, CHNL_INT_STATUS)
|
irq_msk = hisi_sas_read32(hisi_hba, CHNL_INT_STATUS)
|
||||||
& 0xeeeeeeee;
|
& CHNL_INT_STS_MSK;
|
||||||
|
|
||||||
while (irq_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);
|
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);
|
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);
|
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++;
|
phy_no++;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2299,9 +2306,9 @@ out:
|
|||||||
return sts;
|
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_hba *hisi_hba = cq->hisi_hba;
|
||||||
struct hisi_sas_slot *slot;
|
struct hisi_sas_slot *slot;
|
||||||
struct hisi_sas_complete_v3_hdr *complete_queue;
|
struct hisi_sas_complete_v3_hdr *complete_queue;
|
||||||
@@ -2338,6 +2345,8 @@ static void cq_tasklet_v3_hw(unsigned long val)
|
|||||||
/* update rd_point */
|
/* update rd_point */
|
||||||
cq->rd_point = rd_point;
|
cq->rd_point = rd_point;
|
||||||
hisi_sas_write32(hisi_hba, COMPL_Q_0_RD_PTR + (0x14 * queue), 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)
|
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);
|
hisi_sas_write32(hisi_hba, OQ_INT_SRC, 1 << queue);
|
||||||
|
|
||||||
tasklet_schedule(&cq->tasklet);
|
return IRQ_WAKE_THREAD;
|
||||||
|
|
||||||
return IRQ_HANDLED;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void setup_reply_map_v3_hw(struct hisi_hba *hisi_hba, int nvecs)
|
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);
|
BASE_VECTORS_V3_HW);
|
||||||
if (!mask)
|
if (!mask)
|
||||||
goto fallback;
|
goto fallback;
|
||||||
cq->pci_irq_mask = mask;
|
cq->irq_mask = mask;
|
||||||
for_each_cpu(cpu, mask)
|
for_each_cpu(cpu, mask)
|
||||||
hisi_hba->reply_map[cpu] = queue;
|
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,
|
.pre_vectors = BASE_VECTORS_V3_HW,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
dev_info(dev, "Enable MSI auto-affinity\n");
|
||||||
|
|
||||||
min_msi = MIN_AFFINE_VECTORS_V3_HW;
|
min_msi = MIN_AFFINE_VECTORS_V3_HW;
|
||||||
|
|
||||||
hisi_hba->reply_map = devm_kcalloc(dev, nr_cpu_ids,
|
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;
|
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++) {
|
for (i = 0; i < hisi_hba->cq_nvecs; i++) {
|
||||||
struct hisi_sas_cq *cq = &hisi_hba->cq[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;
|
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->irq_no = pci_irq_vector(pdev, nr);
|
||||||
cq_interrupt_v3_hw, irqflags,
|
rc = devm_request_threaded_irq(dev, cq->irq_no,
|
||||||
|
cq_interrupt_v3_hw,
|
||||||
|
cq_thread_v3_hw,
|
||||||
|
irqflags,
|
||||||
DRV_NAME " cq", cq);
|
DRV_NAME " cq", cq);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
dev_err(dev, "could not request cq%d interrupt, rc=%d\n",
|
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;
|
rc = -ENOENT;
|
||||||
goto free_irq_vectors;
|
goto free_irq_vectors;
|
||||||
}
|
}
|
||||||
|
|
||||||
tasklet_init(t, cq_tasklet_v3_hw, (unsigned long)cq);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@@ -2534,7 +2546,6 @@ static int disable_host_v3_hw(struct hisi_hba *hisi_hba)
|
|||||||
|
|
||||||
interrupt_disable_v3_hw(hisi_hba);
|
interrupt_disable_v3_hw(hisi_hba);
|
||||||
hisi_sas_write32(hisi_hba, DLVRY_QUEUE_ENABLE, 0x0);
|
hisi_sas_write32(hisi_hba, DLVRY_QUEUE_ENABLE, 0x0);
|
||||||
hisi_sas_kill_tasklets(hisi_hba);
|
|
||||||
|
|
||||||
hisi_sas_stop_phys(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);
|
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)
|
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,
|
.eh_target_reset_handler = sas_eh_target_reset_handler,
|
||||||
.target_destroy = sas_target_destroy,
|
.target_destroy = sas_target_destroy,
|
||||||
.ioctl = sas_ioctl,
|
.ioctl = sas_ioctl,
|
||||||
|
#ifdef CONFIG_COMPAT
|
||||||
|
.compat_ioctl = sas_ioctl,
|
||||||
|
#endif
|
||||||
.shost_attrs = host_attrs_v3_hw,
|
.shost_attrs = host_attrs_v3_hw,
|
||||||
.tag_alloc_policy = BLK_TAG_ALLOC_RR,
|
.tag_alloc_policy = BLK_TAG_ALLOC_RR,
|
||||||
.host_reset = hisi_sas_host_reset,
|
.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);
|
sas_remove_host(sha->core.shost);
|
||||||
|
|
||||||
hisi_sas_v3_destroy_irqs(pdev, hisi_hba);
|
hisi_sas_v3_destroy_irqs(pdev, hisi_hba);
|
||||||
hisi_sas_kill_tasklets(hisi_hba);
|
|
||||||
pci_release_regions(pdev);
|
pci_release_regions(pdev);
|
||||||
pci_disable_device(pdev);
|
pci_disable_device(pdev);
|
||||||
hisi_sas_free(hisi_hba);
|
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 viosrp_crq *crq = (struct viosrp_crq *)&msg_hi;
|
||||||
struct ibmvscsis_cmd *cmd, *nxt;
|
struct ibmvscsis_cmd *cmd, *nxt;
|
||||||
struct iu_entry *iue;
|
|
||||||
long rc = ADAPT_SUCCESS;
|
long rc = ADAPT_SUCCESS;
|
||||||
bool retry = false;
|
bool retry = false;
|
||||||
|
|
||||||
@@ -1931,8 +1930,6 @@ static void ibmvscsis_send_messages(struct scsi_info *vscsi)
|
|||||||
*/
|
*/
|
||||||
vscsi->credit += 1;
|
vscsi->credit += 1;
|
||||||
} else {
|
} else {
|
||||||
iue = cmd->iue;
|
|
||||||
|
|
||||||
crq->valid = VALID_CMD_RESP_EL;
|
crq->valid = VALID_CMD_RESP_EL;
|
||||||
crq->format = cmd->rsp.format;
|
crq->format = cmd->rsp.format;
|
||||||
|
|
||||||
@@ -3796,7 +3793,6 @@ static int ibmvscsis_queue_data_in(struct se_cmd *se_cmd)
|
|||||||
se_cmd);
|
se_cmd);
|
||||||
struct iu_entry *iue = cmd->iue;
|
struct iu_entry *iue = cmd->iue;
|
||||||
struct scsi_info *vscsi = cmd->adapter;
|
struct scsi_info *vscsi = cmd->adapter;
|
||||||
char *sd;
|
|
||||||
uint len = 0;
|
uint len = 0;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
@@ -3804,7 +3800,6 @@ static int ibmvscsis_queue_data_in(struct se_cmd *se_cmd)
|
|||||||
1);
|
1);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
dev_err(&vscsi->dev, "srp_transfer_data failed: %d\n", rc);
|
dev_err(&vscsi->dev, "srp_transfer_data failed: %d\n", rc);
|
||||||
sd = se_cmd->sense_buffer;
|
|
||||||
se_cmd->scsi_sense_length = 18;
|
se_cmd->scsi_sense_length = 18;
|
||||||
memset(se_cmd->sense_buffer, 0, se_cmd->scsi_sense_length);
|
memset(se_cmd->sense_buffer, 0, se_cmd->scsi_sense_length);
|
||||||
/* Logical Unit Communication Time-out asc/ascq = 0x0801 */
|
/* 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;
|
int cnt, i;
|
||||||
|
|
||||||
|
|||||||
@@ -6727,6 +6727,9 @@ static struct scsi_host_template driver_template = {
|
|||||||
.name = "IPR",
|
.name = "IPR",
|
||||||
.info = ipr_ioa_info,
|
.info = ipr_ioa_info,
|
||||||
.ioctl = ipr_ioctl,
|
.ioctl = ipr_ioctl,
|
||||||
|
#ifdef CONFIG_COMPAT
|
||||||
|
.compat_ioctl = ipr_ioctl,
|
||||||
|
#endif
|
||||||
.queuecommand = ipr_queuecommand,
|
.queuecommand = ipr_queuecommand,
|
||||||
.eh_abort_handler = ipr_eh_abort,
|
.eh_abort_handler = ipr_eh_abort,
|
||||||
.eh_device_reset_handler = ipr_eh_dev_reset,
|
.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,
|
.eh_target_reset_handler = sas_eh_target_reset_handler,
|
||||||
.target_destroy = sas_target_destroy,
|
.target_destroy = sas_target_destroy,
|
||||||
.ioctl = sas_ioctl,
|
.ioctl = sas_ioctl,
|
||||||
|
#ifdef CONFIG_COMPAT
|
||||||
|
.compat_ioctl = sas_ioctl,
|
||||||
|
#endif
|
||||||
.shost_attrs = isci_host_attrs,
|
.shost_attrs = isci_host_attrs,
|
||||||
.track_queue_depth = 1,
|
.track_queue_depth = 1,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -887,6 +887,10 @@ free_host:
|
|||||||
static void iscsi_sw_tcp_session_destroy(struct iscsi_cls_session *cls_session)
|
static void iscsi_sw_tcp_session_destroy(struct iscsi_cls_session *cls_session)
|
||||||
{
|
{
|
||||||
struct Scsi_Host *shost = iscsi_session_to_shost(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_tcp_r2tpool_free(cls_session->dd_data);
|
||||||
iscsi_session_teardown(cls_session);
|
iscsi_session_teardown(cls_session);
|
||||||
|
|||||||
@@ -137,7 +137,7 @@ static void sas_ata_task_done(struct sas_task *task)
|
|||||||
} else {
|
} else {
|
||||||
ac = sas_to_ata_err(stat);
|
ac = sas_to_ata_err(stat);
|
||||||
if (ac) {
|
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. */
|
/* We saw a SAS error. Send a vague error. */
|
||||||
if (!link->sactive) {
|
if (!link->sactive) {
|
||||||
qc->err_mask = ac;
|
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);
|
res = i->dft->lldd_dev_found(dev);
|
||||||
if (res) {
|
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),
|
dev_name(sas_ha->dev),
|
||||||
SAS_ADDR(dev->sas_addr), res);
|
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);
|
ex_assign_report_general(dev, rg_resp);
|
||||||
|
|
||||||
if (dev->ex_dev.configuring) {
|
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));
|
SAS_ADDR(dev->sas_addr));
|
||||||
schedule_timeout_interruptible(5*HZ);
|
schedule_timeout_interruptible(5*HZ);
|
||||||
} else
|
} else
|
||||||
@@ -881,7 +881,7 @@ static struct domain_device *sas_ex_discover_end_dev(
|
|||||||
|
|
||||||
res = sas_discover_end_dev(child);
|
res = sas_discover_end_dev(child);
|
||||||
if (res) {
|
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(child->sas_addr),
|
||||||
SAS_ADDR(parent->sas_addr), phy_id, res);
|
SAS_ADDR(parent->sas_addr), phy_id, res);
|
||||||
goto out_list_del;
|
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)
|
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" :
|
func, dev->parent ? "exp-attached" :
|
||||||
"direct-attached",
|
"direct-attached",
|
||||||
SAS_ADDR(dev->sas_addr), err);
|
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);
|
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),
|
dev_name(&phy->phy->dev), dev_name(&port->port->dev),
|
||||||
port->phy_mask,
|
port->phy_mask,
|
||||||
SAS_ADDR(port->attached_sas_addr));
|
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);
|
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),
|
SAS_ADDR(dev->sas_addr),
|
||||||
cmd->device->lun);
|
cmd->device->lun);
|
||||||
|
|
||||||
@@ -615,7 +615,7 @@ static void sas_eh_handle_sas_errors(struct Scsi_Host *shost, struct list_head *
|
|||||||
reset:
|
reset:
|
||||||
tmf_resp = sas_recover_lu(task->dev, cmd);
|
tmf_resp = sas_recover_lu(task->dev, cmd);
|
||||||
if (tmf_resp == TMF_RESP_FUNC_COMPLETE) {
|
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),
|
SAS_ADDR(task->dev),
|
||||||
cmd->device->lun);
|
cmd->device->lun);
|
||||||
sas_eh_finish_cmd(cmd);
|
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
|
* of effort could recover from errors. Quite
|
||||||
* possibly the HA just disappeared.
|
* 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),
|
SAS_ADDR(task->dev->sas_addr),
|
||||||
cmd->device->lun);
|
cmd->device->lun);
|
||||||
|
|
||||||
@@ -851,7 +851,7 @@ int sas_slave_configure(struct scsi_device *scsi_dev)
|
|||||||
if (scsi_dev->tagged_supported) {
|
if (scsi_dev->tagged_supported) {
|
||||||
scsi_change_queue_depth(scsi_dev, SAS_DEF_QD);
|
scsi_change_queue_depth(scsi_dev, SAS_DEF_QD);
|
||||||
} else {
|
} 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);
|
SAS_ADDR(dev->sas_addr), scsi_dev->lun);
|
||||||
scsi_change_queue_depth(scsi_dev, 1);
|
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);
|
memcpy(tstat->buf, iu->sense_data, tstat->buf_valid_size);
|
||||||
|
|
||||||
if (iu->status != SAM_STAT_CHECK_CONDITION)
|
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);
|
SAS_ADDR(task->dev->sas_addr), iu->status);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -1223,6 +1223,8 @@ struct lpfc_hba {
|
|||||||
#define LPFC_POLL_HB 1 /* slowpath heartbeat */
|
#define LPFC_POLL_HB 1 /* slowpath heartbeat */
|
||||||
#define LPFC_POLL_FASTPATH 0 /* called from fastpath */
|
#define LPFC_POLL_FASTPATH 0 /* called from fastpath */
|
||||||
#define LPFC_POLL_SLOWPATH 1 /* called from slowpath */
|
#define LPFC_POLL_SLOWPATH 1 /* called from slowpath */
|
||||||
|
|
||||||
|
char os_host_name[MAXHOSTNAMELEN];
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline struct Scsi_Host *
|
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 :
|
* The 'topology' is not a configurable parameter if :
|
||||||
* - persistent topology enabled
|
* - persistent topology enabled
|
||||||
* - G7 adapters
|
* - G7/G6 with no private loop support
|
||||||
* - 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->sli4_hba.pc_sli4_params.pls &&
|
||||||
phba->pcidev->device == PCI_DEVICE_ID_LANCER_G6_FC) ||
|
(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_G7_FC))) &&
|
||||||
val == 4) {
|
val == 4) {
|
||||||
lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT,
|
lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT,
|
||||||
"3114 Loop mode not supported\n");
|
"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_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_ns_cmd(struct lpfc_vport *, int, uint8_t, uint32_t);
|
||||||
int lpfc_fdmi_cmd(struct lpfc_vport *, struct lpfc_nodelist *, int, 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_tmo(struct timer_list *);
|
||||||
void lpfc_delayed_disc_timeout_handler(struct lpfc_vport *);
|
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,
|
lpfc_vport_symbolic_node_name(struct lpfc_vport *vport, char *symbol,
|
||||||
size_t size)
|
size_t size)
|
||||||
{
|
{
|
||||||
char fwrev[FW_REV_STR_SIZE];
|
char fwrev[FW_REV_STR_SIZE] = {0};
|
||||||
int n;
|
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);
|
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);
|
scnprintf(tmp, sizeof(tmp), " DV%s", lpfc_release_version);
|
||||||
if (size < n)
|
if (strlcat(symbol, tmp, size) >= size)
|
||||||
return n;
|
goto buffer_done;
|
||||||
|
|
||||||
n += scnprintf(symbol + n, size - n, " FV%s", fwrev);
|
scnprintf(tmp, sizeof(tmp), " HN:%s", vport->phba->os_host_name);
|
||||||
if (size < n)
|
if (strlcat(symbol, tmp, size) >= size)
|
||||||
return n;
|
goto buffer_done;
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
/* Note :- OS name is "Linux" */
|
/* Note :- OS name is "Linux" */
|
||||||
n += scnprintf(symbol + n, size - n, " OS:%s",
|
scnprintf(tmp, sizeof(tmp), " OS:%s", init_utsname()->sysname);
|
||||||
init_utsname()->sysname);
|
strlcat(symbol, tmp, size);
|
||||||
return n;
|
|
||||||
|
buffer_done:
|
||||||
|
return strnlen(symbol, size);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32_t
|
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.
|
* @vport: pointer to a host virtual N_Port data structure.
|
||||||
*
|
*
|
||||||
* Called from hbeat timeout routine to check if the number of discovered
|
* Check how many mapped NPorts we are connected to
|
||||||
* ports has changed. If so, re-register thar port Attribute.
|
* Check if our hostname changed
|
||||||
|
* Called from hbeat timeout routine to check if any FDMI parameters
|
||||||
|
* changed. If so, re-register those Attributes.
|
||||||
*/
|
*/
|
||||||
void
|
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_hba *phba = vport->phba;
|
||||||
struct lpfc_nodelist *ndlp;
|
struct lpfc_nodelist *ndlp;
|
||||||
@@ -2018,17 +2022,41 @@ lpfc_fdmi_num_disc_check(struct lpfc_vport *vport)
|
|||||||
if (!(vport->fc_flag & FC_FABRIC))
|
if (!(vport->fc_flag & FC_FABRIC))
|
||||||
return;
|
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))
|
if (!(vport->fdmi_port_mask & LPFC_FDMI_PORT_ATTR_num_disc))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
/* Check if the number of mapped NPorts changed */
|
||||||
cnt = lpfc_find_map_node(vport);
|
cnt = lpfc_find_map_node(vport);
|
||||||
if (cnt == vport->fdmi_num_disc)
|
if (cnt == vport->fdmi_num_disc)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
ndlp = lpfc_findnode_did(vport, FDMI_DID);
|
|
||||||
if (!ndlp || !NLP_CHK_NODE_ACT(ndlp))
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (vport->port_type == LPFC_PHYSICAL_PORT) {
|
if (vport->port_type == LPFC_PHYSICAL_PORT) {
|
||||||
lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_RPA,
|
lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_RPA,
|
||||||
LPFC_FDMI_PORT_ATTR_num_disc);
|
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;
|
ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
|
||||||
memset(ae, 0, 256);
|
memset(ae, 0, 256);
|
||||||
|
|
||||||
snprintf(ae->un.AttrString, sizeof(ae->un.AttrString), "%s",
|
scnprintf(ae->un.AttrString, sizeof(ae->un.AttrString), "%s",
|
||||||
init_utsname()->nodename);
|
vport->phba->os_host_name);
|
||||||
|
|
||||||
len = strnlen(ae->un.AttrString, sizeof(ae->un.AttrString));
|
len = strnlen(ae->un.AttrString, sizeof(ae->un.AttrString));
|
||||||
len += (len & 3) ? (4 - (len & 3)) : 4;
|
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;
|
int copied = 0;
|
||||||
struct lpfc_dmabuf *dmabuf, *next;
|
struct lpfc_dmabuf *dmabuf, *next;
|
||||||
|
|
||||||
|
memset(buffer, 0, size);
|
||||||
|
|
||||||
spin_lock_irq(&phba->hbalock);
|
spin_lock_irq(&phba->hbalock);
|
||||||
if (phba->ras_fwlog.state != ACTIVE) {
|
if (phba->ras_fwlog.state != ACTIVE) {
|
||||||
spin_unlock_irq(&phba->hbalock);
|
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,
|
list_for_each_entry_safe(dmabuf, next,
|
||||||
&phba->ras_fwlog.fwlog_buff_list, list) {
|
&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);
|
memcpy(buffer + copied, dmabuf->virt, LPFC_RAS_MAX_ENTRY_SIZE);
|
||||||
copied += LPFC_RAS_MAX_ENTRY_SIZE;
|
copied += LPFC_RAS_MAX_ENTRY_SIZE;
|
||||||
if (size > copied)
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
return copied;
|
return copied;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,6 +28,7 @@
|
|||||||
#include <linux/kthread.h>
|
#include <linux/kthread.h>
|
||||||
#include <linux/interrupt.h>
|
#include <linux/interrupt.h>
|
||||||
#include <linux/lockdep.h>
|
#include <linux/lockdep.h>
|
||||||
|
#include <linux/utsname.h>
|
||||||
|
|
||||||
#include <scsi/scsi.h>
|
#include <scsi/scsi.h>
|
||||||
#include <scsi/scsi_device.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);
|
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;
|
return;
|
||||||
out:
|
out:
|
||||||
lpfc_vport_set_state(vport, FC_VPORT_FAILED);
|
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_FW_RESET 0x02
|
||||||
#define LPFC_CHANGE_STATUS_PORT_MIGRATION 0x04
|
#define LPFC_CHANGE_STATUS_PORT_MIGRATION 0x04
|
||||||
#define LPFC_CHANGE_STATUS_PCI_RESET 0x05
|
#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;
|
} response;
|
||||||
} u;
|
} u;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1362,7 +1362,7 @@ lpfc_hb_timeout_handler(struct lpfc_hba *phba)
|
|||||||
if (vports != NULL)
|
if (vports != NULL)
|
||||||
for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) {
|
for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) {
|
||||||
lpfc_rcv_seq_check_edtov(vports[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);
|
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;
|
phba->hba_flag |= HBA_PERSISTENT_TOPO;
|
||||||
switch (phba->pcidev->device) {
|
switch (phba->pcidev->device) {
|
||||||
case PCI_DEVICE_ID_LANCER_G7_FC:
|
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:
|
case PCI_DEVICE_ID_LANCER_G6_FC:
|
||||||
if (!tf) {
|
if (!tf) {
|
||||||
phba->cfg_topology = ((pt == LINK_FLAGS_LOOP)
|
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:
|
case LPFC_SLI_INTF_IF_TYPE_6:
|
||||||
iounmap(phba->sli4_hba.drbl_regs_memmap_p);
|
iounmap(phba->sli4_hba.drbl_regs_memmap_p);
|
||||||
iounmap(phba->sli4_hba.conf_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;
|
break;
|
||||||
case LPFC_SLI_INTF_IF_TYPE_1:
|
case LPFC_SLI_INTF_IF_TYPE_1:
|
||||||
default:
|
default:
|
||||||
|
|||||||
@@ -308,7 +308,7 @@ lpfc_defer_pt2pt_acc(struct lpfc_hba *phba, LPFC_MBOXQ_t *link_mbox)
|
|||||||
mb->mbxStatus);
|
mb->mbxStatus);
|
||||||
mempool_free(login_mbox, phba->mbox_mem_pool);
|
mempool_free(login_mbox, phba->mbox_mem_pool);
|
||||||
mempool_free(link_mbox, phba->mbox_mem_pool);
|
mempool_free(link_mbox, phba->mbox_mem_pool);
|
||||||
lpfc_sli_release_iocbq(phba, save_iocb);
|
kfree(save_iocb);
|
||||||
return;
|
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);
|
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
|
static int
|
||||||
@@ -345,6 +399,7 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
|
|||||||
struct lpfc_iocbq *save_iocb;
|
struct lpfc_iocbq *save_iocb;
|
||||||
struct ls_rjt stat;
|
struct ls_rjt stat;
|
||||||
uint32_t vid, flag;
|
uint32_t vid, flag;
|
||||||
|
u16 rpi;
|
||||||
int rc, defer_acc;
|
int rc, defer_acc;
|
||||||
|
|
||||||
memset(&stat, 0, sizeof (struct ls_rjt));
|
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->vport = vport;
|
||||||
link_mbox->ctx_ndlp = ndlp;
|
link_mbox->ctx_ndlp = ndlp;
|
||||||
|
|
||||||
save_iocb = lpfc_sli_get_iocbq(phba);
|
save_iocb = kzalloc(sizeof(*save_iocb), GFP_KERNEL);
|
||||||
if (!save_iocb)
|
if (!save_iocb)
|
||||||
goto out;
|
goto out;
|
||||||
/* Save info from cmd IOCB used in rsp */
|
/* 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;
|
goto out;
|
||||||
|
|
||||||
/* Registering an existing RPI behaves differently for SLI3 vs SLI4 */
|
/* 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);
|
lpfc_unreg_rpi(vport, ndlp);
|
||||||
|
|
||||||
rc = lpfc_reg_rpi(phba, vport->vpi, icmd->un.rcvels.remoteID,
|
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 &&
|
if ((vport->port_type == LPFC_NPIV_PORT &&
|
||||||
vport->cfg_restrict_login)) {
|
vport->cfg_restrict_login)) {
|
||||||
|
|
||||||
|
/* no deferred ACC */
|
||||||
|
kfree(save_iocb);
|
||||||
|
|
||||||
/* In order to preserve RPIs, we want to cleanup
|
/* In order to preserve RPIs, we want to cleanup
|
||||||
* the default RPI the firmware created to rcv
|
* the default RPI the firmware created to rcv
|
||||||
* this ELS request. The only way to do this is
|
* 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) {
|
if (defer_acc) {
|
||||||
/* So the order here should be:
|
/* So the order here should be:
|
||||||
* Issue CONFIG_LINK mbox
|
* SLI3 pt2pt
|
||||||
* CONFIG_LINK cmpl
|
* Issue CONFIG_LINK mbox
|
||||||
|
* CONFIG_LINK cmpl
|
||||||
|
* SLI4 tgt
|
||||||
|
* Issue UNREG RPI mbx
|
||||||
|
* UNREG RPI cmpl
|
||||||
* Issue PLOGI ACC
|
* Issue PLOGI ACC
|
||||||
* PLOGI ACC cmpl
|
* PLOGI ACC cmpl
|
||||||
* Issue REG_LOGIN mbox
|
* Issue REG_LOGIN mbox
|
||||||
@@ -596,10 +687,9 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
|
|||||||
out:
|
out:
|
||||||
if (defer_acc)
|
if (defer_acc)
|
||||||
lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
|
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);
|
save_iocb, link_mbox, login_mbox);
|
||||||
if (save_iocb)
|
kfree(save_iocb);
|
||||||
lpfc_sli_release_iocbq(phba, save_iocb);
|
|
||||||
if (link_mbox)
|
if (link_mbox)
|
||||||
mempool_free(link_mbox, phba->mbox_mem_pool);
|
mempool_free(link_mbox, phba->mbox_mem_pool);
|
||||||
if (login_mbox)
|
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);
|
spin_lock(&qp->abts_io_buf_list_lock);
|
||||||
list_for_each_entry_safe(psb, next_psb,
|
list_for_each_entry_safe(psb, next_psb,
|
||||||
&qp->lpfc_abts_io_buf_list, list) {
|
&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;
|
continue;
|
||||||
|
|
||||||
if (psb->rdata && psb->rdata->pnode &&
|
if (psb->rdata && psb->rdata->pnode &&
|
||||||
@@ -528,7 +528,7 @@ lpfc_sli4_io_xri_aborted(struct lpfc_hba *phba,
|
|||||||
list_del_init(&psb->list);
|
list_del_init(&psb->list);
|
||||||
psb->flags &= ~LPFC_SBUF_XBUSY;
|
psb->flags &= ~LPFC_SBUF_XBUSY;
|
||||||
psb->status = IOSTAT_SUCCESS;
|
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--;
|
qp->abts_nvme_io_bufs--;
|
||||||
spin_unlock(&qp->abts_io_buf_list_lock);
|
spin_unlock(&qp->abts_io_buf_list_lock);
|
||||||
spin_unlock_irqrestore(&phba->hbalock, iflag);
|
spin_unlock_irqrestore(&phba->hbalock, iflag);
|
||||||
|
|||||||
@@ -4918,8 +4918,17 @@ static int
|
|||||||
lpfc_sli4_rb_setup(struct lpfc_hba *phba)
|
lpfc_sli4_rb_setup(struct lpfc_hba *phba)
|
||||||
{
|
{
|
||||||
phba->hbq_in_use = 1;
|
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;
|
phba->hbq_count = 1;
|
||||||
lpfc_sli_hbqbuf_init_hbqs(phba, LPFC_ELS_HBQ);
|
lpfc_sli_hbqbuf_init_hbqs(phba, LPFC_ELS_HBQ);
|
||||||
/* Initially populate or replenish the HBQs */
|
/* 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;
|
struct lpfc_mbx_wr_object *wr_object;
|
||||||
LPFC_MBOXQ_t *mbox;
|
LPFC_MBOXQ_t *mbox;
|
||||||
int rc = 0, i = 0;
|
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;
|
uint32_t mbox_tmo;
|
||||||
struct lpfc_dmabuf *dmabuf;
|
struct lpfc_dmabuf *dmabuf;
|
||||||
uint32_t written = 0;
|
uint32_t written = 0;
|
||||||
@@ -19506,6 +19515,16 @@ lpfc_wr_object(struct lpfc_hba *phba, struct list_head *dmabuf_list,
|
|||||||
if (check_change_status) {
|
if (check_change_status) {
|
||||||
shdr_change_status = bf_get(lpfc_wr_object_change_status,
|
shdr_change_status = bf_get(lpfc_wr_object_change_status,
|
||||||
&wr_object->u.response);
|
&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) {
|
switch (shdr_change_status) {
|
||||||
case (LPFC_CHANGE_STATUS_PHYS_DEV_RESET):
|
case (LPFC_CHANGE_STATUS_PHYS_DEV_RESET):
|
||||||
lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
|
lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
|
||||||
|
|||||||
@@ -20,7 +20,7 @@
|
|||||||
* included with this package. *
|
* 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"
|
#define LPFC_DRIVER_NAME "lpfc"
|
||||||
|
|
||||||
/* Used for SLI 2/3 */
|
/* Used for SLI 2/3 */
|
||||||
|
|||||||
@@ -21,8 +21,8 @@
|
|||||||
/*
|
/*
|
||||||
* MegaRAID SAS Driver meta data
|
* MegaRAID SAS Driver meta data
|
||||||
*/
|
*/
|
||||||
#define MEGASAS_VERSION "07.710.50.00-rc1"
|
#define MEGASAS_VERSION "07.713.01.00-rc1"
|
||||||
#define MEGASAS_RELDATE "June 28, 2019"
|
#define MEGASAS_RELDATE "Dec 27, 2019"
|
||||||
|
|
||||||
#define MEGASAS_MSIX_NAME_LEN 32
|
#define MEGASAS_MSIX_NAME_LEN 32
|
||||||
|
|
||||||
@@ -2233,9 +2233,9 @@ enum MR_PD_TYPE {
|
|||||||
|
|
||||||
/* JBOD Queue depth definitions */
|
/* JBOD Queue depth definitions */
|
||||||
#define MEGASAS_SATA_QD 32
|
#define MEGASAS_SATA_QD 32
|
||||||
#define MEGASAS_SAS_QD 64
|
#define MEGASAS_SAS_QD 256
|
||||||
#define MEGASAS_DEFAULT_PD_QD 64
|
#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_SIZE 4096
|
||||||
#define MR_DEFAULT_NVME_PAGE_SHIFT 12
|
#define MR_DEFAULT_NVME_PAGE_SHIFT 12
|
||||||
@@ -2640,10 +2640,11 @@ enum MEGASAS_OCR_CAUSE {
|
|||||||
};
|
};
|
||||||
|
|
||||||
enum DCMD_RETURN_STATUS {
|
enum DCMD_RETURN_STATUS {
|
||||||
DCMD_SUCCESS = 0,
|
DCMD_SUCCESS = 0x00,
|
||||||
DCMD_TIMEOUT = 1,
|
DCMD_TIMEOUT = 0x01,
|
||||||
DCMD_FAILED = 2,
|
DCMD_FAILED = 0x02,
|
||||||
DCMD_NOT_FIRED = 3,
|
DCMD_BUSY = 0x03,
|
||||||
|
DCMD_INIT = 0xff,
|
||||||
};
|
};
|
||||||
|
|
||||||
u8
|
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) {
|
if (atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR) {
|
||||||
dev_err(&instance->pdev->dev, "Failed from %s %d\n",
|
dev_err(&instance->pdev->dev, "Failed from %s %d\n",
|
||||||
__func__, __LINE__);
|
__func__, __LINE__);
|
||||||
return DCMD_NOT_FIRED;
|
return DCMD_INIT;
|
||||||
}
|
}
|
||||||
|
|
||||||
instance->instancet->issue_dcmd(instance, cmd);
|
instance->instancet->issue_dcmd(instance, cmd);
|
||||||
@@ -1123,19 +1123,19 @@ megasas_issue_blocked_cmd(struct megasas_instance *instance,
|
|||||||
struct megasas_cmd *cmd, int timeout)
|
struct megasas_cmd *cmd, int timeout)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
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) {
|
if (atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR) {
|
||||||
dev_err(&instance->pdev->dev, "Failed from %s %d\n",
|
dev_err(&instance->pdev->dev, "Failed from %s %d\n",
|
||||||
__func__, __LINE__);
|
__func__, __LINE__);
|
||||||
return DCMD_NOT_FIRED;
|
return DCMD_INIT;
|
||||||
}
|
}
|
||||||
|
|
||||||
instance->instancet->issue_dcmd(instance, cmd);
|
instance->instancet->issue_dcmd(instance, cmd);
|
||||||
|
|
||||||
if (timeout) {
|
if (timeout) {
|
||||||
ret = wait_event_timeout(instance->int_cmd_wait_q,
|
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) {
|
if (!ret) {
|
||||||
dev_err(&instance->pdev->dev,
|
dev_err(&instance->pdev->dev,
|
||||||
"DCMD(opcode: 0x%x) is timed out, func:%s\n",
|
"DCMD(opcode: 0x%x) is timed out, func:%s\n",
|
||||||
@@ -1144,10 +1144,9 @@ megasas_issue_blocked_cmd(struct megasas_instance *instance,
|
|||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
wait_event(instance->int_cmd_wait_q,
|
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) ?
|
return cmd->cmd_status_drv;
|
||||||
DCMD_SUCCESS : DCMD_FAILED;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -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));
|
cpu_to_le32(upper_32_bits(cmd_to_abort->frame_phys_addr));
|
||||||
|
|
||||||
cmd->sync_cmd = 1;
|
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) {
|
if (atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR) {
|
||||||
dev_err(&instance->pdev->dev, "Failed from %s %d\n",
|
dev_err(&instance->pdev->dev, "Failed from %s %d\n",
|
||||||
__func__, __LINE__);
|
__func__, __LINE__);
|
||||||
return DCMD_NOT_FIRED;
|
return DCMD_INIT;
|
||||||
}
|
}
|
||||||
|
|
||||||
instance->instancet->issue_dcmd(instance, cmd);
|
instance->instancet->issue_dcmd(instance, cmd);
|
||||||
|
|
||||||
if (timeout) {
|
if (timeout) {
|
||||||
ret = wait_event_timeout(instance->abort_cmd_wait_q,
|
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) {
|
if (!ret) {
|
||||||
opcode = cmd_to_abort->frame->dcmd.opcode;
|
opcode = cmd_to_abort->frame->dcmd.opcode;
|
||||||
dev_err(&instance->pdev->dev,
|
dev_err(&instance->pdev->dev,
|
||||||
@@ -1212,13 +1211,12 @@ megasas_issue_blocked_abort_cmd(struct megasas_instance *instance,
|
|||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
wait_event(instance->abort_cmd_wait_q,
|
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;
|
cmd->sync_cmd = 0;
|
||||||
|
|
||||||
megasas_return_cmd(instance, cmd);
|
megasas_return_cmd(instance, cmd);
|
||||||
return (cmd->cmd_status_drv == MFI_STAT_OK) ?
|
return cmd->cmd_status_drv;
|
||||||
DCMD_SUCCESS : DCMD_FAILED;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1887,6 +1885,10 @@ void megasas_set_dynamic_target_properties(struct scsi_device *sdev,
|
|||||||
|
|
||||||
mr_device_priv_data->is_tm_capable =
|
mr_device_priv_data->is_tm_capable =
|
||||||
raid->capability.tmCapable;
|
raid->capability.tmCapable;
|
||||||
|
|
||||||
|
if (!raid->flags.isEPD)
|
||||||
|
sdev->no_write_same = 1;
|
||||||
|
|
||||||
} else if (instance->use_seqnum_jbod_fp) {
|
} else if (instance->use_seqnum_jbod_fp) {
|
||||||
pd_index = (sdev->channel * MEGASAS_MAX_DEV_PER_CHANNEL) +
|
pd_index = (sdev->channel * MEGASAS_MAX_DEV_PER_CHANNEL) +
|
||||||
sdev->id;
|
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)
|
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 */
|
/* Set critical error to block I/O & ioctls in case caller didn't */
|
||||||
atomic_set(&instance->adprecovery, MEGASAS_HW_CRITICAL_ERROR);
|
atomic_set(&instance->adprecovery, MEGASAS_HW_CRITICAL_ERROR);
|
||||||
/* Wait 1 second to ensure IO or ioctls in build have posted */
|
/* 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 queue\n",
|
||||||
reset_cmd);
|
reset_cmd);
|
||||||
|
|
||||||
reset_cmd->cmd_status_drv = MFI_STAT_INVALID_STATUS;
|
reset_cmd->cmd_status_drv = DCMD_INIT;
|
||||||
instance->instancet->fire_cmd(instance,
|
instance->instancet->fire_cmd(instance,
|
||||||
reset_cmd->frame_phys_addr,
|
reset_cmd->frame_phys_addr,
|
||||||
0, instance->reg_set);
|
0, instance->reg_set);
|
||||||
@@ -3416,7 +3424,6 @@ static struct scsi_host_template megasas_template = {
|
|||||||
.bios_param = megasas_bios_param,
|
.bios_param = megasas_bios_param,
|
||||||
.change_queue_depth = scsi_change_queue_depth,
|
.change_queue_depth = scsi_change_queue_depth,
|
||||||
.max_segment_size = 0xffffffff,
|
.max_segment_size = 0xffffffff,
|
||||||
.no_write_same = 1,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -3432,7 +3439,11 @@ static void
|
|||||||
megasas_complete_int_cmd(struct megasas_instance *instance,
|
megasas_complete_int_cmd(struct megasas_instance *instance,
|
||||||
struct megasas_cmd *cmd)
|
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);
|
wake_up(&instance->int_cmd_wait_q);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3451,7 +3462,7 @@ megasas_complete_abort(struct megasas_instance *instance,
|
|||||||
{
|
{
|
||||||
if (cmd->sync_cmd) {
|
if (cmd->sync_cmd) {
|
||||||
cmd->sync_cmd = 0;
|
cmd->sync_cmd = 0;
|
||||||
cmd->cmd_status_drv = 0;
|
cmd->cmd_status_drv = DCMD_SUCCESS;
|
||||||
wake_up(&instance->abort_cmd_wait_q);
|
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"
|
dev_notice(&instance->pdev->dev, "%p synchronous cmd"
|
||||||
"on the internal reset queue,"
|
"on the internal reset queue,"
|
||||||
"issue it again.\n", cmd);
|
"issue it again.\n", cmd);
|
||||||
cmd->cmd_status_drv = MFI_STAT_INVALID_STATUS;
|
cmd->cmd_status_drv = DCMD_INIT;
|
||||||
instance->instancet->fire_cmd(instance,
|
instance->instancet->fire_cmd(instance,
|
||||||
cmd->frame_phys_addr,
|
cmd->frame_phys_addr,
|
||||||
0, instance->reg_set);
|
0, instance->reg_set);
|
||||||
@@ -4392,7 +4403,8 @@ dcmd_timeout_ocr_possible(struct megasas_instance *instance) {
|
|||||||
if (instance->adapter_type == MFI_SERIES)
|
if (instance->adapter_type == MFI_SERIES)
|
||||||
return KILL_ADAPTER;
|
return KILL_ADAPTER;
|
||||||
else if (instance->unload ||
|
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;
|
return IGNORE_TIMEOUT;
|
||||||
else
|
else
|
||||||
return INITIATE_OCR;
|
return INITIATE_OCR;
|
||||||
@@ -7593,6 +7605,7 @@ megasas_resume(struct pci_dev *pdev)
|
|||||||
struct Scsi_Host *host;
|
struct Scsi_Host *host;
|
||||||
struct megasas_instance *instance;
|
struct megasas_instance *instance;
|
||||||
int irq_flags = PCI_IRQ_LEGACY;
|
int irq_flags = PCI_IRQ_LEGACY;
|
||||||
|
u32 status_reg;
|
||||||
|
|
||||||
instance = pci_get_drvdata(pdev);
|
instance = pci_get_drvdata(pdev);
|
||||||
|
|
||||||
@@ -7620,9 +7633,35 @@ megasas_resume(struct pci_dev *pdev)
|
|||||||
/*
|
/*
|
||||||
* We expect the FW state to be READY
|
* 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))
|
if (megasas_set_dma_mask(instance))
|
||||||
goto fail_set_dma_mask;
|
goto fail_set_dma_mask;
|
||||||
|
|
||||||
@@ -8036,6 +8075,7 @@ megasas_mgmt_fw_ioctl(struct megasas_instance *instance,
|
|||||||
dma_addr_t sense_handle;
|
dma_addr_t sense_handle;
|
||||||
unsigned long *sense_ptr;
|
unsigned long *sense_ptr;
|
||||||
u32 opcode = 0;
|
u32 opcode = 0;
|
||||||
|
int ret = DCMD_SUCCESS;
|
||||||
|
|
||||||
memset(kbuff_arr, 0, sizeof(kbuff_arr));
|
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 to the SCSI mid-layer
|
||||||
*/
|
*/
|
||||||
cmd->sync_cmd = 1;
|
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;
|
cmd->sync_cmd = 0;
|
||||||
dev_err(&instance->pdev->dev,
|
dev_err(&instance->pdev->dev,
|
||||||
"return -EBUSY from %s %d cmd 0x%x opcode 0x%x cmd->cmd_status_drv 0x%x\n",
|
"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,
|
__func__, __LINE__, cmd->frame->hdr.cmd, opcode,
|
||||||
cmd->cmd_status_drv);
|
cmd->cmd_status_drv);
|
||||||
return -EBUSY;
|
error = -EBUSY;
|
||||||
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd->sync_cmd = 0;
|
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;
|
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
|
* megasas_free_cmds_fusion - Free all the cmds in the free cmd pool
|
||||||
* @instance: Adapter soft state
|
* @instance: Adapter soft state
|
||||||
@@ -1312,7 +1341,9 @@ megasas_sync_pd_seq_num(struct megasas_instance *instance, bool pend) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (ret == DCMD_TIMEOUT)
|
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)
|
if (ret == DCMD_SUCCESS)
|
||||||
instance->pd_seq_map_id++;
|
instance->pd_seq_map_id++;
|
||||||
@@ -1394,7 +1425,9 @@ megasas_get_ld_map_info(struct megasas_instance *instance)
|
|||||||
ret = megasas_issue_polled(instance, cmd);
|
ret = megasas_issue_polled(instance, cmd);
|
||||||
|
|
||||||
if (ret == DCMD_TIMEOUT)
|
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);
|
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;
|
fp_possible = (io_info.fpOkForIo > 0) ? true : false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((instance->perf_mode == MR_BALANCED_PERF_MODE) &&
|
megasas_get_msix_index(instance, scp, cmd, io_info.data_arms);
|
||||||
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()];
|
|
||||||
|
|
||||||
if (instance->adapter_type >= VENTURA_SERIES) {
|
if (instance->adapter_type >= VENTURA_SERIES) {
|
||||||
/* FP for Optimal raid level 1.
|
/* 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;
|
cmd->request_desc->SCSIIO.DevHandle = io_request->DevHandle;
|
||||||
|
|
||||||
if ((instance->perf_mode == MR_BALANCED_PERF_MODE) &&
|
megasas_get_msix_index(instance, scmd, cmd, 1);
|
||||||
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()];
|
|
||||||
|
|
||||||
if (!fp_possible) {
|
if (!fp_possible) {
|
||||||
/* system pd firmware path */
|
/* 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
|
* megasas_refire_mgmt_cmd : Re-fire management commands
|
||||||
* @instance: Controller's soft instance
|
* @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;
|
int j;
|
||||||
struct megasas_cmd_fusion *cmd_fusion;
|
struct megasas_cmd_fusion *cmd_fusion;
|
||||||
@@ -4283,6 +4294,16 @@ static void megasas_refire_mgmt_cmd(struct megasas_instance *instance)
|
|||||||
break;
|
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) {
|
switch (result) {
|
||||||
case REFIRE_CMD:
|
case REFIRE_CMD:
|
||||||
megasas_fire_cmd_fusion(instance, req_desc);
|
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
|
* megasas_track_scsiio : Track SCSI IOs outstanding to a SCSI device
|
||||||
* @instance: per adapter struct
|
* @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)
|
if (instance->requestorId && !instance->skip_heartbeat_timer_del)
|
||||||
del_timer_sync(&instance->sriov_heartbeat_timer);
|
del_timer_sync(&instance->sriov_heartbeat_timer);
|
||||||
set_bit(MEGASAS_FUSION_IN_RESET, &instance->reset_flags);
|
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);
|
atomic_set(&instance->adprecovery, MEGASAS_ADPRESET_SM_POLLING);
|
||||||
instance->instancet->disable_intr(instance);
|
instance->instancet->disable_intr(instance);
|
||||||
megasas_sync_irqs((unsigned long)instance);
|
megasas_sync_irqs((unsigned long)instance);
|
||||||
@@ -4951,7 +5004,9 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int reason)
|
|||||||
goto kill_hba;
|
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 */
|
/* Reset load balance info */
|
||||||
if (fusion->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) *
|
(sizeof(struct LD_LOAD_BALANCE_INFO) *
|
||||||
MAX_LOGICAL_DRIVES_EXT));
|
MAX_LOGICAL_DRIVES_EXT));
|
||||||
|
|
||||||
if (!megasas_get_map_info(instance))
|
if (!megasas_get_map_info(instance)) {
|
||||||
megasas_sync_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);
|
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);
|
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);
|
atomic_set(&instance->adprecovery, MEGASAS_HBA_OPERATIONAL);
|
||||||
|
|
||||||
dev_info(&instance->pdev->dev,
|
dev_info(&instance->pdev->dev,
|
||||||
@@ -5046,7 +5118,7 @@ kill_hba:
|
|||||||
instance->skip_heartbeat_timer_del = 1;
|
instance->skip_heartbeat_timer_del = 1;
|
||||||
retval = FAILED;
|
retval = FAILED;
|
||||||
out:
|
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);
|
mutex_unlock(&instance->reset_mutex);
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -89,6 +89,7 @@ enum MR_RAID_FLAGS_IO_SUB_TYPE {
|
|||||||
|
|
||||||
#define MEGASAS_FP_CMD_LEN 16
|
#define MEGASAS_FP_CMD_LEN 16
|
||||||
#define MEGASAS_FUSION_IN_RESET 0
|
#define MEGASAS_FUSION_IN_RESET 0
|
||||||
|
#define MEGASAS_FUSION_OCR_NOT_POSSIBLE 1
|
||||||
#define RAID_1_PEER_CMDS 2
|
#define RAID_1_PEER_CMDS 2
|
||||||
#define JBOD_MAPS_COUNT 2
|
#define JBOD_MAPS_COUNT 2
|
||||||
#define MEGASAS_REDUCE_QD_COUNT 64
|
#define MEGASAS_REDUCE_QD_COUNT 64
|
||||||
@@ -864,9 +865,20 @@ struct MR_LD_RAID {
|
|||||||
u8 regTypeReqOnRead;
|
u8 regTypeReqOnRead;
|
||||||
__le16 seqNum;
|
__le16 seqNum;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
u32 ldSyncRequired:1;
|
#ifndef MFI_BIG_ENDIAN
|
||||||
u32 reserved:31;
|
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;
|
} flags;
|
||||||
|
|
||||||
u8 LUN[8]; /* 0x24 8 byte LUN field used for SCSI IO's */
|
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.
|
* 08-28-18 02.00.53 Bumped MPI2_HEADER_VERSION_UNIT.
|
||||||
* Added MPI2_IOCSTATUS_FAILURE
|
* Added MPI2_IOCSTATUS_FAILURE
|
||||||
* 12-17-18 02.00.54 Bumped MPI2_HEADER_VERSION_UNIT
|
* 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 */
|
/* 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_DEV (0x00)
|
||||||
#define MPI2_HEADER_VERSION_UNIT_MASK (0xFF00)
|
#define MPI2_HEADER_VERSION_UNIT_MASK (0xFF00)
|
||||||
#define MPI2_HEADER_VERSION_UNIT_SHIFT (8)
|
#define MPI2_HEADER_VERSION_UNIT_SHIFT (8)
|
||||||
@@ -181,6 +184,7 @@
|
|||||||
#define MPI2_IOC_STATE_READY (0x10000000)
|
#define MPI2_IOC_STATE_READY (0x10000000)
|
||||||
#define MPI2_IOC_STATE_OPERATIONAL (0x20000000)
|
#define MPI2_IOC_STATE_OPERATIONAL (0x20000000)
|
||||||
#define MPI2_IOC_STATE_FAULT (0x40000000)
|
#define MPI2_IOC_STATE_FAULT (0x40000000)
|
||||||
|
#define MPI2_IOC_STATE_COREDUMP (0x50000000)
|
||||||
|
|
||||||
#define MPI2_IOC_STATE_MASK (0xF0000000)
|
#define MPI2_IOC_STATE_MASK (0xF0000000)
|
||||||
#define MPI2_IOC_STATE_SHIFT (28)
|
#define MPI2_IOC_STATE_SHIFT (28)
|
||||||
|
|||||||
@@ -249,6 +249,8 @@
|
|||||||
* 08-28-18 02.00.46 Added NVMs Write Cache flag to IOUnitPage1
|
* 08-28-18 02.00.46 Added NVMs Write Cache flag to IOUnitPage1
|
||||||
* Added DMDReport Delay Time defines to PCIeIOUnitPage1
|
* Added DMDReport Delay Time defines to PCIeIOUnitPage1
|
||||||
* 12-17-18 02.00.47 Swap locations of Slotx2 and Slotx4 in ManPage 7.
|
* 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
|
#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_EVENTREPLAY_SLOT_ORDER (0x00000002)
|
||||||
#define MPI2_MANPAGE7_FLAG_USE_SLOT_INFO (0x00000001)
|
#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
|
*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 */
|
/* IO Unit Page 1 Flags defines */
|
||||||
#define MPI26_IOUNITPAGE1_NVME_WRCACHE_MASK (0x00030000)
|
#define MPI26_IOUNITPAGE1_NVME_WRCACHE_MASK (0x00030000)
|
||||||
#define MPI26_IOUNITPAGE1_NVME_WRCACHE_ENABLE (0x00000000)
|
#define MPI26_IOUNITPAGE1_NVME_WRCACHE_SHIFT (16)
|
||||||
#define MPI26_IOUNITPAGE1_NVME_WRCACHE_DISABLE (0x00010000)
|
#define MPI26_IOUNITPAGE1_NVME_WRCACHE_NO_CHANGE (0x00000000)
|
||||||
#define MPI26_IOUNITPAGE1_NVME_WRCACHE_NO_CHANGE (0x00020000)
|
#define MPI26_IOUNITPAGE1_NVME_WRCACHE_ENABLE (0x00010000)
|
||||||
|
#define MPI26_IOUNITPAGE1_NVME_WRCACHE_DISABLE (0x00020000)
|
||||||
#define MPI2_IOUNITPAGE1_ATA_SECURITY_FREEZE_LOCK (0x00004000)
|
#define MPI2_IOUNITPAGE1_ATA_SECURITY_FREEZE_LOCK (0x00004000)
|
||||||
#define MPI25_IOUNITPAGE1_NEW_DEVICE_FAST_PATH_DISABLE (0x00002000)
|
#define MPI25_IOUNITPAGE1_NEW_DEVICE_FAST_PATH_DISABLE (0x00002000)
|
||||||
#define MPI25_IOUNITPAGE1_DISABLE_FAST_PATH (0x00001000)
|
#define MPI25_IOUNITPAGE1_DISABLE_FAST_PATH (0x00001000)
|
||||||
@@ -3931,7 +3936,13 @@ typedef struct _MPI26_CONFIG_PAGE_PCIEDEV_2 {
|
|||||||
U32 MaximumDataTransferSize; /*0x0C */
|
U32 MaximumDataTransferSize; /*0x0C */
|
||||||
U32 Capabilities; /*0x10 */
|
U32 Capabilities; /*0x10 */
|
||||||
U16 NOIOB; /* 0x14 */
|
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,
|
} MPI26_CONFIG_PAGE_PCIEDEV_2, *PTR_MPI26_CONFIG_PAGE_PCIEDEV_2,
|
||||||
Mpi26PCIeDevicePage2_t, *pMpi26PCIeDevicePage2_t;
|
Mpi26PCIeDevicePage2_t, *pMpi26PCIeDevicePage2_t;
|
||||||
|
|
||||||
|
|||||||
@@ -19,6 +19,10 @@
|
|||||||
* 09-07-18 02.06.03 Added MPI26_EVENT_PCIE_TOPO_PI_16_LANES
|
* 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
|
* 12-17-18 02.06.04 Addd MPI2_EXT_IMAGE_TYPE_PBLP
|
||||||
* Shorten some defines to be compatible with DOS
|
* 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
|
#ifndef MPI2_IMAGE_H
|
||||||
#define 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_NVDATA (0x5444564E)
|
||||||
#define MPI26_IMAGE_HEADER_SIG1_GAS_GAUGE (0x20534147)
|
#define MPI26_IMAGE_HEADER_SIG1_GAS_GAUGE (0x20534147)
|
||||||
#define MPI26_IMAGE_HEADER_SIG1_PBLP (0x504C4250)
|
#define MPI26_IMAGE_HEADER_SIG1_PBLP (0x504C4250)
|
||||||
|
/* little-endian "DUMP" */
|
||||||
|
#define MPI26_IMAGE_HEADER_SIG1_COREDUMP (0x504D5544)
|
||||||
|
|
||||||
/**** Definitions for Signature2 field ****/
|
/**** Definitions for Signature2 field ****/
|
||||||
#define MPI26_IMAGE_HEADER_SIGNATURE2_VALUE (0x50584546)
|
#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_MR_NVDATA (0x14)
|
||||||
#define MPI2_FLASH_REGION_CPLD (0x15)
|
#define MPI2_FLASH_REGION_CPLD (0x15)
|
||||||
#define MPI2_FLASH_REGION_PSOC (0x16)
|
#define MPI2_FLASH_REGION_PSOC (0x16)
|
||||||
|
#define MPI2_FLASH_REGION_COREDUMP (0x17)
|
||||||
|
|
||||||
/*ImageRevision */
|
/*ImageRevision */
|
||||||
#define MPI2_FLASH_LAYOUT_IMAGE_REVISION (0x00)
|
#define MPI2_FLASH_LAYOUT_IMAGE_REVISION (0x00)
|
||||||
|
|||||||
@@ -175,6 +175,10 @@
|
|||||||
* Moved FW image definitions ionto new mpi2_image,h
|
* Moved FW image definitions ionto new mpi2_image,h
|
||||||
* 08-14-18 02.00.36 Fixed definition of MPI2_FW_DOWNLOAD_ITYPE_PSOC (0x16)
|
* 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
|
* 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 */
|
/*ConfigurationFlags */
|
||||||
#define MPI26_IOCINIT_CFGFLAGS_NVME_SGL_FORMAT (0x0001)
|
#define MPI26_IOCINIT_CFGFLAGS_NVME_SGL_FORMAT (0x0001)
|
||||||
|
#define MPI26_IOCINIT_CFGFLAGS_COREDUMP_ENABLE (0x0002)
|
||||||
|
|
||||||
/*minimum depth for a Reply Descriptor Post Queue */
|
/*minimum depth for a Reply Descriptor Post Queue */
|
||||||
#define MPI2_RDPQ_DEPTH_MIN (16)
|
#define MPI2_RDPQ_DEPTH_MIN (16)
|
||||||
@@ -377,6 +382,7 @@ typedef struct _MPI2_IOC_FACTS_REPLY {
|
|||||||
/*ProductID field uses MPI2_FW_HEADER_PID_ */
|
/*ProductID field uses MPI2_FW_HEADER_PID_ */
|
||||||
|
|
||||||
/*IOCCapabilities */
|
/*IOCCapabilities */
|
||||||
|
#define MPI26_IOCFACTS_CAPABILITY_COREDUMP_ENABLED (0x00200000)
|
||||||
#define MPI26_IOCFACTS_CAPABILITY_PCIE_SRIOV (0x00100000)
|
#define MPI26_IOCFACTS_CAPABILITY_PCIE_SRIOV (0x00100000)
|
||||||
#define MPI26_IOCFACTS_CAPABILITY_ATOMIC_REQ (0x00080000)
|
#define MPI26_IOCFACTS_CAPABILITY_ATOMIC_REQ (0x00080000)
|
||||||
#define MPI2_IOCFACTS_CAPABILITY_RDPQ_ARRAY_CAPABLE (0x00040000)
|
#define MPI2_IOCFACTS_CAPABILITY_RDPQ_ARRAY_CAPABLE (0x00040000)
|
||||||
@@ -1458,8 +1464,8 @@ typedef struct _MPI2_FW_DOWNLOAD_REQUEST {
|
|||||||
/*MPI v2.6 and newer */
|
/*MPI v2.6 and newer */
|
||||||
#define MPI2_FW_DOWNLOAD_ITYPE_CPLD (0x15)
|
#define MPI2_FW_DOWNLOAD_ITYPE_CPLD (0x15)
|
||||||
#define MPI2_FW_DOWNLOAD_ITYPE_PSOC (0x16)
|
#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_MIN_PRODUCT_SPECIFIC (0xF0)
|
||||||
#define MPI2_FW_DOWNLOAD_ITYPE_TERMINATE (0xFF)
|
|
||||||
|
|
||||||
/*MPI v2.0 FWDownload TransactionContext Element */
|
/*MPI v2.0 FWDownload TransactionContext Element */
|
||||||
typedef struct _MPI2_FW_DOWNLOAD_TCSGE {
|
typedef struct _MPI2_FW_DOWNLOAD_TCSGE {
|
||||||
|
|||||||
@@ -123,8 +123,15 @@ enum mpt3sas_perf_mode {
|
|||||||
MPT_PERF_MODE_LATENCY = 2,
|
MPT_PERF_MODE_LATENCY = 2,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static int
|
||||||
|
_base_wait_on_iocstate(struct MPT3SAS_ADAPTER *ioc,
|
||||||
|
u32 ioc_state, int timeout);
|
||||||
static int
|
static int
|
||||||
_base_get_ioc_facts(struct MPT3SAS_ADAPTER *ioc);
|
_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
|
* 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);
|
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;
|
goto rearm_timer;
|
||||||
spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags);
|
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 */
|
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) {
|
if ((doorbell & MPI2_IOC_STATE_MASK) != MPI2_IOC_STATE_OPERATIONAL) {
|
||||||
rc = mpt3sas_base_hard_reset_handler(ioc, FORCE_BIG_HAMMER);
|
rc = mpt3sas_base_hard_reset_handler(ioc, FORCE_BIG_HAMMER);
|
||||||
ioc_warn(ioc, "%s: hard reset: %s\n",
|
ioc_warn(ioc, "%s: hard reset: %s\n",
|
||||||
__func__, rc == 0 ? "success" : "failed");
|
__func__, rc == 0 ? "success" : "failed");
|
||||||
doorbell = mpt3sas_base_get_iocstate(ioc, 0);
|
doorbell = mpt3sas_base_get_iocstate(ioc, 0);
|
||||||
if ((doorbell & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_FAULT)
|
if ((doorbell & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_FAULT) {
|
||||||
mpt3sas_base_fault_info(ioc, doorbell &
|
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);
|
MPI2_DOORBELL_DATA_MASK);
|
||||||
if (rc && (doorbell & MPI2_IOC_STATE_MASK) !=
|
if (rc && (doorbell & MPI2_IOC_STATE_MASK) !=
|
||||||
MPI2_IOC_STATE_OPERATIONAL)
|
MPI2_IOC_STATE_OPERATIONAL)
|
||||||
return; /* don't rearm timer */
|
return; /* don't rearm timer */
|
||||||
}
|
}
|
||||||
|
ioc->ioc_coredump_loop = 0;
|
||||||
|
|
||||||
spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags);
|
spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags);
|
||||||
rearm_timer:
|
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);
|
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
|
* mpt3sas_halt_firmware - halt's mpt controller firmware
|
||||||
* @ioc: per adapter object
|
* @ioc: per adapter object
|
||||||
@@ -768,9 +863,14 @@ mpt3sas_halt_firmware(struct MPT3SAS_ADAPTER *ioc)
|
|||||||
dump_stack();
|
dump_stack();
|
||||||
|
|
||||||
doorbell = ioc->base_readl(&ioc->chip->Doorbell);
|
doorbell = ioc->base_readl(&ioc->chip->Doorbell);
|
||||||
if ((doorbell & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_FAULT)
|
if ((doorbell & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_FAULT) {
|
||||||
mpt3sas_base_fault_info(ioc , doorbell);
|
mpt3sas_print_fault_code(ioc, doorbell &
|
||||||
else {
|
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);
|
writel(0xC0FFEE00, &ioc->chip->Doorbell);
|
||||||
ioc_err(ioc, "Firmware is halted due to command timeout\n");
|
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 &&
|
if (!ioc->combined_reply_queue &&
|
||||||
ioc->hba_mpi_version_belonged != MPI2_VERSION) {
|
ioc->hba_mpi_version_belonged != MPI2_VERSION) {
|
||||||
|
ioc_info(ioc,
|
||||||
|
"combined ReplyQueue is off, Enabling msix load balance\n");
|
||||||
ioc->msix_load_balance = true;
|
ioc->msix_load_balance = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3115,9 +3217,7 @@ _base_enable_msix(struct MPT3SAS_ADAPTER *ioc)
|
|||||||
|
|
||||||
r = _base_alloc_irq_vectors(ioc);
|
r = _base_alloc_irq_vectors(ioc);
|
||||||
if (r < 0) {
|
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;
|
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));
|
dhsprintk(ioc, pr_info("%s: ioc_state(0x%08x)\n", __func__, ioc_state));
|
||||||
|
|
||||||
if ((ioc_state & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_FAULT) {
|
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);
|
MPI2_DOORBELL_DATA_MASK);
|
||||||
rc = _base_diag_reset(ioc);
|
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;
|
return rc;
|
||||||
@@ -3279,7 +3385,8 @@ mpt3sas_base_map_resources(struct MPT3SAS_ADAPTER *ioc)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (ioc->chip == NULL) {
|
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;
|
r = -EINVAL;
|
||||||
goto out_fail;
|
goto out_fail;
|
||||||
}
|
}
|
||||||
@@ -3318,8 +3425,8 @@ mpt3sas_base_map_resources(struct MPT3SAS_ADAPTER *ioc)
|
|||||||
ioc->combined_reply_index_count,
|
ioc->combined_reply_index_count,
|
||||||
sizeof(resource_size_t *), GFP_KERNEL);
|
sizeof(resource_size_t *), GFP_KERNEL);
|
||||||
if (!ioc->replyPostRegisterIndex) {
|
if (!ioc->replyPostRegisterIndex) {
|
||||||
dfailprintk(ioc,
|
ioc_err(ioc,
|
||||||
ioc_warn(ioc, "allocation for reply Post Register Index failed!!!\n"));
|
"allocation for replyPostRegisterIndex failed!\n");
|
||||||
r = -ENOMEM;
|
r = -ENOMEM;
|
||||||
goto out_fail;
|
goto out_fail;
|
||||||
}
|
}
|
||||||
@@ -3466,6 +3573,22 @@ _base_get_msix_index(struct MPT3SAS_ADAPTER *ioc,
|
|||||||
return ioc->cpu_msix_table[raw_smp_processor_id()];
|
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
|
* _base_get_high_iops_msix_index - get the msix index of
|
||||||
* high iops queues
|
* 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
|
* reply queues in terms of batch count 16 when outstanding
|
||||||
* IOs on the target device is >=8.
|
* 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)
|
MPT3SAS_DEVICE_HIGH_IOPS_DEPTH)
|
||||||
return base_mod64((
|
return base_mod64((
|
||||||
atomic64_add_return(1, &ioc->high_iops_outstanding) /
|
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_alloc_coherent(&ioc->pdev->dev, data_length,
|
||||||
&fwpkg_data_dma, GFP_KERNEL);
|
&fwpkg_data_dma, GFP_KERNEL);
|
||||||
if (!fwpkg_data) {
|
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__);
|
__FILE__, __LINE__, __func__);
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
@@ -4994,12 +5118,13 @@ _base_allocate_memory_pools(struct MPT3SAS_ADAPTER *ioc)
|
|||||||
ioc->reply_free_queue_depth = ioc->hba_queue_depth + 64;
|
ioc->reply_free_queue_depth = ioc->hba_queue_depth + 64;
|
||||||
}
|
}
|
||||||
|
|
||||||
dinitprintk(ioc,
|
ioc_info(ioc,
|
||||||
ioc_info(ioc, "scatter gather: sge_in_main_msg(%d), sge_per_chain(%d), sge_per_io(%d), chains_per_io(%d)\n",
|
"scatter gather: sge_in_main_msg(%d), sge_per_chain(%d), "
|
||||||
ioc->max_sges_in_main_message,
|
"sge_per_io(%d), chains_per_io(%d)\n",
|
||||||
ioc->max_sges_in_chain_message,
|
ioc->max_sges_in_main_message,
|
||||||
ioc->shost->sg_tablesize,
|
ioc->max_sges_in_chain_message,
|
||||||
ioc->chains_needed_per_io));
|
ioc->shost->sg_tablesize,
|
||||||
|
ioc->chains_needed_per_io);
|
||||||
|
|
||||||
/* reply post queue, 16 byte align */
|
/* reply post queue, 16 byte align */
|
||||||
reply_post_free_sz = ioc->reply_post_queue_depth *
|
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->internal_dma = ioc->hi_priority_dma + (ioc->hi_priority_depth *
|
||||||
ioc->request_sz);
|
ioc->request_sz);
|
||||||
|
|
||||||
dinitprintk(ioc,
|
ioc_info(ioc,
|
||||||
ioc_info(ioc, "request pool(0x%p): depth(%d), frame_size(%d), pool_size(%d kB)\n",
|
"request pool(0x%p) - dma(0x%llx): "
|
||||||
ioc->request, ioc->hba_queue_depth,
|
"depth(%d), frame_size(%d), pool_size(%d kB)\n",
|
||||||
ioc->request_sz,
|
ioc->request, (unsigned long long) ioc->request_dma,
|
||||||
(ioc->hba_queue_depth * ioc->request_sz) / 1024));
|
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;
|
total_sz += sz;
|
||||||
|
|
||||||
dinitprintk(ioc,
|
dinitprintk(ioc,
|
||||||
@@ -5302,13 +5425,12 @@ _base_allocate_memory_pools(struct MPT3SAS_ADAPTER *ioc)
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
dinitprintk(ioc,
|
ioc_info(ioc,
|
||||||
ioc_info(ioc, "sense pool(0x%p): depth(%d), element_size(%d), pool_size(%d kB)\n",
|
"sense pool(0x%p)- dma(0x%llx): depth(%d),"
|
||||||
ioc->sense, ioc->scsiio_depth,
|
"element_size(%d), pool_size(%d kB)\n",
|
||||||
SCSI_SENSE_BUFFERSIZE, sz / 1024));
|
ioc->sense, (unsigned long long)ioc->sense_dma, ioc->scsiio_depth,
|
||||||
dinitprintk(ioc,
|
SCSI_SENSE_BUFFERSIZE, sz / 1024);
|
||||||
ioc_info(ioc, "sense_dma(0x%llx)\n",
|
|
||||||
(unsigned long long)ioc->sense_dma));
|
|
||||||
total_sz += sz;
|
total_sz += sz;
|
||||||
|
|
||||||
/* reply pool, 4 byte align */
|
/* 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");
|
ioc_err(ioc, "config page: dma_pool_alloc failed\n");
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
dinitprintk(ioc,
|
|
||||||
ioc_info(ioc, "config page(0x%p): size(%d)\n",
|
ioc_info(ioc, "config page(0x%p) - dma(0x%llx): size(%d)\n",
|
||||||
ioc->config_page, ioc->config_page_sz));
|
ioc->config_page, (unsigned long long)ioc->config_page_dma,
|
||||||
dinitprintk(ioc,
|
ioc->config_page_sz);
|
||||||
ioc_info(ioc, "config_page_dma(0x%llx)\n",
|
|
||||||
(unsigned long long)ioc->config_page_dma));
|
|
||||||
total_sz += ioc->config_page_sz;
|
total_sz += ioc->config_page_sz;
|
||||||
|
|
||||||
ioc_info(ioc, "Allocated physical memory: size(%d kB)\n",
|
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;
|
return 0;
|
||||||
if (count && current_state == MPI2_IOC_STATE_FAULT)
|
if (count && current_state == MPI2_IOC_STATE_FAULT)
|
||||||
break;
|
break;
|
||||||
|
if (count && current_state == MPI2_IOC_STATE_COREDUMP)
|
||||||
|
break;
|
||||||
|
|
||||||
usleep_range(1000, 1500);
|
usleep_range(1000, 1500);
|
||||||
count++;
|
count++;
|
||||||
@@ -5547,7 +5669,12 @@ _base_wait_for_doorbell_ack(struct MPT3SAS_ADAPTER *ioc, int timeout)
|
|||||||
doorbell = ioc->base_readl(&ioc->chip->Doorbell);
|
doorbell = ioc->base_readl(&ioc->chip->Doorbell);
|
||||||
if ((doorbell & MPI2_IOC_STATE_MASK) ==
|
if ((doorbell & MPI2_IOC_STATE_MASK) ==
|
||||||
MPI2_IOC_STATE_FAULT) {
|
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;
|
return -EFAULT;
|
||||||
}
|
}
|
||||||
} else if (int_status == 0xFFFFFFFF)
|
} 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;
|
u32 ioc_state;
|
||||||
int r = 0;
|
int r = 0;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
if (reset_type != MPI2_FUNCTION_IOC_MESSAGE_UNIT_RESET) {
|
if (reset_type != MPI2_FUNCTION_IOC_MESSAGE_UNIT_RESET) {
|
||||||
ioc_err(ioc, "%s: unknown reset_type\n", __func__);
|
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;
|
r = -EFAULT;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
ioc_state = _base_wait_on_iocstate(ioc, MPI2_IOC_STATE_READY, timeout);
|
ioc_state = _base_wait_on_iocstate(ioc, MPI2_IOC_STATE_READY, timeout);
|
||||||
if (ioc_state) {
|
if (ioc_state) {
|
||||||
ioc_err(ioc, "%s: failed going to ready state (ioc_state=0x%x)\n",
|
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;
|
goto out;
|
||||||
}
|
}
|
||||||
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",
|
ioc_info(ioc, "message unit reset: %s\n",
|
||||||
r == 0 ? "SUCCESS" : "FAILED");
|
r == 0 ? "SUCCESS" : "FAILED");
|
||||||
return r;
|
return r;
|
||||||
@@ -5782,7 +5931,7 @@ _base_handshake_req_reply_wait(struct MPT3SAS_ADAPTER *ioc, int request_bytes,
|
|||||||
mfp = (__le32 *)reply;
|
mfp = (__le32 *)reply;
|
||||||
pr_info("\toffset:data\n");
|
pr_info("\toffset:data\n");
|
||||||
for (i = 0; i < reply_bytes/4; i++)
|
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]));
|
le32_to_cpu(mfp[i]));
|
||||||
}
|
}
|
||||||
return 0;
|
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)
|
||||||
ioc->ioc_link_reset_in_progress = 0;
|
ioc->ioc_link_reset_in_progress = 0;
|
||||||
if (!(ioc->base_cmds.status & MPT3_CMD_COMPLETE)) {
|
if (!(ioc->base_cmds.status & MPT3_CMD_COMPLETE)) {
|
||||||
issue_reset =
|
mpt3sas_check_cmd_timeout(ioc, ioc->base_cmds.status,
|
||||||
mpt3sas_base_check_cmd_timeout(ioc,
|
mpi_request, sizeof(Mpi2SasIoUnitControlRequest_t)/4,
|
||||||
ioc->base_cmds.status, mpi_request,
|
issue_reset);
|
||||||
sizeof(Mpi2SasIoUnitControlRequest_t)/4);
|
|
||||||
goto issue_host_reset;
|
goto issue_host_reset;
|
||||||
}
|
}
|
||||||
if (ioc->base_cmds.status & MPT3_CMD_REPLY_VALID)
|
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,
|
wait_for_completion_timeout(&ioc->base_cmds.done,
|
||||||
msecs_to_jiffies(10000));
|
msecs_to_jiffies(10000));
|
||||||
if (!(ioc->base_cmds.status & MPT3_CMD_COMPLETE)) {
|
if (!(ioc->base_cmds.status & MPT3_CMD_COMPLETE)) {
|
||||||
issue_reset =
|
mpt3sas_check_cmd_timeout(ioc,
|
||||||
mpt3sas_base_check_cmd_timeout(ioc,
|
ioc->base_cmds.status, mpi_request,
|
||||||
ioc->base_cmds.status, mpi_request,
|
sizeof(Mpi2SepRequest_t)/4, issue_reset);
|
||||||
sizeof(Mpi2SepRequest_t)/4);
|
|
||||||
goto issue_host_reset;
|
goto issue_host_reset;
|
||||||
}
|
}
|
||||||
if (ioc->base_cmds.status & MPT3_CMD_REPLY_VALID)
|
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) {
|
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);
|
MPI2_DOORBELL_DATA_MASK);
|
||||||
goto issue_diag_reset;
|
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);
|
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);
|
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
|
/* This time stamp specifies number of milliseconds
|
||||||
* since epoch ~ midnight January 1, 1970.
|
* since epoch ~ midnight January 1, 1970.
|
||||||
*/
|
*/
|
||||||
@@ -6220,9 +6379,9 @@ _base_send_ioc_init(struct MPT3SAS_ADAPTER *ioc)
|
|||||||
int i;
|
int i;
|
||||||
|
|
||||||
mfp = (__le32 *)&mpi_request;
|
mfp = (__le32 *)&mpi_request;
|
||||||
pr_info("\toffset:data\n");
|
ioc_info(ioc, "\toffset:data\n");
|
||||||
for (i = 0; i < sizeof(Mpi2IOCInitRequest_t)/4; i++)
|
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]));
|
le32_to_cpu(mfp[i]));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -6592,8 +6751,11 @@ _base_diag_reset(struct MPT3SAS_ADAPTER *ioc)
|
|||||||
/* wait 100 msec */
|
/* wait 100 msec */
|
||||||
msleep(100);
|
msleep(100);
|
||||||
|
|
||||||
if (count++ > 20)
|
if (count++ > 20) {
|
||||||
|
ioc_info(ioc,
|
||||||
|
"Stop writing magic sequence after 20 retries\n");
|
||||||
goto out;
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
host_diagnostic = ioc->base_readl(&ioc->chip->HostDiagnostic);
|
host_diagnostic = ioc->base_readl(&ioc->chip->HostDiagnostic);
|
||||||
drsprintk(ioc,
|
drsprintk(ioc,
|
||||||
@@ -6617,8 +6779,11 @@ _base_diag_reset(struct MPT3SAS_ADAPTER *ioc)
|
|||||||
|
|
||||||
host_diagnostic = ioc->base_readl(&ioc->chip->HostDiagnostic);
|
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;
|
goto out;
|
||||||
|
}
|
||||||
if (!(host_diagnostic & MPI2_DIAG_RESET_ADAPTER))
|
if (!(host_diagnostic & MPI2_DIAG_RESET_ADAPTER))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -6705,16 +6870,33 @@ _base_make_ioc_ready(struct MPT3SAS_ADAPTER *ioc, enum reset_type type)
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (ioc_state & MPI2_DOORBELL_USED) {
|
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;
|
goto issue_diag_reset;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((ioc_state & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_FAULT) {
|
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);
|
MPI2_DOORBELL_DATA_MASK);
|
||||||
goto issue_diag_reset;
|
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)
|
if (type == FORCE_BIG_HAMMER)
|
||||||
goto issue_diag_reset;
|
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->cpu_msix_table = kzalloc(ioc->cpu_msix_table_sz, GFP_KERNEL);
|
||||||
ioc->reply_queue_count = 1;
|
ioc->reply_queue_count = 1;
|
||||||
if (!ioc->cpu_msix_table) {
|
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;
|
r = -ENOMEM;
|
||||||
goto out_free_resources;
|
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,
|
ioc->reply_post_host_index = kcalloc(ioc->cpu_msix_table_sz,
|
||||||
sizeof(resource_size_t *), GFP_KERNEL);
|
sizeof(resource_size_t *), GFP_KERNEL);
|
||||||
if (!ioc->reply_post_host_index) {
|
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;
|
r = -ENOMEM;
|
||||||
goto out_free_resources;
|
goto out_free_resources;
|
||||||
}
|
}
|
||||||
@@ -7195,6 +7375,7 @@ mpt3sas_base_attach(struct MPT3SAS_ADAPTER *ioc)
|
|||||||
sizeof(struct mpt3sas_facts));
|
sizeof(struct mpt3sas_facts));
|
||||||
|
|
||||||
ioc->non_operational_loop = 0;
|
ioc->non_operational_loop = 0;
|
||||||
|
ioc->ioc_coredump_loop = 0;
|
||||||
ioc->got_task_abort_from_ioctl = 0;
|
ioc->got_task_abort_from_ioctl = 0;
|
||||||
return 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
|
* @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);
|
dtmprintk(ioc,
|
||||||
mpt3sas_ctl_after_reset_handler(ioc);
|
ioc_info(ioc, "%s: clear outstanding mpt cmds\n", __func__));
|
||||||
dtmprintk(ioc, ioc_info(ioc, "%s: MPT3_IOC_AFTER_RESET\n", __func__));
|
|
||||||
if (ioc->transport_cmds.status & MPT3_CMD_PENDING) {
|
if (ioc->transport_cmds.status & MPT3_CMD_PENDING) {
|
||||||
ioc->transport_cmds.status |= MPT3_CMD_RESET;
|
ioc->transport_cmds.status |= MPT3_CMD_RESET;
|
||||||
mpt3sas_base_free_smid(ioc, ioc->transport_cmds.smid);
|
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
|
* _base_reset_done_handler - reset done handler
|
||||||
* @ioc: per adapter object
|
* @ioc: per adapter object
|
||||||
@@ -7474,7 +7666,9 @@ mpt3sas_base_hard_reset_handler(struct MPT3SAS_ADAPTER *ioc,
|
|||||||
MPT3_DIAG_BUFFER_IS_RELEASED))) {
|
MPT3_DIAG_BUFFER_IS_RELEASED))) {
|
||||||
is_trigger = 1;
|
is_trigger = 1;
|
||||||
ioc_state = mpt3sas_base_get_iocstate(ioc, 0);
|
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;
|
is_fault = 1;
|
||||||
}
|
}
|
||||||
_base_pre_reset_handler(ioc);
|
_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);
|
r = _base_make_ioc_ready(ioc, type);
|
||||||
if (r)
|
if (r)
|
||||||
goto out;
|
goto out;
|
||||||
_base_after_reset_handler(ioc);
|
_base_clear_outstanding_commands(ioc);
|
||||||
|
|
||||||
/* If this hard reset is called while port enable is active, then
|
/* If this hard reset is called while port enable is active, then
|
||||||
* there is no reason to call make_ioc_operational
|
* 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);
|
_base_reset_done_handler(ioc);
|
||||||
|
|
||||||
out:
|
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);
|
spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags);
|
||||||
ioc->shost_recovery = 0;
|
ioc->shost_recovery = 0;
|
||||||
|
|||||||
@@ -76,8 +76,8 @@
|
|||||||
#define MPT3SAS_DRIVER_NAME "mpt3sas"
|
#define MPT3SAS_DRIVER_NAME "mpt3sas"
|
||||||
#define MPT3SAS_AUTHOR "Avago Technologies <MPT-FusionLinux.pdl@avagotech.com>"
|
#define MPT3SAS_AUTHOR "Avago Technologies <MPT-FusionLinux.pdl@avagotech.com>"
|
||||||
#define MPT3SAS_DESCRIPTION "LSI MPT Fusion SAS 3.0 Device Driver"
|
#define MPT3SAS_DESCRIPTION "LSI MPT Fusion SAS 3.0 Device Driver"
|
||||||
#define MPT3SAS_DRIVER_VERSION "32.100.00.00"
|
#define MPT3SAS_DRIVER_VERSION "33.100.00.00"
|
||||||
#define MPT3SAS_MAJOR_VERSION 32
|
#define MPT3SAS_MAJOR_VERSION 33
|
||||||
#define MPT3SAS_MINOR_VERSION 100
|
#define MPT3SAS_MINOR_VERSION 100
|
||||||
#define MPT3SAS_BUILD_VERSION 0
|
#define MPT3SAS_BUILD_VERSION 0
|
||||||
#define MPT3SAS_RELEASE_VERSION 00
|
#define MPT3SAS_RELEASE_VERSION 00
|
||||||
@@ -90,6 +90,10 @@
|
|||||||
#define MPT2SAS_BUILD_VERSION 0
|
#define MPT2SAS_BUILD_VERSION 0
|
||||||
#define MPT2SAS_RELEASE_VERSION 00
|
#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.
|
* Set MPT3SAS_SG_DEPTH value based on user input.
|
||||||
*/
|
*/
|
||||||
@@ -140,6 +144,7 @@
|
|||||||
#define MAX_CHAIN_ELEMT_SZ 16
|
#define MAX_CHAIN_ELEMT_SZ 16
|
||||||
#define DEFAULT_NUM_FWCHAIN_ELEMTS 8
|
#define DEFAULT_NUM_FWCHAIN_ELEMTS 8
|
||||||
|
|
||||||
|
#define IO_UNIT_CONTROL_SHUTDOWN_TIMEOUT 6
|
||||||
#define FW_IMG_HDR_READ_TIMEOUT 15
|
#define FW_IMG_HDR_READ_TIMEOUT 15
|
||||||
|
|
||||||
#define IOC_OPERATIONAL_WAIT_COUNT 10
|
#define IOC_OPERATIONAL_WAIT_COUNT 10
|
||||||
@@ -398,7 +403,10 @@ struct Mpi2ManufacturingPage11_t {
|
|||||||
u8 HostTraceBufferFlags; /* 4Fh */
|
u8 HostTraceBufferFlags; /* 4Fh */
|
||||||
u16 HostTraceBufferMaxSizeKB; /* 50h */
|
u16 HostTraceBufferMaxSizeKB; /* 50h */
|
||||||
u16 HostTraceBufferMinSizeKB; /* 52h */
|
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
|
* @connector_name: ASCII value of the Connector's name
|
||||||
* @serial_number: pointer of serial number string allocated runtime
|
* @serial_number: pointer of serial number string allocated runtime
|
||||||
* @access_status: Device's Access Status
|
* @access_status: Device's Access Status
|
||||||
|
* @shutdown_latency: NVMe device's RTD3 Entry Latency
|
||||||
* @refcount: reference count for deletion
|
* @refcount: reference count for deletion
|
||||||
*/
|
*/
|
||||||
struct _pcie_device {
|
struct _pcie_device {
|
||||||
@@ -611,6 +620,7 @@ struct _pcie_device {
|
|||||||
u8 *serial_number;
|
u8 *serial_number;
|
||||||
u8 reset_timeout;
|
u8 reset_timeout;
|
||||||
u8 access_status;
|
u8 access_status;
|
||||||
|
u16 shutdown_latency;
|
||||||
struct kref refcount;
|
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: table for mapping cpus to msix index
|
||||||
* @cpu_msix_table_sz: table size
|
* @cpu_msix_table_sz: table size
|
||||||
* @total_io_cnt: Gives total IO count, used to load balance the interrupts
|
* @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
|
* @high_iops_outstanding: used to load balance the interrupts
|
||||||
* within high iops reply queues
|
* within high iops reply queues
|
||||||
* @msix_load_balance: Enables load balancing of interrupts across
|
* @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_context: unique id for each logged event
|
||||||
* @event_log: event log pointer
|
* @event_log: event log pointer
|
||||||
* @event_masks: events that are masked
|
* @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
|
* @facts: static facts data
|
||||||
* @prev_fw_facts: previous fw facts data
|
* @prev_fw_facts: previous fw facts data
|
||||||
* @pfacts: static port facts data
|
* @pfacts: static port facts data
|
||||||
@@ -1231,6 +1246,7 @@ struct MPT3SAS_ADAPTER {
|
|||||||
u32 ioc_reset_count;
|
u32 ioc_reset_count;
|
||||||
MPT3SAS_FLUSH_RUNNING_CMDS schedule_dead_ioc_flush_running_cmds;
|
MPT3SAS_FLUSH_RUNNING_CMDS schedule_dead_ioc_flush_running_cmds;
|
||||||
u32 non_operational_loop;
|
u32 non_operational_loop;
|
||||||
|
u8 ioc_coredump_loop;
|
||||||
atomic64_t total_io_cnt;
|
atomic64_t total_io_cnt;
|
||||||
atomic64_t high_iops_outstanding;
|
atomic64_t high_iops_outstanding;
|
||||||
bool msix_load_balance;
|
bool msix_load_balance;
|
||||||
@@ -1283,7 +1299,7 @@ struct MPT3SAS_ADAPTER {
|
|||||||
|
|
||||||
u8 tm_custom_handling;
|
u8 tm_custom_handling;
|
||||||
u8 nvme_abort_timeout;
|
u8 nvme_abort_timeout;
|
||||||
|
u16 max_shutdown_latency;
|
||||||
|
|
||||||
/* static config pages */
|
/* static config pages */
|
||||||
struct mpt3sas_facts facts;
|
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);
|
u32 mpt3sas_base_get_iocstate(struct MPT3SAS_ADAPTER *ioc, int cooked);
|
||||||
|
|
||||||
void mpt3sas_base_fault_info(struct MPT3SAS_ADAPTER *ioc , u16 fault_code);
|
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,
|
int mpt3sas_base_sas_iounit_control(struct MPT3SAS_ADAPTER *ioc,
|
||||||
Mpi2SasIoUnitControlReply_t *mpi_reply,
|
Mpi2SasIoUnitControlReply_t *mpi_reply,
|
||||||
Mpi2SasIoUnitControlRequest_t *mpi_request);
|
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 mpt3sas_base_check_cmd_timeout(struct MPT3SAS_ADAPTER *ioc,
|
||||||
u8 status, void *mpi_request, int sz);
|
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);
|
int mpt3sas_wait_for_ioc(struct MPT3SAS_ADAPTER *ioc, int wait_count);
|
||||||
|
|
||||||
/* scsih shared API */
|
/* 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,
|
u8 mpt3sas_scsih_event_callback(struct MPT3SAS_ADAPTER *ioc, u8 msix_index,
|
||||||
u32 reply);
|
u32 reply);
|
||||||
void mpt3sas_scsih_pre_reset_handler(struct MPT3SAS_ADAPTER *ioc);
|
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);
|
void mpt3sas_scsih_reset_done_handler(struct MPT3SAS_ADAPTER *ioc);
|
||||||
|
|
||||||
int mpt3sas_scsih_issue_tm(struct MPT3SAS_ADAPTER *ioc, u16 handle, u64 lun,
|
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,
|
u8 mpt3sas_ctl_done(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index,
|
||||||
u32 reply);
|
u32 reply);
|
||||||
void mpt3sas_ctl_pre_reset_handler(struct MPT3SAS_ADAPTER *ioc);
|
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);
|
void mpt3sas_ctl_reset_done_handler(struct MPT3SAS_ADAPTER *ioc);
|
||||||
u8 mpt3sas_ctl_event_callback(struct MPT3SAS_ADAPTER *ioc,
|
u8 mpt3sas_ctl_event_callback(struct MPT3SAS_ADAPTER *ioc,
|
||||||
u8 msix_index, u32 reply);
|
u8 msix_index, u32 reply);
|
||||||
|
|||||||
@@ -101,9 +101,6 @@ _config_display_some_debug(struct MPT3SAS_ADAPTER *ioc, u16 smid,
|
|||||||
Mpi2ConfigRequest_t *mpi_request;
|
Mpi2ConfigRequest_t *mpi_request;
|
||||||
char *desc = NULL;
|
char *desc = NULL;
|
||||||
|
|
||||||
if (!(ioc->logging_level & MPT_DEBUG_CONFIG))
|
|
||||||
return;
|
|
||||||
|
|
||||||
mpi_request = mpt3sas_base_get_msg_frame(ioc, smid);
|
mpi_request = mpt3sas_base_get_msg_frame(ioc, smid);
|
||||||
switch (mpi_request->Header.PageType & MPI2_CONFIG_PAGETYPE_MASK) {
|
switch (mpi_request->Header.PageType & MPI2_CONFIG_PAGETYPE_MASK) {
|
||||||
case MPI2_CONFIG_PAGETYPE_IO_UNIT:
|
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);
|
mpi_reply->MsgLength*4);
|
||||||
}
|
}
|
||||||
ioc->config_cmds.status &= ~MPT3_CMD_PENDING;
|
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;
|
ioc->config_cmds.smid = USHRT_MAX;
|
||||||
complete(&ioc->config_cmds.done);
|
complete(&ioc->config_cmds.done);
|
||||||
return 1;
|
return 1;
|
||||||
@@ -305,6 +303,7 @@ _config_request(struct MPT3SAS_ADAPTER *ioc, Mpi2ConfigRequest_t
|
|||||||
u8 retry_count, issue_host_reset = 0;
|
u8 retry_count, issue_host_reset = 0;
|
||||||
struct config_request mem;
|
struct config_request mem;
|
||||||
u32 ioc_status = UINT_MAX;
|
u32 ioc_status = UINT_MAX;
|
||||||
|
u8 issue_reset = 0;
|
||||||
|
|
||||||
mutex_lock(&ioc->config_cmds.mutex);
|
mutex_lock(&ioc->config_cmds.mutex);
|
||||||
if (ioc->config_cmds.status != MPT3_CMD_NOT_USED) {
|
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);
|
config_request = mpt3sas_base_get_msg_frame(ioc, smid);
|
||||||
ioc->config_cmds.smid = smid;
|
ioc->config_cmds.smid = smid;
|
||||||
memcpy(config_request, mpi_request, sizeof(Mpi2ConfigRequest_t));
|
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);
|
init_completion(&ioc->config_cmds.done);
|
||||||
ioc->put_smid_default(ioc, smid);
|
ioc->put_smid_default(ioc, smid);
|
||||||
wait_for_completion_timeout(&ioc->config_cmds.done, timeout*HZ);
|
wait_for_completion_timeout(&ioc->config_cmds.done, timeout*HZ);
|
||||||
if (!(ioc->config_cmds.status & MPT3_CMD_COMPLETE)) {
|
if (!(ioc->config_cmds.status & MPT3_CMD_COMPLETE)) {
|
||||||
mpt3sas_base_check_cmd_timeout(ioc,
|
if (!(ioc->logging_level & MPT_DEBUG_CONFIG))
|
||||||
ioc->config_cmds.status, mpi_request,
|
_config_display_some_debug(ioc,
|
||||||
sizeof(Mpi2ConfigRequest_t)/4);
|
smid, "config_request", NULL);
|
||||||
|
mpt3sas_check_cmd_timeout(ioc,
|
||||||
|
ioc->config_cmds.status, mpi_request,
|
||||||
|
sizeof(Mpi2ConfigRequest_t)/4, issue_reset);
|
||||||
retry_count++;
|
retry_count++;
|
||||||
if (ioc->config_cmds.smid == smid)
|
if (ioc->config_cmds.smid == smid)
|
||||||
mpt3sas_base_free_smid(ioc, 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 */
|
/* Reply Frame Sanity Checks to workaround FW issues */
|
||||||
if ((mpi_request->Header.PageType & 0xF) !=
|
if ((mpi_request->Header.PageType & 0xF) !=
|
||||||
(mpi_reply->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_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",
|
panic("%s: %s: Firmware BUG: mpi_reply mismatch: Requested PageType(0x%02x) Reply PageType(0x%02x)\n",
|
||||||
ioc->name, __func__,
|
ioc->name, __func__,
|
||||||
mpi_request->Header.PageType & 0xF,
|
mpi_request->Header.PageType & 0xF,
|
||||||
@@ -415,8 +421,11 @@ _config_request(struct MPT3SAS_ADAPTER *ioc, Mpi2ConfigRequest_t
|
|||||||
if (((mpi_request->Header.PageType & 0xF) ==
|
if (((mpi_request->Header.PageType & 0xF) ==
|
||||||
MPI2_CONFIG_PAGETYPE_EXTENDED) &&
|
MPI2_CONFIG_PAGETYPE_EXTENDED) &&
|
||||||
mpi_request->ExtPageType != mpi_reply->ExtPageType) {
|
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_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",
|
panic("%s: %s: Firmware BUG: mpi_reply mismatch: Requested ExtPageType(0x%02x) Reply ExtPageType(0x%02x)\n",
|
||||||
ioc->name, __func__,
|
ioc->name, __func__,
|
||||||
mpi_request->ExtPageType,
|
mpi_request->ExtPageType,
|
||||||
@@ -439,8 +448,11 @@ _config_request(struct MPT3SAS_ADAPTER *ioc, Mpi2ConfigRequest_t
|
|||||||
if (p) {
|
if (p) {
|
||||||
if ((mpi_request->Header.PageType & 0xF) !=
|
if ((mpi_request->Header.PageType & 0xF) !=
|
||||||
(p[3] & 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_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,
|
_debug_dump_config(p, min_t(u16, mem.sz,
|
||||||
config_page_sz)/4);
|
config_page_sz)/4);
|
||||||
panic("%s: %s: Firmware BUG: config page mismatch: Requested PageType(0x%02x) Reply PageType(0x%02x)\n",
|
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) ==
|
if (((mpi_request->Header.PageType & 0xF) ==
|
||||||
MPI2_CONFIG_PAGETYPE_EXTENDED) &&
|
MPI2_CONFIG_PAGETYPE_EXTENDED) &&
|
||||||
(mpi_request->ExtPageType != p[6])) {
|
(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_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,
|
_debug_dump_config(p, min_t(u16, mem.sz,
|
||||||
config_page_sz)/4);
|
config_page_sz)/4);
|
||||||
panic("%s: %s: Firmware BUG: config page mismatch: Requested ExtPageType(0x%02x) Reply ExtPageType(0x%02x)\n",
|
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:
|
case MPI2_FUNCTION_SMP_PASSTHROUGH:
|
||||||
desc = "smp_passthrough";
|
desc = "smp_passthrough";
|
||||||
break;
|
break;
|
||||||
|
case MPI2_FUNCTION_TOOLBOX:
|
||||||
|
desc = "toolbox";
|
||||||
|
break;
|
||||||
|
case MPI2_FUNCTION_NVME_ENCAPSULATED:
|
||||||
|
desc = "nvme_encapsulated";
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!desc)
|
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
|
* @ioc: per adapter object
|
||||||
*
|
*
|
||||||
* The handler for doing any required cleanup or initialization.
|
* 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) {
|
if (ioc->ctl_cmds.status & MPT3_CMD_PENDING) {
|
||||||
ioc->ctl_cmds.status |= MPT3_CMD_RESET;
|
ioc->ctl_cmds.status |= MPT3_CMD_RESET;
|
||||||
mpt3sas_base_free_smid(ioc, ioc->ctl_cmds.smid);
|
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;
|
ioc->ignore_loginfos = 0;
|
||||||
}
|
}
|
||||||
if (!(ioc->ctl_cmds.status & MPT3_CMD_COMPLETE)) {
|
if (!(ioc->ctl_cmds.status & MPT3_CMD_COMPLETE)) {
|
||||||
issue_reset =
|
mpt3sas_check_cmd_timeout(ioc,
|
||||||
mpt3sas_base_check_cmd_timeout(ioc,
|
ioc->ctl_cmds.status, mpi_request,
|
||||||
ioc->ctl_cmds.status, mpi_request,
|
karg.data_sge_offset, issue_reset);
|
||||||
karg.data_sge_offset);
|
|
||||||
goto issue_host_reset;
|
goto issue_host_reset;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1325,7 +1331,8 @@ _ctl_do_reset(struct MPT3SAS_ADAPTER *ioc, void __user *arg)
|
|||||||
__func__));
|
__func__));
|
||||||
|
|
||||||
retval = mpt3sas_base_hard_reset_handler(ioc, FORCE_BIG_HAMMER);
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1733,10 +1740,9 @@ _ctl_diag_register_2(struct MPT3SAS_ADAPTER *ioc,
|
|||||||
MPT3_IOCTL_DEFAULT_TIMEOUT*HZ);
|
MPT3_IOCTL_DEFAULT_TIMEOUT*HZ);
|
||||||
|
|
||||||
if (!(ioc->ctl_cmds.status & MPT3_CMD_COMPLETE)) {
|
if (!(ioc->ctl_cmds.status & MPT3_CMD_COMPLETE)) {
|
||||||
issue_reset =
|
mpt3sas_check_cmd_timeout(ioc,
|
||||||
mpt3sas_base_check_cmd_timeout(ioc,
|
ioc->ctl_cmds.status, mpi_request,
|
||||||
ioc->ctl_cmds.status, mpi_request,
|
sizeof(Mpi2DiagBufferPostRequest_t)/4, issue_reset);
|
||||||
sizeof(Mpi2DiagBufferPostRequest_t)/4);
|
|
||||||
goto issue_host_reset;
|
goto issue_host_reset;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2108,6 +2114,7 @@ mpt3sas_send_diag_release(struct MPT3SAS_ADAPTER *ioc, u8 buffer_type,
|
|||||||
u16 ioc_status;
|
u16 ioc_status;
|
||||||
u32 ioc_state;
|
u32 ioc_state;
|
||||||
int rc;
|
int rc;
|
||||||
|
u8 reset_needed = 0;
|
||||||
|
|
||||||
dctlprintk(ioc, ioc_info(ioc, "%s\n",
|
dctlprintk(ioc, ioc_info(ioc, "%s\n",
|
||||||
__func__));
|
__func__));
|
||||||
@@ -2115,6 +2122,7 @@ mpt3sas_send_diag_release(struct MPT3SAS_ADAPTER *ioc, u8 buffer_type,
|
|||||||
rc = 0;
|
rc = 0;
|
||||||
*issue_reset = 0;
|
*issue_reset = 0;
|
||||||
|
|
||||||
|
|
||||||
ioc_state = mpt3sas_base_get_iocstate(ioc, 1);
|
ioc_state = mpt3sas_base_get_iocstate(ioc, 1);
|
||||||
if (ioc_state != MPI2_IOC_STATE_OPERATIONAL) {
|
if (ioc_state != MPI2_IOC_STATE_OPERATIONAL) {
|
||||||
if (ioc->diag_buffer_status[buffer_type] &
|
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);
|
MPT3_IOCTL_DEFAULT_TIMEOUT*HZ);
|
||||||
|
|
||||||
if (!(ioc->ctl_cmds.status & MPT3_CMD_COMPLETE)) {
|
if (!(ioc->ctl_cmds.status & MPT3_CMD_COMPLETE)) {
|
||||||
*issue_reset = mpt3sas_base_check_cmd_timeout(ioc,
|
mpt3sas_check_cmd_timeout(ioc,
|
||||||
ioc->ctl_cmds.status, mpi_request,
|
ioc->ctl_cmds.status, mpi_request,
|
||||||
sizeof(Mpi2DiagReleaseRequest_t)/4);
|
sizeof(Mpi2DiagReleaseRequest_t)/4, reset_needed);
|
||||||
|
*issue_reset = reset_needed;
|
||||||
rc = -EFAULT;
|
rc = -EFAULT;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
@@ -2417,10 +2426,9 @@ _ctl_diag_read_buffer(struct MPT3SAS_ADAPTER *ioc, void __user *arg)
|
|||||||
MPT3_IOCTL_DEFAULT_TIMEOUT*HZ);
|
MPT3_IOCTL_DEFAULT_TIMEOUT*HZ);
|
||||||
|
|
||||||
if (!(ioc->ctl_cmds.status & MPT3_CMD_COMPLETE)) {
|
if (!(ioc->ctl_cmds.status & MPT3_CMD_COMPLETE)) {
|
||||||
issue_reset =
|
mpt3sas_check_cmd_timeout(ioc,
|
||||||
mpt3sas_base_check_cmd_timeout(ioc,
|
ioc->ctl_cmds.status, mpi_request,
|
||||||
ioc->ctl_cmds.status, mpi_request,
|
sizeof(Mpi2DiagBufferPostRequest_t)/4, issue_reset);
|
||||||
sizeof(Mpi2DiagBufferPostRequest_t)/4);
|
|
||||||
goto issue_host_reset;
|
goto issue_host_reset;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1049,6 +1049,34 @@ mpt3sas_get_pdev_by_handle(struct MPT3SAS_ADAPTER *ioc, u16 handle)
|
|||||||
return pcie_device;
|
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.
|
* _scsih_pcie_device_remove - remove pcie_device from list.
|
||||||
* @ioc: per adapter object
|
* @ioc: per adapter object
|
||||||
@@ -1063,6 +1091,7 @@ _scsih_pcie_device_remove(struct MPT3SAS_ADAPTER *ioc,
|
|||||||
{
|
{
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
int was_on_pcie_device_list = 0;
|
int was_on_pcie_device_list = 0;
|
||||||
|
u8 update_latency = 0;
|
||||||
|
|
||||||
if (!pcie_device)
|
if (!pcie_device)
|
||||||
return;
|
return;
|
||||||
@@ -1082,11 +1111,21 @@ _scsih_pcie_device_remove(struct MPT3SAS_ADAPTER *ioc,
|
|||||||
list_del_init(&pcie_device->list);
|
list_del_init(&pcie_device->list);
|
||||||
was_on_pcie_device_list = 1;
|
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);
|
spin_unlock_irqrestore(&ioc->pcie_device_lock, flags);
|
||||||
if (was_on_pcie_device_list) {
|
if (was_on_pcie_device_list) {
|
||||||
kfree(pcie_device->serial_number);
|
kfree(pcie_device->serial_number);
|
||||||
pcie_device_put(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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1101,6 +1140,7 @@ _scsih_pcie_device_remove_by_handle(struct MPT3SAS_ADAPTER *ioc, u16 handle)
|
|||||||
struct _pcie_device *pcie_device;
|
struct _pcie_device *pcie_device;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
int was_on_pcie_device_list = 0;
|
int was_on_pcie_device_list = 0;
|
||||||
|
u8 update_latency = 0;
|
||||||
|
|
||||||
if (ioc->shost_recovery)
|
if (ioc->shost_recovery)
|
||||||
return;
|
return;
|
||||||
@@ -1113,12 +1153,22 @@ _scsih_pcie_device_remove_by_handle(struct MPT3SAS_ADAPTER *ioc, u16 handle)
|
|||||||
was_on_pcie_device_list = 1;
|
was_on_pcie_device_list = 1;
|
||||||
pcie_device_put(pcie_device);
|
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);
|
spin_unlock_irqrestore(&ioc->pcie_device_lock, flags);
|
||||||
if (was_on_pcie_device_list) {
|
if (was_on_pcie_device_list) {
|
||||||
_scsih_pcie_device_remove_from_sml(ioc, pcie_device);
|
_scsih_pcie_device_remove_from_sml(ioc, pcie_device);
|
||||||
pcie_device_put(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;
|
max_depth = 1;
|
||||||
if (qdepth > max_depth)
|
if (qdepth > max_depth)
|
||||||
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;
|
u16 smid = 0;
|
||||||
u32 ioc_state;
|
u32 ioc_state;
|
||||||
int rc;
|
int rc;
|
||||||
|
u8 issue_reset = 0;
|
||||||
|
|
||||||
lockdep_assert_held(&ioc->tm_cmds.mutex);
|
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) {
|
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);
|
MPI2_DOORBELL_DATA_MASK);
|
||||||
rc = mpt3sas_base_hard_reset_handler(ioc, FORCE_BIG_HAMMER);
|
rc = mpt3sas_base_hard_reset_handler(ioc, FORCE_BIG_HAMMER);
|
||||||
return (!rc) ? SUCCESS : FAILED;
|
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);
|
ioc->put_smid_hi_priority(ioc, smid, msix_task);
|
||||||
wait_for_completion_timeout(&ioc->tm_cmds.done, timeout*HZ);
|
wait_for_completion_timeout(&ioc->tm_cmds.done, timeout*HZ);
|
||||||
if (!(ioc->tm_cmds.status & MPT3_CMD_COMPLETE)) {
|
if (!(ioc->tm_cmds.status & MPT3_CMD_COMPLETE)) {
|
||||||
if (mpt3sas_base_check_cmd_timeout(ioc,
|
mpt3sas_check_cmd_timeout(ioc,
|
||||||
ioc->tm_cmds.status, mpi_request,
|
ioc->tm_cmds.status, mpi_request,
|
||||||
sizeof(Mpi2SCSITaskManagementRequest_t)/4)) {
|
sizeof(Mpi2SCSITaskManagementRequest_t)/4, issue_reset);
|
||||||
|
if (issue_reset) {
|
||||||
rc = mpt3sas_base_hard_reset_handler(ioc,
|
rc = mpt3sas_base_hard_reset_handler(ioc,
|
||||||
FORCE_BIG_HAMMER);
|
FORCE_BIG_HAMMER);
|
||||||
rc = (!rc) ? SUCCESS : FAILED;
|
rc = (!rc) ? SUCCESS : FAILED;
|
||||||
@@ -2875,15 +2938,17 @@ scsih_abort(struct scsi_cmnd *scmd)
|
|||||||
|
|
||||||
u8 timeout = 30;
|
u8 timeout = 30;
|
||||||
struct _pcie_device *pcie_device = NULL;
|
struct _pcie_device *pcie_device = NULL;
|
||||||
sdev_printk(KERN_INFO, scmd->device,
|
sdev_printk(KERN_INFO, scmd->device, "attempting task abort!"
|
||||||
"attempting task abort! scmd(%p)\n", scmd);
|
"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);
|
_scsih_tm_display_info(ioc, scmd);
|
||||||
|
|
||||||
sas_device_priv_data = scmd->device->hostdata;
|
sas_device_priv_data = scmd->device->hostdata;
|
||||||
if (!sas_device_priv_data || !sas_device_priv_data->sas_target ||
|
if (!sas_device_priv_data || !sas_device_priv_data->sas_target ||
|
||||||
ioc->remove_host) {
|
ioc->remove_host) {
|
||||||
sdev_printk(KERN_INFO, scmd->device,
|
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->result = DID_NO_CONNECT << 16;
|
||||||
scmd->scsi_done(scmd);
|
scmd->scsi_done(scmd);
|
||||||
r = SUCCESS;
|
r = SUCCESS;
|
||||||
@@ -2892,6 +2957,8 @@ scsih_abort(struct scsi_cmnd *scmd)
|
|||||||
|
|
||||||
/* check for completed command */
|
/* check for completed command */
|
||||||
if (st == NULL || st->cb_idx == 0xFF) {
|
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;
|
scmd->result = DID_RESET << 16;
|
||||||
r = SUCCESS;
|
r = SUCCESS;
|
||||||
goto out;
|
goto out;
|
||||||
@@ -2920,7 +2987,7 @@ scsih_abort(struct scsi_cmnd *scmd)
|
|||||||
if (r == SUCCESS && st->cb_idx != 0xFF)
|
if (r == SUCCESS && st->cb_idx != 0xFF)
|
||||||
r = FAILED;
|
r = FAILED;
|
||||||
out:
|
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);
|
((r == SUCCESS) ? "SUCCESS" : "FAILED"), scmd);
|
||||||
if (pcie_device)
|
if (pcie_device)
|
||||||
pcie_device_put(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;
|
struct MPT3SAS_TARGET *target_priv_data = starget->hostdata;
|
||||||
|
|
||||||
sdev_printk(KERN_INFO, scmd->device,
|
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);
|
_scsih_tm_display_info(ioc, scmd);
|
||||||
|
|
||||||
sas_device_priv_data = scmd->device->hostdata;
|
sas_device_priv_data = scmd->device->hostdata;
|
||||||
if (!sas_device_priv_data || !sas_device_priv_data->sas_target ||
|
if (!sas_device_priv_data || !sas_device_priv_data->sas_target ||
|
||||||
ioc->remove_host) {
|
ioc->remove_host) {
|
||||||
sdev_printk(KERN_INFO, scmd->device,
|
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->result = DID_NO_CONNECT << 16;
|
||||||
scmd->scsi_done(scmd);
|
scmd->scsi_done(scmd);
|
||||||
r = SUCCESS;
|
r = SUCCESS;
|
||||||
@@ -2996,7 +3063,7 @@ scsih_dev_reset(struct scsi_cmnd *scmd)
|
|||||||
if (r == SUCCESS && atomic_read(&scmd->device->device_busy))
|
if (r == SUCCESS && atomic_read(&scmd->device->device_busy))
|
||||||
r = FAILED;
|
r = FAILED;
|
||||||
out:
|
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);
|
((r == SUCCESS) ? "SUCCESS" : "FAILED"), scmd);
|
||||||
|
|
||||||
if (sas_device)
|
if (sas_device)
|
||||||
@@ -3027,15 +3094,15 @@ scsih_target_reset(struct scsi_cmnd *scmd)
|
|||||||
struct scsi_target *starget = scmd->device->sdev_target;
|
struct scsi_target *starget = scmd->device->sdev_target;
|
||||||
struct MPT3SAS_TARGET *target_priv_data = starget->hostdata;
|
struct MPT3SAS_TARGET *target_priv_data = starget->hostdata;
|
||||||
|
|
||||||
starget_printk(KERN_INFO, starget, "attempting target reset! scmd(%p)\n",
|
starget_printk(KERN_INFO, starget,
|
||||||
scmd);
|
"attempting target reset! scmd(0x%p)\n", scmd);
|
||||||
_scsih_tm_display_info(ioc, scmd);
|
_scsih_tm_display_info(ioc, scmd);
|
||||||
|
|
||||||
sas_device_priv_data = scmd->device->hostdata;
|
sas_device_priv_data = scmd->device->hostdata;
|
||||||
if (!sas_device_priv_data || !sas_device_priv_data->sas_target ||
|
if (!sas_device_priv_data || !sas_device_priv_data->sas_target ||
|
||||||
ioc->remove_host) {
|
ioc->remove_host) {
|
||||||
starget_printk(KERN_INFO, starget, "target been deleted! scmd(%p)\n",
|
starget_printk(KERN_INFO, starget,
|
||||||
scmd);
|
"target been deleted! scmd(0x%p)\n", scmd);
|
||||||
scmd->result = DID_NO_CONNECT << 16;
|
scmd->result = DID_NO_CONNECT << 16;
|
||||||
scmd->scsi_done(scmd);
|
scmd->scsi_done(scmd);
|
||||||
r = SUCCESS;
|
r = SUCCESS;
|
||||||
@@ -3074,7 +3141,7 @@ scsih_target_reset(struct scsi_cmnd *scmd)
|
|||||||
if (r == SUCCESS && atomic_read(&starget->target_busy))
|
if (r == SUCCESS && atomic_read(&starget->target_busy))
|
||||||
r = FAILED;
|
r = FAILED;
|
||||||
out:
|
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);
|
((r == SUCCESS) ? "SUCCESS" : "FAILED"), scmd);
|
||||||
|
|
||||||
if (sas_device)
|
if (sas_device)
|
||||||
@@ -3097,7 +3164,7 @@ scsih_host_reset(struct scsi_cmnd *scmd)
|
|||||||
struct MPT3SAS_ADAPTER *ioc = shost_priv(scmd->device->host);
|
struct MPT3SAS_ADAPTER *ioc = shost_priv(scmd->device->host);
|
||||||
int r, retval;
|
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);
|
scsi_print_command(scmd);
|
||||||
|
|
||||||
if (ioc->is_driver_loading || ioc->remove_host) {
|
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);
|
retval = mpt3sas_base_hard_reset_handler(ioc, FORCE_BIG_HAMMER);
|
||||||
r = (retval < 0) ? FAILED : SUCCESS;
|
r = (retval < 0) ? FAILED : SUCCESS;
|
||||||
out:
|
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);
|
r == SUCCESS ? "SUCCESS" : "FAILED", scmd);
|
||||||
|
|
||||||
return r;
|
return r;
|
||||||
@@ -4475,6 +4542,7 @@ static void
|
|||||||
_scsih_temp_threshold_events(struct MPT3SAS_ADAPTER *ioc,
|
_scsih_temp_threshold_events(struct MPT3SAS_ADAPTER *ioc,
|
||||||
Mpi2EventDataTemperature_t *event_data)
|
Mpi2EventDataTemperature_t *event_data)
|
||||||
{
|
{
|
||||||
|
u32 doorbell;
|
||||||
if (ioc->temp_sensors_count >= event_data->SensorNum) {
|
if (ioc->temp_sensors_count >= event_data->SensorNum) {
|
||||||
ioc_err(ioc, "Temperature Threshold flags %s%s%s%s exceeded for Sensor: %d !!!\n",
|
ioc_err(ioc, "Temperature Threshold flags %s%s%s%s exceeded for Sensor: %d !!!\n",
|
||||||
le16_to_cpu(event_data->Status) & 0x1 ? "0 " : " ",
|
le16_to_cpu(event_data->Status) & 0x1 ? "0 " : " ",
|
||||||
@@ -4484,6 +4552,18 @@ _scsih_temp_threshold_events(struct MPT3SAS_ADAPTER *ioc,
|
|||||||
event_data->SensorNum);
|
event_data->SensorNum);
|
||||||
ioc_err(ioc, "Current Temp In Celsius: %d\n",
|
ioc_err(ioc, "Current Temp In Celsius: %d\n",
|
||||||
event_data->CurrentTemperature);
|
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)))) {
|
le32_to_cpu(pcie_device_pg0.DeviceInfo)))) {
|
||||||
pcie_device->nvme_mdts =
|
pcie_device->nvme_mdts =
|
||||||
le32_to_cpu(pcie_device_pg2.MaximumDataTransferSize);
|
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)
|
if (pcie_device_pg2.ControllerResetTO)
|
||||||
pcie_device->reset_timeout =
|
pcie_device->reset_timeout =
|
||||||
pcie_device_pg2.ControllerResetTO;
|
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);
|
wait_for_completion_timeout(&ioc->scsih_cmds.done, 10*HZ);
|
||||||
|
|
||||||
if (!(ioc->scsih_cmds.status & MPT3_CMD_COMPLETE)) {
|
if (!(ioc->scsih_cmds.status & MPT3_CMD_COMPLETE)) {
|
||||||
issue_reset =
|
mpt3sas_check_cmd_timeout(ioc,
|
||||||
mpt3sas_base_check_cmd_timeout(ioc,
|
ioc->scsih_cmds.status, mpi_request,
|
||||||
ioc->scsih_cmds.status, mpi_request,
|
sizeof(Mpi2RaidActionRequest_t)/4, issue_reset);
|
||||||
sizeof(Mpi2RaidActionRequest_t)/4);
|
|
||||||
rc = -EFAULT;
|
rc = -EFAULT;
|
||||||
goto out;
|
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
|
* @ioc: per adapter object
|
||||||
*
|
*
|
||||||
* The handler for doing any required cleanup or initialization.
|
* The handler for doing any required cleanup or initialization.
|
||||||
*/
|
*/
|
||||||
void
|
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) {
|
if (ioc->scsih_cmds.status & MPT3_CMD_PENDING) {
|
||||||
ioc->scsih_cmds.status |= MPT3_CMD_RESET;
|
ioc->scsih_cmds.status |= MPT3_CMD_RESET;
|
||||||
mpt3sas_base_free_smid(ioc, ioc->scsih_cmds.smid);
|
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_remove_unresponding_devices(ioc);
|
||||||
_scsih_scan_for_devices_after_reset(ioc);
|
_scsih_scan_for_devices_after_reset(ioc);
|
||||||
|
_scsih_set_nvme_max_shutdown_latency(ioc);
|
||||||
break;
|
break;
|
||||||
case MPT3SAS_PORT_ENABLE_COMPLETE:
|
case MPT3SAS_PORT_ENABLE_COMPLETE:
|
||||||
ioc->start_scan = 0;
|
ioc->start_scan = 0;
|
||||||
@@ -9659,6 +9751,75 @@ _scsih_expander_node_remove(struct MPT3SAS_ADAPTER *ioc,
|
|||||||
kfree(sas_expander);
|
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
|
* _scsih_ir_shutdown - IR shutdown notification
|
||||||
* @ioc: per adapter object
|
* @ioc: per adapter object
|
||||||
@@ -9851,6 +10012,7 @@ scsih_shutdown(struct pci_dev *pdev)
|
|||||||
&ioc->ioc_pg1_copy);
|
&ioc->ioc_pg1_copy);
|
||||||
|
|
||||||
_scsih_ir_shutdown(ioc);
|
_scsih_ir_shutdown(ioc);
|
||||||
|
_scsih_nvme_shutdown(ioc);
|
||||||
mpt3sas_base_detach(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->tm_sas_control_cb_idx = tm_sas_control_cb_idx;
|
||||||
ioc->logging_level = logging_level;
|
ioc->logging_level = logging_level;
|
||||||
ioc->schedule_dead_ioc_flush_running_cmds = &_scsih_flush_running_cmds;
|
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.
|
* Enable MEMORY MOVE support flag.
|
||||||
*/
|
*/
|
||||||
@@ -10681,6 +10845,7 @@ scsih_suspend(struct pci_dev *pdev, pm_message_t state)
|
|||||||
mpt3sas_base_stop_watchdog(ioc);
|
mpt3sas_base_stop_watchdog(ioc);
|
||||||
flush_scheduled_work();
|
flush_scheduled_work();
|
||||||
scsi_block_requests(shost);
|
scsi_block_requests(shost);
|
||||||
|
_scsih_nvme_shutdown(ioc);
|
||||||
device_state = pci_choose_state(pdev, state);
|
device_state = pci_choose_state(pdev, state);
|
||||||
ioc_info(ioc, "pdev=0x%p, slot=%s, entering operating state [D%d]\n",
|
ioc_info(ioc, "pdev=0x%p, slot=%s, entering operating state [D%d]\n",
|
||||||
pdev, pci_name(pdev), device_state);
|
pdev, pci_name(pdev), device_state);
|
||||||
@@ -10715,7 +10880,7 @@ scsih_resume(struct pci_dev *pdev)
|
|||||||
r = mpt3sas_base_map_resources(ioc);
|
r = mpt3sas_base_map_resources(ioc);
|
||||||
if (r)
|
if (r)
|
||||||
return r;
|
return r;
|
||||||
|
ioc_info(ioc, "Issuing Hard Reset as part of OS Resume\n");
|
||||||
mpt3sas_base_hard_reset_handler(ioc, SOFT_RESET);
|
mpt3sas_base_hard_reset_handler(ioc, SOFT_RESET);
|
||||||
scsi_unblock_requests(shost);
|
scsi_unblock_requests(shost);
|
||||||
mpt3sas_base_start_watchdog(ioc);
|
mpt3sas_base_start_watchdog(ioc);
|
||||||
@@ -10784,6 +10949,7 @@ scsih_pci_slot_reset(struct pci_dev *pdev)
|
|||||||
if (rc)
|
if (rc)
|
||||||
return PCI_ERS_RESULT_DISCONNECT;
|
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);
|
rc = mpt3sas_base_hard_reset_handler(ioc, FORCE_BIG_HAMMER);
|
||||||
|
|
||||||
ioc_warn(ioc, "hard reset: %s\n",
|
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);
|
sas_device_put(sas_device);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((ioc->logging_level & MPT_DEBUG_TRANSPORT))
|
dev_info(&rphy->dev,
|
||||||
dev_printk(KERN_INFO, &rphy->dev,
|
"add: handle(0x%04x), sas_addr(0x%016llx)\n", handle,
|
||||||
"add: handle(0x%04x), sas_addr(0x%016llx)\n",
|
(unsigned long long)mpt3sas_port->remote_identify.sas_address);
|
||||||
handle, (unsigned long long)
|
|
||||||
mpt3sas_port->remote_identify.sas_address);
|
|
||||||
mpt3sas_port->rphy = rphy;
|
mpt3sas_port->rphy = rphy;
|
||||||
spin_lock_irqsave(&ioc->sas_node_lock, flags);
|
spin_lock_irqsave(&ioc->sas_node_lock, flags);
|
||||||
list_add_tail(&mpt3sas_port->port_list, &sas_node->sas_port_list);
|
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)
|
if (!ioc->remove_host)
|
||||||
sas_port_delete(mpt3sas_port->port);
|
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);
|
kfree(mpt3sas_port);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -47,6 +47,9 @@ static struct scsi_host_template mvs_sht = {
|
|||||||
.eh_target_reset_handler = sas_eh_target_reset_handler,
|
.eh_target_reset_handler = sas_eh_target_reset_handler,
|
||||||
.target_destroy = sas_target_destroy,
|
.target_destroy = sas_target_destroy,
|
||||||
.ioctl = sas_ioctl,
|
.ioctl = sas_ioctl,
|
||||||
|
#ifdef CONFIG_COMPAT
|
||||||
|
.compat_ioctl = sas_ioctl,
|
||||||
|
#endif
|
||||||
.shost_attrs = mvst_host_attrs,
|
.shost_attrs = mvst_host_attrs,
|
||||||
.track_queue_depth = 1,
|
.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
|
* Linux Driver for Mylex DAC960/AcceleRAID/eXtremeRAID PCI RAID Controllers
|
||||||
*
|
*
|
||||||
* Copyright 2017 Hannes Reinecke, SUSE Linux GmbH <hare@suse.com>
|
* 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
|
* Linux Driver for Mylex DAC960/AcceleRAID/eXtremeRAID PCI RAID Controllers
|
||||||
*
|
*
|
||||||
* This driver supports the newer, SCSI-based firmware interface only.
|
* 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,
|
.eh_target_reset_handler = sas_eh_target_reset_handler,
|
||||||
.target_destroy = sas_target_destroy,
|
.target_destroy = sas_target_destroy,
|
||||||
.ioctl = sas_ioctl,
|
.ioctl = sas_ioctl,
|
||||||
|
#ifdef CONFIG_COMPAT
|
||||||
|
.compat_ioctl = sas_ioctl,
|
||||||
|
#endif
|
||||||
.shost_attrs = pm8001_host_attrs,
|
.shost_attrs = pm8001_host_attrs,
|
||||||
.track_queue_depth = 1,
|
.track_queue_depth = 1,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1699,6 +1699,16 @@ qla1280_load_firmware_pio(struct scsi_qla_host *ha)
|
|||||||
return err;
|
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 */
|
#define DUMP_IT_BACK 0 /* for debug of RISC loading */
|
||||||
static int
|
static int
|
||||||
qla1280_load_firmware_dma(struct scsi_qla_host *ha)
|
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++)
|
for(i = 0; i < cnt; i++)
|
||||||
((__le16 *)ha->request_ring)[i] = fw_data[i];
|
((__le16 *)ha->request_ring)[i] = fw_data[i];
|
||||||
|
|
||||||
mb[0] = MBC_LOAD_RAM;
|
mb[0] = LOAD_CMD;
|
||||||
mb[1] = risc_address;
|
mb[1] = risc_address;
|
||||||
mb[4] = cnt;
|
mb[4] = cnt;
|
||||||
mb[3] = ha->request_dma & 0xffff;
|
mb[3] = ha->request_dma & 0xffff;
|
||||||
@@ -1759,8 +1769,7 @@ qla1280_load_firmware_dma(struct scsi_qla_host *ha)
|
|||||||
__func__, mb[0],
|
__func__, mb[0],
|
||||||
(void *)(long)ha->request_dma,
|
(void *)(long)ha->request_dma,
|
||||||
mb[6], mb[7], mb[2], mb[3]);
|
mb[6], mb[7], mb[2], mb[3]);
|
||||||
err = qla1280_mailbox_command(ha, BIT_4 | BIT_3 | BIT_2 |
|
err = qla1280_mailbox_command(ha, CMD_ARGS, mb);
|
||||||
BIT_1 | BIT_0, mb);
|
|
||||||
if (err) {
|
if (err) {
|
||||||
printk(KERN_ERR "scsi(%li): Failed to load partial "
|
printk(KERN_ERR "scsi(%li): Failed to load partial "
|
||||||
"segment of f\n", ha->host_no);
|
"segment of f\n", ha->host_no);
|
||||||
@@ -1768,7 +1777,7 @@ qla1280_load_firmware_dma(struct scsi_qla_host *ha)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#if DUMP_IT_BACK
|
#if DUMP_IT_BACK
|
||||||
mb[0] = MBC_DUMP_RAM;
|
mb[0] = DUMP_CMD;
|
||||||
mb[1] = risc_address;
|
mb[1] = risc_address;
|
||||||
mb[4] = cnt;
|
mb[4] = cnt;
|
||||||
mb[3] = p_tbuf & 0xffff;
|
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[7] = upper_32_bits(p_tbuf) & 0xffff;
|
||||||
mb[6] = upper_32_bits(p_tbuf) >> 16;
|
mb[6] = upper_32_bits(p_tbuf) >> 16;
|
||||||
|
|
||||||
err = qla1280_mailbox_command(ha, BIT_4 | BIT_3 | BIT_2 |
|
err = qla1280_mailbox_command(ha, CMD_ARGS, mb);
|
||||||
BIT_1 | BIT_0, mb);
|
|
||||||
if (err) {
|
if (err) {
|
||||||
printk(KERN_ERR
|
printk(KERN_ERR
|
||||||
"Failed to dump partial segment of f/w\n");
|
"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_MAILBOX_REGISTER_TEST 6 /* Wrap incoming mailboxes */
|
||||||
#define MBC_VERIFY_CHECKSUM 7 /* Verify checksum */
|
#define MBC_VERIFY_CHECKSUM 7 /* Verify checksum */
|
||||||
#define MBC_ABOUT_FIRMWARE 8 /* Get firmware revision */
|
#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_REQUEST_QUEUE 0x10 /* Initialize request queue */
|
||||||
#define MBC_INIT_RESPONSE_QUEUE 0x11 /* Initialize response queue */
|
#define MBC_INIT_RESPONSE_QUEUE 0x11 /* Initialize response queue */
|
||||||
#define MBC_EXECUTE_IOCB 0x12 /* Execute IOCB command */
|
#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 ||
|
if (sp->type == SRB_CT_CMD ||
|
||||||
sp->type == SRB_FXIOCB_BCMD ||
|
sp->type == SRB_FXIOCB_BCMD ||
|
||||||
sp->type == SRB_ELS_CMD_HST)
|
sp->type == SRB_ELS_CMD_HST)
|
||||||
kfree(sp->fcport);
|
qla2x00_free_fcport(sp->fcport);
|
||||||
|
|
||||||
qla2x00_rel_sp(sp);
|
qla2x00_rel_sp(sp);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -405,7 +406,7 @@ done_unmap_sg:
|
|||||||
|
|
||||||
done_free_fcport:
|
done_free_fcport:
|
||||||
if (bsg_request->msgcode == FC_BSG_RPT_ELS)
|
if (bsg_request->msgcode == FC_BSG_RPT_ELS)
|
||||||
kfree(fcport);
|
qla2x00_free_fcport(fcport);
|
||||||
done:
|
done:
|
||||||
return rval;
|
return rval;
|
||||||
}
|
}
|
||||||
@@ -545,7 +546,7 @@ qla2x00_process_ct(struct bsg_job *bsg_job)
|
|||||||
return rval;
|
return rval;
|
||||||
|
|
||||||
done_free_fcport:
|
done_free_fcport:
|
||||||
kfree(fcport);
|
qla2x00_free_fcport(fcport);
|
||||||
done_unmap_sg:
|
done_unmap_sg:
|
||||||
dma_unmap_sg(&ha->pdev->dev, bsg_job->request_payload.sg_list,
|
dma_unmap_sg(&ha->pdev->dev, bsg_job->request_payload.sg_list,
|
||||||
bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE);
|
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 &&
|
if (atomic_read(&vha->loop_state) == LOOP_READY &&
|
||||||
(ha->current_topology == ISP_CFG_F ||
|
(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)) &&
|
req_data_len == MAX_ELS_FRAME_PAYLOAD)) &&
|
||||||
elreq.options == EXTERNAL_LOOPBACK) {
|
elreq.options == EXTERNAL_LOOPBACK) {
|
||||||
type = "FC_BSG_HST_VENDOR_ECHO_DIAG";
|
type = "FC_BSG_HST_VENDOR_ECHO_DIAG";
|
||||||
@@ -2049,7 +2050,7 @@ qlafx00_mgmt_cmd(struct bsg_job *bsg_job)
|
|||||||
return rval;
|
return rval;
|
||||||
|
|
||||||
done_free_fcport:
|
done_free_fcport:
|
||||||
kfree(fcport);
|
qla2x00_free_fcport(fcport);
|
||||||
|
|
||||||
done_unmap_rsp_sg:
|
done_unmap_rsp_sg:
|
||||||
if (piocb_rqst->flags & SRB_FXDISC_RESP_DMA_VALID)
|
if (piocb_rqst->flags & SRB_FXDISC_RESP_DMA_VALID)
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
* | Device Discovery | 0x2134 | 0x210e-0x2116 |
|
* | Device Discovery | 0x2134 | 0x210e-0x2116 |
|
||||||
* | | | 0x211a |
|
* | | | 0x211a |
|
||||||
* | | | 0x211c-0x2128 |
|
* | | | 0x211c-0x2128 |
|
||||||
* | | | 0x212a-0x2130 |
|
* | | | 0x212a-0x2134 |
|
||||||
* | Queue Command and IO tracing | 0x3074 | 0x300b |
|
* | Queue Command and IO tracing | 0x3074 | 0x300b |
|
||||||
* | | | 0x3027-0x3028 |
|
* | | | 0x3027-0x3028 |
|
||||||
* | | | 0x303d-0x3041 |
|
* | | | 0x303d-0x3041 |
|
||||||
|
|||||||
@@ -2402,6 +2402,7 @@ typedef struct fc_port {
|
|||||||
unsigned int scan_needed:1;
|
unsigned int scan_needed:1;
|
||||||
unsigned int n2n_flag:1;
|
unsigned int n2n_flag:1;
|
||||||
unsigned int explicit_logout:1;
|
unsigned int explicit_logout:1;
|
||||||
|
unsigned int prli_pend_timer:1;
|
||||||
|
|
||||||
struct completion nvme_del_done;
|
struct completion nvme_del_done;
|
||||||
uint32_t nvme_prli_service_param;
|
uint32_t nvme_prli_service_param;
|
||||||
@@ -2428,6 +2429,7 @@ typedef struct fc_port {
|
|||||||
struct work_struct free_work;
|
struct work_struct free_work;
|
||||||
struct work_struct reg_work;
|
struct work_struct reg_work;
|
||||||
uint64_t jiffies_at_registration;
|
uint64_t jiffies_at_registration;
|
||||||
|
unsigned long prli_expired;
|
||||||
struct qlt_plogi_ack_t *plogi_link[QLT_PLOGI_LINK_MAX];
|
struct qlt_plogi_ack_t *plogi_link[QLT_PLOGI_LINK_MAX];
|
||||||
|
|
||||||
uint16_t tgt_id;
|
uint16_t tgt_id;
|
||||||
@@ -2464,6 +2466,7 @@ typedef struct fc_port {
|
|||||||
struct qla_tgt_sess *tgt_session;
|
struct qla_tgt_sess *tgt_session;
|
||||||
struct ct_sns_desc ct_desc;
|
struct ct_sns_desc ct_desc;
|
||||||
enum discovery_state disc_state;
|
enum discovery_state disc_state;
|
||||||
|
atomic_t shadow_disc_state;
|
||||||
enum discovery_state next_disc_state;
|
enum discovery_state next_disc_state;
|
||||||
enum login_state fw_login_state;
|
enum login_state fw_login_state;
|
||||||
unsigned long dm_login_expire;
|
unsigned long dm_login_expire;
|
||||||
@@ -2510,6 +2513,19 @@ struct event_arg {
|
|||||||
|
|
||||||
extern const char *const port_state_str[5];
|
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.
|
* FC port flags.
|
||||||
*/
|
*/
|
||||||
@@ -3263,7 +3279,6 @@ enum qla_work_type {
|
|||||||
QLA_EVT_IDC_ACK,
|
QLA_EVT_IDC_ACK,
|
||||||
QLA_EVT_ASYNC_LOGIN,
|
QLA_EVT_ASYNC_LOGIN,
|
||||||
QLA_EVT_ASYNC_LOGOUT,
|
QLA_EVT_ASYNC_LOGOUT,
|
||||||
QLA_EVT_ASYNC_LOGOUT_DONE,
|
|
||||||
QLA_EVT_ASYNC_ADISC,
|
QLA_EVT_ASYNC_ADISC,
|
||||||
QLA_EVT_UEVENT,
|
QLA_EVT_UEVENT,
|
||||||
QLA_EVT_AENFX,
|
QLA_EVT_AENFX,
|
||||||
@@ -3953,7 +3968,7 @@ struct qla_hw_data {
|
|||||||
void *sfp_data;
|
void *sfp_data;
|
||||||
dma_addr_t sfp_data_dma;
|
dma_addr_t sfp_data_dma;
|
||||||
|
|
||||||
void *flt;
|
struct qla_flt_header *flt;
|
||||||
dma_addr_t flt_dma;
|
dma_addr_t flt_dma;
|
||||||
|
|
||||||
#define XGMAC_DATA_SIZE 4096
|
#define XGMAC_DATA_SIZE 4096
|
||||||
@@ -4845,6 +4860,9 @@ struct sff_8247_a0 {
|
|||||||
(ha->fc4_type_priority == FC4_PRIORITY_NVME)) || \
|
(ha->fc4_type_priority == FC4_PRIORITY_NVME)) || \
|
||||||
NVME_ONLY_TARGET(fcport)) \
|
NVME_ONLY_TARGET(fcport)) \
|
||||||
|
|
||||||
|
#define PRLI_PHASE(_cls) \
|
||||||
|
((_cls == DSC_LS_PRLI_PEND) || (_cls == DSC_LS_PRLI_COMP))
|
||||||
|
|
||||||
#include "qla_target.h"
|
#include "qla_target.h"
|
||||||
#include "qla_gbl.h"
|
#include "qla_gbl.h"
|
||||||
#include "qla_dbg.h"
|
#include "qla_dbg.h"
|
||||||
|
|||||||
@@ -1354,12 +1354,12 @@ struct vp_rpt_id_entry_24xx {
|
|||||||
uint8_t port_id[3];
|
uint8_t port_id[3];
|
||||||
uint8_t format;
|
uint8_t format;
|
||||||
union {
|
union {
|
||||||
struct {
|
struct _f0 {
|
||||||
/* format 0 loop */
|
/* format 0 loop */
|
||||||
uint8_t vp_idx_map[16];
|
uint8_t vp_idx_map[16];
|
||||||
uint8_t reserved_4[32];
|
uint8_t reserved_4[32];
|
||||||
} f0;
|
} f0;
|
||||||
struct {
|
struct _f1 {
|
||||||
/* format 1 fabric */
|
/* format 1 fabric */
|
||||||
uint8_t vpstat1_subcode; /* vp_status=1 subcode */
|
uint8_t vpstat1_subcode; /* vp_status=1 subcode */
|
||||||
uint8_t flags;
|
uint8_t flags;
|
||||||
@@ -1381,21 +1381,22 @@ struct vp_rpt_id_entry_24xx {
|
|||||||
uint16_t bbcr;
|
uint16_t bbcr;
|
||||||
uint8_t reserved_5[6];
|
uint8_t reserved_5[6];
|
||||||
} f1;
|
} f1;
|
||||||
struct { /* format 2: N2N direct connect */
|
struct _f2 { /* format 2: N2N direct connect */
|
||||||
uint8_t vpstat1_subcode;
|
uint8_t vpstat1_subcode;
|
||||||
uint8_t flags;
|
uint8_t flags;
|
||||||
uint16_t rsv6;
|
uint16_t fip_flags;
|
||||||
uint8_t rsv2[12];
|
uint8_t rsv2[12];
|
||||||
|
|
||||||
uint8_t ls_rjt_vendor;
|
uint8_t ls_rjt_vendor;
|
||||||
uint8_t ls_rjt_explanation;
|
uint8_t ls_rjt_explanation;
|
||||||
uint8_t ls_rjt_reason;
|
uint8_t ls_rjt_reason;
|
||||||
uint8_t rsv3[5];
|
uint8_t rsv3[5];
|
||||||
|
|
||||||
uint8_t port_name[8];
|
uint8_t port_name[8];
|
||||||
uint8_t node_name[8];
|
uint8_t node_name[8];
|
||||||
uint8_t remote_nport_id[4];
|
uint16_t bbcr;
|
||||||
uint32_t reserved_5;
|
uint8_t reserved_5[2];
|
||||||
|
uint8_t remote_nport_id[4];
|
||||||
} f2;
|
} f2;
|
||||||
} u;
|
} u;
|
||||||
};
|
};
|
||||||
@@ -1470,13 +1471,6 @@ struct qla_flt_location {
|
|||||||
uint16_t checksum;
|
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_FW 0x01
|
||||||
#define FLT_REG_BOOT_CODE 0x07
|
#define FLT_REG_BOOT_CODE 0x07
|
||||||
#define FLT_REG_VPD_0 0x14
|
#define FLT_REG_VPD_0 0x14
|
||||||
@@ -1537,6 +1531,14 @@ struct qla_flt_region {
|
|||||||
uint32_t end;
|
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_REGION_SIZE 16
|
||||||
#define FLT_MAX_REGIONS 0xFF
|
#define FLT_MAX_REGIONS 0xFF
|
||||||
#define FLT_REGIONS_SIZE (FLT_REGION_SIZE * FLT_MAX_REGIONS)
|
#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 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 *,
|
extern void qla2x00_async_login_done(struct scsi_qla_host *, fc_port_t *,
|
||||||
uint16_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 *,
|
struct qla_work_evt *qla2x00_alloc_work(struct scsi_qla_host *,
|
||||||
enum qla_work_type);
|
enum qla_work_type);
|
||||||
extern int qla24xx_async_gnl(struct scsi_qla_host *, fc_port_t *);
|
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);
|
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 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_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 void qla2x00_set_fcport_state(fc_port_t *fcport, int state);
|
||||||
extern fc_port_t *
|
extern fc_port_t *
|
||||||
@@ -182,8 +181,6 @@ extern int qla2x00_post_async_login_work(struct scsi_qla_host *, fc_port_t *,
|
|||||||
uint16_t *);
|
uint16_t *);
|
||||||
extern int qla2x00_post_async_logout_work(struct scsi_qla_host *, fc_port_t *,
|
extern int qla2x00_post_async_logout_work(struct scsi_qla_host *, fc_port_t *,
|
||||||
uint16_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 *,
|
extern int qla2x00_post_async_adisc_work(struct scsi_qla_host *, fc_port_t *,
|
||||||
uint16_t *);
|
uint16_t *);
|
||||||
extern int qla2x00_post_async_adisc_done_work(struct scsi_qla_host *,
|
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_relogin(struct scsi_qla_host *);
|
||||||
extern void qla2x00_do_work(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_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_schedule_work(scsi_qla_host_t *, int);
|
||||||
extern void qla83xx_service_idc_aen(struct work_struct *);
|
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 void qla2x00_sp_free_dma(srb_t *sp);
|
||||||
extern char *qla2x00_get_fw_version_str(struct scsi_qla_host *, char *);
|
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_device_lost(scsi_qla_host_t *, fc_port_t *, int);
|
||||||
extern void qla2x00_mark_all_devices_lost(scsi_qla_host_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 *);
|
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;
|
return QLA_FUNCTION_FAILED;
|
||||||
|
|
||||||
e->u.fcport.fcport = fcport;
|
e->u.fcport.fcport = fcport;
|
||||||
fcport->flags |= FCF_ASYNC_ACTIVE;
|
|
||||||
return qla2x00_post_work(vha, e);
|
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:
|
done_free_sp:
|
||||||
sp->free(sp);
|
sp->free(sp);
|
||||||
fcport->flags &= ~FCF_ASYNC_SENT;
|
|
||||||
done:
|
done:
|
||||||
fcport->flags &= ~FCF_ASYNC_ACTIVE;
|
|
||||||
return rval;
|
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))
|
if (!vha->flags.online || (fcport->flags & FCF_ASYNC_SENT))
|
||||||
return rval;
|
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);
|
sp = qla2x00_get_sp(vha, fcport, GFP_ATOMIC);
|
||||||
if (!sp)
|
if (!sp)
|
||||||
goto done;
|
goto done;
|
||||||
@@ -4464,7 +4461,6 @@ int qla24xx_async_gfpnid(scsi_qla_host_t *vha, fc_port_t *fcport)
|
|||||||
|
|
||||||
done_free_sp:
|
done_free_sp:
|
||||||
sp->free(sp);
|
sp->free(sp);
|
||||||
fcport->flags &= ~FCF_ASYNC_SENT;
|
|
||||||
done:
|
done:
|
||||||
return rval;
|
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