mirror of
https://github.com/torvalds/linux.git
synced 2026-03-08 01:04:41 +01:00
s390 updates for 7.0 merge window
- Drop support for outdated 3590/3592 and 3480 tape devices, and limit support to virtualized 3490E types devices - Implement exception based WARN() and WARN_ONCE() similar to x86 - Slightly optimize preempt primitives like __preempt_count_add() and __preempt_count_dec_and_test() - A couple of small fixes and improvements -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEECMNfWEw3SLnmiLkZIg7DeRspbsIFAmmHePIACgkQIg7DeRsp bsIQeA//ZBOWwSlIkGhdH/qn7F2RMxq/FkvYN28YvCo1VFdAiqRXjDBH8yXE9Px4 MghsDY1GzmW3M56Qq/rYZ2UhK0dIgpu9l8SJa5uxRaIzhIUxjmNJa+f3LhtCTZZH 9timoL5zL+n8QwwLPo9DgKy+m/BOodKBeI9cHFYoia64eJqo1xDVg8tYzW+vlVZT LZt0kT6Nz/Hrkg/uOhsz40IGzR/fcsNeDGTF+JIjqcfpdMSAeDMeleWVRacw/0BZ q1gifRXxe04N8bjS7c98RiKX7CD3xQzzibH2ert2Mupu+yir6pvAlgYHOif3Z8gi 6trcSWaxZCCslS2U7O1g/hyz1WXEFC+iDwajGiqT0XRSjuQ2FeVmfqcmaE0CekyY 5mpdtwfLrNSZJL422a3lckqz73gkge5hC46wgvhpvx7lb4IF6paYsk6FPDZlxw+/ THxbrYufs71VACvcfRs5MXSS94qkzkdgo5jhnS/m5zhblIrdkBUz29c5g24qUWo1 ihyzkqtwMFHpKXE9rHK/Z80uZXr4/cLPpMq8XYXRQHZ6vFyZFfu4QpLHWTQ0VMyp ZBijhRqzlN/nAItAfBsgJ5QipHk2WL7V8zoi5xu7QeH+lrZ+7+koSVxGJAZbG4OO 3fv6Nucjr/zCbyRKrjEaWaXzdMCVSdfrtfTQgftgFHTO8IxVLjc= =xeBU -----END PGP SIGNATURE----- Merge tag 's390-7.0-1' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux Pull s390 updates from Heiko Carstens: - Drop support for outdated 3590/3592 and 3480 tape devices, and limit support to virtualized 3490E types devices - Implement exception based WARN() and WARN_ONCE() similar to x86 - Slightly optimize preempt primitives like __preempt_count_add() and __preempt_count_dec_and_test() - A couple of small fixes and improvements * tag 's390-7.0-1' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux: (35 commits) s390/tape: Consolidate tape config options and modules s390/cio: Fix device lifecycle handling in css_alloc_subchannel() s390/tape: Rename tape_34xx.c to tape_3490.c s390/tape: Cleanup sense data analysis and error handling s390/tape: Remove 3480 tape device type s390/tape: Remove unused command definitions s390/tape: Remove special block id handling s390/tape: Remove tape load display support s390/tape: Remove support for 3590/3592 models s390/kexec: Emit an error message when cmdline is too long s390/configs: Enable BLK_DEV_NULL_BLK as module s390: Document s390 stackprotector support s390/perf: Disable register readout on sampling events s390/Kconfig: Define non-zero ILLEGAL_POINTER_VALUE s390/bug: Prevent tail-call optimization s390/bug: Skip __WARN_trap() in call traces s390/bug: Implement WARN_ONCE() s390/bug: Implement __WARN_printf() s390/traps: Copy monitor code to pt_regs s390/bug: Introduce and use monitor code macro ...
This commit is contained in:
commit
c48953d819
37 changed files with 1158 additions and 3310 deletions
|
|
@ -109,3 +109,7 @@ Virtual memory layout
|
|||
| KASAN shadow | KASAN untracked
|
||||
| |
|
||||
+------------------+ ASCE limit
|
||||
| |
|
||||
| CONFIG_ILLEGAL_POINTER_VALUE causes memory access fault
|
||||
| |
|
||||
+------------------+
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@
|
|||
| parisc: | TODO |
|
||||
| powerpc: | ok |
|
||||
| riscv: | ok |
|
||||
| s390: | TODO |
|
||||
| s390: | ok |
|
||||
| sh: | ok |
|
||||
| sparc: | TODO |
|
||||
| um: | TODO |
|
||||
|
|
|
|||
|
|
@ -69,6 +69,12 @@ config CC_HAS_ASM_AOR_FORMAT_FLAGS
|
|||
Clang versions before 19.1.0 do not support A,
|
||||
O, and R inline assembly format flags.
|
||||
|
||||
config CC_HAS_ASM_IMMEDIATE_STRINGS
|
||||
def_bool !(CC_IS_GCC && GCC_VERSION < 90000)
|
||||
help
|
||||
GCC versions before 9.0.0 cannot handle strings as immediate
|
||||
input operands in inline assemblies.
|
||||
|
||||
config CC_HAS_STACKPROTECTOR_GLOBAL
|
||||
def_bool $(cc-option, -mstack-protector-guard=global -mstack-protector-guard-record)
|
||||
|
||||
|
|
@ -85,6 +91,7 @@ config S390
|
|||
select ARCH_ENABLE_MEMORY_HOTREMOVE
|
||||
select ARCH_ENABLE_SPLIT_PMD_PTLOCK if PGTABLE_LEVELS > 2
|
||||
select ARCH_ENABLE_THP_MIGRATION if TRANSPARENT_HUGEPAGE
|
||||
select ARCH_HAS_CC_CAN_LINK
|
||||
select ARCH_HAS_CPU_FINALIZE_INIT
|
||||
select ARCH_HAS_CURRENT_STACK_POINTER
|
||||
select ARCH_HAS_DEBUG_VIRTUAL
|
||||
|
|
@ -294,6 +301,14 @@ config PGTABLE_LEVELS
|
|||
|
||||
source "kernel/livepatch/Kconfig"
|
||||
|
||||
config ARCH_CC_CAN_LINK
|
||||
bool
|
||||
default $(cc_can_link_user,-m64)
|
||||
|
||||
config ARCH_USERFLAGS
|
||||
string
|
||||
default "-m64"
|
||||
|
||||
config ARCH_SUPPORTS_KEXEC
|
||||
def_bool y
|
||||
|
||||
|
|
@ -704,6 +719,10 @@ config ARCH_SPARSEMEM_ENABLE
|
|||
config ARCH_SPARSEMEM_DEFAULT
|
||||
def_bool y
|
||||
|
||||
config ILLEGAL_POINTER_VALUE
|
||||
hex
|
||||
default 0xdead000000000000
|
||||
|
||||
config MAX_PHYSMEM_BITS
|
||||
int "Maximum size of supported physical memory in bits (42-53)"
|
||||
range 42 53
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ KBUILD_AFLAGS := $(filter-out $(CC_FLAGS_MARCH),$(KBUILD_AFLAGS_DECOMPRESSOR))
|
|||
KBUILD_CFLAGS := $(filter-out $(CC_FLAGS_MARCH),$(KBUILD_CFLAGS_DECOMPRESSOR))
|
||||
KBUILD_AFLAGS += $(CC_FLAGS_MARCH_MINIMUM) -D__DISABLE_EXPORTS
|
||||
KBUILD_CFLAGS += $(CC_FLAGS_MARCH_MINIMUM) -D__DISABLE_EXPORTS
|
||||
KBUILD_CFLAGS += $(call cc-option, -Wno-default-const-init-unsafe)
|
||||
|
||||
CFLAGS_sclp_early_core.o += -I$(srctree)/drivers/s390/char
|
||||
|
||||
|
|
|
|||
|
|
@ -336,6 +336,7 @@ static unsigned long setup_kernel_memory_layout(unsigned long kernel_size)
|
|||
BUILD_BUG_ON(!IS_ALIGNED(TEXT_OFFSET, THREAD_SIZE));
|
||||
BUILD_BUG_ON(!IS_ALIGNED(__NO_KASLR_START_KERNEL, THREAD_SIZE));
|
||||
BUILD_BUG_ON(__NO_KASLR_END_KERNEL > _REGION1_SIZE);
|
||||
BUILD_BUG_ON(CONFIG_ILLEGAL_POINTER_VALUE < _REGION1_SIZE);
|
||||
vsize = get_vmem_size(ident_map_size, vmemmap_size, vmalloc_size, _REGION3_SIZE);
|
||||
boot_debug("vmem size estimated: 0x%016lx\n", vsize);
|
||||
if (IS_ENABLED(CONFIG_KASAN) || __NO_KASLR_END_KERNEL > _REGION2_SIZE ||
|
||||
|
|
|
|||
|
|
@ -446,6 +446,7 @@ CONFIG_BLK_DEV_RAM_SIZE=32768
|
|||
CONFIG_VIRTIO_BLK=y
|
||||
CONFIG_BLK_DEV_RBD=m
|
||||
CONFIG_BLK_DEV_NVME=m
|
||||
CONFIG_BLK_DEV_NULL_BLK=m
|
||||
CONFIG_ENCLOSURE_SERVICES=m
|
||||
CONFIG_GENWQE=m
|
||||
CONFIG_RAID_ATTRS=m
|
||||
|
|
|
|||
|
|
@ -436,6 +436,7 @@ CONFIG_BLK_DEV_RAM_SIZE=32768
|
|||
CONFIG_VIRTIO_BLK=y
|
||||
CONFIG_BLK_DEV_RBD=m
|
||||
CONFIG_BLK_DEV_NVME=m
|
||||
CONFIG_BLK_DEV_NULL_BLK=m
|
||||
CONFIG_ENCLOSURE_SERVICES=m
|
||||
CONFIG_GENWQE=m
|
||||
CONFIG_RAID_ATTRS=m
|
||||
|
|
|
|||
|
|
@ -78,7 +78,7 @@ union ap_queue_status_reg {
|
|||
};
|
||||
|
||||
/**
|
||||
* ap_intructions_available() - Test if AP instructions are available.
|
||||
* ap_instructions_available() - Test if AP instructions are available.
|
||||
*
|
||||
* Returns true if the AP instructions are installed, otherwise false.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#include <linux/kvm_host.h>
|
||||
#include <linux/ftrace.h>
|
||||
#include <asm/bug.h>
|
||||
#include <asm/fpu.h>
|
||||
#include <asm/nospec-branch.h>
|
||||
#include <asm-generic/asm-prototypes.h>
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@
|
|||
*/
|
||||
#if defined(__GCC_ASM_FLAG_OUTPUTS__) && !(IS_ENABLED(CONFIG_CC_ASM_FLAG_OUTPUT_BROKEN))
|
||||
|
||||
#define __HAVE_ASM_FLAG_OUTPUTS__
|
||||
#define __HAVE_ASM_FLAG_OUTPUTS__ 1
|
||||
|
||||
#define CC_IPM(sym)
|
||||
#define CC_OUT(sym, var) "=@cc" (var)
|
||||
|
|
|
|||
|
|
@ -2,60 +2,127 @@
|
|||
#ifndef _ASM_S390_BUG_H
|
||||
#define _ASM_S390_BUG_H
|
||||
|
||||
#include <linux/stringify.h>
|
||||
#include <linux/compiler.h>
|
||||
#include <linux/const.h>
|
||||
|
||||
#ifdef CONFIG_BUG
|
||||
#define MONCODE_BUG _AC(0, U)
|
||||
#define MONCODE_BUG_ARG _AC(1, U)
|
||||
|
||||
#ifndef CONFIG_DEBUG_BUGVERBOSE
|
||||
#define _BUGVERBOSE_LOCATION(file, line)
|
||||
#ifndef __ASSEMBLER__
|
||||
#if defined(CONFIG_BUG) && defined(CONFIG_CC_HAS_ASM_IMMEDIATE_STRINGS)
|
||||
|
||||
#ifdef CONFIG_DEBUG_BUGVERBOSE
|
||||
#define __BUG_ENTRY_VERBOSE(format, file, line) \
|
||||
" .long " format " - . # bug_entry::format\n" \
|
||||
" .long " file " - . # bug_entry::file\n" \
|
||||
" .short " line " # bug_entry::line\n"
|
||||
#else
|
||||
#define __BUGVERBOSE_LOCATION(file, line) \
|
||||
.pushsection .rodata.str, "aMS", @progbits, 1; \
|
||||
.align 2; \
|
||||
10002: .ascii file "\0"; \
|
||||
.popsection; \
|
||||
\
|
||||
.long 10002b - .; \
|
||||
.short line;
|
||||
#define _BUGVERBOSE_LOCATION(file, line) __BUGVERBOSE_LOCATION(file, line)
|
||||
#define __BUG_ENTRY_VERBOSE(format, file, line)
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_GENERIC_BUG
|
||||
#define __BUG_ENTRY(cond_str, flags)
|
||||
#ifdef CONFIG_DEBUG_BUGVERBOSE_DETAILED
|
||||
#define WARN_CONDITION_STR(cond_str) cond_str
|
||||
#else
|
||||
#define __BUG_ENTRY(cond_str, flags) \
|
||||
.pushsection __bug_table, "aw"; \
|
||||
.align 4; \
|
||||
10000: .long 10001f - .; \
|
||||
_BUGVERBOSE_LOCATION(WARN_CONDITION_STR(cond_str) __FILE__, __LINE__) \
|
||||
.short flags; \
|
||||
.popsection; \
|
||||
10001:
|
||||
#define WARN_CONDITION_STR(cond_str) ""
|
||||
#endif
|
||||
|
||||
#define ASM_BUG_FLAGS(cond_str, flags) \
|
||||
__BUG_ENTRY(cond_str, flags) \
|
||||
mc 0,0
|
||||
#define __BUG_ENTRY(format, file, line, flags, size) \
|
||||
" .section __bug_table,\"aw\"\n" \
|
||||
"1: .long 0b - . # bug_entry::bug_addr\n" \
|
||||
__BUG_ENTRY_VERBOSE(format, file, line) \
|
||||
" .short "flags" # bug_entry::flags\n" \
|
||||
" .org 1b+"size"\n" \
|
||||
" .previous"
|
||||
|
||||
#define ASM_BUG() ASM_BUG_FLAGS("", 0)
|
||||
|
||||
#define __BUG_FLAGS(cond_str, flags) \
|
||||
asm_inline volatile(__stringify(ASM_BUG_FLAGS(cond_str, flags)));
|
||||
|
||||
#define __WARN_FLAGS(cond_str, flags) \
|
||||
do { \
|
||||
__BUG_FLAGS(cond_str, BUGFLAG_WARNING|(flags)); \
|
||||
#define __BUG_ASM(cond_str, flags) \
|
||||
do { \
|
||||
asm_inline volatile("\n" \
|
||||
"0: mc %[monc](%%r0),0\n" \
|
||||
__BUG_ENTRY("%[frmt]", "%[file]", "%[line]", \
|
||||
"%[flgs]", "%[size]") \
|
||||
: \
|
||||
: [monc] "i" (MONCODE_BUG), \
|
||||
[frmt] "i" (WARN_CONDITION_STR(cond_str)), \
|
||||
[file] "i" (__FILE__), \
|
||||
[line] "i" (__LINE__), \
|
||||
[flgs] "i" (flags), \
|
||||
[size] "i" (sizeof(struct bug_entry))); \
|
||||
} while (0)
|
||||
|
||||
#define BUG() \
|
||||
do { \
|
||||
__BUG_FLAGS("", 0); \
|
||||
unreachable(); \
|
||||
#define BUG() \
|
||||
do { \
|
||||
__BUG_ASM("", 0); \
|
||||
unreachable(); \
|
||||
} while (0)
|
||||
|
||||
#define __WARN_FLAGS(cond_str, flags) \
|
||||
do { \
|
||||
__BUG_ASM(cond_str, BUGFLAG_WARNING | (flags)); \
|
||||
} while (0)
|
||||
|
||||
#define __WARN_bug_entry(flags, format) \
|
||||
({ \
|
||||
struct bug_entry *bug; \
|
||||
\
|
||||
asm_inline volatile("\n" \
|
||||
"0: larl %[bug],1f\n" \
|
||||
__BUG_ENTRY("%[frmt]", "%[file]", "%[line]", \
|
||||
"%[flgs]", "%[size]") \
|
||||
: [bug] "=d" (bug) \
|
||||
: [frmt] "i" (format), \
|
||||
[file] "i" (__FILE__), \
|
||||
[line] "i" (__LINE__), \
|
||||
[flgs] "i" (flags), \
|
||||
[size] "i" (sizeof(struct bug_entry))); \
|
||||
bug; \
|
||||
})
|
||||
|
||||
/*
|
||||
* Variable Argument List (va_list) as defined in ELF Application
|
||||
* Binary Interface s390x Supplement documentation.
|
||||
*/
|
||||
struct arch_va_list {
|
||||
long __gpr;
|
||||
long __fpr;
|
||||
void *__overflow_arg_area;
|
||||
void *__reg_save_area;
|
||||
};
|
||||
|
||||
struct bug_entry;
|
||||
struct pt_regs;
|
||||
|
||||
void *__warn_args(struct arch_va_list *args, struct pt_regs *regs);
|
||||
void __WARN_trap(struct bug_entry *bug, ...);
|
||||
|
||||
#define __WARN_print_arg(flags, format, arg...) \
|
||||
do { \
|
||||
int __flags = (flags) | BUGFLAG_WARNING | BUGFLAG_ARGS; \
|
||||
\
|
||||
__WARN_trap(__WARN_bug_entry(__flags, format), ## arg); \
|
||||
/* prevent tail-call optimization */ \
|
||||
asm(""); \
|
||||
} while (0)
|
||||
|
||||
#define __WARN_printf(taint, fmt, arg...) \
|
||||
__WARN_print_arg(BUGFLAG_TAINT(taint), fmt, ## arg)
|
||||
|
||||
#define WARN_ONCE(cond, format, arg...) \
|
||||
({ \
|
||||
int __ret_warn_on = !!(cond); \
|
||||
\
|
||||
if (unlikely(__ret_warn_on)) { \
|
||||
__WARN_print_arg(BUGFLAG_ONCE|BUGFLAG_TAINT(TAINT_WARN),\
|
||||
format, ## arg); \
|
||||
} \
|
||||
__ret_warn_on; \
|
||||
})
|
||||
|
||||
#define HAVE_ARCH_BUG
|
||||
#define HAVE_ARCH_BUG_FORMAT
|
||||
#define HAVE_ARCH_BUG_FORMAT_ARGS
|
||||
|
||||
#endif /* CONFIG_BUG */
|
||||
#endif /* CONFIG_BUG && CONFIG_CC_HAS_ASM_IMMEDIATE_STRINGS */
|
||||
#endif /* __ASSEMBLER__ */
|
||||
|
||||
#include <asm-generic/bug.h>
|
||||
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
#define ZPCI_IOMAP_SHIFT 48
|
||||
#define ZPCI_IOMAP_ADDR_SHIFT 62
|
||||
#define ZPCI_IOMAP_ADDR_BASE (1UL << ZPCI_IOMAP_ADDR_SHIFT)
|
||||
#define ZPCI_IOMAP_ADDR_MAX ((1UL << (ZPCI_IOMAP_ADDR_SHIFT + 1)) - 1)
|
||||
#define ZPCI_IOMAP_ADDR_OFF_MASK ((1UL << ZPCI_IOMAP_SHIFT) - 1)
|
||||
#define ZPCI_IOMAP_MAX_ENTRIES \
|
||||
(1UL << (ZPCI_IOMAP_ADDR_SHIFT - ZPCI_IOMAP_SHIFT))
|
||||
|
|
|
|||
|
|
@ -8,7 +8,10 @@
|
|||
#include <asm/cmpxchg.h>
|
||||
#include <asm/march.h>
|
||||
|
||||
/* We use the MSB mostly because its available */
|
||||
/*
|
||||
* Use MSB so it is possible to read preempt_count with LLGT which
|
||||
* reads the least significant 31 bits with a single instruction.
|
||||
*/
|
||||
#define PREEMPT_NEED_RESCHED 0x80000000
|
||||
|
||||
/*
|
||||
|
|
@ -23,7 +26,20 @@
|
|||
*/
|
||||
static __always_inline int preempt_count(void)
|
||||
{
|
||||
return READ_ONCE(get_lowcore()->preempt_count) & ~PREEMPT_NEED_RESCHED;
|
||||
unsigned long lc_preempt, count;
|
||||
|
||||
BUILD_BUG_ON(sizeof_field(struct lowcore, preempt_count) != sizeof(int));
|
||||
lc_preempt = offsetof(struct lowcore, preempt_count);
|
||||
/* READ_ONCE(get_lowcore()->preempt_count) & ~PREEMPT_NEED_RESCHED */
|
||||
asm_inline(
|
||||
ALTERNATIVE("llgt %[count],%[offzero](%%r0)\n",
|
||||
"llgt %[count],%[offalt](%%r0)\n",
|
||||
ALT_FEATURE(MFEATURE_LOWCORE))
|
||||
: [count] "=d" (count)
|
||||
: [offzero] "i" (lc_preempt),
|
||||
[offalt] "i" (lc_preempt + LOWCORE_ALT_ADDRESS),
|
||||
"m" (((struct lowcore *)0)->preempt_count));
|
||||
return count;
|
||||
}
|
||||
|
||||
static __always_inline void preempt_count_set(int pc)
|
||||
|
|
@ -68,7 +84,17 @@ static __always_inline void __preempt_count_add(int val)
|
|||
*/
|
||||
if (!IS_ENABLED(CONFIG_PROFILE_ALL_BRANCHES)) {
|
||||
if (__builtin_constant_p(val) && (val >= -128) && (val <= 127)) {
|
||||
__atomic_add_const(val, &get_lowcore()->preempt_count);
|
||||
unsigned long lc_preempt;
|
||||
|
||||
lc_preempt = offsetof(struct lowcore, preempt_count);
|
||||
asm_inline(
|
||||
ALTERNATIVE("asi %[offzero](%%r0),%[val]\n",
|
||||
"asi %[offalt](%%r0),%[val]\n",
|
||||
ALT_FEATURE(MFEATURE_LOWCORE))
|
||||
: "+m" (((struct lowcore *)0)->preempt_count)
|
||||
: [offzero] "i" (lc_preempt), [val] "i" (val),
|
||||
[offalt] "i" (lc_preempt + LOWCORE_ALT_ADDRESS)
|
||||
: "cc");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
@ -87,7 +113,22 @@ static __always_inline void __preempt_count_sub(int val)
|
|||
*/
|
||||
static __always_inline bool __preempt_count_dec_and_test(void)
|
||||
{
|
||||
#ifdef __HAVE_ASM_FLAG_OUTPUTS__
|
||||
unsigned long lc_preempt;
|
||||
int cc;
|
||||
|
||||
lc_preempt = offsetof(struct lowcore, preempt_count);
|
||||
asm_inline(
|
||||
ALTERNATIVE("alsi %[offzero](%%r0),%[val]\n",
|
||||
"alsi %[offalt](%%r0),%[val]\n",
|
||||
ALT_FEATURE(MFEATURE_LOWCORE))
|
||||
: "=@cc" (cc), "+m" (((struct lowcore *)0)->preempt_count)
|
||||
: [offzero] "i" (lc_preempt), [val] "i" (-1),
|
||||
[offalt] "i" (lc_preempt + LOWCORE_ALT_ADDRESS));
|
||||
return (cc == 0) || (cc == 2);
|
||||
#else
|
||||
return __atomic_add_const_and_test(-1, &get_lowcore()->preempt_count);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -120,7 +120,10 @@ struct pt_regs {
|
|||
unsigned long gprs[NUM_GPRS];
|
||||
};
|
||||
};
|
||||
unsigned long orig_gpr2;
|
||||
union {
|
||||
unsigned long orig_gpr2;
|
||||
unsigned long monitor_code;
|
||||
};
|
||||
union {
|
||||
struct {
|
||||
unsigned int int_code;
|
||||
|
|
@ -214,16 +217,23 @@ void update_cr_regs(struct task_struct *task);
|
|||
#define arch_has_single_step() (1)
|
||||
#define arch_has_block_step() (1)
|
||||
|
||||
#define user_mode(regs) (((regs)->psw.mask & PSW_MASK_PSTATE) != 0)
|
||||
#define instruction_pointer(regs) ((regs)->psw.addr)
|
||||
#define user_stack_pointer(regs)((regs)->gprs[15])
|
||||
#define profile_pc(regs) instruction_pointer(regs)
|
||||
|
||||
static inline long regs_return_value(struct pt_regs *regs)
|
||||
static __always_inline bool user_mode(const struct pt_regs *regs)
|
||||
{
|
||||
return psw_bits(regs->psw).pstate;
|
||||
}
|
||||
|
||||
static inline long regs_return_value(const struct pt_regs *regs)
|
||||
{
|
||||
return regs->gprs[2];
|
||||
}
|
||||
|
||||
static __always_inline unsigned long instruction_pointer(const struct pt_regs *regs)
|
||||
{
|
||||
return regs->psw.addr;
|
||||
}
|
||||
|
||||
static inline void instruction_pointer_set(struct pt_regs *regs,
|
||||
unsigned long val)
|
||||
{
|
||||
|
|
@ -233,19 +243,26 @@ static inline void instruction_pointer_set(struct pt_regs *regs,
|
|||
int regs_query_register_offset(const char *name);
|
||||
const char *regs_query_register_name(unsigned int offset);
|
||||
|
||||
static __always_inline unsigned long kernel_stack_pointer(struct pt_regs *regs)
|
||||
static __always_inline unsigned long kernel_stack_pointer(const struct pt_regs *regs)
|
||||
{
|
||||
return regs->gprs[15];
|
||||
}
|
||||
|
||||
static __always_inline unsigned long regs_get_register(struct pt_regs *regs, unsigned int offset)
|
||||
static __always_inline unsigned long user_stack_pointer(const struct pt_regs *regs)
|
||||
{
|
||||
return regs->gprs[15];
|
||||
}
|
||||
|
||||
static __always_inline unsigned long regs_get_register(const struct pt_regs *regs,
|
||||
unsigned int offset)
|
||||
{
|
||||
if (offset >= NUM_GPRS)
|
||||
return 0;
|
||||
return regs->gprs[offset];
|
||||
}
|
||||
|
||||
static __always_inline int regs_within_kernel_stack(struct pt_regs *regs, unsigned long addr)
|
||||
static __always_inline int regs_within_kernel_stack(const struct pt_regs *regs,
|
||||
unsigned long addr)
|
||||
{
|
||||
unsigned long ksp = kernel_stack_pointer(regs);
|
||||
|
||||
|
|
@ -261,7 +278,8 @@ static __always_inline int regs_within_kernel_stack(struct pt_regs *regs, unsign
|
|||
* is specifined by @regs. If the @n th entry is NOT in the kernel stack,
|
||||
* this returns 0.
|
||||
*/
|
||||
static __always_inline unsigned long regs_get_kernel_stack_nth(struct pt_regs *regs, unsigned int n)
|
||||
static __always_inline unsigned long regs_get_kernel_stack_nth(const struct pt_regs *regs,
|
||||
unsigned int n)
|
||||
{
|
||||
unsigned long addr;
|
||||
|
||||
|
|
@ -278,8 +296,8 @@ static __always_inline unsigned long regs_get_kernel_stack_nth(struct pt_regs *r
|
|||
*
|
||||
* regs_get_kernel_argument() returns @n th argument of the function call.
|
||||
*/
|
||||
static inline unsigned long regs_get_kernel_argument(struct pt_regs *regs,
|
||||
unsigned int n)
|
||||
static __always_inline unsigned long regs_get_kernel_argument(const struct pt_regs *regs,
|
||||
unsigned int n)
|
||||
{
|
||||
unsigned int argoffset = STACK_FRAME_OVERHEAD / sizeof(long);
|
||||
|
||||
|
|
@ -290,7 +308,7 @@ static inline unsigned long regs_get_kernel_argument(struct pt_regs *regs,
|
|||
return regs_get_kernel_stack_nth(regs, argoffset + n);
|
||||
}
|
||||
|
||||
static inline void regs_set_return_value(struct pt_regs *regs, unsigned long rc)
|
||||
static __always_inline void regs_set_return_value(struct pt_regs *regs, unsigned long rc)
|
||||
{
|
||||
regs->gprs[2] = rc;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,103 +0,0 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
|
||||
/*************************************************************************
|
||||
*
|
||||
* enables user programs to display messages and control encryption
|
||||
* on s390 tape devices
|
||||
*
|
||||
* Copyright IBM Corp. 2001, 2006
|
||||
* Author(s): Michael Holzheu <holzheu@de.ibm.com>
|
||||
*
|
||||
*************************************************************************/
|
||||
|
||||
#ifndef _TAPE390_H
|
||||
#define _TAPE390_H
|
||||
|
||||
#define TAPE390_DISPLAY _IOW('d', 1, struct display_struct)
|
||||
|
||||
/*
|
||||
* The TAPE390_DISPLAY ioctl calls the Load Display command
|
||||
* which transfers 17 bytes of data from the channel to the subsystem:
|
||||
* - 1 format control byte, and
|
||||
* - two 8-byte messages
|
||||
*
|
||||
* Format control byte:
|
||||
* 0-2: New Message Overlay
|
||||
* 3: Alternate Messages
|
||||
* 4: Blink Message
|
||||
* 5: Display Low/High Message
|
||||
* 6: Reserved
|
||||
* 7: Automatic Load Request
|
||||
*
|
||||
*/
|
||||
|
||||
typedef struct display_struct {
|
||||
char cntrl;
|
||||
char message1[8];
|
||||
char message2[8];
|
||||
} display_struct;
|
||||
|
||||
/*
|
||||
* Tape encryption support
|
||||
*/
|
||||
|
||||
struct tape390_crypt_info {
|
||||
char capability;
|
||||
char status;
|
||||
char medium_status;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
|
||||
/* Macros for "capable" field */
|
||||
#define TAPE390_CRYPT_SUPPORTED_MASK 0x01
|
||||
#define TAPE390_CRYPT_SUPPORTED(x) \
|
||||
((x.capability & TAPE390_CRYPT_SUPPORTED_MASK))
|
||||
|
||||
/* Macros for "status" field */
|
||||
#define TAPE390_CRYPT_ON_MASK 0x01
|
||||
#define TAPE390_CRYPT_ON(x) (((x.status) & TAPE390_CRYPT_ON_MASK))
|
||||
|
||||
/* Macros for "medium status" field */
|
||||
#define TAPE390_MEDIUM_LOADED_MASK 0x01
|
||||
#define TAPE390_MEDIUM_ENCRYPTED_MASK 0x02
|
||||
#define TAPE390_MEDIUM_ENCRYPTED(x) \
|
||||
(((x.medium_status) & TAPE390_MEDIUM_ENCRYPTED_MASK))
|
||||
#define TAPE390_MEDIUM_LOADED(x) \
|
||||
(((x.medium_status) & TAPE390_MEDIUM_LOADED_MASK))
|
||||
|
||||
/*
|
||||
* The TAPE390_CRYPT_SET ioctl is used to switch on/off encryption.
|
||||
* The "encryption_capable" and "tape_status" fields are ignored for this ioctl!
|
||||
*/
|
||||
#define TAPE390_CRYPT_SET _IOW('d', 2, struct tape390_crypt_info)
|
||||
|
||||
/*
|
||||
* The TAPE390_CRYPT_QUERY ioctl is used to query the encryption state.
|
||||
*/
|
||||
#define TAPE390_CRYPT_QUERY _IOR('d', 3, struct tape390_crypt_info)
|
||||
|
||||
/* Values for "kekl1/2_type" and "kekl1/2_type_on_tape" fields */
|
||||
#define TAPE390_KEKL_TYPE_NONE 0
|
||||
#define TAPE390_KEKL_TYPE_LABEL 1
|
||||
#define TAPE390_KEKL_TYPE_HASH 2
|
||||
|
||||
struct tape390_kekl {
|
||||
unsigned char type;
|
||||
unsigned char type_on_tape;
|
||||
char label[65];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct tape390_kekl_pair {
|
||||
struct tape390_kekl kekl[2];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/*
|
||||
* The TAPE390_KEKL_SET ioctl is used to set Key Encrypting Key labels.
|
||||
*/
|
||||
#define TAPE390_KEKL_SET _IOW('d', 4, struct tape390_kekl_pair)
|
||||
|
||||
/*
|
||||
* The TAPE390_KEKL_QUERY ioctl is used to query Key Encrypting Key labels.
|
||||
*/
|
||||
#define TAPE390_KEKL_QUERY _IOR('d', 5, struct tape390_kekl_pair)
|
||||
|
||||
#endif
|
||||
|
|
@ -23,6 +23,7 @@
|
|||
#include <asm/unistd.h>
|
||||
#include <asm/page.h>
|
||||
#include <asm/sigp.h>
|
||||
#include <asm/bug.h>
|
||||
#include <asm/irq.h>
|
||||
#include <asm/fpu-insn.h>
|
||||
#include <asm/setup.h>
|
||||
|
|
@ -173,6 +174,16 @@ SYM_FUNC_START(__switch_to_asm)
|
|||
BR_EX %r14
|
||||
SYM_FUNC_END(__switch_to_asm)
|
||||
|
||||
#if defined(CONFIG_BUG) && defined(CONFIG_CC_HAS_ASM_IMMEDIATE_STRINGS)
|
||||
|
||||
SYM_FUNC_START(__WARN_trap)
|
||||
mc MONCODE_BUG_ARG(%r0),0
|
||||
BR_EX %r14
|
||||
SYM_FUNC_END(__WARN_trap)
|
||||
EXPORT_SYMBOL(__WARN_trap)
|
||||
|
||||
#endif /* CONFIG_BUG && CONFIG_CC_HAS_ASM_IMMEDIATE_STRINGS */
|
||||
|
||||
#if IS_ENABLED(CONFIG_KVM)
|
||||
/*
|
||||
* __sie64a calling convention:
|
||||
|
|
|
|||
|
|
@ -270,8 +270,10 @@ void *kexec_file_add_components(struct kimage *image,
|
|||
if (image->kernel_buf_len < minsize + max_command_line_size)
|
||||
goto out;
|
||||
|
||||
if (image->cmdline_buf_len >= max_command_line_size)
|
||||
if (image->cmdline_buf_len >= max_command_line_size) {
|
||||
pr_err("Kernel command line exceeds supported limit of %lu", max_command_line_size);
|
||||
goto out;
|
||||
}
|
||||
|
||||
memcpy(data.parm->command_line, image->cmdline_buf,
|
||||
image->cmdline_buf_len);
|
||||
|
|
|
|||
|
|
@ -841,7 +841,7 @@ static bool is_callchain_event(struct perf_event *event)
|
|||
u64 sample_type = event->attr.sample_type;
|
||||
|
||||
return sample_type & (PERF_SAMPLE_CALLCHAIN | PERF_SAMPLE_REGS_USER |
|
||||
PERF_SAMPLE_STACK_USER);
|
||||
PERF_SAMPLE_REGS_INTR | PERF_SAMPLE_STACK_USER);
|
||||
}
|
||||
|
||||
static int cpumsf_pmu_event_init(struct perf_event *event)
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@
|
|||
#include <linux/cpu.h>
|
||||
#include <linux/entry-common.h>
|
||||
#include <linux/kmsan.h>
|
||||
#include <linux/bug.h>
|
||||
#include <asm/asm-extable.h>
|
||||
#include <asm/irqflags.h>
|
||||
#include <asm/ptrace.h>
|
||||
|
|
@ -220,11 +221,48 @@ static void space_switch_exception(struct pt_regs *regs)
|
|||
do_trap(regs, SIGILL, ILL_PRVOPC, "space switch event");
|
||||
}
|
||||
|
||||
#if defined(CONFIG_BUG) && defined(CONFIG_CC_HAS_ASM_IMMEDIATE_STRINGS)
|
||||
|
||||
void *__warn_args(struct arch_va_list *args, struct pt_regs *regs)
|
||||
{
|
||||
struct stack_frame *stack_frame;
|
||||
|
||||
/*
|
||||
* Generate va_list from pt_regs. See ELF Application Binary Interface
|
||||
* s390x Supplement documentation for details.
|
||||
*
|
||||
* - __overflow_arg_area needs to point to the parameter area, which
|
||||
* is right above the standard stack frame (160 bytes)
|
||||
*
|
||||
* - __reg_save_area needs to point to a register save area where
|
||||
* general registers (%r2 - %r6) can be found at offset 16. Which
|
||||
* means that the gprs save area of pt_regs can be used
|
||||
*
|
||||
* - __gpr must be set to one, since the first parameter has been
|
||||
* processed (pointer to bug_entry)
|
||||
*/
|
||||
stack_frame = (struct stack_frame *)regs->gprs[15];
|
||||
args->__overflow_arg_area = stack_frame + 1;
|
||||
args->__reg_save_area = regs->gprs;
|
||||
args->__gpr = 1;
|
||||
return args;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_BUG && CONFIG_CC_HAS_ASM_IMMEDIATE_STRINGS */
|
||||
|
||||
static void monitor_event_exception(struct pt_regs *regs)
|
||||
{
|
||||
enum bug_trap_type btt;
|
||||
|
||||
if (user_mode(regs))
|
||||
return;
|
||||
switch (report_bug(regs->psw.addr - (regs->int_code >> 16), regs)) {
|
||||
if (regs->monitor_code == MONCODE_BUG_ARG) {
|
||||
regs->psw.addr = regs->gprs[14];
|
||||
btt = report_bug_entry((struct bug_entry *)regs->gprs[2], regs);
|
||||
} else {
|
||||
btt = report_bug(regs->psw.addr - (regs->int_code >> 16), regs);
|
||||
}
|
||||
switch (btt) {
|
||||
case BUG_TRAP_TYPE_NONE:
|
||||
fixup_exception(regs);
|
||||
break;
|
||||
|
|
@ -258,11 +296,12 @@ static void __init test_monitor_call(void)
|
|||
if (!IS_ENABLED(CONFIG_BUG))
|
||||
return;
|
||||
asm_inline volatile(
|
||||
" mc 0,0\n"
|
||||
" mc %[monc](%%r0),0\n"
|
||||
"0: lhi %[val],0\n"
|
||||
"1:\n"
|
||||
EX_TABLE(0b, 1b)
|
||||
: [val] "+d" (val));
|
||||
: [val] "+d" (val)
|
||||
: [monc] "i" (MONCODE_BUG));
|
||||
if (!val)
|
||||
panic("Monitor call doesn't work!\n");
|
||||
}
|
||||
|
|
@ -297,6 +336,7 @@ void noinstr __do_pgm_check(struct pt_regs *regs)
|
|||
teid.val = lc->trans_exc_code;
|
||||
regs->int_code = lc->pgm_int_code;
|
||||
regs->int_parm_long = teid.val;
|
||||
regs->monitor_code = lc->monitor_code;
|
||||
/*
|
||||
* In case of a guest fault, short-circuit the fault handler and return.
|
||||
* This way the sie64a() function will return 0; fault address and
|
||||
|
|
|
|||
|
|
@ -231,24 +231,33 @@ int zpci_fmb_disable_device(struct zpci_dev *zdev)
|
|||
static int zpci_cfg_load(struct zpci_dev *zdev, int offset, u32 *val, u8 len)
|
||||
{
|
||||
u64 req = ZPCI_CREATE_REQ(zdev->fh, ZPCI_PCIAS_CFGSPC, len);
|
||||
int rc = -ENODEV;
|
||||
u64 data;
|
||||
int rc;
|
||||
|
||||
if (!zdev_enabled(zdev))
|
||||
goto out_err;
|
||||
|
||||
rc = __zpci_load(&data, req, offset);
|
||||
if (!rc) {
|
||||
data = le64_to_cpu((__force __le64) data);
|
||||
data >>= (8 - len) * 8;
|
||||
*val = (u32) data;
|
||||
} else
|
||||
*val = 0xffffffff;
|
||||
if (rc)
|
||||
goto out_err;
|
||||
data = le64_to_cpu((__force __le64)data);
|
||||
data >>= (8 - len) * 8;
|
||||
*val = (u32)data;
|
||||
return 0;
|
||||
|
||||
out_err:
|
||||
PCI_SET_ERROR_RESPONSE(val);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int zpci_cfg_store(struct zpci_dev *zdev, int offset, u32 val, u8 len)
|
||||
{
|
||||
u64 req = ZPCI_CREATE_REQ(zdev->fh, ZPCI_PCIAS_CFGSPC, len);
|
||||
int rc = -ENODEV;
|
||||
u64 data = val;
|
||||
int rc;
|
||||
|
||||
if (!zdev_enabled(zdev))
|
||||
return rc;
|
||||
|
||||
data <<= (8 - len) * 8;
|
||||
data = (__force u64) cpu_to_le64(data);
|
||||
|
|
@ -397,7 +406,9 @@ static int pci_read(struct pci_bus *bus, unsigned int devfn, int where,
|
|||
{
|
||||
struct zpci_dev *zdev = zdev_from_bus(bus, devfn);
|
||||
|
||||
return (zdev) ? zpci_cfg_load(zdev, where, val, size) : -ENODEV;
|
||||
if (!zdev || zpci_cfg_load(zdev, where, val, size))
|
||||
return PCIBIOS_DEVICE_NOT_FOUND;
|
||||
return PCIBIOS_SUCCESSFUL;
|
||||
}
|
||||
|
||||
static int pci_write(struct pci_bus *bus, unsigned int devfn, int where,
|
||||
|
|
@ -405,7 +416,9 @@ static int pci_write(struct pci_bus *bus, unsigned int devfn, int where,
|
|||
{
|
||||
struct zpci_dev *zdev = zdev_from_bus(bus, devfn);
|
||||
|
||||
return (zdev) ? zpci_cfg_store(zdev, where, val, size) : -ENODEV;
|
||||
if (!zdev || zpci_cfg_store(zdev, where, val, size))
|
||||
return PCIBIOS_DEVICE_NOT_FOUND;
|
||||
return PCIBIOS_SUCCESSFUL;
|
||||
}
|
||||
|
||||
static struct pci_ops pci_root_ops = {
|
||||
|
|
@ -1052,6 +1065,8 @@ static int zpci_mem_init(void)
|
|||
{
|
||||
BUILD_BUG_ON(!is_power_of_2(__alignof__(struct zpci_fmb)) ||
|
||||
__alignof__(struct zpci_fmb) < sizeof(struct zpci_fmb));
|
||||
BUILD_BUG_ON((CONFIG_ILLEGAL_POINTER_VALUE + 0x10000 > ZPCI_IOMAP_ADDR_BASE) &&
|
||||
(CONFIG_ILLEGAL_POINTER_VALUE <= ZPCI_IOMAP_ADDR_MAX));
|
||||
|
||||
zdev_fmb_cache = kmem_cache_create("PCI_FMB_cache", sizeof(struct zpci_fmb),
|
||||
__alignof__(struct zpci_fmb), 0, NULL);
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ KBUILD_CFLAGS += -D__DISABLE_EXPORTS
|
|||
KBUILD_CFLAGS += $(CLANG_FLAGS)
|
||||
KBUILD_CFLAGS += $(if $(CONFIG_CC_IS_CLANG),-Wno-microsoft-anon-tag)
|
||||
KBUILD_CFLAGS += $(call cc-option,-fno-PIE)
|
||||
KBUILD_CFLAGS += $(call cc-option, -Wno-default-const-init-unsafe)
|
||||
KBUILD_AFLAGS := $(filter-out -DCC_USING_EXPOLINE,$(KBUILD_AFLAGS))
|
||||
KBUILD_AFLAGS += -D__DISABLE_EXPORTS
|
||||
|
||||
|
|
|
|||
|
|
@ -106,37 +106,12 @@ config S390_UV_UAPI
|
|||
|
||||
config S390_TAPE
|
||||
def_tristate m
|
||||
prompt "S/390 tape device support"
|
||||
prompt "Support for 3490E tape on VTS"
|
||||
depends on CCW
|
||||
help
|
||||
Select this option if you want to access channel-attached tape
|
||||
devices on IBM S/390 or zSeries.
|
||||
If you select this option you will also want to select at
|
||||
least one of the tape interface options and one of the tape
|
||||
hardware options in order to access a tape device.
|
||||
This option is also available as a module. The module will be
|
||||
called tape390 and include all selected interfaces and
|
||||
hardware drivers.
|
||||
|
||||
comment "S/390 tape hardware support"
|
||||
depends on S390_TAPE
|
||||
|
||||
config S390_TAPE_34XX
|
||||
def_tristate m
|
||||
prompt "Support for 3480/3490 tape hardware"
|
||||
depends on S390_TAPE
|
||||
help
|
||||
Select this option if you want to access IBM 3480/3490 magnetic
|
||||
tape subsystems and 100% compatibles.
|
||||
It is safe to say "Y" here.
|
||||
|
||||
config S390_TAPE_3590
|
||||
def_tristate m
|
||||
prompt "Support for 3590 tape hardware"
|
||||
depends on S390_TAPE
|
||||
help
|
||||
Select this option if you want to access IBM 3590 magnetic
|
||||
tape subsystems and 100% compatibles.
|
||||
Select this option if you want to access channel-attached IBM 3490E
|
||||
tape devices on VTS, such as IBM TS7700.
|
||||
This option is also available as a module.
|
||||
It is safe to say "Y" here.
|
||||
|
||||
config VMLOGRDR
|
||||
|
|
|
|||
|
|
@ -39,10 +39,8 @@ obj-$(CONFIG_VMLOGRDR) += vmlogrdr.o
|
|||
obj-$(CONFIG_VMCP) += vmcp.o
|
||||
|
||||
tape-$(CONFIG_PROC_FS) += tape_proc.o
|
||||
tape-objs := tape_core.o tape_std.o tape_char.o $(tape-y)
|
||||
obj-$(CONFIG_S390_TAPE) += tape.o tape_class.o
|
||||
obj-$(CONFIG_S390_TAPE_34XX) += tape_34xx.o
|
||||
obj-$(CONFIG_S390_TAPE_3590) += tape_3590.o
|
||||
tape_s390-objs := tape_3490.o tape_char.o tape_class.o tape_core.o tape_std.o $(tape-y)
|
||||
obj-$(CONFIG_S390_TAPE) += tape_s390.o
|
||||
obj-$(CONFIG_MONREADER) += monreader.o
|
||||
obj-$(CONFIG_MONWRITER) += monwriter.o
|
||||
obj-$(CONFIG_S390_VMUR) += vmur.o
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* tape device driver for 3480/3490E/3590 tapes.
|
||||
* tape device driver for 3490E tapes.
|
||||
*
|
||||
* S390 and zSeries version
|
||||
* Copyright IBM Corp. 2001, 2009
|
||||
|
|
@ -98,10 +98,6 @@ enum tape_op {
|
|||
TO_DIS, /* Tape display */
|
||||
TO_ASSIGN, /* Assign tape to channel path */
|
||||
TO_UNASSIGN, /* Unassign tape from channel path */
|
||||
TO_CRYPT_ON, /* Enable encrpytion */
|
||||
TO_CRYPT_OFF, /* Disable encrpytion */
|
||||
TO_KEKL_SET, /* Set KEK label */
|
||||
TO_KEKL_QUERY, /* Query KEK label */
|
||||
TO_RDC, /* Read device characteristics */
|
||||
TO_SIZE, /* #entries in tape_op_t */
|
||||
};
|
||||
|
|
@ -155,8 +151,6 @@ struct tape_discipline {
|
|||
struct tape_request *(*read_block)(struct tape_device *);
|
||||
struct tape_request *(*write_block)(struct tape_device *);
|
||||
void (*process_eov)(struct tape_device*);
|
||||
/* ioctl function for additional ioctls. */
|
||||
int (*ioctl_fn)(struct tape_device *, unsigned int, unsigned long);
|
||||
/* Array of tape commands with TAPE_NR_MTOPS entries */
|
||||
tape_mtop_fn *mtop_array;
|
||||
};
|
||||
|
|
@ -192,7 +186,6 @@ struct tape_device {
|
|||
|
||||
/* Device discipline information. */
|
||||
struct tape_discipline * discipline;
|
||||
void * discdata;
|
||||
|
||||
/* Generic status flags */
|
||||
long tape_generic_status;
|
||||
|
|
@ -281,6 +274,10 @@ extern void tapechar_exit(void);
|
|||
extern int tapechar_setup_device(struct tape_device *);
|
||||
extern void tapechar_cleanup_device(struct tape_device *);
|
||||
|
||||
/* Externals from tape_3490.c */
|
||||
extern int tape_3490_init(void);
|
||||
extern void tape_3490_exit(void);
|
||||
|
||||
/* tape initialisation functions */
|
||||
#ifdef CONFIG_PROC_FS
|
||||
extern void tape_proc_init (void);
|
||||
|
|
|
|||
825
drivers/s390/char/tape_3490.c
Normal file
825
drivers/s390/char/tape_3490.c
Normal file
|
|
@ -0,0 +1,825 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* tape device discipline for 3490 tapes.
|
||||
*
|
||||
* Copyright IBM Corp. 2001, 2009
|
||||
* Author(s): Carsten Otte <cotte@de.ibm.com>
|
||||
* Tuan Ngo-Anh <ngoanh@de.ibm.com>
|
||||
* Martin Schwidefsky <schwidefsky@de.ibm.com>
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) "tape_3490: " fmt
|
||||
|
||||
#include <linux/export.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/bio.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#define TAPE_DBF_AREA tape_3490_dbf
|
||||
|
||||
#include "tape.h"
|
||||
#include "tape_std.h"
|
||||
|
||||
/*
|
||||
* Pointer to debug area.
|
||||
*/
|
||||
debug_info_t *TAPE_DBF_AREA = NULL;
|
||||
EXPORT_SYMBOL(TAPE_DBF_AREA);
|
||||
|
||||
struct tape_3490_block_id {
|
||||
unsigned int unused : 10;
|
||||
unsigned int block : 22;
|
||||
};
|
||||
|
||||
/*
|
||||
* Medium sense for 3490 tapes. There is no 'real' medium sense call.
|
||||
* So we just do a normal sense.
|
||||
*/
|
||||
static void __tape_3490_medium_sense(struct tape_request *request)
|
||||
{
|
||||
struct tape_device *device = request->device;
|
||||
unsigned char *sense;
|
||||
|
||||
if (request->rc == 0) {
|
||||
sense = request->cpdata;
|
||||
|
||||
/*
|
||||
* This isn't quite correct. But since INTERVENTION_REQUIRED
|
||||
* means that the drive is 'neither ready nor on-line' it is
|
||||
* only slightly inaccurate to say there is no tape loaded if
|
||||
* the drive isn't online...
|
||||
*/
|
||||
if (sense[0] & SENSE_INTERVENTION_REQUIRED)
|
||||
tape_med_state_set(device, MS_UNLOADED);
|
||||
else
|
||||
tape_med_state_set(device, MS_LOADED);
|
||||
|
||||
if (sense[1] & SENSE_WRITE_PROTECT)
|
||||
device->tape_generic_status |= GMT_WR_PROT(~0);
|
||||
else
|
||||
device->tape_generic_status &= ~GMT_WR_PROT(~0);
|
||||
} else
|
||||
DBF_EVENT(4, "tape_3490: medium sense failed with rc=%d\n",
|
||||
request->rc);
|
||||
tape_free_request(request);
|
||||
}
|
||||
|
||||
static int tape_3490_medium_sense(struct tape_device *device)
|
||||
{
|
||||
struct tape_request *request;
|
||||
int rc;
|
||||
|
||||
request = tape_alloc_request(1, 32);
|
||||
if (IS_ERR(request)) {
|
||||
DBF_EXCEPTION(6, "MSEN fail\n");
|
||||
return PTR_ERR(request);
|
||||
}
|
||||
|
||||
request->op = TO_MSEN;
|
||||
tape_ccw_end(request->cpaddr, SENSE, 32, request->cpdata);
|
||||
rc = tape_do_io_interruptible(device, request);
|
||||
__tape_3490_medium_sense(request);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void tape_3490_medium_sense_async(struct tape_device *device)
|
||||
{
|
||||
struct tape_request *request;
|
||||
|
||||
request = tape_alloc_request(1, 32);
|
||||
if (IS_ERR(request)) {
|
||||
DBF_EXCEPTION(6, "MSEN fail\n");
|
||||
return;
|
||||
}
|
||||
|
||||
request->op = TO_MSEN;
|
||||
tape_ccw_end(request->cpaddr, SENSE, 32, request->cpdata);
|
||||
request->callback = (void *) __tape_3490_medium_sense;
|
||||
request->callback_data = NULL;
|
||||
tape_do_io_async(device, request);
|
||||
}
|
||||
|
||||
struct tape_3490_work {
|
||||
struct tape_device *device;
|
||||
enum tape_op op;
|
||||
struct work_struct work;
|
||||
};
|
||||
|
||||
/*
|
||||
* These functions are currently used only to schedule a medium_sense for
|
||||
* later execution. This is because we get an interrupt whenever a medium
|
||||
* is inserted but cannot call tape_do_io* from an interrupt context.
|
||||
* Maybe that's useful for other actions we want to start from the
|
||||
* interrupt handler.
|
||||
* Note: the work handler is called by the system work queue. The tape
|
||||
* commands started by the handler need to be asynchrounous, otherwise
|
||||
* a deadlock can occur e.g. in case of a deferred cc=1 (see __tape_do_irq).
|
||||
*/
|
||||
static void
|
||||
tape_3490_work_handler(struct work_struct *work)
|
||||
{
|
||||
struct tape_3490_work *p =
|
||||
container_of(work, struct tape_3490_work, work);
|
||||
struct tape_device *device = p->device;
|
||||
|
||||
switch(p->op) {
|
||||
case TO_MSEN:
|
||||
tape_3490_medium_sense_async(device);
|
||||
break;
|
||||
default:
|
||||
DBF_EVENT(3, "T3490: internal error: unknown work\n");
|
||||
}
|
||||
tape_put_device(device);
|
||||
kfree(p);
|
||||
}
|
||||
|
||||
static int
|
||||
tape_3490_schedule_work(struct tape_device *device, enum tape_op op)
|
||||
{
|
||||
struct tape_3490_work *p;
|
||||
|
||||
if ((p = kzalloc(sizeof(*p), GFP_ATOMIC)) == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
INIT_WORK(&p->work, tape_3490_work_handler);
|
||||
|
||||
p->device = tape_get_device(device);
|
||||
p->op = op;
|
||||
|
||||
schedule_work(&p->work);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Done Handler is called when dev stat = DEVICE-END (successful operation)
|
||||
*/
|
||||
static inline int
|
||||
tape_3490_done(struct tape_request *request)
|
||||
{
|
||||
DBF_EVENT(6, "%s done\n", tape_op_verbose[request->op]);
|
||||
return TAPE_IO_SUCCESS;
|
||||
}
|
||||
|
||||
static inline int
|
||||
tape_3490_erp_failed(struct tape_request *request, int rc)
|
||||
{
|
||||
DBF_EVENT(3, "Error recovery failed for %s (RC=%d)\n",
|
||||
tape_op_verbose[request->op], rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static inline int
|
||||
tape_3490_erp_succeeded(struct tape_request *request)
|
||||
{
|
||||
DBF_EVENT(3, "Error Recovery successful for %s\n",
|
||||
tape_op_verbose[request->op]);
|
||||
return tape_3490_done(request);
|
||||
}
|
||||
|
||||
static inline int
|
||||
tape_3490_erp_retry(struct tape_request *request)
|
||||
{
|
||||
DBF_EVENT(3, "xerp retr %s\n", tape_op_verbose[request->op]);
|
||||
return TAPE_IO_RETRY;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function is called, when no request is outstanding and we get an
|
||||
* interrupt
|
||||
*/
|
||||
static int
|
||||
tape_3490_unsolicited_irq(struct tape_device *device, struct irb *irb)
|
||||
{
|
||||
if (irb->scsw.cmd.dstat == 0x85) { /* READY */
|
||||
/* A medium was inserted in the drive. */
|
||||
DBF_EVENT(6, "xuud med\n");
|
||||
tape_3490_schedule_work(device, TO_MSEN);
|
||||
} else {
|
||||
DBF_EVENT(3, "unsol.irq! dev end: %08x\n", device->cdev_id);
|
||||
tape_dump_sense_dbf(device, NULL, irb);
|
||||
}
|
||||
return TAPE_IO_SUCCESS;
|
||||
}
|
||||
|
||||
static int
|
||||
tape_3490_erp_bug(struct tape_device *device, struct tape_request *request,
|
||||
struct irb *irb, int no)
|
||||
{
|
||||
if (request->op != TO_ASSIGN) {
|
||||
dev_err(&device->cdev->dev, "An unexpected condition %d "
|
||||
"occurred in tape error recovery\n", no);
|
||||
tape_dump_sense_dbf(device, request, irb);
|
||||
}
|
||||
return tape_3490_erp_failed(request, -EIO);
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle data overrun between cu and drive. The channel speed might
|
||||
* be too slow.
|
||||
*/
|
||||
static int
|
||||
tape_3490_erp_overrun(struct tape_device *device, struct tape_request *request,
|
||||
struct irb *irb)
|
||||
{
|
||||
if (irb->ecw[3] == 0x40) {
|
||||
dev_warn (&device->cdev->dev, "A data overrun occurred between"
|
||||
" the control unit and tape unit\n");
|
||||
return tape_3490_erp_failed(request, -EIO);
|
||||
}
|
||||
return tape_3490_erp_bug(device, request, irb, -1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle record sequence error.
|
||||
*/
|
||||
static int
|
||||
tape_3490_erp_sequence(struct tape_device *device,
|
||||
struct tape_request *request, struct irb *irb)
|
||||
{
|
||||
if (irb->ecw[3] == 0x41) {
|
||||
/*
|
||||
* cu detected incorrect block-id sequence on tape.
|
||||
*/
|
||||
dev_warn (&device->cdev->dev, "The block ID sequence on the "
|
||||
"tape is incorrect\n");
|
||||
return tape_3490_erp_failed(request, -EIO);
|
||||
}
|
||||
/*
|
||||
* Record sequence error bit is set, but erpa does not
|
||||
* show record sequence error.
|
||||
*/
|
||||
return tape_3490_erp_bug(device, request, irb, -2);
|
||||
}
|
||||
|
||||
/*
|
||||
* This function analyses the tape's sense-data in case of a unit-check.
|
||||
* If possible, it tries to recover from the error. Else the user is
|
||||
* informed about the problem.
|
||||
*/
|
||||
static int
|
||||
tape_3490_unit_check(struct tape_device *device, struct tape_request *request,
|
||||
struct irb *irb)
|
||||
{
|
||||
int inhibit_cu_recovery;
|
||||
__u8* sense;
|
||||
|
||||
inhibit_cu_recovery = (*device->modeset_byte & 0x80) ? 1 : 0;
|
||||
sense = irb->ecw;
|
||||
|
||||
if (
|
||||
sense[0] & SENSE_COMMAND_REJECT &&
|
||||
sense[1] & SENSE_WRITE_PROTECT
|
||||
) {
|
||||
if (
|
||||
request->op == TO_DSE ||
|
||||
request->op == TO_WRI ||
|
||||
request->op == TO_WTM
|
||||
) {
|
||||
/* medium is write protected */
|
||||
return tape_3490_erp_failed(request, -EACCES);
|
||||
} else {
|
||||
return tape_3490_erp_bug(device, request, irb, -3);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Special cases for various tape-states when reaching
|
||||
* end of recorded area
|
||||
*
|
||||
* FIXME: Maybe a special case of the special case:
|
||||
* sense[0] == SENSE_EQUIPMENT_CHECK &&
|
||||
* sense[1] == SENSE_DRIVE_ONLINE &&
|
||||
* sense[3] == 0x47 (Volume Fenced)
|
||||
*
|
||||
* This was caused by continued FSF or FSR after an
|
||||
* 'End Of Data'.
|
||||
*/
|
||||
if ((
|
||||
sense[0] == SENSE_DATA_CHECK ||
|
||||
sense[0] == SENSE_EQUIPMENT_CHECK ||
|
||||
sense[0] == (SENSE_EQUIPMENT_CHECK | SENSE_DEFERRED_UNIT_CHECK)
|
||||
) && (
|
||||
sense[1] == SENSE_DRIVE_ONLINE ||
|
||||
sense[1] == (SENSE_BEGINNING_OF_TAPE | SENSE_WRITE_MODE)
|
||||
)) {
|
||||
switch (request->op) {
|
||||
/*
|
||||
* sense[0] == SENSE_DATA_CHECK &&
|
||||
* sense[1] == SENSE_DRIVE_ONLINE
|
||||
* sense[3] == 0x36 (End Of Data)
|
||||
*
|
||||
* Further seeks might return a 'Volume Fenced'.
|
||||
*/
|
||||
case TO_FSF:
|
||||
case TO_FSB:
|
||||
/* Trying to seek beyond end of recorded area */
|
||||
return tape_3490_erp_failed(request, -ENOSPC);
|
||||
case TO_BSB:
|
||||
return tape_3490_erp_retry(request);
|
||||
|
||||
/*
|
||||
* sense[0] == SENSE_DATA_CHECK &&
|
||||
* sense[1] == SENSE_DRIVE_ONLINE &&
|
||||
* sense[3] == 0x36 (End Of Data)
|
||||
*/
|
||||
case TO_LBL:
|
||||
/* Block could not be located. */
|
||||
return tape_3490_erp_failed(request, -EIO);
|
||||
|
||||
case TO_RFO:
|
||||
/* Read beyond end of recorded area -> 0 bytes read */
|
||||
return tape_3490_erp_failed(request, 0);
|
||||
|
||||
/*
|
||||
* sense[0] == SENSE_EQUIPMENT_CHECK &&
|
||||
* sense[1] == SENSE_DRIVE_ONLINE &&
|
||||
* sense[3] == 0x38 (Physical End Of Volume)
|
||||
*/
|
||||
case TO_WRI:
|
||||
/* Writing at physical end of volume */
|
||||
return tape_3490_erp_failed(request, -ENOSPC);
|
||||
default:
|
||||
return tape_3490_erp_failed(request, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/* Sensing special bits */
|
||||
if (sense[0] & SENSE_BUS_OUT_CHECK)
|
||||
return tape_3490_erp_retry(request);
|
||||
|
||||
if (sense[0] & SENSE_DATA_CHECK) {
|
||||
/*
|
||||
* hardware failure, damaged tape or improper
|
||||
* operating conditions
|
||||
*/
|
||||
switch (sense[3]) {
|
||||
case 0x23:
|
||||
/* a read data check occurred */
|
||||
if ((sense[2] & SENSE_TAPE_SYNC_MODE) ||
|
||||
inhibit_cu_recovery)
|
||||
// data check is not permanent, may be
|
||||
// recovered. We always use async-mode with
|
||||
// cu-recovery, so this should *never* happen.
|
||||
return tape_3490_erp_bug(device, request,
|
||||
irb, -4);
|
||||
|
||||
/* data check is permanent, CU recovery has failed */
|
||||
dev_warn (&device->cdev->dev, "A read error occurred "
|
||||
"that cannot be recovered\n");
|
||||
return tape_3490_erp_failed(request, -EIO);
|
||||
case 0x25:
|
||||
// a write data check occurred
|
||||
if ((sense[2] & SENSE_TAPE_SYNC_MODE) ||
|
||||
inhibit_cu_recovery)
|
||||
// data check is not permanent, may be
|
||||
// recovered. We always use async-mode with
|
||||
// cu-recovery, so this should *never* happen.
|
||||
return tape_3490_erp_bug(device, request,
|
||||
irb, -5);
|
||||
|
||||
// data check is permanent, cu-recovery has failed
|
||||
dev_warn (&device->cdev->dev, "A write error on the "
|
||||
"tape cannot be recovered\n");
|
||||
return tape_3490_erp_failed(request, -EIO);
|
||||
case 0x28:
|
||||
/* ID-Mark at tape start couldn't be written */
|
||||
dev_warn (&device->cdev->dev, "Writing the ID-mark "
|
||||
"failed\n");
|
||||
return tape_3490_erp_failed(request, -EIO);
|
||||
case 0x31:
|
||||
/* Tape void. Tried to read beyond end of device. */
|
||||
dev_warn (&device->cdev->dev, "Reading the tape beyond"
|
||||
" the end of the recorded area failed\n");
|
||||
return tape_3490_erp_failed(request, -ENOSPC);
|
||||
case 0x41:
|
||||
/* Record sequence error. */
|
||||
dev_warn (&device->cdev->dev, "The tape contains an "
|
||||
"incorrect block ID sequence\n");
|
||||
return tape_3490_erp_failed(request, -EIO);
|
||||
}
|
||||
}
|
||||
|
||||
if (sense[0] & SENSE_OVERRUN)
|
||||
return tape_3490_erp_overrun(device, request, irb);
|
||||
|
||||
if (sense[1] & SENSE_RECORD_SEQUENCE_ERR)
|
||||
return tape_3490_erp_sequence(device, request, irb);
|
||||
|
||||
/* Sensing erpa codes */
|
||||
switch (sense[3]) {
|
||||
case 0x00:
|
||||
/* Unit check with erpa code 0. Report and ignore. */
|
||||
return TAPE_IO_SUCCESS;
|
||||
case 0x27:
|
||||
/*
|
||||
* Command reject. May indicate illegal channel program or
|
||||
* buffer over/underrun. Since all channel programs are
|
||||
* issued by this driver and ought be correct, we assume a
|
||||
* over/underrun situation and retry the channel program.
|
||||
*/
|
||||
return tape_3490_erp_retry(request);
|
||||
case 0x29:
|
||||
/*
|
||||
* Function incompatible. Either the tape is idrc compressed
|
||||
* but the hardware isn't capable to do idrc, or a perform
|
||||
* subsystem func is issued and the CU is not on-line.
|
||||
*/
|
||||
return tape_3490_erp_failed(request, -EIO);
|
||||
case 0x2b:
|
||||
/*
|
||||
* Environmental data present. Indicates either unload
|
||||
* completed ok or read buffered log command completed ok.
|
||||
*/
|
||||
if (request->op == TO_RUN) {
|
||||
/* Rewind unload completed ok. */
|
||||
tape_med_state_set(device, MS_UNLOADED);
|
||||
return tape_3490_erp_succeeded(request);
|
||||
}
|
||||
/* tape_3490 doesn't use read buffered log commands. */
|
||||
return tape_3490_erp_bug(device, request, irb, sense[3]);
|
||||
case 0x2c:
|
||||
/*
|
||||
* Permanent equipment check. CU has tried recovery, but
|
||||
* did not succeed.
|
||||
*/
|
||||
return tape_3490_erp_failed(request, -EIO);
|
||||
case 0x2d:
|
||||
/* Data security erase failure. */
|
||||
if (request->op == TO_DSE)
|
||||
return tape_3490_erp_failed(request, -EIO);
|
||||
/* Data security erase failure, but no such command issued. */
|
||||
return tape_3490_erp_bug(device, request, irb, sense[3]);
|
||||
case 0x2e:
|
||||
/*
|
||||
* Not capable. This indicates either that the drive fails
|
||||
* reading the format id mark or that format specified
|
||||
* is not supported by the drive.
|
||||
*/
|
||||
dev_warn (&device->cdev->dev, "The tape unit cannot process "
|
||||
"the tape format\n");
|
||||
return tape_3490_erp_failed(request, -EMEDIUMTYPE);
|
||||
case 0x30:
|
||||
/* The medium is write protected. */
|
||||
dev_warn (&device->cdev->dev, "The tape medium is write-"
|
||||
"protected\n");
|
||||
return tape_3490_erp_failed(request, -EACCES);
|
||||
case 0x35:
|
||||
/*
|
||||
* Drive equipment check. One of the following:
|
||||
* - cu cannot recover from a drive detected error
|
||||
* - a check code message is shown on drive display
|
||||
* - the cartridge loader does not respond correctly
|
||||
* - a failure occurs during an index, load, or unload cycle
|
||||
*/
|
||||
dev_warn (&device->cdev->dev, "An equipment check has occurred"
|
||||
" on the tape unit\n");
|
||||
return tape_3490_erp_failed(request, -EIO);
|
||||
case 0x36:
|
||||
/* End of data. */
|
||||
return tape_3490_erp_failed(request, -EIO);
|
||||
case 0x38:
|
||||
/*
|
||||
* Physical end of tape. A read/write operation reached
|
||||
* the physical end of tape.
|
||||
*/
|
||||
if (request->op==TO_WRI ||
|
||||
request->op==TO_DSE ||
|
||||
request->op==TO_WTM)
|
||||
return tape_3490_erp_failed(request, -ENOSPC);
|
||||
return tape_3490_erp_failed(request, -EIO);
|
||||
case 0x39:
|
||||
/* Backward at Beginning of tape. */
|
||||
return tape_3490_erp_failed(request, -EIO);
|
||||
case 0x42:
|
||||
/*
|
||||
* Degraded mode. A condition that can cause degraded
|
||||
* performance is detected.
|
||||
*/
|
||||
dev_warn (&device->cdev->dev, "The tape subsystem is running "
|
||||
"in degraded mode\n");
|
||||
return tape_3490_erp_retry(request);
|
||||
case 0x43:
|
||||
/* Drive not ready. */
|
||||
tape_med_state_set(device, MS_UNLOADED);
|
||||
/* Some commands commands are successful even in this case */
|
||||
if (sense[1] & SENSE_DRIVE_ONLINE) {
|
||||
switch(request->op) {
|
||||
case TO_ASSIGN:
|
||||
case TO_UNASSIGN:
|
||||
case TO_DIS:
|
||||
case TO_NOP:
|
||||
return tape_3490_done(request);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return tape_3490_erp_failed(request, -ENOMEDIUM);
|
||||
case 0x44:
|
||||
/* Locate Block unsuccessful. */
|
||||
if (request->op != TO_BLOCK && request->op != TO_LBL)
|
||||
/* No locate block was issued. */
|
||||
return tape_3490_erp_bug(device, request,
|
||||
irb, sense[3]);
|
||||
return tape_3490_erp_failed(request, -EIO);
|
||||
case 0x45:
|
||||
/* The drive is assigned to a different channel path. */
|
||||
dev_warn (&device->cdev->dev, "The tape unit is already "
|
||||
"assigned\n");
|
||||
return tape_3490_erp_failed(request, -EIO);
|
||||
case 0x47:
|
||||
/* Volume fenced. CU reports volume integrity is lost. */
|
||||
dev_warn (&device->cdev->dev, "The control unit has fenced "
|
||||
"access to the tape volume\n");
|
||||
return tape_3490_erp_failed(request, -EIO);
|
||||
case 0x48:
|
||||
/* Log sense data and retry request. */
|
||||
return tape_3490_erp_retry(request);
|
||||
case 0x4d:
|
||||
/*
|
||||
* Resetting event received. Since the driver does
|
||||
* not support resetting event recovery (which has to
|
||||
* be handled by the I/O Layer), retry our command.
|
||||
*/
|
||||
return tape_3490_erp_retry(request);
|
||||
case 0x4e:
|
||||
/*
|
||||
* Maximum block size exceeded. This indicates, that
|
||||
* the block to be written is larger than allowed for
|
||||
* buffered mode.
|
||||
*/
|
||||
dev_warn (&device->cdev->dev,
|
||||
"The maximum block size for buffered mode is exceeded\n");
|
||||
return tape_3490_erp_failed(request, -ENOBUFS);
|
||||
case 0x50:
|
||||
/*
|
||||
* Read buffered log (Overflow). CU is running in extended
|
||||
* buffered log mode, and a counter overflows. This should
|
||||
* never happen, since we're never running in extended
|
||||
* buffered log mode.
|
||||
*/
|
||||
return tape_3490_erp_retry(request);
|
||||
case 0x51:
|
||||
/*
|
||||
* Read buffered log (EOV). EOF processing occurs while the
|
||||
* CU is in extended buffered log mode. This should never
|
||||
* happen, since we're never running in extended buffered
|
||||
* log mode.
|
||||
*/
|
||||
return tape_3490_erp_retry(request);
|
||||
case 0x52:
|
||||
/* End of Volume complete. Rewind unload completed ok. */
|
||||
if (request->op == TO_RUN) {
|
||||
tape_med_state_set(device, MS_UNLOADED);
|
||||
return tape_3490_erp_succeeded(request);
|
||||
}
|
||||
return tape_3490_erp_bug(device, request, irb, sense[3]);
|
||||
case 0x53:
|
||||
/* Global command intercept. */
|
||||
return tape_3490_erp_retry(request);
|
||||
case 0x54:
|
||||
/* Channel interface recovery (temporary). */
|
||||
return tape_3490_erp_retry(request);
|
||||
case 0x55:
|
||||
/* Channel interface recovery (permanent). */
|
||||
dev_warn (&device->cdev->dev, "A channel interface error cannot be"
|
||||
" recovered\n");
|
||||
return tape_3490_erp_failed(request, -EIO);
|
||||
case 0x56:
|
||||
/* Channel protocol error. */
|
||||
dev_warn (&device->cdev->dev, "A channel protocol error "
|
||||
"occurred\n");
|
||||
return tape_3490_erp_failed(request, -EIO);
|
||||
case 0x57:
|
||||
/* Global status intercept. */
|
||||
return tape_3490_erp_retry(request);
|
||||
/* The following erpas should have been covered earlier. */
|
||||
case 0x23: /* Read data check. */
|
||||
case 0x25: /* Write data check. */
|
||||
case 0x28: /* Write id mark check. */
|
||||
case 0x31: /* Tape void. */
|
||||
case 0x40: /* Overrun error. */
|
||||
case 0x41: /* Record sequence error. */
|
||||
/* All other erpas are reserved for future use. */
|
||||
default:
|
||||
return tape_3490_erp_bug(device, request, irb, sense[3]);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 3490 interrupt handler
|
||||
*/
|
||||
static int
|
||||
tape_3490_irq(struct tape_device *device, struct tape_request *request,
|
||||
struct irb *irb)
|
||||
{
|
||||
if (request == NULL)
|
||||
return tape_3490_unsolicited_irq(device, irb);
|
||||
|
||||
if ((irb->scsw.cmd.dstat & DEV_STAT_UNIT_EXCEP) &&
|
||||
(irb->scsw.cmd.dstat & DEV_STAT_DEV_END) &&
|
||||
(request->op == TO_WRI)) {
|
||||
/* Write at end of volume */
|
||||
return tape_3490_erp_failed(request, -ENOSPC);
|
||||
}
|
||||
|
||||
if (irb->scsw.cmd.dstat & DEV_STAT_UNIT_CHECK)
|
||||
return tape_3490_unit_check(device, request, irb);
|
||||
|
||||
if (irb->scsw.cmd.dstat & DEV_STAT_DEV_END) {
|
||||
/*
|
||||
* A unit exception occurs on skipping over a tapemark block.
|
||||
*/
|
||||
if (irb->scsw.cmd.dstat & DEV_STAT_UNIT_EXCEP) {
|
||||
if (request->op == TO_BSB || request->op == TO_FSB)
|
||||
request->rescnt++;
|
||||
else
|
||||
DBF_EVENT(5, "Unit Exception!\n");
|
||||
}
|
||||
return tape_3490_done(request);
|
||||
}
|
||||
|
||||
DBF_EVENT(6, "xunknownirq\n");
|
||||
tape_dump_sense_dbf(device, request, irb);
|
||||
return TAPE_IO_STOP;
|
||||
}
|
||||
|
||||
static int
|
||||
tape_3490_setup_device(struct tape_device * device)
|
||||
{
|
||||
int rc;
|
||||
|
||||
DBF_EVENT(6, "3490 device setup\n");
|
||||
if ((rc = tape_std_assign(device)) == 0) {
|
||||
if ((rc = tape_3490_medium_sense(device)) != 0) {
|
||||
DBF_LH(3, "3490 medium sense returned %d\n", rc);
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void
|
||||
tape_3490_cleanup_device(struct tape_device *device)
|
||||
{
|
||||
tape_std_unassign(device);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* MTTELL: Tell block. Return the number of block relative to current file.
|
||||
*/
|
||||
static int
|
||||
tape_3490_mttell(struct tape_device *device, int mt_count)
|
||||
{
|
||||
struct {
|
||||
struct tape_3490_block_id cbid;
|
||||
struct tape_3490_block_id dbid;
|
||||
} __attribute__ ((packed)) block_id;
|
||||
int rc;
|
||||
|
||||
rc = tape_std_read_block_id(device, (__u64 *) &block_id);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
return block_id.cbid.block;
|
||||
}
|
||||
|
||||
/*
|
||||
* MTSEEK: seek to the specified block.
|
||||
*/
|
||||
static int
|
||||
tape_3490_mtseek(struct tape_device *device, int mt_count)
|
||||
{
|
||||
struct tape_request *request;
|
||||
struct tape_3490_block_id * bid;
|
||||
|
||||
if (mt_count > 0x3fffff) {
|
||||
DBF_EXCEPTION(6, "xsee parm\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
request = tape_alloc_request(3, 4);
|
||||
if (IS_ERR(request))
|
||||
return PTR_ERR(request);
|
||||
|
||||
/* setup ccws */
|
||||
request->op = TO_LBL;
|
||||
bid = (struct tape_3490_block_id *) request->cpdata;
|
||||
bid->block = mt_count;
|
||||
|
||||
tape_ccw_cc(request->cpaddr, MODE_SET_DB, 1, device->modeset_byte);
|
||||
tape_ccw_cc(request->cpaddr + 1, LOCATE, 4, request->cpdata);
|
||||
tape_ccw_end(request->cpaddr + 2, NOP, 0, NULL);
|
||||
|
||||
/* execute it */
|
||||
return tape_do_io_free(device, request);
|
||||
}
|
||||
|
||||
/*
|
||||
* List of 3490 tape commands.
|
||||
*/
|
||||
static tape_mtop_fn tape_3490_mtop[TAPE_NR_MTOPS] = {
|
||||
[MTRESET] = tape_std_mtreset,
|
||||
[MTFSF] = tape_std_mtfsf,
|
||||
[MTBSF] = tape_std_mtbsf,
|
||||
[MTFSR] = tape_std_mtfsr,
|
||||
[MTBSR] = tape_std_mtbsr,
|
||||
[MTWEOF] = tape_std_mtweof,
|
||||
[MTREW] = tape_std_mtrew,
|
||||
[MTOFFL] = tape_std_mtoffl,
|
||||
[MTNOP] = tape_std_mtnop,
|
||||
[MTRETEN] = tape_std_mtreten,
|
||||
[MTBSFM] = tape_std_mtbsfm,
|
||||
[MTFSFM] = tape_std_mtfsfm,
|
||||
[MTEOM] = tape_std_mteom,
|
||||
[MTERASE] = tape_std_mterase,
|
||||
[MTRAS1] = NULL,
|
||||
[MTRAS2] = NULL,
|
||||
[MTRAS3] = NULL,
|
||||
[MTSETBLK] = tape_std_mtsetblk,
|
||||
[MTSETDENSITY] = NULL,
|
||||
[MTSEEK] = tape_3490_mtseek,
|
||||
[MTTELL] = tape_3490_mttell,
|
||||
[MTSETDRVBUFFER] = NULL,
|
||||
[MTFSS] = NULL,
|
||||
[MTBSS] = NULL,
|
||||
[MTWSM] = NULL,
|
||||
[MTLOCK] = NULL,
|
||||
[MTUNLOCK] = NULL,
|
||||
[MTLOAD] = tape_std_mtload,
|
||||
[MTUNLOAD] = tape_std_mtunload,
|
||||
[MTCOMPRESSION] = tape_std_mtcompression,
|
||||
[MTSETPART] = NULL,
|
||||
[MTMKPART] = NULL
|
||||
};
|
||||
|
||||
/*
|
||||
* Tape discipline structure for 3490.
|
||||
*/
|
||||
static struct tape_discipline tape_discipline_3490 = {
|
||||
.owner = THIS_MODULE,
|
||||
.setup_device = tape_3490_setup_device,
|
||||
.cleanup_device = tape_3490_cleanup_device,
|
||||
.process_eov = tape_std_process_eov,
|
||||
.irq = tape_3490_irq,
|
||||
.read_block = tape_std_read_block,
|
||||
.write_block = tape_std_write_block,
|
||||
.mtop_array = tape_3490_mtop
|
||||
};
|
||||
|
||||
static struct ccw_device_id tape_3490_ids[] = {
|
||||
{ CCW_DEVICE_DEVTYPE(0x3490, 0, 0x3490, 0), .driver_info = tape_3490},
|
||||
{ /* end of list */ },
|
||||
};
|
||||
|
||||
static int
|
||||
tape_3490_online(struct ccw_device *cdev)
|
||||
{
|
||||
return tape_generic_online(
|
||||
dev_get_drvdata(&cdev->dev),
|
||||
&tape_discipline_3490
|
||||
);
|
||||
}
|
||||
|
||||
static struct ccw_driver tape_3490_driver = {
|
||||
.driver = {
|
||||
.name = "tape_3490",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.ids = tape_3490_ids,
|
||||
.probe = tape_generic_probe,
|
||||
.remove = tape_generic_remove,
|
||||
.set_online = tape_3490_online,
|
||||
.set_offline = tape_generic_offline,
|
||||
.int_class = IRQIO_TAP,
|
||||
};
|
||||
|
||||
int tape_3490_init(void)
|
||||
{
|
||||
int rc;
|
||||
|
||||
TAPE_DBF_AREA = debug_register ( "tape_3490", 2, 2, 4*sizeof(long));
|
||||
debug_register_view(TAPE_DBF_AREA, &debug_sprintf_view);
|
||||
#ifdef DBF_LIKE_HELL
|
||||
debug_set_level(TAPE_DBF_AREA, 6);
|
||||
#endif
|
||||
|
||||
DBF_EVENT(3, "3490 init\n");
|
||||
/* Register driver for 3490 tapes. */
|
||||
rc = ccw_driver_register(&tape_3490_driver);
|
||||
if (rc)
|
||||
DBF_EVENT(3, "3490 init failed\n");
|
||||
else
|
||||
DBF_EVENT(3, "3490 registered\n");
|
||||
return rc;
|
||||
}
|
||||
|
||||
void tape_3490_exit(void)
|
||||
{
|
||||
ccw_driver_unregister(&tape_3490_driver);
|
||||
|
||||
debug_unregister(TAPE_DBF_AREA);
|
||||
}
|
||||
|
||||
MODULE_DEVICE_TABLE(ccw, tape_3490_ids);
|
||||
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
|
@ -1,175 +0,0 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* tape device discipline for 3590 tapes.
|
||||
*
|
||||
* Copyright IBM Corp. 2001, 2006
|
||||
* Author(s): Stefan Bader <shbader@de.ibm.com>
|
||||
* Michael Holzheu <holzheu@de.ibm.com>
|
||||
* Martin Schwidefsky <schwidefsky@de.ibm.com>
|
||||
*/
|
||||
|
||||
#ifndef _TAPE_3590_H
|
||||
#define _TAPE_3590_H
|
||||
|
||||
#define MEDIUM_SENSE 0xc2
|
||||
#define READ_PREVIOUS 0x0a
|
||||
#define MODE_SENSE 0xcf
|
||||
#define PERFORM_SS_FUNC 0x77
|
||||
#define READ_SS_DATA 0x3e
|
||||
|
||||
#define PREP_RD_SS_DATA 0x18
|
||||
#define RD_ATTMSG 0x3
|
||||
|
||||
#define SENSE_BRA_PER 0
|
||||
#define SENSE_BRA_CONT 1
|
||||
#define SENSE_BRA_RE 2
|
||||
#define SENSE_BRA_DRE 3
|
||||
|
||||
#define SENSE_FMT_LIBRARY 0x23
|
||||
#define SENSE_FMT_UNSOLICITED 0x40
|
||||
#define SENSE_FMT_COMMAND_REJ 0x41
|
||||
#define SENSE_FMT_COMMAND_EXEC0 0x50
|
||||
#define SENSE_FMT_COMMAND_EXEC1 0x51
|
||||
#define SENSE_FMT_EVENT0 0x60
|
||||
#define SENSE_FMT_EVENT1 0x61
|
||||
#define SENSE_FMT_MIM 0x70
|
||||
#define SENSE_FMT_SIM 0x71
|
||||
|
||||
#define MSENSE_UNASSOCIATED 0x00
|
||||
#define MSENSE_ASSOCIATED_MOUNT 0x01
|
||||
#define MSENSE_ASSOCIATED_UMOUNT 0x02
|
||||
#define MSENSE_CRYPT_MASK 0x00000010
|
||||
|
||||
#define TAPE_3590_MAX_MSG 0xb0
|
||||
|
||||
/* Datatypes */
|
||||
|
||||
struct tape_3590_disc_data {
|
||||
struct tape390_crypt_info crypt_info;
|
||||
int read_back_op;
|
||||
};
|
||||
|
||||
#define TAPE_3590_CRYPT_INFO(device) \
|
||||
((struct tape_3590_disc_data*)(device->discdata))->crypt_info
|
||||
#define TAPE_3590_READ_BACK_OP(device) \
|
||||
((struct tape_3590_disc_data*)(device->discdata))->read_back_op
|
||||
|
||||
struct tape_3590_sense {
|
||||
|
||||
unsigned int command_rej:1;
|
||||
unsigned int interv_req:1;
|
||||
unsigned int bus_out_check:1;
|
||||
unsigned int eq_check:1;
|
||||
unsigned int data_check:1;
|
||||
unsigned int overrun:1;
|
||||
unsigned int def_unit_check:1;
|
||||
unsigned int assgnd_elsew:1;
|
||||
|
||||
unsigned int locate_fail:1;
|
||||
unsigned int inst_online:1;
|
||||
unsigned int reserved:1;
|
||||
unsigned int blk_seq_err:1;
|
||||
unsigned int begin_part:1;
|
||||
unsigned int wr_mode:1;
|
||||
unsigned int wr_prot:1;
|
||||
unsigned int not_cap:1;
|
||||
|
||||
unsigned int bra:2;
|
||||
unsigned int lc:3;
|
||||
unsigned int vlf_active:1;
|
||||
unsigned int stm:1;
|
||||
unsigned int med_pos:1;
|
||||
|
||||
unsigned int rac:8;
|
||||
|
||||
unsigned int rc_rqc:16;
|
||||
|
||||
unsigned int mc:8;
|
||||
|
||||
unsigned int sense_fmt:8;
|
||||
|
||||
union {
|
||||
struct {
|
||||
unsigned int emc:4;
|
||||
unsigned int smc:4;
|
||||
unsigned int sev:2;
|
||||
unsigned int reserved:6;
|
||||
unsigned int md:8;
|
||||
unsigned int refcode:8;
|
||||
unsigned int mid:16;
|
||||
unsigned int mp:16;
|
||||
unsigned char volid[6];
|
||||
unsigned int fid:8;
|
||||
} f70;
|
||||
struct {
|
||||
unsigned int emc:4;
|
||||
unsigned int smc:4;
|
||||
unsigned int sev:2;
|
||||
unsigned int reserved1:5;
|
||||
unsigned int mdf:1;
|
||||
unsigned char md[3];
|
||||
unsigned int simid:8;
|
||||
unsigned int uid:16;
|
||||
unsigned int refcode1:16;
|
||||
unsigned int refcode2:16;
|
||||
unsigned int refcode3:16;
|
||||
unsigned int reserved2:8;
|
||||
} f71;
|
||||
unsigned char data[14];
|
||||
} fmt;
|
||||
unsigned char pad[10];
|
||||
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct tape_3590_med_sense {
|
||||
unsigned int macst:4;
|
||||
unsigned int masst:4;
|
||||
char pad1[7];
|
||||
unsigned int flags;
|
||||
char pad2[116];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct tape_3590_rdc_data {
|
||||
char data[64];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/* Datastructures for 3592 encryption support */
|
||||
|
||||
struct tape3592_kekl {
|
||||
__u8 flags;
|
||||
char label[64];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct tape3592_kekl_pair {
|
||||
__u8 count;
|
||||
struct tape3592_kekl kekl[2];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct tape3592_kekl_query_data {
|
||||
__u16 len;
|
||||
__u8 fmt;
|
||||
__u8 mc;
|
||||
__u32 id;
|
||||
__u8 flags;
|
||||
struct tape3592_kekl_pair kekls;
|
||||
char reserved[116];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct tape3592_kekl_query_order {
|
||||
__u8 code;
|
||||
__u8 flags;
|
||||
char reserved1[2];
|
||||
__u8 max_count;
|
||||
char reserved2[35];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct tape3592_kekl_set_order {
|
||||
__u8 code;
|
||||
__u8 flags;
|
||||
char reserved1[2];
|
||||
__u8 op;
|
||||
struct tape3592_kekl_pair kekls;
|
||||
char reserved2[120];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
#endif /* _TAPE_3590_H */
|
||||
|
|
@ -412,10 +412,7 @@ __tapechar_ioctl(struct tape_device *device,
|
|||
|
||||
return put_user_mtget(data, &get);
|
||||
}
|
||||
/* Try the discipline ioctl function. */
|
||||
if (device->discipline->ioctl_fn == NULL)
|
||||
return -EINVAL;
|
||||
return device->discipline->ioctl_fn(device, no, (unsigned long)data);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static long
|
||||
|
|
|
|||
|
|
@ -15,13 +15,6 @@
|
|||
|
||||
#include "tape_class.h"
|
||||
|
||||
MODULE_AUTHOR("Stefan Bader <shbader@de.ibm.com>");
|
||||
MODULE_DESCRIPTION(
|
||||
"Copyright IBM Corp. 2004 All Rights Reserved.\n"
|
||||
"tape_class.c"
|
||||
);
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
static const struct class tape_class = {
|
||||
.name = "tape390",
|
||||
};
|
||||
|
|
@ -116,16 +109,12 @@ void unregister_tape_dev(struct device *device, struct tape_class_device *tcd)
|
|||
}
|
||||
EXPORT_SYMBOL(unregister_tape_dev);
|
||||
|
||||
|
||||
static int __init tape_init(void)
|
||||
int tape_class_init(void)
|
||||
{
|
||||
return class_register(&tape_class);
|
||||
}
|
||||
|
||||
static void __exit tape_exit(void)
|
||||
void tape_class_exit(void)
|
||||
{
|
||||
class_unregister(&tape_class);
|
||||
}
|
||||
|
||||
postcore_initcall(tape_init);
|
||||
module_exit(tape_exit);
|
||||
|
|
|
|||
|
|
@ -55,5 +55,7 @@ struct tape_class_device *register_tape_dev(
|
|||
char * node_name
|
||||
);
|
||||
void unregister_tape_dev(struct device *device, struct tape_class_device *tcd);
|
||||
int tape_class_init(void);
|
||||
void tape_class_exit(void);
|
||||
|
||||
#endif /* __TAPE_CLASS_H__ */
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@
|
|||
|
||||
#include "tape.h"
|
||||
#include "tape_std.h"
|
||||
#include "tape_class.h"
|
||||
|
||||
#define LONG_BUSY_TIMEOUT 180 /* seconds */
|
||||
|
||||
|
|
@ -74,9 +75,7 @@ const char *tape_op_verbose[TO_SIZE] =
|
|||
[TO_LOAD] = "LOA", [TO_READ_CONFIG] = "RCF",
|
||||
[TO_READ_ATTMSG] = "RAT",
|
||||
[TO_DIS] = "DIS", [TO_ASSIGN] = "ASS",
|
||||
[TO_UNASSIGN] = "UAS", [TO_CRYPT_ON] = "CON",
|
||||
[TO_CRYPT_OFF] = "COF", [TO_KEKL_SET] = "KLS",
|
||||
[TO_KEKL_QUERY] = "KLQ",[TO_RDC] = "RDC",
|
||||
[TO_UNASSIGN] = "UAS", [TO_RDC] = "RDC",
|
||||
};
|
||||
|
||||
static int devid_to_int(struct ccw_dev_id *dev_id)
|
||||
|
|
@ -1312,7 +1311,9 @@ tape_init (void)
|
|||
#endif
|
||||
DBF_EVENT(3, "tape init\n");
|
||||
tape_proc_init();
|
||||
tape_class_init();
|
||||
tapechar_init ();
|
||||
tape_3490_init();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -1325,14 +1326,15 @@ tape_exit(void)
|
|||
DBF_EVENT(6, "tape exit\n");
|
||||
|
||||
/* Get rid of the frontends */
|
||||
tape_3490_exit();
|
||||
tapechar_exit();
|
||||
tape_class_exit();
|
||||
tape_proc_cleanup();
|
||||
debug_unregister (TAPE_DBF_AREA);
|
||||
}
|
||||
|
||||
MODULE_AUTHOR("(C) 2001 IBM Deutschland Entwicklung GmbH by Carsten Otte and "
|
||||
"Michael Holzheu (cotte@de.ibm.com,holzheu@de.ibm.com)");
|
||||
MODULE_DESCRIPTION("Linux on zSeries channel attached tape device driver");
|
||||
MODULE_AUTHOR("IBM Corporation");
|
||||
MODULE_DESCRIPTION("s390 channel-attached tape device driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
module_init(tape_init);
|
||||
|
|
|
|||
|
|
@ -22,7 +22,6 @@
|
|||
#include <asm/types.h>
|
||||
#include <asm/idals.h>
|
||||
#include <asm/ebcdic.h>
|
||||
#include <asm/tape390.h>
|
||||
|
||||
#define TAPE_DBF_AREA tape_core_dbf
|
||||
|
||||
|
|
@ -118,36 +117,6 @@ tape_std_unassign (struct tape_device *device)
|
|||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* TAPE390_DISPLAY: Show a string on the tape display.
|
||||
*/
|
||||
int
|
||||
tape_std_display(struct tape_device *device, struct display_struct *disp)
|
||||
{
|
||||
struct tape_request *request;
|
||||
int rc;
|
||||
|
||||
request = tape_alloc_request(2, 17);
|
||||
if (IS_ERR(request)) {
|
||||
DBF_EVENT(3, "TAPE: load display failed\n");
|
||||
return PTR_ERR(request);
|
||||
}
|
||||
request->op = TO_DIS;
|
||||
|
||||
*(unsigned char *) request->cpdata = disp->cntrl;
|
||||
DBF_EVENT(5, "TAPE: display cntrl=%04x\n", disp->cntrl);
|
||||
memcpy(((unsigned char *) request->cpdata) + 1, disp->message1, 8);
|
||||
memcpy(((unsigned char *) request->cpdata) + 9, disp->message2, 8);
|
||||
ASCEBC(((unsigned char*) request->cpdata) + 1, 16);
|
||||
|
||||
tape_ccw_cc(request->cpaddr, LOAD_DISPLAY, 17, request->cpdata);
|
||||
tape_ccw_end(request->cpaddr + 1, NOP, 0, NULL);
|
||||
|
||||
rc = tape_do_io_interruptible(device, request);
|
||||
tape_free_request(request);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read block id.
|
||||
*/
|
||||
|
|
@ -696,7 +665,6 @@ tape_std_process_eov(struct tape_device *device)
|
|||
|
||||
EXPORT_SYMBOL(tape_std_assign);
|
||||
EXPORT_SYMBOL(tape_std_unassign);
|
||||
EXPORT_SYMBOL(tape_std_display);
|
||||
EXPORT_SYMBOL(tape_std_read_block_id);
|
||||
EXPORT_SYMBOL(tape_std_mtload);
|
||||
EXPORT_SYMBOL(tape_std_mtsetblk);
|
||||
|
|
|
|||
|
|
@ -11,8 +11,6 @@
|
|||
#ifndef _TAPE_STD_H
|
||||
#define _TAPE_STD_H
|
||||
|
||||
#include <asm/tape390.h>
|
||||
|
||||
/*
|
||||
* Biggest block size of 256K to handle.
|
||||
*/
|
||||
|
|
@ -21,54 +19,25 @@
|
|||
/*
|
||||
* The CCW commands for the Tape type of command.
|
||||
*/
|
||||
#define INVALID_00 0x00 /* Invalid cmd */
|
||||
#define BACKSPACEBLOCK 0x27 /* Back Space block */
|
||||
#define BACKSPACEFILE 0x2f /* Back Space file */
|
||||
#define DATA_SEC_ERASE 0x97 /* Data security erase */
|
||||
#define ERASE_GAP 0x17 /* Erase Gap */
|
||||
#define FORSPACEBLOCK 0x37 /* Forward space block */
|
||||
#define FORSPACEFILE 0x3F /* Forward Space file */
|
||||
#define FORCE_STREAM_CNT 0xEB /* Forced streaming count # */
|
||||
#define NOP 0x03 /* No operation */
|
||||
#define READ_FORWARD 0x02 /* Read forward */
|
||||
#define REWIND 0x07 /* Rewind */
|
||||
#define REWIND_UNLOAD 0x0F /* Rewind and Unload */
|
||||
#define SENSE 0x04 /* Sense */
|
||||
#define NEW_MODE_SET 0xEB /* Guess it is Mode set */
|
||||
#define WRITE_CMD 0x01 /* Write */
|
||||
#define WRITETAPEMARK 0x1F /* Write Tape Mark */
|
||||
|
||||
#define ASSIGN 0xB7 /* 3420 REJECT,3480 OK */
|
||||
#define CONTROL_ACCESS 0xE3 /* Set high speed */
|
||||
#define DIAG_MODE_SET 0x0B /* 3420 NOP, 3480 REJECT */
|
||||
#define LOAD_DISPLAY 0x9F /* 3420 REJECT,3480 OK */
|
||||
#define LOCATE 0x4F /* 3420 REJ, 3480 NOP */
|
||||
#define LOOP_WRITE_TO_READ 0x8B /* 3480 REJECT */
|
||||
#define MODE_SET_DB 0xDB /* 3420 REJECT,3480 OK */
|
||||
#define MODE_SET_C3 0xC3 /* for 3420 */
|
||||
#define MODE_SET_CB 0xCB /* for 3420 */
|
||||
#define MODE_SET_D3 0xD3 /* for 3420 */
|
||||
#define READ_BACKWARD 0x0C /* */
|
||||
#define READ_BLOCK_ID 0x22 /* 3420 REJECT,3480 OK */
|
||||
#define READ_BUFFER 0x12 /* 3420 REJECT,3480 OK */
|
||||
#define READ_BUFF_LOG 0x24 /* 3420 REJECT,3480 OK */
|
||||
#define RELEASE 0xD4 /* 3420 NOP, 3480 REJECT */
|
||||
#define REQ_TRK_IN_ERROR 0x1B /* 3420 NOP, 3480 REJECT */
|
||||
#define RESERVE 0xF4 /* 3420 NOP, 3480 REJECT */
|
||||
#define SENSE_GROUP_ID 0x34 /* 3420 REJECT,3480 OK */
|
||||
#define SENSE_ID 0xE4 /* 3420 REJECT,3480 OK */
|
||||
#define READ_DEV_CHAR 0x64 /* Read device characteristics */
|
||||
#define SET_DIAGNOSE 0x4B /* 3420 NOP, 3480 REJECT */
|
||||
#define SET_GROUP_ID 0xAF /* 3420 REJECT,3480 OK */
|
||||
#define SET_TAPE_WRITE_IMMED 0xC3 /* for 3480 */
|
||||
#define SUSPEND 0x5B /* 3420 REJ, 3480 NOP */
|
||||
#define SYNC 0x43 /* Synchronize (flush buffer) */
|
||||
#define UNASSIGN 0xC7 /* 3420 REJECT,3480 OK */
|
||||
#define PERF_SUBSYS_FUNC 0x77 /* 3490 CMD */
|
||||
#define READ_CONFIG_DATA 0xFA /* 3490 CMD */
|
||||
#define READ_MESSAGE_ID 0x4E /* 3490 CMD */
|
||||
#define READ_SUBSYS_DATA 0x3E /* 3490 CMD */
|
||||
#define SET_INTERFACE_ID 0x73 /* 3490 CMD */
|
||||
#define ASSIGN 0xB7 /* Assign */
|
||||
#define LOCATE 0x4F /* Locate Block */
|
||||
#define MODE_SET_DB 0xDB /* Mode Set */
|
||||
#define READ_BLOCK_ID 0x22 /* Read Block ID */
|
||||
#define UNASSIGN 0xC7 /* Unassign */
|
||||
|
||||
#define SENSE_COMMAND_REJECT 0x80
|
||||
#define SENSE_INTERVENTION_REQUIRED 0x40
|
||||
|
|
@ -105,7 +74,6 @@ struct tape_request *tape_std_write_block(struct tape_device *);
|
|||
int tape_std_assign(struct tape_device *);
|
||||
int tape_std_unassign(struct tape_device *);
|
||||
int tape_std_read_block_id(struct tape_device *device, __u64 *id);
|
||||
int tape_std_display(struct tape_device *, struct display_struct *disp);
|
||||
int tape_std_terminate_write(struct tape_device *);
|
||||
|
||||
/* Standard magnetic tape commands. */
|
||||
|
|
@ -133,10 +101,7 @@ void tape_std_process_eov(struct tape_device *);
|
|||
|
||||
/* S390 tape types */
|
||||
enum s390_tape_type {
|
||||
tape_3480,
|
||||
tape_3490,
|
||||
tape_3590,
|
||||
tape_3592,
|
||||
};
|
||||
|
||||
#endif // _TAPE_STD_H
|
||||
|
|
|
|||
|
|
@ -235,7 +235,7 @@ struct subchannel *css_alloc_subchannel(struct subchannel_id schid,
|
|||
return sch;
|
||||
|
||||
err:
|
||||
kfree(sch);
|
||||
put_device(&sch->dev);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -52,24 +52,24 @@ MODULE_LICENSE("GPL");
|
|||
|
||||
int ap_domain_index = -1; /* Adjunct Processor Domain Index */
|
||||
static DEFINE_SPINLOCK(ap_domain_lock);
|
||||
module_param_named(domain, ap_domain_index, int, 0440);
|
||||
module_param_named(domain, ap_domain_index, int, 0444);
|
||||
MODULE_PARM_DESC(domain, "domain index for ap devices");
|
||||
EXPORT_SYMBOL(ap_domain_index);
|
||||
|
||||
static int ap_thread_flag;
|
||||
module_param_named(poll_thread, ap_thread_flag, int, 0440);
|
||||
module_param_named(poll_thread, ap_thread_flag, int, 0444);
|
||||
MODULE_PARM_DESC(poll_thread, "Turn on/off poll thread, default is 0 (off).");
|
||||
|
||||
static char *apm_str;
|
||||
module_param_named(apmask, apm_str, charp, 0440);
|
||||
module_param_named(apmask, apm_str, charp, 0444);
|
||||
MODULE_PARM_DESC(apmask, "AP bus adapter mask.");
|
||||
|
||||
static char *aqm_str;
|
||||
module_param_named(aqmask, aqm_str, charp, 0440);
|
||||
module_param_named(aqmask, aqm_str, charp, 0444);
|
||||
MODULE_PARM_DESC(aqmask, "AP bus domain mask.");
|
||||
|
||||
static int ap_useirq = 1;
|
||||
module_param_named(useirq, ap_useirq, int, 0440);
|
||||
module_param_named(useirq, ap_useirq, int, 0444);
|
||||
MODULE_PARM_DESC(useirq, "Use interrupt if available, default is 1 (on).");
|
||||
|
||||
atomic_t ap_max_msg_size = ATOMIC_INIT(AP_DEFAULT_MAX_MSG_SIZE);
|
||||
|
|
@ -130,7 +130,7 @@ debug_info_t *ap_dbf_info;
|
|||
*/
|
||||
static mempool_t *ap_msg_pool;
|
||||
static unsigned int ap_msg_pool_min_items = 8;
|
||||
module_param_named(msgpool_min_items, ap_msg_pool_min_items, uint, 0440);
|
||||
module_param_named(msgpool_min_items, ap_msg_pool_min_items, uint, 0400);
|
||||
MODULE_PARM_DESC(msgpool_min_items, "AP message pool minimal items");
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ MODULE_DESCRIPTION("Cryptographic Coprocessor interface, " \
|
|||
MODULE_LICENSE("GPL");
|
||||
|
||||
unsigned int zcrypt_mempool_threshold = 5;
|
||||
module_param_named(mempool_threshold, zcrypt_mempool_threshold, uint, 0440);
|
||||
module_param_named(mempool_threshold, zcrypt_mempool_threshold, uint, 0400);
|
||||
MODULE_PARM_DESC(mempool_threshold, "CCA and EP11 request/reply mempool minimal items (min: 1)");
|
||||
|
||||
/*
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue