^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * ipl/reipl/dump support for Linux on s390.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright IBM Corp. 2005, 2012
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * Author(s): Michael Holzheu <holzheu@de.ibm.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * Heiko Carstens <heiko.carstens@de.ibm.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * Volker Sameske <sameske@de.ibm.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/types.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/export.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/delay.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/reboot.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <linux/ctype.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <linux/fs.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <linux/gfp.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include <linux/crash_dump.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #include <linux/debug_locks.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #include <asm/diag.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #include <asm/ipl.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #include <asm/smp.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #include <asm/setup.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #include <asm/cpcmd.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) #include <asm/ebcdic.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) #include <asm/sclp.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) #include <asm/checksum.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) #include <asm/debug.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) #include <asm/os_info.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) #include <asm/sections.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) #include <asm/boot_data.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) #include "entry.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) #define IPL_PARM_BLOCK_VERSION 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) #define IPL_UNKNOWN_STR "unknown"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) #define IPL_CCW_STR "ccw"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) #define IPL_FCP_STR "fcp"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) #define IPL_FCP_DUMP_STR "fcp_dump"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) #define IPL_NVME_STR "nvme"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) #define IPL_NVME_DUMP_STR "nvme_dump"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) #define IPL_NSS_STR "nss"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) #define DUMP_CCW_STR "ccw"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) #define DUMP_FCP_STR "fcp"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) #define DUMP_NVME_STR "nvme"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) #define DUMP_NONE_STR "none"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) * Four shutdown trigger types are supported:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) * - panic
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) * - halt
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) * - power off
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) * - reipl
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) * - restart
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) #define ON_PANIC_STR "on_panic"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) #define ON_HALT_STR "on_halt"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) #define ON_POFF_STR "on_poff"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) #define ON_REIPL_STR "on_reboot"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) #define ON_RESTART_STR "on_restart"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) struct shutdown_action;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) struct shutdown_trigger {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) char *name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) struct shutdown_action *action;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) * The following shutdown action types are supported:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) #define SHUTDOWN_ACTION_IPL_STR "ipl"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) #define SHUTDOWN_ACTION_REIPL_STR "reipl"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) #define SHUTDOWN_ACTION_DUMP_STR "dump"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) #define SHUTDOWN_ACTION_VMCMD_STR "vmcmd"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) #define SHUTDOWN_ACTION_STOP_STR "stop"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) #define SHUTDOWN_ACTION_DUMP_REIPL_STR "dump_reipl"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) struct shutdown_action {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) char *name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) void (*fn) (struct shutdown_trigger *trigger);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) int (*init) (void);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) int init_rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) static char *ipl_type_str(enum ipl_type type)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) switch (type) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) case IPL_TYPE_CCW:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) return IPL_CCW_STR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) case IPL_TYPE_FCP:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) return IPL_FCP_STR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) case IPL_TYPE_FCP_DUMP:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) return IPL_FCP_DUMP_STR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) case IPL_TYPE_NSS:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) return IPL_NSS_STR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) case IPL_TYPE_NVME:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) return IPL_NVME_STR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) case IPL_TYPE_NVME_DUMP:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) return IPL_NVME_DUMP_STR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) case IPL_TYPE_UNKNOWN:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) return IPL_UNKNOWN_STR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) enum dump_type {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) DUMP_TYPE_NONE = 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) DUMP_TYPE_CCW = 2,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) DUMP_TYPE_FCP = 4,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) DUMP_TYPE_NVME = 8,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) static char *dump_type_str(enum dump_type type)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) switch (type) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) case DUMP_TYPE_NONE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) return DUMP_NONE_STR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) case DUMP_TYPE_CCW:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) return DUMP_CCW_STR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) case DUMP_TYPE_FCP:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) return DUMP_FCP_STR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) case DUMP_TYPE_NVME:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) return DUMP_NVME_STR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) int __bootdata_preserved(ipl_block_valid);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) struct ipl_parameter_block __bootdata_preserved(ipl_block);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) int __bootdata_preserved(ipl_secure_flag);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) unsigned long __bootdata_preserved(ipl_cert_list_addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) unsigned long __bootdata_preserved(ipl_cert_list_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) unsigned long __bootdata(early_ipl_comp_list_addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) unsigned long __bootdata(early_ipl_comp_list_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) static int reipl_capabilities = IPL_TYPE_UNKNOWN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) static enum ipl_type reipl_type = IPL_TYPE_UNKNOWN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) static struct ipl_parameter_block *reipl_block_fcp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) static struct ipl_parameter_block *reipl_block_nvme;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) static struct ipl_parameter_block *reipl_block_ccw;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) static struct ipl_parameter_block *reipl_block_nss;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) static struct ipl_parameter_block *reipl_block_actual;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) static int dump_capabilities = DUMP_TYPE_NONE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) static enum dump_type dump_type = DUMP_TYPE_NONE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) static struct ipl_parameter_block *dump_block_fcp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) static struct ipl_parameter_block *dump_block_nvme;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) static struct ipl_parameter_block *dump_block_ccw;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) static struct sclp_ipl_info sclp_ipl_info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) static bool reipl_nvme_clear;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) static bool reipl_fcp_clear;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) static bool reipl_ccw_clear;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) static inline int __diag308(unsigned long subcode, void *addr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) register unsigned long _addr asm("0") = (unsigned long) addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) register unsigned long _rc asm("1") = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) asm volatile(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) " diag %0,%2,0x308\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) "0: nopr %%r7\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) EX_TABLE(0b,0b)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) : "+d" (_addr), "+d" (_rc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) : "d" (subcode) : "cc", "memory");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) return _rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) int diag308(unsigned long subcode, void *addr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) if (IS_ENABLED(CONFIG_KASAN))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) __arch_local_irq_stosm(0x04); /* enable DAT */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) diag_stat_inc(DIAG_STAT_X308);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) return __diag308(subcode, addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) EXPORT_SYMBOL_GPL(diag308);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) /* SYSFS */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) #define IPL_ATTR_SHOW_FN(_prefix, _name, _format, args...) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) static ssize_t sys_##_prefix##_##_name##_show(struct kobject *kobj, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) struct kobj_attribute *attr, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) char *page) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) { \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) return scnprintf(page, PAGE_SIZE, _format, ##args); \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) #define IPL_ATTR_CCW_STORE_FN(_prefix, _name, _ipl_blk) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) static ssize_t sys_##_prefix##_##_name##_store(struct kobject *kobj, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) struct kobj_attribute *attr, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) const char *buf, size_t len) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) { \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) unsigned long long ssid, devno; \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) if (sscanf(buf, "0.%llx.%llx\n", &ssid, &devno) != 2) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) return -EINVAL; \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) if (ssid > __MAX_SSID || devno > __MAX_SUBCHANNEL) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) return -EINVAL; \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) _ipl_blk.ssid = ssid; \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) _ipl_blk.devno = devno; \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) return len; \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) #define DEFINE_IPL_CCW_ATTR_RW(_prefix, _name, _ipl_blk) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) IPL_ATTR_SHOW_FN(_prefix, _name, "0.%x.%04x\n", \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) _ipl_blk.ssid, _ipl_blk.devno); \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) IPL_ATTR_CCW_STORE_FN(_prefix, _name, _ipl_blk); \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) static struct kobj_attribute sys_##_prefix##_##_name##_attr = \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) __ATTR(_name, (S_IRUGO | S_IWUSR), \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) sys_##_prefix##_##_name##_show, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) sys_##_prefix##_##_name##_store) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) #define DEFINE_IPL_ATTR_RO(_prefix, _name, _format, _value) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) IPL_ATTR_SHOW_FN(_prefix, _name, _format, _value) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) static struct kobj_attribute sys_##_prefix##_##_name##_attr = \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) __ATTR(_name, S_IRUGO, sys_##_prefix##_##_name##_show, NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) #define DEFINE_IPL_ATTR_RW(_prefix, _name, _fmt_out, _fmt_in, _value) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) IPL_ATTR_SHOW_FN(_prefix, _name, _fmt_out, (unsigned long long) _value) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) static ssize_t sys_##_prefix##_##_name##_store(struct kobject *kobj, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) struct kobj_attribute *attr, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) const char *buf, size_t len) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) { \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) unsigned long long value; \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) if (sscanf(buf, _fmt_in, &value) != 1) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) return -EINVAL; \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) _value = value; \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) return len; \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) } \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) static struct kobj_attribute sys_##_prefix##_##_name##_attr = \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) __ATTR(_name,(S_IRUGO | S_IWUSR), \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) sys_##_prefix##_##_name##_show, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) sys_##_prefix##_##_name##_store)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) #define DEFINE_IPL_ATTR_STR_RW(_prefix, _name, _fmt_out, _fmt_in, _value)\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) IPL_ATTR_SHOW_FN(_prefix, _name, _fmt_out, _value) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) static ssize_t sys_##_prefix##_##_name##_store(struct kobject *kobj, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) struct kobj_attribute *attr, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) const char *buf, size_t len) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) { \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) strncpy(_value, buf, sizeof(_value) - 1); \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) strim(_value); \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) return len; \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) } \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) static struct kobj_attribute sys_##_prefix##_##_name##_attr = \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) __ATTR(_name,(S_IRUGO | S_IWUSR), \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) sys_##_prefix##_##_name##_show, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) sys_##_prefix##_##_name##_store)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) * ipl section
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) static __init enum ipl_type get_ipl_type(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) if (!ipl_block_valid)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) return IPL_TYPE_UNKNOWN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) switch (ipl_block.pb0_hdr.pbt) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) case IPL_PBT_CCW:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) return IPL_TYPE_CCW;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) case IPL_PBT_FCP:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) if (ipl_block.fcp.opt == IPL_PB0_FCP_OPT_DUMP)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) return IPL_TYPE_FCP_DUMP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) return IPL_TYPE_FCP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) case IPL_PBT_NVME:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) if (ipl_block.nvme.opt == IPL_PB0_NVME_OPT_DUMP)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) return IPL_TYPE_NVME_DUMP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) return IPL_TYPE_NVME;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) return IPL_TYPE_UNKNOWN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) struct ipl_info ipl_info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) EXPORT_SYMBOL_GPL(ipl_info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) static ssize_t ipl_type_show(struct kobject *kobj, struct kobj_attribute *attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) char *page)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) return sprintf(page, "%s\n", ipl_type_str(ipl_info.type));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) static struct kobj_attribute sys_ipl_type_attr = __ATTR_RO(ipl_type);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) static ssize_t ipl_secure_show(struct kobject *kobj,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) struct kobj_attribute *attr, char *page)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) return sprintf(page, "%i\n", !!ipl_secure_flag);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) static struct kobj_attribute sys_ipl_secure_attr =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) __ATTR(secure, 0444, ipl_secure_show, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) static ssize_t ipl_has_secure_show(struct kobject *kobj,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) struct kobj_attribute *attr, char *page)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) return sprintf(page, "%i\n", !!sclp.has_sipl);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) static struct kobj_attribute sys_ipl_has_secure_attr =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) __ATTR(has_secure, 0444, ipl_has_secure_show, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) static ssize_t ipl_vm_parm_show(struct kobject *kobj,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) struct kobj_attribute *attr, char *page)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) char parm[DIAG308_VMPARM_SIZE + 1] = {};
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) if (ipl_block_valid && (ipl_block.pb0_hdr.pbt == IPL_PBT_CCW))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) ipl_block_get_ascii_vmparm(parm, sizeof(parm), &ipl_block);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) return sprintf(page, "%s\n", parm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) static struct kobj_attribute sys_ipl_vm_parm_attr =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) __ATTR(parm, S_IRUGO, ipl_vm_parm_show, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) static ssize_t sys_ipl_device_show(struct kobject *kobj,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) struct kobj_attribute *attr, char *page)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) switch (ipl_info.type) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) case IPL_TYPE_CCW:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) return sprintf(page, "0.%x.%04x\n", ipl_block.ccw.ssid,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) ipl_block.ccw.devno);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) case IPL_TYPE_FCP:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) case IPL_TYPE_FCP_DUMP:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) return sprintf(page, "0.0.%04x\n", ipl_block.fcp.devno);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) case IPL_TYPE_NVME:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) case IPL_TYPE_NVME_DUMP:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) return sprintf(page, "%08ux\n", ipl_block.nvme.fid);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) static struct kobj_attribute sys_ipl_device_attr =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) __ATTR(device, S_IRUGO, sys_ipl_device_show, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) static ssize_t ipl_parameter_read(struct file *filp, struct kobject *kobj,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) struct bin_attribute *attr, char *buf,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) loff_t off, size_t count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) return memory_read_from_buffer(buf, count, &off, &ipl_block,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) ipl_block.hdr.len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) static struct bin_attribute ipl_parameter_attr =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) __BIN_ATTR(binary_parameter, S_IRUGO, ipl_parameter_read, NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) PAGE_SIZE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) static ssize_t ipl_scp_data_read(struct file *filp, struct kobject *kobj,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) struct bin_attribute *attr, char *buf,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) loff_t off, size_t count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) unsigned int size = ipl_block.fcp.scp_data_len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) void *scp_data = &ipl_block.fcp.scp_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) return memory_read_from_buffer(buf, count, &off, scp_data, size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) static ssize_t ipl_nvme_scp_data_read(struct file *filp, struct kobject *kobj,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) struct bin_attribute *attr, char *buf,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) loff_t off, size_t count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) unsigned int size = ipl_block.nvme.scp_data_len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) void *scp_data = &ipl_block.nvme.scp_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) return memory_read_from_buffer(buf, count, &off, scp_data, size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) static struct bin_attribute ipl_scp_data_attr =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) __BIN_ATTR(scp_data, S_IRUGO, ipl_scp_data_read, NULL, PAGE_SIZE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) static struct bin_attribute ipl_nvme_scp_data_attr =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) __BIN_ATTR(scp_data, S_IRUGO, ipl_nvme_scp_data_read, NULL, PAGE_SIZE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) static struct bin_attribute *ipl_fcp_bin_attrs[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) &ipl_parameter_attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) &ipl_scp_data_attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) static struct bin_attribute *ipl_nvme_bin_attrs[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) &ipl_parameter_attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) &ipl_nvme_scp_data_attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) /* FCP ipl device attributes */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) DEFINE_IPL_ATTR_RO(ipl_fcp, wwpn, "0x%016llx\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) (unsigned long long)ipl_block.fcp.wwpn);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) DEFINE_IPL_ATTR_RO(ipl_fcp, lun, "0x%016llx\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) (unsigned long long)ipl_block.fcp.lun);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) DEFINE_IPL_ATTR_RO(ipl_fcp, bootprog, "%lld\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) (unsigned long long)ipl_block.fcp.bootprog);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) DEFINE_IPL_ATTR_RO(ipl_fcp, br_lba, "%lld\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) (unsigned long long)ipl_block.fcp.br_lba);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) /* NVMe ipl device attributes */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) DEFINE_IPL_ATTR_RO(ipl_nvme, fid, "0x%08llx\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) (unsigned long long)ipl_block.nvme.fid);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) DEFINE_IPL_ATTR_RO(ipl_nvme, nsid, "0x%08llx\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) (unsigned long long)ipl_block.nvme.nsid);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) DEFINE_IPL_ATTR_RO(ipl_nvme, bootprog, "%lld\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) (unsigned long long)ipl_block.nvme.bootprog);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) DEFINE_IPL_ATTR_RO(ipl_nvme, br_lba, "%lld\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) (unsigned long long)ipl_block.nvme.br_lba);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) static ssize_t ipl_ccw_loadparm_show(struct kobject *kobj,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) struct kobj_attribute *attr, char *page)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) char loadparm[LOADPARM_LEN + 1] = {};
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) if (!sclp_ipl_info.is_valid)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) return sprintf(page, "#unknown#\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) memcpy(loadparm, &sclp_ipl_info.loadparm, LOADPARM_LEN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) EBCASC(loadparm, LOADPARM_LEN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) strim(loadparm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) return sprintf(page, "%s\n", loadparm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) static struct kobj_attribute sys_ipl_ccw_loadparm_attr =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) __ATTR(loadparm, 0444, ipl_ccw_loadparm_show, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) static struct attribute *ipl_fcp_attrs[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) &sys_ipl_type_attr.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) &sys_ipl_device_attr.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) &sys_ipl_fcp_wwpn_attr.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) &sys_ipl_fcp_lun_attr.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) &sys_ipl_fcp_bootprog_attr.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) &sys_ipl_fcp_br_lba_attr.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) &sys_ipl_ccw_loadparm_attr.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) &sys_ipl_secure_attr.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) &sys_ipl_has_secure_attr.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) static struct attribute_group ipl_fcp_attr_group = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) .attrs = ipl_fcp_attrs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) .bin_attrs = ipl_fcp_bin_attrs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) static struct attribute *ipl_nvme_attrs[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) &sys_ipl_type_attr.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) &sys_ipl_nvme_fid_attr.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) &sys_ipl_nvme_nsid_attr.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) &sys_ipl_nvme_bootprog_attr.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) &sys_ipl_nvme_br_lba_attr.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) &sys_ipl_ccw_loadparm_attr.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) &sys_ipl_secure_attr.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) &sys_ipl_has_secure_attr.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) static struct attribute_group ipl_nvme_attr_group = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) .attrs = ipl_nvme_attrs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) .bin_attrs = ipl_nvme_bin_attrs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) /* CCW ipl device attributes */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) static struct attribute *ipl_ccw_attrs_vm[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) &sys_ipl_type_attr.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) &sys_ipl_device_attr.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) &sys_ipl_ccw_loadparm_attr.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) &sys_ipl_vm_parm_attr.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) &sys_ipl_secure_attr.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) &sys_ipl_has_secure_attr.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) static struct attribute *ipl_ccw_attrs_lpar[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) &sys_ipl_type_attr.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) &sys_ipl_device_attr.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) &sys_ipl_ccw_loadparm_attr.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) &sys_ipl_secure_attr.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) &sys_ipl_has_secure_attr.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) static struct attribute_group ipl_ccw_attr_group_vm = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) .attrs = ipl_ccw_attrs_vm,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) static struct attribute_group ipl_ccw_attr_group_lpar = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) .attrs = ipl_ccw_attrs_lpar
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) /* UNKNOWN ipl device attributes */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) static struct attribute *ipl_unknown_attrs[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) &sys_ipl_type_attr.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) static struct attribute_group ipl_unknown_attr_group = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) .attrs = ipl_unknown_attrs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) static struct kset *ipl_kset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) static void __ipl_run(void *unused)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) __bpon();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) diag308(DIAG308_LOAD_CLEAR, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) static void ipl_run(struct shutdown_trigger *trigger)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521) smp_call_ipl_cpu(__ipl_run, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524) static int __init ipl_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) int rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) ipl_kset = kset_create_and_add("ipl", NULL, firmware_kobj);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) if (!ipl_kset) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) rc = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) switch (ipl_info.type) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) case IPL_TYPE_CCW:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535) if (MACHINE_IS_VM)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) rc = sysfs_create_group(&ipl_kset->kobj,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) &ipl_ccw_attr_group_vm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) rc = sysfs_create_group(&ipl_kset->kobj,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) &ipl_ccw_attr_group_lpar);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) case IPL_TYPE_FCP:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) case IPL_TYPE_FCP_DUMP:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) rc = sysfs_create_group(&ipl_kset->kobj, &ipl_fcp_attr_group);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546) case IPL_TYPE_NVME:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) case IPL_TYPE_NVME_DUMP:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) rc = sysfs_create_group(&ipl_kset->kobj, &ipl_nvme_attr_group);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) rc = sysfs_create_group(&ipl_kset->kobj,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552) &ipl_unknown_attr_group);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) if (rc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557) panic("ipl_init failed: rc = %i\n", rc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562) static struct shutdown_action __refdata ipl_action = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) .name = SHUTDOWN_ACTION_IPL_STR,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564) .fn = ipl_run,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) .init = ipl_init,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569) * reipl shutdown action: Reboot Linux on shutdown.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572) /* VM IPL PARM attributes */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573) static ssize_t reipl_generic_vmparm_show(struct ipl_parameter_block *ipb,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574) char *page)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576) char vmparm[DIAG308_VMPARM_SIZE + 1] = {};
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578) ipl_block_get_ascii_vmparm(vmparm, sizeof(vmparm), ipb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579) return sprintf(page, "%s\n", vmparm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) static ssize_t reipl_generic_vmparm_store(struct ipl_parameter_block *ipb,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583) size_t vmparm_max,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584) const char *buf, size_t len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586) int i, ip_len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588) /* ignore trailing newline */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589) ip_len = len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590) if ((len > 0) && (buf[len - 1] == '\n'))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591) ip_len--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593) if (ip_len > vmparm_max)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596) /* parm is used to store kernel options, check for common chars */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597) for (i = 0; i < ip_len; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598) if (!(isalnum(buf[i]) || isascii(buf[i]) || isprint(buf[i])))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601) memset(ipb->ccw.vm_parm, 0, DIAG308_VMPARM_SIZE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602) ipb->ccw.vm_parm_len = ip_len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603) if (ip_len > 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604) ipb->ccw.vm_flags |= IPL_PB0_CCW_VM_FLAG_VP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605) memcpy(ipb->ccw.vm_parm, buf, ip_len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606) ASCEBC(ipb->ccw.vm_parm, ip_len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608) ipb->ccw.vm_flags &= ~IPL_PB0_CCW_VM_FLAG_VP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611) return len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614) /* NSS wrapper */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615) static ssize_t reipl_nss_vmparm_show(struct kobject *kobj,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616) struct kobj_attribute *attr, char *page)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618) return reipl_generic_vmparm_show(reipl_block_nss, page);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621) static ssize_t reipl_nss_vmparm_store(struct kobject *kobj,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622) struct kobj_attribute *attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623) const char *buf, size_t len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625) return reipl_generic_vmparm_store(reipl_block_nss, 56, buf, len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628) /* CCW wrapper */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629) static ssize_t reipl_ccw_vmparm_show(struct kobject *kobj,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630) struct kobj_attribute *attr, char *page)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 631) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 632) return reipl_generic_vmparm_show(reipl_block_ccw, page);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 633) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 634)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 635) static ssize_t reipl_ccw_vmparm_store(struct kobject *kobj,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 636) struct kobj_attribute *attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 637) const char *buf, size_t len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 638) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 639) return reipl_generic_vmparm_store(reipl_block_ccw, 64, buf, len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 640) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 641)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 642) static struct kobj_attribute sys_reipl_nss_vmparm_attr =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 643) __ATTR(parm, S_IRUGO | S_IWUSR, reipl_nss_vmparm_show,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 644) reipl_nss_vmparm_store);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 645) static struct kobj_attribute sys_reipl_ccw_vmparm_attr =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 646) __ATTR(parm, S_IRUGO | S_IWUSR, reipl_ccw_vmparm_show,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 647) reipl_ccw_vmparm_store);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 648)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 649) /* FCP reipl device attributes */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 650)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 651) static ssize_t reipl_fcp_scpdata_read(struct file *filp, struct kobject *kobj,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 652) struct bin_attribute *attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 653) char *buf, loff_t off, size_t count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 654) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 655) size_t size = reipl_block_fcp->fcp.scp_data_len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 656) void *scp_data = reipl_block_fcp->fcp.scp_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 657)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 658) return memory_read_from_buffer(buf, count, &off, scp_data, size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 659) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 660)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 661) static ssize_t reipl_fcp_scpdata_write(struct file *filp, struct kobject *kobj,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 662) struct bin_attribute *attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 663) char *buf, loff_t off, size_t count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 664) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 665) size_t scpdata_len = count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 666) size_t padding;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 667)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 668)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 669) if (off)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 670) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 671)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 672) memcpy(reipl_block_fcp->fcp.scp_data, buf, count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 673) if (scpdata_len % 8) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 674) padding = 8 - (scpdata_len % 8);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 675) memset(reipl_block_fcp->fcp.scp_data + scpdata_len,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 676) 0, padding);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 677) scpdata_len += padding;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 678) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 679)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 680) reipl_block_fcp->hdr.len = IPL_BP_FCP_LEN + scpdata_len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 681) reipl_block_fcp->fcp.len = IPL_BP0_FCP_LEN + scpdata_len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 682) reipl_block_fcp->fcp.scp_data_len = scpdata_len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 683)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 684) return count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 685) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 686) static struct bin_attribute sys_reipl_fcp_scp_data_attr =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 687) __BIN_ATTR(scp_data, (S_IRUGO | S_IWUSR), reipl_fcp_scpdata_read,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 688) reipl_fcp_scpdata_write, DIAG308_SCPDATA_SIZE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 689)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 690) static struct bin_attribute *reipl_fcp_bin_attrs[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 691) &sys_reipl_fcp_scp_data_attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 692) NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 693) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 694)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 695) DEFINE_IPL_ATTR_RW(reipl_fcp, wwpn, "0x%016llx\n", "%llx\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 696) reipl_block_fcp->fcp.wwpn);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 697) DEFINE_IPL_ATTR_RW(reipl_fcp, lun, "0x%016llx\n", "%llx\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 698) reipl_block_fcp->fcp.lun);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 699) DEFINE_IPL_ATTR_RW(reipl_fcp, bootprog, "%lld\n", "%lld\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 700) reipl_block_fcp->fcp.bootprog);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 701) DEFINE_IPL_ATTR_RW(reipl_fcp, br_lba, "%lld\n", "%lld\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 702) reipl_block_fcp->fcp.br_lba);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 703) DEFINE_IPL_ATTR_RW(reipl_fcp, device, "0.0.%04llx\n", "0.0.%llx\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 704) reipl_block_fcp->fcp.devno);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 705)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 706) static void reipl_get_ascii_loadparm(char *loadparm,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 707) struct ipl_parameter_block *ibp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 708) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 709) memcpy(loadparm, ibp->common.loadparm, LOADPARM_LEN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 710) EBCASC(loadparm, LOADPARM_LEN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 711) loadparm[LOADPARM_LEN] = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 712) strim(loadparm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 713) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 714)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 715) static ssize_t reipl_generic_loadparm_show(struct ipl_parameter_block *ipb,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 716) char *page)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 717) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 718) char buf[LOADPARM_LEN + 1];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 719)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 720) reipl_get_ascii_loadparm(buf, ipb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 721) return sprintf(page, "%s\n", buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 722) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 723)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 724) static ssize_t reipl_generic_loadparm_store(struct ipl_parameter_block *ipb,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 725) const char *buf, size_t len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 726) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 727) int i, lp_len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 728)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 729) /* ignore trailing newline */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 730) lp_len = len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 731) if ((len > 0) && (buf[len - 1] == '\n'))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 732) lp_len--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 733) /* loadparm can have max 8 characters and must not start with a blank */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 734) if ((lp_len > LOADPARM_LEN) || ((lp_len > 0) && (buf[0] == ' ')))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 735) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 736) /* loadparm can only contain "a-z,A-Z,0-9,SP,." */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 737) for (i = 0; i < lp_len; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 738) if (isalpha(buf[i]) || isdigit(buf[i]) || (buf[i] == ' ') ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 739) (buf[i] == '.'))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 740) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 741) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 742) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 743) /* initialize loadparm with blanks */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 744) memset(ipb->common.loadparm, ' ', LOADPARM_LEN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 745) /* copy and convert to ebcdic */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 746) memcpy(ipb->common.loadparm, buf, lp_len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 747) ASCEBC(ipb->common.loadparm, LOADPARM_LEN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 748) ipb->common.flags |= IPL_PB0_FLAG_LOADPARM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 749) return len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 750) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 751)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 752) /* FCP wrapper */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 753) static ssize_t reipl_fcp_loadparm_show(struct kobject *kobj,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 754) struct kobj_attribute *attr, char *page)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 755) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 756) return reipl_generic_loadparm_show(reipl_block_fcp, page);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 757) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 758)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 759) static ssize_t reipl_fcp_loadparm_store(struct kobject *kobj,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 760) struct kobj_attribute *attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 761) const char *buf, size_t len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 762) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 763) return reipl_generic_loadparm_store(reipl_block_fcp, buf, len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 764) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 765)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 766) static struct kobj_attribute sys_reipl_fcp_loadparm_attr =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 767) __ATTR(loadparm, S_IRUGO | S_IWUSR, reipl_fcp_loadparm_show,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 768) reipl_fcp_loadparm_store);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 769)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 770) static ssize_t reipl_fcp_clear_show(struct kobject *kobj,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 771) struct kobj_attribute *attr, char *page)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 772) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 773) return sprintf(page, "%u\n", reipl_fcp_clear);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 774) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 775)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 776) static ssize_t reipl_fcp_clear_store(struct kobject *kobj,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 777) struct kobj_attribute *attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 778) const char *buf, size_t len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 779) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 780) if (strtobool(buf, &reipl_fcp_clear) < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 781) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 782) return len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 783) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 784)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 785) static struct attribute *reipl_fcp_attrs[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 786) &sys_reipl_fcp_device_attr.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 787) &sys_reipl_fcp_wwpn_attr.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 788) &sys_reipl_fcp_lun_attr.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 789) &sys_reipl_fcp_bootprog_attr.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 790) &sys_reipl_fcp_br_lba_attr.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 791) &sys_reipl_fcp_loadparm_attr.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 792) NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 793) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 794)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 795) static struct attribute_group reipl_fcp_attr_group = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 796) .attrs = reipl_fcp_attrs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 797) .bin_attrs = reipl_fcp_bin_attrs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 798) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 799)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 800) static struct kobj_attribute sys_reipl_fcp_clear_attr =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 801) __ATTR(clear, 0644, reipl_fcp_clear_show, reipl_fcp_clear_store);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 802)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 803) /* NVME reipl device attributes */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 804)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 805) static ssize_t reipl_nvme_scpdata_read(struct file *filp, struct kobject *kobj,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 806) struct bin_attribute *attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 807) char *buf, loff_t off, size_t count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 808) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 809) size_t size = reipl_block_nvme->nvme.scp_data_len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 810) void *scp_data = reipl_block_nvme->nvme.scp_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 811)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 812) return memory_read_from_buffer(buf, count, &off, scp_data, size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 813) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 814)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 815) static ssize_t reipl_nvme_scpdata_write(struct file *filp, struct kobject *kobj,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 816) struct bin_attribute *attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 817) char *buf, loff_t off, size_t count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 818) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 819) size_t scpdata_len = count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 820) size_t padding;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 821)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 822) if (off)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 823) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 824)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 825) memcpy(reipl_block_nvme->nvme.scp_data, buf, count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 826) if (scpdata_len % 8) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 827) padding = 8 - (scpdata_len % 8);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 828) memset(reipl_block_nvme->nvme.scp_data + scpdata_len,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 829) 0, padding);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 830) scpdata_len += padding;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 831) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 832)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 833) reipl_block_nvme->hdr.len = IPL_BP_FCP_LEN + scpdata_len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 834) reipl_block_nvme->nvme.len = IPL_BP0_FCP_LEN + scpdata_len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 835) reipl_block_nvme->nvme.scp_data_len = scpdata_len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 836)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 837) return count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 838) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 839)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 840) static struct bin_attribute sys_reipl_nvme_scp_data_attr =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 841) __BIN_ATTR(scp_data, (S_IRUGO | S_IWUSR), reipl_nvme_scpdata_read,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 842) reipl_nvme_scpdata_write, DIAG308_SCPDATA_SIZE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 843)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 844) static struct bin_attribute *reipl_nvme_bin_attrs[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 845) &sys_reipl_nvme_scp_data_attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 846) NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 847) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 848)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 849) DEFINE_IPL_ATTR_RW(reipl_nvme, fid, "0x%08llx\n", "%llx\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 850) reipl_block_nvme->nvme.fid);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 851) DEFINE_IPL_ATTR_RW(reipl_nvme, nsid, "0x%08llx\n", "%llx\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 852) reipl_block_nvme->nvme.nsid);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 853) DEFINE_IPL_ATTR_RW(reipl_nvme, bootprog, "%lld\n", "%lld\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 854) reipl_block_nvme->nvme.bootprog);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 855) DEFINE_IPL_ATTR_RW(reipl_nvme, br_lba, "%lld\n", "%lld\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 856) reipl_block_nvme->nvme.br_lba);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 857)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 858) /* nvme wrapper */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 859) static ssize_t reipl_nvme_loadparm_show(struct kobject *kobj,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 860) struct kobj_attribute *attr, char *page)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 861) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 862) return reipl_generic_loadparm_show(reipl_block_nvme, page);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 863) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 864)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 865) static ssize_t reipl_nvme_loadparm_store(struct kobject *kobj,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 866) struct kobj_attribute *attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 867) const char *buf, size_t len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 868) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 869) return reipl_generic_loadparm_store(reipl_block_nvme, buf, len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 870) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 871)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 872) static struct kobj_attribute sys_reipl_nvme_loadparm_attr =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 873) __ATTR(loadparm, S_IRUGO | S_IWUSR, reipl_nvme_loadparm_show,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 874) reipl_nvme_loadparm_store);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 875)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 876) static struct attribute *reipl_nvme_attrs[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 877) &sys_reipl_nvme_fid_attr.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 878) &sys_reipl_nvme_nsid_attr.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 879) &sys_reipl_nvme_bootprog_attr.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 880) &sys_reipl_nvme_br_lba_attr.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 881) &sys_reipl_nvme_loadparm_attr.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 882) NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 883) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 884)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 885) static struct attribute_group reipl_nvme_attr_group = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 886) .attrs = reipl_nvme_attrs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 887) .bin_attrs = reipl_nvme_bin_attrs
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 888) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 889)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 890) static ssize_t reipl_nvme_clear_show(struct kobject *kobj,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 891) struct kobj_attribute *attr, char *page)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 892) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 893) return sprintf(page, "%u\n", reipl_nvme_clear);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 894) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 895)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 896) static ssize_t reipl_nvme_clear_store(struct kobject *kobj,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 897) struct kobj_attribute *attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 898) const char *buf, size_t len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 899) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 900) if (strtobool(buf, &reipl_nvme_clear) < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 901) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 902) return len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 903) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 904)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 905) static struct kobj_attribute sys_reipl_nvme_clear_attr =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 906) __ATTR(clear, 0644, reipl_nvme_clear_show, reipl_nvme_clear_store);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 907)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 908) /* CCW reipl device attributes */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 909) DEFINE_IPL_CCW_ATTR_RW(reipl_ccw, device, reipl_block_ccw->ccw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 910)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 911) /* NSS wrapper */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 912) static ssize_t reipl_nss_loadparm_show(struct kobject *kobj,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 913) struct kobj_attribute *attr, char *page)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 914) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 915) return reipl_generic_loadparm_show(reipl_block_nss, page);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 916) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 917)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 918) static ssize_t reipl_nss_loadparm_store(struct kobject *kobj,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 919) struct kobj_attribute *attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 920) const char *buf, size_t len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 921) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 922) return reipl_generic_loadparm_store(reipl_block_nss, buf, len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 923) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 924)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 925) /* CCW wrapper */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 926) static ssize_t reipl_ccw_loadparm_show(struct kobject *kobj,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 927) struct kobj_attribute *attr, char *page)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 928) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 929) return reipl_generic_loadparm_show(reipl_block_ccw, page);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 930) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 931)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 932) static ssize_t reipl_ccw_loadparm_store(struct kobject *kobj,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 933) struct kobj_attribute *attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 934) const char *buf, size_t len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 935) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 936) return reipl_generic_loadparm_store(reipl_block_ccw, buf, len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 937) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 938)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 939) static struct kobj_attribute sys_reipl_ccw_loadparm_attr =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 940) __ATTR(loadparm, S_IRUGO | S_IWUSR, reipl_ccw_loadparm_show,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 941) reipl_ccw_loadparm_store);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 942)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 943) static ssize_t reipl_ccw_clear_show(struct kobject *kobj,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 944) struct kobj_attribute *attr, char *page)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 945) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 946) return sprintf(page, "%u\n", reipl_ccw_clear);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 947) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 948)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 949) static ssize_t reipl_ccw_clear_store(struct kobject *kobj,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 950) struct kobj_attribute *attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 951) const char *buf, size_t len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 952) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 953) if (strtobool(buf, &reipl_ccw_clear) < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 954) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 955) return len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 956) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 957)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 958) static struct kobj_attribute sys_reipl_ccw_clear_attr =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 959) __ATTR(clear, 0644, reipl_ccw_clear_show, reipl_ccw_clear_store);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 960)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 961) static struct attribute *reipl_ccw_attrs_vm[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 962) &sys_reipl_ccw_device_attr.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 963) &sys_reipl_ccw_loadparm_attr.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 964) &sys_reipl_ccw_vmparm_attr.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 965) &sys_reipl_ccw_clear_attr.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 966) NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 967) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 968)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 969) static struct attribute *reipl_ccw_attrs_lpar[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 970) &sys_reipl_ccw_device_attr.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 971) &sys_reipl_ccw_loadparm_attr.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 972) &sys_reipl_ccw_clear_attr.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 973) NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 974) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 975)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 976) static struct attribute_group reipl_ccw_attr_group_vm = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 977) .name = IPL_CCW_STR,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 978) .attrs = reipl_ccw_attrs_vm,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 979) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 980)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 981) static struct attribute_group reipl_ccw_attr_group_lpar = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 982) .name = IPL_CCW_STR,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 983) .attrs = reipl_ccw_attrs_lpar,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 984) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 985)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 986)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 987) /* NSS reipl device attributes */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 988) static void reipl_get_ascii_nss_name(char *dst,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 989) struct ipl_parameter_block *ipb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 990) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 991) memcpy(dst, ipb->ccw.nss_name, NSS_NAME_SIZE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 992) EBCASC(dst, NSS_NAME_SIZE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 993) dst[NSS_NAME_SIZE] = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 994) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 995)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 996) static ssize_t reipl_nss_name_show(struct kobject *kobj,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 997) struct kobj_attribute *attr, char *page)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 998) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 999) char nss_name[NSS_NAME_SIZE + 1] = {};
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1000)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1001) reipl_get_ascii_nss_name(nss_name, reipl_block_nss);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1002) return sprintf(page, "%s\n", nss_name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1003) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1004)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1005) static ssize_t reipl_nss_name_store(struct kobject *kobj,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1006) struct kobj_attribute *attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1007) const char *buf, size_t len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1008) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1009) int nss_len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1010)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1011) /* ignore trailing newline */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1012) nss_len = len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1013) if ((len > 0) && (buf[len - 1] == '\n'))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1014) nss_len--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1015)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1016) if (nss_len > NSS_NAME_SIZE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1017) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1018)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1019) memset(reipl_block_nss->ccw.nss_name, 0x40, NSS_NAME_SIZE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1020) if (nss_len > 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1021) reipl_block_nss->ccw.vm_flags |= IPL_PB0_CCW_VM_FLAG_NSS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1022) memcpy(reipl_block_nss->ccw.nss_name, buf, nss_len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1023) ASCEBC(reipl_block_nss->ccw.nss_name, nss_len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1024) EBC_TOUPPER(reipl_block_nss->ccw.nss_name, nss_len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1025) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1026) reipl_block_nss->ccw.vm_flags &= ~IPL_PB0_CCW_VM_FLAG_NSS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1027) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1028)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1029) return len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1030) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1031)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1032) static struct kobj_attribute sys_reipl_nss_name_attr =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1033) __ATTR(name, S_IRUGO | S_IWUSR, reipl_nss_name_show,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1034) reipl_nss_name_store);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1035)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1036) static struct kobj_attribute sys_reipl_nss_loadparm_attr =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1037) __ATTR(loadparm, S_IRUGO | S_IWUSR, reipl_nss_loadparm_show,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1038) reipl_nss_loadparm_store);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1039)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1040) static struct attribute *reipl_nss_attrs[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1041) &sys_reipl_nss_name_attr.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1042) &sys_reipl_nss_loadparm_attr.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1043) &sys_reipl_nss_vmparm_attr.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1044) NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1045) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1046)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1047) static struct attribute_group reipl_nss_attr_group = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1048) .name = IPL_NSS_STR,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1049) .attrs = reipl_nss_attrs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1050) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1051)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1052) void set_os_info_reipl_block(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1053) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1054) os_info_entry_add(OS_INFO_REIPL_BLOCK, reipl_block_actual,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1055) reipl_block_actual->hdr.len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1056) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1057)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1058) /* reipl type */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1059)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1060) static int reipl_set_type(enum ipl_type type)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1061) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1062) if (!(reipl_capabilities & type))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1063) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1064)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1065) switch(type) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1066) case IPL_TYPE_CCW:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1067) reipl_block_actual = reipl_block_ccw;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1068) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1069) case IPL_TYPE_FCP:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1070) reipl_block_actual = reipl_block_fcp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1071) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1072) case IPL_TYPE_NVME:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1073) reipl_block_actual = reipl_block_nvme;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1074) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1075) case IPL_TYPE_NSS:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1076) reipl_block_actual = reipl_block_nss;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1077) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1078) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1079) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1080) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1081) reipl_type = type;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1082) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1083) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1084)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1085) static ssize_t reipl_type_show(struct kobject *kobj,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1086) struct kobj_attribute *attr, char *page)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1087) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1088) return sprintf(page, "%s\n", ipl_type_str(reipl_type));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1089) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1090)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1091) static ssize_t reipl_type_store(struct kobject *kobj,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1092) struct kobj_attribute *attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1093) const char *buf, size_t len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1094) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1095) int rc = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1096)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1097) if (strncmp(buf, IPL_CCW_STR, strlen(IPL_CCW_STR)) == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1098) rc = reipl_set_type(IPL_TYPE_CCW);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1099) else if (strncmp(buf, IPL_FCP_STR, strlen(IPL_FCP_STR)) == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1100) rc = reipl_set_type(IPL_TYPE_FCP);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1101) else if (strncmp(buf, IPL_NVME_STR, strlen(IPL_NVME_STR)) == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1102) rc = reipl_set_type(IPL_TYPE_NVME);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1103) else if (strncmp(buf, IPL_NSS_STR, strlen(IPL_NSS_STR)) == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1104) rc = reipl_set_type(IPL_TYPE_NSS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1105) return (rc != 0) ? rc : len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1106) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1107)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1108) static struct kobj_attribute reipl_type_attr =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1109) __ATTR(reipl_type, 0644, reipl_type_show, reipl_type_store);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1110)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1111) static struct kset *reipl_kset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1112) static struct kset *reipl_fcp_kset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1113) static struct kset *reipl_nvme_kset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1114)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1115) static void __reipl_run(void *unused)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1116) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1117) switch (reipl_type) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1118) case IPL_TYPE_CCW:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1119) diag308(DIAG308_SET, reipl_block_ccw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1120) if (reipl_ccw_clear)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1121) diag308(DIAG308_LOAD_CLEAR, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1122) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1123) diag308(DIAG308_LOAD_NORMAL_DUMP, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1124) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1125) case IPL_TYPE_FCP:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1126) diag308(DIAG308_SET, reipl_block_fcp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1127) if (reipl_fcp_clear)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1128) diag308(DIAG308_LOAD_CLEAR, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1129) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1130) diag308(DIAG308_LOAD_NORMAL, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1131) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1132) case IPL_TYPE_NVME:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1133) diag308(DIAG308_SET, reipl_block_nvme);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1134) if (reipl_nvme_clear)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1135) diag308(DIAG308_LOAD_CLEAR, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1136) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1137) diag308(DIAG308_LOAD_NORMAL, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1138) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1139) case IPL_TYPE_NSS:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1140) diag308(DIAG308_SET, reipl_block_nss);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1141) diag308(DIAG308_LOAD_CLEAR, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1142) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1143) case IPL_TYPE_UNKNOWN:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1144) diag308(DIAG308_LOAD_CLEAR, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1145) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1146) case IPL_TYPE_FCP_DUMP:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1147) case IPL_TYPE_NVME_DUMP:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1148) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1149) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1150) disabled_wait();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1151) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1152)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1153) static void reipl_run(struct shutdown_trigger *trigger)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1154) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1155) smp_call_ipl_cpu(__reipl_run, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1156) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1157)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1158) static void reipl_block_ccw_init(struct ipl_parameter_block *ipb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1159) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1160) ipb->hdr.len = IPL_BP_CCW_LEN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1161) ipb->hdr.version = IPL_PARM_BLOCK_VERSION;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1162) ipb->pb0_hdr.len = IPL_BP0_CCW_LEN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1163) ipb->pb0_hdr.pbt = IPL_PBT_CCW;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1164) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1165)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1166) static void reipl_block_ccw_fill_parms(struct ipl_parameter_block *ipb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1167) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1168) /* LOADPARM */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1169) /* check if read scp info worked and set loadparm */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1170) if (sclp_ipl_info.is_valid)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1171) memcpy(ipb->ccw.loadparm, &sclp_ipl_info.loadparm, LOADPARM_LEN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1172) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1173) /* read scp info failed: set empty loadparm (EBCDIC blanks) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1174) memset(ipb->ccw.loadparm, 0x40, LOADPARM_LEN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1175) ipb->ccw.flags = IPL_PB0_FLAG_LOADPARM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1176)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1177) /* VM PARM */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1178) if (MACHINE_IS_VM && ipl_block_valid &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1179) (ipl_block.ccw.vm_flags & IPL_PB0_CCW_VM_FLAG_VP)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1180)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1181) ipb->ccw.vm_flags |= IPL_PB0_CCW_VM_FLAG_VP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1182) ipb->ccw.vm_parm_len = ipl_block.ccw.vm_parm_len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1183) memcpy(ipb->ccw.vm_parm,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1184) ipl_block.ccw.vm_parm, DIAG308_VMPARM_SIZE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1185) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1186) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1187)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1188) static int __init reipl_nss_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1189) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1190) int rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1191)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1192) if (!MACHINE_IS_VM)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1193) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1194)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1195) reipl_block_nss = (void *) get_zeroed_page(GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1196) if (!reipl_block_nss)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1197) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1198)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1199) rc = sysfs_create_group(&reipl_kset->kobj, &reipl_nss_attr_group);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1200) if (rc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1201) return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1202)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1203) reipl_block_ccw_init(reipl_block_nss);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1204) reipl_capabilities |= IPL_TYPE_NSS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1205) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1206) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1207)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1208) static int __init reipl_ccw_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1209) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1210) int rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1211)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1212) reipl_block_ccw = (void *) get_zeroed_page(GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1213) if (!reipl_block_ccw)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1214) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1215)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1216) rc = sysfs_create_group(&reipl_kset->kobj,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1217) MACHINE_IS_VM ? &reipl_ccw_attr_group_vm
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1218) : &reipl_ccw_attr_group_lpar);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1219) if (rc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1220) return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1221)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1222) reipl_block_ccw_init(reipl_block_ccw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1223) if (ipl_info.type == IPL_TYPE_CCW) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1224) reipl_block_ccw->ccw.ssid = ipl_block.ccw.ssid;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1225) reipl_block_ccw->ccw.devno = ipl_block.ccw.devno;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1226) reipl_block_ccw_fill_parms(reipl_block_ccw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1227) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1228)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1229) reipl_capabilities |= IPL_TYPE_CCW;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1230) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1231) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1232)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1233) static int __init reipl_fcp_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1234) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1235) int rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1236)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1237) reipl_block_fcp = (void *) get_zeroed_page(GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1238) if (!reipl_block_fcp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1239) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1240)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1241) /* sysfs: create fcp kset for mixing attr group and bin attrs */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1242) reipl_fcp_kset = kset_create_and_add(IPL_FCP_STR, NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1243) &reipl_kset->kobj);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1244) if (!reipl_fcp_kset) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1245) free_page((unsigned long) reipl_block_fcp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1246) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1247) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1248)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1249) rc = sysfs_create_group(&reipl_fcp_kset->kobj, &reipl_fcp_attr_group);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1250) if (rc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1251) goto out1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1252)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1253) if (test_facility(141)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1254) rc = sysfs_create_file(&reipl_fcp_kset->kobj,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1255) &sys_reipl_fcp_clear_attr.attr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1256) if (rc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1257) goto out2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1258) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1259) reipl_fcp_clear = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1260) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1261)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1262) if (ipl_info.type == IPL_TYPE_FCP) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1263) memcpy(reipl_block_fcp, &ipl_block, sizeof(ipl_block));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1264) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1265) * Fix loadparm: There are systems where the (SCSI) LOADPARM
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1266) * is invalid in the SCSI IPL parameter block, so take it
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1267) * always from sclp_ipl_info.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1268) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1269) memcpy(reipl_block_fcp->fcp.loadparm, sclp_ipl_info.loadparm,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1270) LOADPARM_LEN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1271) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1272) reipl_block_fcp->hdr.len = IPL_BP_FCP_LEN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1273) reipl_block_fcp->hdr.version = IPL_PARM_BLOCK_VERSION;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1274) reipl_block_fcp->fcp.len = IPL_BP0_FCP_LEN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1275) reipl_block_fcp->fcp.pbt = IPL_PBT_FCP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1276) reipl_block_fcp->fcp.opt = IPL_PB0_FCP_OPT_IPL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1277) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1278) reipl_capabilities |= IPL_TYPE_FCP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1279) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1280)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1281) out2:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1282) sysfs_remove_group(&reipl_fcp_kset->kobj, &reipl_fcp_attr_group);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1283) out1:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1284) kset_unregister(reipl_fcp_kset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1285) free_page((unsigned long) reipl_block_fcp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1286) return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1287) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1288)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1289) static int __init reipl_nvme_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1290) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1291) int rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1292)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1293) reipl_block_nvme = (void *) get_zeroed_page(GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1294) if (!reipl_block_nvme)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1295) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1296)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1297) /* sysfs: create kset for mixing attr group and bin attrs */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1298) reipl_nvme_kset = kset_create_and_add(IPL_NVME_STR, NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1299) &reipl_kset->kobj);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1300) if (!reipl_nvme_kset) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1301) free_page((unsigned long) reipl_block_nvme);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1302) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1303) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1304)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1305) rc = sysfs_create_group(&reipl_nvme_kset->kobj, &reipl_nvme_attr_group);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1306) if (rc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1307) goto out1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1308)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1309) if (test_facility(141)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1310) rc = sysfs_create_file(&reipl_nvme_kset->kobj,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1311) &sys_reipl_nvme_clear_attr.attr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1312) if (rc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1313) goto out2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1314) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1315) reipl_nvme_clear = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1316) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1317)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1318) if (ipl_info.type == IPL_TYPE_NVME) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1319) memcpy(reipl_block_nvme, &ipl_block, sizeof(ipl_block));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1320) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1321) * Fix loadparm: There are systems where the (SCSI) LOADPARM
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1322) * is invalid in the IPL parameter block, so take it
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1323) * always from sclp_ipl_info.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1324) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1325) memcpy(reipl_block_nvme->nvme.loadparm, sclp_ipl_info.loadparm,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1326) LOADPARM_LEN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1327) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1328) reipl_block_nvme->hdr.len = IPL_BP_NVME_LEN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1329) reipl_block_nvme->hdr.version = IPL_PARM_BLOCK_VERSION;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1330) reipl_block_nvme->nvme.len = IPL_BP0_NVME_LEN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1331) reipl_block_nvme->nvme.pbt = IPL_PBT_NVME;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1332) reipl_block_nvme->nvme.opt = IPL_PB0_NVME_OPT_IPL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1333) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1334) reipl_capabilities |= IPL_TYPE_NVME;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1335) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1336)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1337) out2:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1338) sysfs_remove_group(&reipl_nvme_kset->kobj, &reipl_nvme_attr_group);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1339) out1:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1340) kset_unregister(reipl_nvme_kset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1341) free_page((unsigned long) reipl_block_nvme);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1342) return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1343) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1344)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1345) static int __init reipl_type_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1346) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1347) enum ipl_type reipl_type = ipl_info.type;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1348) struct ipl_parameter_block *reipl_block;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1349) unsigned long size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1350)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1351) reipl_block = os_info_old_entry(OS_INFO_REIPL_BLOCK, &size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1352) if (!reipl_block)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1353) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1354) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1355) * If we have an OS info reipl block, this will be used
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1356) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1357) if (reipl_block->pb0_hdr.pbt == IPL_PBT_FCP) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1358) memcpy(reipl_block_fcp, reipl_block, size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1359) reipl_type = IPL_TYPE_FCP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1360) } else if (reipl_block->pb0_hdr.pbt == IPL_PBT_NVME) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1361) memcpy(reipl_block_nvme, reipl_block, size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1362) reipl_type = IPL_TYPE_NVME;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1363) } else if (reipl_block->pb0_hdr.pbt == IPL_PBT_CCW) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1364) memcpy(reipl_block_ccw, reipl_block, size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1365) reipl_type = IPL_TYPE_CCW;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1366) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1367) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1368) return reipl_set_type(reipl_type);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1369) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1370)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1371) static int __init reipl_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1372) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1373) int rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1374)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1375) reipl_kset = kset_create_and_add("reipl", NULL, firmware_kobj);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1376) if (!reipl_kset)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1377) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1378) rc = sysfs_create_file(&reipl_kset->kobj, &reipl_type_attr.attr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1379) if (rc) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1380) kset_unregister(reipl_kset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1381) return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1382) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1383) rc = reipl_ccw_init();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1384) if (rc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1385) return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1386) rc = reipl_fcp_init();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1387) if (rc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1388) return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1389) rc = reipl_nvme_init();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1390) if (rc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1391) return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1392) rc = reipl_nss_init();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1393) if (rc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1394) return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1395) return reipl_type_init();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1396) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1397)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1398) static struct shutdown_action __refdata reipl_action = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1399) .name = SHUTDOWN_ACTION_REIPL_STR,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1400) .fn = reipl_run,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1401) .init = reipl_init,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1402) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1403)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1404) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1405) * dump shutdown action: Dump Linux on shutdown.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1406) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1407)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1408) /* FCP dump device attributes */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1409)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1410) DEFINE_IPL_ATTR_RW(dump_fcp, wwpn, "0x%016llx\n", "%llx\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1411) dump_block_fcp->fcp.wwpn);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1412) DEFINE_IPL_ATTR_RW(dump_fcp, lun, "0x%016llx\n", "%llx\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1413) dump_block_fcp->fcp.lun);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1414) DEFINE_IPL_ATTR_RW(dump_fcp, bootprog, "%lld\n", "%lld\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1415) dump_block_fcp->fcp.bootprog);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1416) DEFINE_IPL_ATTR_RW(dump_fcp, br_lba, "%lld\n", "%lld\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1417) dump_block_fcp->fcp.br_lba);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1418) DEFINE_IPL_ATTR_RW(dump_fcp, device, "0.0.%04llx\n", "0.0.%llx\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1419) dump_block_fcp->fcp.devno);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1420)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1421) static struct attribute *dump_fcp_attrs[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1422) &sys_dump_fcp_device_attr.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1423) &sys_dump_fcp_wwpn_attr.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1424) &sys_dump_fcp_lun_attr.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1425) &sys_dump_fcp_bootprog_attr.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1426) &sys_dump_fcp_br_lba_attr.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1427) NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1428) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1429)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1430) static struct attribute_group dump_fcp_attr_group = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1431) .name = IPL_FCP_STR,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1432) .attrs = dump_fcp_attrs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1433) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1434)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1435) /* NVME dump device attributes */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1436) DEFINE_IPL_ATTR_RW(dump_nvme, fid, "0x%08llx\n", "%llx\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1437) dump_block_nvme->nvme.fid);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1438) DEFINE_IPL_ATTR_RW(dump_nvme, nsid, "0x%08llx\n", "%llx\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1439) dump_block_nvme->nvme.nsid);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1440) DEFINE_IPL_ATTR_RW(dump_nvme, bootprog, "%lld\n", "%llx\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1441) dump_block_nvme->nvme.bootprog);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1442) DEFINE_IPL_ATTR_RW(dump_nvme, br_lba, "%lld\n", "%llx\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1443) dump_block_nvme->nvme.br_lba);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1444)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1445) static struct attribute *dump_nvme_attrs[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1446) &sys_dump_nvme_fid_attr.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1447) &sys_dump_nvme_nsid_attr.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1448) &sys_dump_nvme_bootprog_attr.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1449) &sys_dump_nvme_br_lba_attr.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1450) NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1451) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1452)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1453) static struct attribute_group dump_nvme_attr_group = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1454) .name = IPL_NVME_STR,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1455) .attrs = dump_nvme_attrs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1456) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1457)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1458) /* CCW dump device attributes */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1459) DEFINE_IPL_CCW_ATTR_RW(dump_ccw, device, dump_block_ccw->ccw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1460)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1461) static struct attribute *dump_ccw_attrs[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1462) &sys_dump_ccw_device_attr.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1463) NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1464) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1465)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1466) static struct attribute_group dump_ccw_attr_group = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1467) .name = IPL_CCW_STR,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1468) .attrs = dump_ccw_attrs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1469) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1470)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1471) /* dump type */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1472)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1473) static int dump_set_type(enum dump_type type)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1474) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1475) if (!(dump_capabilities & type))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1476) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1477) dump_type = type;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1478) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1479) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1480)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1481) static ssize_t dump_type_show(struct kobject *kobj,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1482) struct kobj_attribute *attr, char *page)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1483) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1484) return sprintf(page, "%s\n", dump_type_str(dump_type));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1485) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1486)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1487) static ssize_t dump_type_store(struct kobject *kobj,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1488) struct kobj_attribute *attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1489) const char *buf, size_t len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1490) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1491) int rc = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1492)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1493) if (strncmp(buf, DUMP_NONE_STR, strlen(DUMP_NONE_STR)) == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1494) rc = dump_set_type(DUMP_TYPE_NONE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1495) else if (strncmp(buf, DUMP_CCW_STR, strlen(DUMP_CCW_STR)) == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1496) rc = dump_set_type(DUMP_TYPE_CCW);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1497) else if (strncmp(buf, DUMP_FCP_STR, strlen(DUMP_FCP_STR)) == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1498) rc = dump_set_type(DUMP_TYPE_FCP);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1499) else if (strncmp(buf, DUMP_NVME_STR, strlen(DUMP_NVME_STR)) == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1500) rc = dump_set_type(DUMP_TYPE_NVME);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1501) return (rc != 0) ? rc : len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1502) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1503)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1504) static struct kobj_attribute dump_type_attr =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1505) __ATTR(dump_type, 0644, dump_type_show, dump_type_store);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1506)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1507) static struct kset *dump_kset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1508)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1509) static void diag308_dump(void *dump_block)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1510) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1511) diag308(DIAG308_SET, dump_block);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1512) while (1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1513) if (diag308(DIAG308_LOAD_NORMAL_DUMP, NULL) != 0x302)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1514) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1515) udelay_simple(USEC_PER_SEC);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1516) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1517) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1518)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1519) static void __dump_run(void *unused)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1520) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1521) switch (dump_type) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1522) case DUMP_TYPE_CCW:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1523) diag308_dump(dump_block_ccw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1524) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1525) case DUMP_TYPE_FCP:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1526) diag308_dump(dump_block_fcp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1527) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1528) case DUMP_TYPE_NVME:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1529) diag308_dump(dump_block_nvme);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1530) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1531) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1532) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1533) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1534) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1535)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1536) static void dump_run(struct shutdown_trigger *trigger)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1537) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1538) if (dump_type == DUMP_TYPE_NONE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1539) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1540) smp_send_stop();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1541) smp_call_ipl_cpu(__dump_run, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1542) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1543)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1544) static int __init dump_ccw_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1545) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1546) int rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1547)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1548) dump_block_ccw = (void *) get_zeroed_page(GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1549) if (!dump_block_ccw)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1550) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1551) rc = sysfs_create_group(&dump_kset->kobj, &dump_ccw_attr_group);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1552) if (rc) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1553) free_page((unsigned long)dump_block_ccw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1554) return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1555) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1556) dump_block_ccw->hdr.len = IPL_BP_CCW_LEN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1557) dump_block_ccw->hdr.version = IPL_PARM_BLOCK_VERSION;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1558) dump_block_ccw->ccw.len = IPL_BP0_CCW_LEN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1559) dump_block_ccw->ccw.pbt = IPL_PBT_CCW;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1560) dump_capabilities |= DUMP_TYPE_CCW;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1561) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1562) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1563)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1564) static int __init dump_fcp_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1565) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1566) int rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1567)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1568) if (!sclp_ipl_info.has_dump)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1569) return 0; /* LDIPL DUMP is not installed */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1570) dump_block_fcp = (void *) get_zeroed_page(GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1571) if (!dump_block_fcp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1572) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1573) rc = sysfs_create_group(&dump_kset->kobj, &dump_fcp_attr_group);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1574) if (rc) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1575) free_page((unsigned long)dump_block_fcp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1576) return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1577) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1578) dump_block_fcp->hdr.len = IPL_BP_FCP_LEN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1579) dump_block_fcp->hdr.version = IPL_PARM_BLOCK_VERSION;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1580) dump_block_fcp->fcp.len = IPL_BP0_FCP_LEN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1581) dump_block_fcp->fcp.pbt = IPL_PBT_FCP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1582) dump_block_fcp->fcp.opt = IPL_PB0_FCP_OPT_DUMP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1583) dump_capabilities |= DUMP_TYPE_FCP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1584) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1585) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1586)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1587) static int __init dump_nvme_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1588) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1589) int rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1590)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1591) if (!sclp_ipl_info.has_dump)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1592) return 0; /* LDIPL DUMP is not installed */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1593) dump_block_nvme = (void *) get_zeroed_page(GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1594) if (!dump_block_nvme)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1595) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1596) rc = sysfs_create_group(&dump_kset->kobj, &dump_nvme_attr_group);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1597) if (rc) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1598) free_page((unsigned long)dump_block_nvme);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1599) return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1600) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1601) dump_block_nvme->hdr.len = IPL_BP_NVME_LEN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1602) dump_block_nvme->hdr.version = IPL_PARM_BLOCK_VERSION;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1603) dump_block_nvme->fcp.len = IPL_BP0_NVME_LEN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1604) dump_block_nvme->fcp.pbt = IPL_PBT_NVME;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1605) dump_block_nvme->fcp.opt = IPL_PB0_NVME_OPT_DUMP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1606) dump_capabilities |= DUMP_TYPE_NVME;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1607) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1608) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1609)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1610) static int __init dump_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1611) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1612) int rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1613)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1614) dump_kset = kset_create_and_add("dump", NULL, firmware_kobj);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1615) if (!dump_kset)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1616) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1617) rc = sysfs_create_file(&dump_kset->kobj, &dump_type_attr.attr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1618) if (rc) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1619) kset_unregister(dump_kset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1620) return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1621) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1622) rc = dump_ccw_init();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1623) if (rc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1624) return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1625) rc = dump_fcp_init();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1626) if (rc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1627) return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1628) rc = dump_nvme_init();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1629) if (rc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1630) return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1631) dump_set_type(DUMP_TYPE_NONE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1632) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1633) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1634)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1635) static struct shutdown_action __refdata dump_action = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1636) .name = SHUTDOWN_ACTION_DUMP_STR,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1637) .fn = dump_run,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1638) .init = dump_init,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1639) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1640)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1641) static void dump_reipl_run(struct shutdown_trigger *trigger)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1642) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1643) unsigned long ipib = (unsigned long) reipl_block_actual;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1644) unsigned int csum;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1645)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1646) csum = (__force unsigned int)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1647) csum_partial(reipl_block_actual, reipl_block_actual->hdr.len, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1648) mem_assign_absolute(S390_lowcore.ipib, ipib);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1649) mem_assign_absolute(S390_lowcore.ipib_checksum, csum);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1650) dump_run(trigger);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1651) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1652)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1653) static struct shutdown_action __refdata dump_reipl_action = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1654) .name = SHUTDOWN_ACTION_DUMP_REIPL_STR,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1655) .fn = dump_reipl_run,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1656) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1657)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1658) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1659) * vmcmd shutdown action: Trigger vm command on shutdown.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1660) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1661)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1662) static char vmcmd_on_reboot[128];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1663) static char vmcmd_on_panic[128];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1664) static char vmcmd_on_halt[128];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1665) static char vmcmd_on_poff[128];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1666) static char vmcmd_on_restart[128];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1667)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1668) DEFINE_IPL_ATTR_STR_RW(vmcmd, on_reboot, "%s\n", "%s\n", vmcmd_on_reboot);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1669) DEFINE_IPL_ATTR_STR_RW(vmcmd, on_panic, "%s\n", "%s\n", vmcmd_on_panic);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1670) DEFINE_IPL_ATTR_STR_RW(vmcmd, on_halt, "%s\n", "%s\n", vmcmd_on_halt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1671) DEFINE_IPL_ATTR_STR_RW(vmcmd, on_poff, "%s\n", "%s\n", vmcmd_on_poff);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1672) DEFINE_IPL_ATTR_STR_RW(vmcmd, on_restart, "%s\n", "%s\n", vmcmd_on_restart);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1673)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1674) static struct attribute *vmcmd_attrs[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1675) &sys_vmcmd_on_reboot_attr.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1676) &sys_vmcmd_on_panic_attr.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1677) &sys_vmcmd_on_halt_attr.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1678) &sys_vmcmd_on_poff_attr.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1679) &sys_vmcmd_on_restart_attr.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1680) NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1681) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1682)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1683) static struct attribute_group vmcmd_attr_group = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1684) .attrs = vmcmd_attrs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1685) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1686)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1687) static struct kset *vmcmd_kset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1688)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1689) static void vmcmd_run(struct shutdown_trigger *trigger)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1690) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1691) char *cmd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1692)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1693) if (strcmp(trigger->name, ON_REIPL_STR) == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1694) cmd = vmcmd_on_reboot;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1695) else if (strcmp(trigger->name, ON_PANIC_STR) == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1696) cmd = vmcmd_on_panic;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1697) else if (strcmp(trigger->name, ON_HALT_STR) == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1698) cmd = vmcmd_on_halt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1699) else if (strcmp(trigger->name, ON_POFF_STR) == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1700) cmd = vmcmd_on_poff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1701) else if (strcmp(trigger->name, ON_RESTART_STR) == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1702) cmd = vmcmd_on_restart;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1703) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1704) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1705)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1706) if (strlen(cmd) == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1707) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1708) __cpcmd(cmd, NULL, 0, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1709) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1710)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1711) static int vmcmd_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1712) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1713) if (!MACHINE_IS_VM)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1714) return -EOPNOTSUPP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1715) vmcmd_kset = kset_create_and_add("vmcmd", NULL, firmware_kobj);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1716) if (!vmcmd_kset)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1717) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1718) return sysfs_create_group(&vmcmd_kset->kobj, &vmcmd_attr_group);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1719) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1720)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1721) static struct shutdown_action vmcmd_action = {SHUTDOWN_ACTION_VMCMD_STR,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1722) vmcmd_run, vmcmd_init};
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1723)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1724) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1725) * stop shutdown action: Stop Linux on shutdown.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1726) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1727)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1728) static void stop_run(struct shutdown_trigger *trigger)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1729) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1730) if (strcmp(trigger->name, ON_PANIC_STR) == 0 ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1731) strcmp(trigger->name, ON_RESTART_STR) == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1732) disabled_wait();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1733) smp_stop_cpu();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1734) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1735)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1736) static struct shutdown_action stop_action = {SHUTDOWN_ACTION_STOP_STR,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1737) stop_run, NULL};
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1738)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1739) /* action list */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1740)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1741) static struct shutdown_action *shutdown_actions_list[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1742) &ipl_action, &reipl_action, &dump_reipl_action, &dump_action,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1743) &vmcmd_action, &stop_action};
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1744) #define SHUTDOWN_ACTIONS_COUNT (sizeof(shutdown_actions_list) / sizeof(void *))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1745)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1746) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1747) * Trigger section
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1748) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1749)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1750) static struct kset *shutdown_actions_kset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1751)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1752) static int set_trigger(const char *buf, struct shutdown_trigger *trigger,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1753) size_t len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1754) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1755) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1756)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1757) for (i = 0; i < SHUTDOWN_ACTIONS_COUNT; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1758) if (sysfs_streq(buf, shutdown_actions_list[i]->name)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1759) if (shutdown_actions_list[i]->init_rc) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1760) return shutdown_actions_list[i]->init_rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1761) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1762) trigger->action = shutdown_actions_list[i];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1763) return len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1764) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1765) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1766) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1767) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1768) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1769)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1770) /* on reipl */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1771)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1772) static struct shutdown_trigger on_reboot_trigger = {ON_REIPL_STR,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1773) &reipl_action};
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1774)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1775) static ssize_t on_reboot_show(struct kobject *kobj,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1776) struct kobj_attribute *attr, char *page)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1777) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1778) return sprintf(page, "%s\n", on_reboot_trigger.action->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1779) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1780)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1781) static ssize_t on_reboot_store(struct kobject *kobj,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1782) struct kobj_attribute *attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1783) const char *buf, size_t len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1784) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1785) return set_trigger(buf, &on_reboot_trigger, len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1786) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1787) static struct kobj_attribute on_reboot_attr = __ATTR_RW(on_reboot);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1788)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1789) static void do_machine_restart(char *__unused)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1790) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1791) smp_send_stop();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1792) on_reboot_trigger.action->fn(&on_reboot_trigger);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1793) reipl_run(NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1794) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1795) void (*_machine_restart)(char *command) = do_machine_restart;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1796)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1797) /* on panic */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1798)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1799) static struct shutdown_trigger on_panic_trigger = {ON_PANIC_STR, &stop_action};
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1800)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1801) static ssize_t on_panic_show(struct kobject *kobj,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1802) struct kobj_attribute *attr, char *page)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1803) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1804) return sprintf(page, "%s\n", on_panic_trigger.action->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1805) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1806)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1807) static ssize_t on_panic_store(struct kobject *kobj,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1808) struct kobj_attribute *attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1809) const char *buf, size_t len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1810) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1811) return set_trigger(buf, &on_panic_trigger, len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1812) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1813) static struct kobj_attribute on_panic_attr = __ATTR_RW(on_panic);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1814)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1815) static void do_panic(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1816) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1817) lgr_info_log();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1818) on_panic_trigger.action->fn(&on_panic_trigger);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1819) stop_run(&on_panic_trigger);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1820) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1821)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1822) /* on restart */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1823)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1824) static struct shutdown_trigger on_restart_trigger = {ON_RESTART_STR,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1825) &stop_action};
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1826)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1827) static ssize_t on_restart_show(struct kobject *kobj,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1828) struct kobj_attribute *attr, char *page)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1829) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1830) return sprintf(page, "%s\n", on_restart_trigger.action->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1831) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1832)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1833) static ssize_t on_restart_store(struct kobject *kobj,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1834) struct kobj_attribute *attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1835) const char *buf, size_t len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1836) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1837) return set_trigger(buf, &on_restart_trigger, len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1838) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1839) static struct kobj_attribute on_restart_attr = __ATTR_RW(on_restart);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1840)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1841) static void __do_restart(void *ignore)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1842) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1843) __arch_local_irq_stosm(0x04); /* enable DAT */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1844) smp_send_stop();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1845) #ifdef CONFIG_CRASH_DUMP
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1846) crash_kexec(NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1847) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1848) on_restart_trigger.action->fn(&on_restart_trigger);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1849) stop_run(&on_restart_trigger);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1850) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1851)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1852) void do_restart(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1853) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1854) tracing_off();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1855) debug_locks_off();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1856) lgr_info_log();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1857) smp_call_online_cpu(__do_restart, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1858) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1859)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1860) /* on halt */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1861)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1862) static struct shutdown_trigger on_halt_trigger = {ON_HALT_STR, &stop_action};
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1863)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1864) static ssize_t on_halt_show(struct kobject *kobj,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1865) struct kobj_attribute *attr, char *page)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1866) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1867) return sprintf(page, "%s\n", on_halt_trigger.action->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1868) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1869)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1870) static ssize_t on_halt_store(struct kobject *kobj,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1871) struct kobj_attribute *attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1872) const char *buf, size_t len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1873) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1874) return set_trigger(buf, &on_halt_trigger, len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1875) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1876) static struct kobj_attribute on_halt_attr = __ATTR_RW(on_halt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1877)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1878) static void do_machine_halt(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1879) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1880) smp_send_stop();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1881) on_halt_trigger.action->fn(&on_halt_trigger);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1882) stop_run(&on_halt_trigger);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1883) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1884) void (*_machine_halt)(void) = do_machine_halt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1885)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1886) /* on power off */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1887)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1888) static struct shutdown_trigger on_poff_trigger = {ON_POFF_STR, &stop_action};
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1889)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1890) static ssize_t on_poff_show(struct kobject *kobj,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1891) struct kobj_attribute *attr, char *page)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1892) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1893) return sprintf(page, "%s\n", on_poff_trigger.action->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1894) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1895)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1896) static ssize_t on_poff_store(struct kobject *kobj,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1897) struct kobj_attribute *attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1898) const char *buf, size_t len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1899) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1900) return set_trigger(buf, &on_poff_trigger, len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1901) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1902) static struct kobj_attribute on_poff_attr = __ATTR_RW(on_poff);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1903)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1904) static void do_machine_power_off(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1905) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1906) smp_send_stop();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1907) on_poff_trigger.action->fn(&on_poff_trigger);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1908) stop_run(&on_poff_trigger);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1909) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1910) void (*_machine_power_off)(void) = do_machine_power_off;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1911)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1912) static struct attribute *shutdown_action_attrs[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1913) &on_restart_attr.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1914) &on_reboot_attr.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1915) &on_panic_attr.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1916) &on_halt_attr.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1917) &on_poff_attr.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1918) NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1919) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1920)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1921) static struct attribute_group shutdown_action_attr_group = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1922) .attrs = shutdown_action_attrs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1923) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1924)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1925) static void __init shutdown_triggers_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1926) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1927) shutdown_actions_kset = kset_create_and_add("shutdown_actions", NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1928) firmware_kobj);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1929) if (!shutdown_actions_kset)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1930) goto fail;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1931) if (sysfs_create_group(&shutdown_actions_kset->kobj,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1932) &shutdown_action_attr_group))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1933) goto fail;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1934) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1935) fail:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1936) panic("shutdown_triggers_init failed\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1937) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1938)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1939) static void __init shutdown_actions_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1940) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1941) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1942)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1943) for (i = 0; i < SHUTDOWN_ACTIONS_COUNT; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1944) if (!shutdown_actions_list[i]->init)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1945) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1946) shutdown_actions_list[i]->init_rc =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1947) shutdown_actions_list[i]->init();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1948) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1949) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1950)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1951) static int __init s390_ipl_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1952) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1953) char str[8] = {0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40};
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1954)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1955) sclp_early_get_ipl_info(&sclp_ipl_info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1956) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1957) * Fix loadparm: There are systems where the (SCSI) LOADPARM
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1958) * returned by read SCP info is invalid (contains EBCDIC blanks)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1959) * when the system has been booted via diag308. In that case we use
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1960) * the value from diag308, if available.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1961) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1962) * There are also systems where diag308 store does not work in
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1963) * case the system is booted from HMC. Fortunately in this case
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1964) * READ SCP info provides the correct value.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1965) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1966) if (memcmp(sclp_ipl_info.loadparm, str, sizeof(str)) == 0 && ipl_block_valid)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1967) memcpy(sclp_ipl_info.loadparm, ipl_block.ccw.loadparm, LOADPARM_LEN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1968) shutdown_actions_init();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1969) shutdown_triggers_init();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1970) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1971) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1972)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1973) __initcall(s390_ipl_init);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1974)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1975) static void __init strncpy_skip_quote(char *dst, char *src, int n)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1976) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1977) int sx, dx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1978)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1979) dx = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1980) for (sx = 0; src[sx] != 0; sx++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1981) if (src[sx] == '"')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1982) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1983) dst[dx++] = src[sx];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1984) if (dx >= n)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1985) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1986) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1987) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1988)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1989) static int __init vmcmd_on_reboot_setup(char *str)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1990) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1991) if (!MACHINE_IS_VM)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1992) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1993) strncpy_skip_quote(vmcmd_on_reboot, str, 127);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1994) vmcmd_on_reboot[127] = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1995) on_reboot_trigger.action = &vmcmd_action;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1996) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1997) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1998) __setup("vmreboot=", vmcmd_on_reboot_setup);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1999)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2000) static int __init vmcmd_on_panic_setup(char *str)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2001) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2002) if (!MACHINE_IS_VM)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2003) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2004) strncpy_skip_quote(vmcmd_on_panic, str, 127);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2005) vmcmd_on_panic[127] = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2006) on_panic_trigger.action = &vmcmd_action;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2007) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2008) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2009) __setup("vmpanic=", vmcmd_on_panic_setup);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2010)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2011) static int __init vmcmd_on_halt_setup(char *str)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2012) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2013) if (!MACHINE_IS_VM)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2014) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2015) strncpy_skip_quote(vmcmd_on_halt, str, 127);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2016) vmcmd_on_halt[127] = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2017) on_halt_trigger.action = &vmcmd_action;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2018) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2019) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2020) __setup("vmhalt=", vmcmd_on_halt_setup);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2021)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2022) static int __init vmcmd_on_poff_setup(char *str)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2023) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2024) if (!MACHINE_IS_VM)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2025) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2026) strncpy_skip_quote(vmcmd_on_poff, str, 127);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2027) vmcmd_on_poff[127] = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2028) on_poff_trigger.action = &vmcmd_action;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2029) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2030) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2031) __setup("vmpoff=", vmcmd_on_poff_setup);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2032)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2033) static int on_panic_notify(struct notifier_block *self,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2034) unsigned long event, void *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2035) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2036) do_panic();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2037) return NOTIFY_OK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2038) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2039)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2040) static struct notifier_block on_panic_nb = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2041) .notifier_call = on_panic_notify,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2042) .priority = INT_MIN,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2043) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2044)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2045) void __init setup_ipl(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2046) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2047) BUILD_BUG_ON(sizeof(struct ipl_parameter_block) != PAGE_SIZE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2048)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2049) ipl_info.type = get_ipl_type();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2050) switch (ipl_info.type) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2051) case IPL_TYPE_CCW:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2052) ipl_info.data.ccw.dev_id.ssid = ipl_block.ccw.ssid;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2053) ipl_info.data.ccw.dev_id.devno = ipl_block.ccw.devno;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2054) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2055) case IPL_TYPE_FCP:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2056) case IPL_TYPE_FCP_DUMP:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2057) ipl_info.data.fcp.dev_id.ssid = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2058) ipl_info.data.fcp.dev_id.devno = ipl_block.fcp.devno;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2059) ipl_info.data.fcp.wwpn = ipl_block.fcp.wwpn;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2060) ipl_info.data.fcp.lun = ipl_block.fcp.lun;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2061) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2062) case IPL_TYPE_NVME:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2063) case IPL_TYPE_NVME_DUMP:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2064) ipl_info.data.nvme.fid = ipl_block.nvme.fid;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2065) ipl_info.data.nvme.nsid = ipl_block.nvme.nsid;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2066) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2067) case IPL_TYPE_NSS:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2068) case IPL_TYPE_UNKNOWN:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2069) /* We have no info to copy */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2070) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2071) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2072) atomic_notifier_chain_register(&panic_notifier_list, &on_panic_nb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2073) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2074)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2075) void s390_reset_system(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2076) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2077) /* Disable prefixing */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2078) set_prefix(0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2079)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2080) /* Disable lowcore protection */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2081) __ctl_clear_bit(0, 28);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2082) diag_dma_ops.diag308_reset();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2083) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2084)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2085) #ifdef CONFIG_KEXEC_FILE
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2086)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2087) int ipl_report_add_component(struct ipl_report *report, struct kexec_buf *kbuf,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2088) unsigned char flags, unsigned short cert)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2089) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2090) struct ipl_report_component *comp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2091)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2092) comp = vzalloc(sizeof(*comp));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2093) if (!comp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2094) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2095) list_add_tail(&comp->list, &report->components);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2096)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2097) comp->entry.addr = kbuf->mem;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2098) comp->entry.len = kbuf->memsz;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2099) comp->entry.flags = flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2100) comp->entry.certificate_index = cert;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2101)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2102) report->size += sizeof(comp->entry);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2103)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2104) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2105) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2106)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2107) int ipl_report_add_certificate(struct ipl_report *report, void *key,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2108) unsigned long addr, unsigned long len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2109) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2110) struct ipl_report_certificate *cert;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2111)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2112) cert = vzalloc(sizeof(*cert));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2113) if (!cert)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2114) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2115) list_add_tail(&cert->list, &report->certificates);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2116)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2117) cert->entry.addr = addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2118) cert->entry.len = len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2119) cert->key = key;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2120)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2121) report->size += sizeof(cert->entry);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2122) report->size += cert->entry.len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2123)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2124) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2125) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2126)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2127) struct ipl_report *ipl_report_init(struct ipl_parameter_block *ipib)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2128) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2129) struct ipl_report *report;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2130)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2131) report = vzalloc(sizeof(*report));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2132) if (!report)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2133) return ERR_PTR(-ENOMEM);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2134)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2135) report->ipib = ipib;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2136) INIT_LIST_HEAD(&report->components);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2137) INIT_LIST_HEAD(&report->certificates);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2138)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2139) report->size = ALIGN(ipib->hdr.len, 8);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2140) report->size += sizeof(struct ipl_rl_hdr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2141) report->size += sizeof(struct ipl_rb_components);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2142) report->size += sizeof(struct ipl_rb_certificates);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2143)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2144) return report;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2145) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2146)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2147) void *ipl_report_finish(struct ipl_report *report)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2148) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2149) struct ipl_report_certificate *cert;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2150) struct ipl_report_component *comp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2151) struct ipl_rb_certificates *certs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2152) struct ipl_parameter_block *ipib;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2153) struct ipl_rb_components *comps;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2154) struct ipl_rl_hdr *rl_hdr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2155) void *buf, *ptr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2156)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2157) buf = vzalloc(report->size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2158) if (!buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2159) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2160) ptr = buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2161)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2162) memcpy(ptr, report->ipib, report->ipib->hdr.len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2163) ipib = ptr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2164) if (ipl_secure_flag)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2165) ipib->hdr.flags |= IPL_PL_FLAG_SIPL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2166) ipib->hdr.flags |= IPL_PL_FLAG_IPLSR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2167) ptr += report->ipib->hdr.len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2168) ptr = PTR_ALIGN(ptr, 8);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2169)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2170) rl_hdr = ptr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2171) ptr += sizeof(*rl_hdr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2172)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2173) comps = ptr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2174) comps->rbt = IPL_RBT_COMPONENTS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2175) ptr += sizeof(*comps);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2176) list_for_each_entry(comp, &report->components, list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2177) memcpy(ptr, &comp->entry, sizeof(comp->entry));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2178) ptr += sizeof(comp->entry);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2179) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2180) comps->len = ptr - (void *)comps;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2181)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2182) certs = ptr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2183) certs->rbt = IPL_RBT_CERTIFICATES;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2184) ptr += sizeof(*certs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2185) list_for_each_entry(cert, &report->certificates, list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2186) memcpy(ptr, &cert->entry, sizeof(cert->entry));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2187) ptr += sizeof(cert->entry);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2188) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2189) certs->len = ptr - (void *)certs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2190) rl_hdr->len = ptr - (void *)rl_hdr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2191)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2192) list_for_each_entry(cert, &report->certificates, list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2193) memcpy(ptr, cert->key, cert->entry.len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2194) ptr += cert->entry.len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2195) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2196)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2197) BUG_ON(ptr > buf + report->size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2198) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2199) return buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2200) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2201)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2202) int ipl_report_free(struct ipl_report *report)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2203) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2204) struct ipl_report_component *comp, *ncomp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2205) struct ipl_report_certificate *cert, *ncert;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2206)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2207) list_for_each_entry_safe(comp, ncomp, &report->components, list)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2208) vfree(comp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2209)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2210) list_for_each_entry_safe(cert, ncert, &report->certificates, list)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2211) vfree(cert);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2212)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2213) vfree(report);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2214)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2215) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2216) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2217)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2218) #endif