forked from pool/s390-tools
5500b3a5bc
- Added the following patches for Fate#326825 (bsc#1113329) I/O device pre-configuration * s390-tools-sles15sp1-01-zdev-use-libutil-provided-path-functions.patch * s390-tools-sles15sp1-02-zdev-Prepare-for-firmware-configuration-file-support.patch * s390-tools-sles15sp1-03-zdev-Add-support-for-reading-firmware-configuration-.patch * s390-tools-sles15sp1-04-zdev-Implement-no-settle.patch * s390-tools-sles15sp1-05-zdev-Write-zfcp-lun-udev-rules-to-separate-files.patch * s390-tools-sles15sp1-06-zdev-Add-support-for-handling-auto-configuration-dat.patch * s390-tools-sles15sp1-07-zdev-Integrate-firmware-auto-configuration-with-drac.patch * s390-tools-sles15sp1-08-zdev-Integrate-firmware-auto-configuration-with-init.patch * s390-tools-sles15sp1-09-zdev-Implement-internal-device-attributes.patch * s390-tools-sles15sp1-10-zdev-Implement-support-for-early-device-configuratio.patch * s390-tools-sles15sp1-11-zdev-Do-not-call-zipl-on-initrd-update.patch - Removed the obsolete customize-zdev-root-update-script.patch - Replaced s390-tools-sles15-zdev-fix-qeth-BridgePort-and-VNICC-conflict-checking.patch with s390-tools-sles15sp1-zdev-fix-qeth-BridgePort-and-VNICC-conflict-checking.patch to fit the current version. OBS-URL: https://build.opensuse.org/request/show/655900 OBS-URL: https://build.opensuse.org/package/show/Base:System/s390-tools?expand=0&rev=61
508 lines
15 KiB
Diff
508 lines
15 KiB
Diff
Subject: zdev: Implement internal device attributes
|
|
From: Peter Oberparleiter <oberpar@linux.ibm.com>
|
|
|
|
Summary: zdev: Add support for handling I/O configuration data
|
|
Description: LPARs that are running in IBM Dynamic Partition Manager (DPM) mode
|
|
can access a firmware-generated I/O configuration data file that
|
|
contains s390-specific information about available I/O devices
|
|
such as qeth device numbers and parameters, and FCP device IDs.
|
|
|
|
This data file is intended to remove the need for users to
|
|
manually enter the corresponding device data during installation.
|
|
|
|
Linux kernels with the corresponding support make the I/O
|
|
configuration data available at the following location:
|
|
|
|
/sys/firmware/sclp_sd/config/data
|
|
|
|
This patch set adds support for handling this data file using the
|
|
chzdev and lszdev tools:
|
|
|
|
- I/O configuration data can be applied using chzdev's --import
|
|
option
|
|
- Initial RAM-Disk scripts automatically apply the
|
|
I/O configuration data to the system configuration
|
|
- lszdev can be used to display the applied auto-configuration
|
|
data
|
|
- chzdev can be used to manually override the
|
|
auto-configuration data
|
|
|
|
Upstream-ID: c0392efa39e48cb12fdf3524b2f9e683e46f0f14
|
|
Problem-ID: LS1604
|
|
|
|
Upstream-Description:
|
|
|
|
zdev: Implement internal device attributes
|
|
|
|
This change adds base infrastructure for implementing internal device
|
|
attributes. In the context of the zdev tools, an internal device
|
|
attribute is a new type of device attribute with the following
|
|
characteristics:
|
|
|
|
- Can be set and removed like normal device attributes
|
|
- Affects zdev-internal handling only
|
|
- Does not correspond to an actual device attribute, that is
|
|
it has no representation in SysFS
|
|
- Can not be set in the active configuration
|
|
- Name starts with "zdev:" to prevent conflicts with actual
|
|
device attributes
|
|
|
|
Values for internal device attributes are stored in udev rules alongside
|
|
the normal persistent configuration of a device. They are encoded as
|
|
udev environment variables. Note that they have no further effect on
|
|
udev processing.
|
|
|
|
Signed-off-by: Peter Oberparleiter <oberpar@linux.vnet.ibm.com>
|
|
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
|
|
|
|
|
|
Signed-off-by: Peter Oberparleiter <oberpar@linux.ibm.com>
|
|
---
|
|
zdev/include/attrib.h | 2
|
|
zdev/include/internal.h | 20 +++++++++
|
|
zdev/include/misc.h | 1
|
|
zdev/include/udev.h | 7 +++
|
|
zdev/src/Makefile | 4 -
|
|
zdev/src/device.c | 15 +++++++
|
|
zdev/src/internal.c | 25 ++++++++++++
|
|
zdev/src/misc.c | 15 +++++++
|
|
zdev/src/udev.c | 32 +++++++++++++++
|
|
zdev/src/udev_ccw.c | 16 +++++++
|
|
zdev/src/udev_ccwgroup.c | 11 +++++
|
|
zdev/src/udev_zfcp_lun.c | 80 ++++++++++++++++++++++++++++++++++++---
|
|
12 files changed, 220 insertions(+), 8 deletions(-)
|
|
|
|
--- a/zdev/include/attrib.h
|
|
+++ b/zdev/include/attrib.h
|
|
@@ -189,6 +189,7 @@ struct value_map {
|
|
* in the persistent configuration
|
|
* @nounload: (Device type attributes only) This attribute can be set while
|
|
* the corresponding kernel module remains loaded.
|
|
+ * @internal: This attribute only affects internal handling
|
|
* @order: A number indicating the order in which to apply attribute
|
|
* @order_cmp: A function determining if a setting for this attribute should
|
|
* be applied before (-1) or after (1) another setting, or
|
|
@@ -216,6 +217,7 @@ struct attrib {
|
|
unsigned int activerem :1;
|
|
unsigned int defunset :1;
|
|
unsigned int nounload :1;
|
|
+ unsigned int internal :1;
|
|
|
|
/* Optional */
|
|
int order;
|
|
--- /dev/null
|
|
+++ b/zdev/include/internal.h
|
|
@@ -0,0 +1,20 @@
|
|
+/*
|
|
+ * zdev - Modify and display the persistent configuration of devices
|
|
+ *
|
|
+ * Copyright IBM Corp. 2017
|
|
+ *
|
|
+ * s390-tools is free software; you can redistribute it and/or modify
|
|
+ * it under the terms of the MIT license. See LICENSE for details.
|
|
+ */
|
|
+
|
|
+#ifndef INTERNAL_H
|
|
+#define INTERNAL_H
|
|
+
|
|
+#include <stdbool.h>
|
|
+
|
|
+#define INTERNAL_ATTR_PREFIX "zdev:"
|
|
+
|
|
+const char *internal_get_name(const char *name);
|
|
+bool internal_by_name(const char *name);
|
|
+
|
|
+#endif /* INTERNAL_H */
|
|
--- a/zdev/include/misc.h
|
|
+++ b/zdev/include/misc.h
|
|
@@ -183,6 +183,7 @@ bool str_to_config(const char *, config_
|
|
char *quote_str(const char *, int);
|
|
char *unquote_str(const char *);
|
|
char *shrink_str(const char *);
|
|
+char *misc_strrstr(const char *haystack, const char *needle);
|
|
|
|
struct util_list *strlist_new(void);
|
|
void strlist_free(struct util_list *);
|
|
--- a/zdev/include/udev.h
|
|
+++ b/zdev/include/udev.h
|
|
@@ -13,6 +13,9 @@
|
|
#include "lib/util_list.h"
|
|
#include "exit_code.h"
|
|
|
|
+struct attrib;
|
|
+struct setting_list;
|
|
+
|
|
extern int udev_need_settle;
|
|
extern int udev_no_settle;
|
|
|
|
@@ -46,4 +49,8 @@ exit_code_t udev_remove_rule(const char
|
|
|
|
void udev_settle(void);
|
|
|
|
+void udev_add_internal_from_entry(struct setting_list *list,
|
|
+ struct udev_entry_node *entry,
|
|
+ struct attrib **attribs);
|
|
+
|
|
#endif /* UDEV_H */
|
|
--- a/zdev/src/Makefile
|
|
+++ b/zdev/src/Makefile
|
|
@@ -8,7 +8,7 @@ ALL_CPPFLAGS += -I ../include -std=gnu99
|
|
chzdev_objects += attrib.o chzdev.o device.o devnode.o devtype.o exit_code.o \
|
|
export.o hash.o inuse.o misc.o namespace.o opts.o path.o \
|
|
root.o select.o setting.o subtype.o table.o table_attribs.o \
|
|
- table_types.o net.o firmware.o
|
|
+ table_types.o net.o firmware.o internal.o
|
|
|
|
# Devtype Helpers
|
|
chzdev_objects += blkinfo.o ccw.o ccwgroup.o findmnt.o modprobe.o module.o \
|
|
@@ -38,7 +38,7 @@ chzdev_objects += generic_ccw.o
|
|
lszdev_objects += attrib.o lszdev.o device.o devnode.o devtype.o exit_code.o \
|
|
export.o hash.o inuse.o misc.o namespace.o opts.o path.o \
|
|
root.o select.o setting.o subtype.o table.o table_types.o \
|
|
- net.o
|
|
+ net.o internal.o
|
|
|
|
# Devtype Helpers
|
|
lszdev_objects += blkinfo.o ccw.o ccwgroup.o findmnt.o modprobe.o module.o \
|
|
--- a/zdev/src/device.c
|
|
+++ b/zdev/src/device.c
|
|
@@ -16,6 +16,7 @@
|
|
#include "attrib.h"
|
|
#include "device.h"
|
|
#include "devtype.h"
|
|
+#include "internal.h"
|
|
#include "misc.h"
|
|
#include "namespace.h"
|
|
#include "setting.h"
|
|
@@ -221,6 +222,9 @@ static exit_code_t apply_setting(struct
|
|
goto err_activeonly_forceable;
|
|
if (!force && SCOPE_AUTOCONF(config) && a->activeonly)
|
|
goto err_activeonly_forceable;
|
|
+ /* Check for internal. */
|
|
+ if (config == config_active && a->internal)
|
|
+ goto err_int_noactive;
|
|
/* Check for multiple values. */
|
|
if (!force && !a->multi && strlist_find(processed, key))
|
|
goto err_multi_forceable;
|
|
@@ -230,6 +234,9 @@ static exit_code_t apply_setting(struct
|
|
goto err_unknown;
|
|
if (!force)
|
|
goto err_unknown_forceable;
|
|
+ /* Check for internal. */
|
|
+ if (config == config_active && internal_by_name(key))
|
|
+ goto err_int_noactive;
|
|
}
|
|
|
|
strlist_add(processed, "%s", key);
|
|
@@ -294,6 +301,11 @@ err_activeonly_forceable:
|
|
delayed_forceable("Attribute '%s' should only be changed in the active "
|
|
"config\n", a->name);
|
|
return EXIT_INVALID_SETTING;
|
|
+
|
|
+err_int_noactive:
|
|
+ delayed_err("Internal attribute '%s' cannot be set in the active config\n",
|
|
+ key);
|
|
+ return EXIT_INVALID_SETTING;
|
|
}
|
|
|
|
/* Apply device settings from strlist to device. */
|
|
@@ -542,6 +554,9 @@ exit_code_t device_write_active_settings
|
|
s = p->ptr;
|
|
if (!s->modified || s->removed)
|
|
continue;
|
|
+ if ((s->attrib && s->attrib->internal) ||
|
|
+ internal_by_name(s->name))
|
|
+ continue;
|
|
|
|
path = subtype_get_active_attrib_path(st, dev, s->name);
|
|
if (!path) {
|
|
--- /dev/null
|
|
+++ b/zdev/src/internal.c
|
|
@@ -0,0 +1,25 @@
|
|
+/*
|
|
+ * zdev - Modify and display the persistent configuration of devices
|
|
+ *
|
|
+ * Copyright IBM Corp. 2017
|
|
+ *
|
|
+ * s390-tools is free software; you can redistribute it and/or modify
|
|
+ * it under the terms of the MIT license. See LICENSE for details.
|
|
+ */
|
|
+
|
|
+#include <stdbool.h>
|
|
+
|
|
+#include "internal.h"
|
|
+#include "misc.h"
|
|
+
|
|
+/* Return identifier of internal attribute with specified @name. */
|
|
+const char *internal_get_name(const char *name)
|
|
+{
|
|
+ return name + sizeof(INTERNAL_ATTR_PREFIX) - 1;
|
|
+}
|
|
+
|
|
+/* Check if attribute is internal by name. */
|
|
+bool internal_by_name(const char *name)
|
|
+{
|
|
+ return starts_with(name, INTERNAL_ATTR_PREFIX);
|
|
+}
|
|
--- a/zdev/src/misc.c
|
|
+++ b/zdev/src/misc.c
|
|
@@ -1717,3 +1717,18 @@ void debug_init(int argc, char *argv[])
|
|
fprintf(stderr, "%s\"%s\"", i > 0 ? ", " : "", argv[i]);
|
|
fprintf(stderr, "\n");
|
|
}
|
|
+
|
|
+/* Return the last occurrence of @needle in @haystack, or %NULL if @needle
|
|
+ * was not found. */
|
|
+char *misc_strrstr(const char *haystack, const char *needle)
|
|
+{
|
|
+ char *result, *next;
|
|
+
|
|
+ result = strstr(haystack, needle);
|
|
+ if (result) {
|
|
+ while ((next = strstr(result + 1, needle)))
|
|
+ result = next;
|
|
+ }
|
|
+
|
|
+ return result;
|
|
+}
|
|
--- a/zdev/src/udev.c
|
|
+++ b/zdev/src/udev.c
|
|
@@ -409,3 +409,35 @@ void udev_settle(void)
|
|
return;
|
|
misc_system(err_ignore, "%s settle", PATH_UDEVADM);
|
|
}
|
|
+
|
|
+/* Extract internal attribute settings from @entry and add to @list.
|
|
+ * Associate corresponding attribute if found in @attribs. */
|
|
+void udev_add_internal_from_entry(struct setting_list *list,
|
|
+ struct udev_entry_node *entry,
|
|
+ struct attrib **attribs)
|
|
+{
|
|
+ char *copy, *name, *end, *u;
|
|
+ struct attrib *a;
|
|
+
|
|
+ /* ENV{zdev_var}="1" */
|
|
+ copy = misc_strdup(entry->key);
|
|
+
|
|
+ /* Find attribute name start. */
|
|
+ name = strchr(copy, '{');
|
|
+ end = strrchr(copy, '}');
|
|
+ if (!name || !end)
|
|
+ goto out;
|
|
+ *end = 0;
|
|
+ name++;
|
|
+
|
|
+ /* zdev_ => zdev: */
|
|
+ u = strchr(name, '_');
|
|
+ if (u)
|
|
+ *u = ':';
|
|
+
|
|
+ a = attrib_find(attribs, name);
|
|
+ setting_list_apply_actual(list, a, name, entry->value);
|
|
+
|
|
+out:
|
|
+ free(copy);
|
|
+}
|
|
--- a/zdev/src/udev_ccw.c
|
|
+++ b/zdev/src/udev_ccw.c
|
|
@@ -18,6 +18,7 @@
|
|
#include "attrib.h"
|
|
#include "ccw.h"
|
|
#include "device.h"
|
|
+#include "internal.h"
|
|
#include "misc.h"
|
|
#include "path.h"
|
|
#include "setting.h"
|
|
@@ -49,6 +50,12 @@ static void add_setting_from_entry(struc
|
|
char *copy, *name, *end;
|
|
struct attrib *a;
|
|
|
|
+ /* ENV{zdev_var}="1" */
|
|
+ if (starts_with(entry->key, "ENV{zdev_") &&
|
|
+ strcmp(entry->op, "=") == 0) {
|
|
+ udev_add_internal_from_entry(list, entry, attribs);
|
|
+ return;
|
|
+ }
|
|
/* ATTR{[ccw/0.0.37bf]online}=1 */
|
|
if (strncmp(entry->key, "ATTR{[ccw/", 10) != 0 ||
|
|
strcmp(entry->op, "=") != 0)
|
|
@@ -190,7 +197,14 @@ exit_code_t udev_ccw_write_device(struct
|
|
s = p->ptr;
|
|
if (s->removed)
|
|
continue;
|
|
- fprintf(fd, "ATTR{[ccw/%s]%s}=\"%s\"\n", id, s->name, s->value);
|
|
+ if ((s->attrib && s->attrib->internal) ||
|
|
+ internal_by_name(s->name)) {
|
|
+ fprintf(fd, "ENV{zdev_%s}=\"%s\"\n",
|
|
+ internal_get_name(s->name), s->value);
|
|
+ } else {
|
|
+ fprintf(fd, "ATTR{[ccw/%s]%s}=\"%s\"\n", id, s->name,
|
|
+ s->value);
|
|
+ }
|
|
}
|
|
|
|
/* Write udev rule epilog. */
|
|
--- a/zdev/src/udev_ccwgroup.c
|
|
+++ b/zdev/src/udev_ccwgroup.c
|
|
@@ -18,6 +18,7 @@
|
|
#include "attrib.h"
|
|
#include "ccwgroup.h"
|
|
#include "device.h"
|
|
+#include "internal.h"
|
|
#include "misc.h"
|
|
#include "path.h"
|
|
#include "setting.h"
|
|
@@ -68,6 +69,12 @@ static void add_setting_from_entry(struc
|
|
char *copy, *name, *end;
|
|
struct attrib *a;
|
|
|
|
+ /* ENV{zdev_var}="1" */
|
|
+ if (starts_with(entry->key, "ENV{zdev_") &&
|
|
+ strcmp(entry->op, "=") == 0) {
|
|
+ udev_add_internal_from_entry(list, entry, attribs);
|
|
+ return;
|
|
+ }
|
|
/* ATTR{[ccwgroup/0.0.f5f0]online}=1 */
|
|
if (strncmp(entry->key, "ATTR{[ccwgroup/", 10) != 0 ||
|
|
strcmp(entry->op, "=") != 0)
|
|
@@ -282,6 +289,10 @@ exit_code_t udev_ccwgroup_write_device(s
|
|
fprintf(fd, "ATTR{[ccwgroup/%s]%s}=\"%s\"\n",
|
|
ccw_id, s->name, str->str);
|
|
}
|
|
+ } else if ((s->attrib && s->attrib->internal) ||
|
|
+ internal_by_name(s->name)) {
|
|
+ fprintf(fd, "ENV{zdev_%s}=\"%s\"\n",
|
|
+ internal_get_name(s->name), s->value);
|
|
} else {
|
|
fprintf(fd, "ATTR{[ccwgroup/%s]%s}=\"%s\"\n", ccw_id,
|
|
s->name, s->value);
|
|
--- a/zdev/src/udev_zfcp_lun.c
|
|
+++ b/zdev/src/udev_zfcp_lun.c
|
|
@@ -18,6 +18,7 @@
|
|
|
|
#include "attrib.h"
|
|
#include "device.h"
|
|
+#include "internal.h"
|
|
#include "misc.h"
|
|
#include "path.h"
|
|
#include "scsi.h"
|
|
@@ -128,7 +129,7 @@ static bool zfcp_lun_devid_from_entry(st
|
|
struct udev_entry_node *entry)
|
|
{
|
|
struct zfcp_lun_devid id;
|
|
- char *copy = NULL, *s;
|
|
+ char *copy = NULL, *s, *e, *u;
|
|
int i;
|
|
bool rc = false;
|
|
|
|
@@ -182,6 +183,28 @@ static bool zfcp_lun_devid_from_entry(st
|
|
goto out;
|
|
}
|
|
|
|
+ /*ENV{zdev_var__0_0_1941_0x500507630510c1ae_0x402340d400000000}="1"*/
|
|
+ if (starts_with(entry->key, "ENV{zdev_")) {
|
|
+ copy = misc_strdup(entry->key);
|
|
+
|
|
+ /* Find ID start (last __) and end (last }). */
|
|
+ s = misc_strrstr(copy, "__");
|
|
+ e = strrchr(copy, '}');
|
|
+ if (!s || !e)
|
|
+ goto out;
|
|
+ *e = 0;
|
|
+ s += 2;
|
|
+ /* Convert variable name to ID format. */
|
|
+ for (i = 0, u = s; (u = strchr(u, '_')); i++, u++) {
|
|
+ if (i < 2)
|
|
+ *u = '.';
|
|
+ else
|
|
+ *u = ':';
|
|
+ }
|
|
+ rc = zfcp_lun_parse_devid(&id, s, err_ignore) == EXIT_OK ?
|
|
+ true : false;
|
|
+ }
|
|
+
|
|
out:
|
|
free(copy);
|
|
if (rc)
|
|
@@ -211,11 +234,46 @@ static struct zfcp_lun_node *zfcp_lun_no
|
|
return node;
|
|
}
|
|
|
|
+static void add_internal_setting_from_entry(struct udev_entry_node *entry,
|
|
+ struct zfcp_lun_node *node)
|
|
+{
|
|
+ char *copy, *name, *end, *u;
|
|
+ struct attrib *a;
|
|
+
|
|
+ /*ENV{zdev_var__0_0_1941_0x500507630510c1ae_0x402340d400000000}="1"*/
|
|
+ copy = misc_strdup(entry->key);
|
|
+
|
|
+ /* Find attribute name start and end. */
|
|
+ name = strchr(copy, '{');
|
|
+ end = misc_strrstr(copy, "__");
|
|
+ if (!name || !end)
|
|
+ goto out;
|
|
+ *end = 0;
|
|
+ name++;
|
|
+
|
|
+ /* zdev_ => zdev: */
|
|
+ u = strchr(name, '_');
|
|
+ if (u)
|
|
+ *u = ':';
|
|
+
|
|
+ a = attrib_find(zfcp_lun_subtype.dev_attribs, name);
|
|
+ setting_list_apply_actual(node->fc_settings, a, name, entry->value);
|
|
+
|
|
+out:
|
|
+ free(copy);
|
|
+}
|
|
+
|
|
static void add_fc_setting_from_entry(struct udev_entry_node *entry,
|
|
struct zfcp_lun_node *node)
|
|
{
|
|
char *copy, *s, *e;
|
|
|
|
+ /*ENV{zdev_var__0_0_1941_0x500507630510c1ae_0x402340d400000000}="1"*/
|
|
+ if (starts_with(entry->key, "ENV{zdev_") &&
|
|
+ strcmp(entry->op, "=") == 0) {
|
|
+ add_internal_setting_from_entry(entry, node);
|
|
+ return;
|
|
+ }
|
|
/*ATTR{[ccw/0.0.1941]0x500507630510c1ae/0x402340d400000000/failed}="0"*/
|
|
if (!starts_with(entry->key, "ATTR{[ccw/"))
|
|
return;
|
|
@@ -490,7 +548,7 @@ static struct zfcp_lun_node *state_to_zf
|
|
s->value);
|
|
setting_list_add(node->scsi_settings, n);
|
|
} else {
|
|
- n = setting_new(NULL, s->name, s->value);
|
|
+ n = setting_new(s->attrib, s->name, s->value);
|
|
setting_list_add(node->fc_settings, n);
|
|
}
|
|
}
|
|
@@ -580,9 +638,21 @@ static exit_code_t write_luns_rule(const
|
|
node->id.lun);
|
|
|
|
util_list_iterate(&node->fc_settings->list, s) {
|
|
- fprintf(fd, "ATTR{[ccw/%s]0x%016" PRIx64 "/0x%016"
|
|
- PRIx64 "/%s}=\"%s\"\n", hba_id, node->id.wwpn,
|
|
- node->id.lun, s->name, s->value);
|
|
+ if ((s->attrib && s->attrib->internal) ||
|
|
+ internal_by_name(s->name)) {
|
|
+ fprintf(fd, "ENV{zdev_%s__%x_%x_%04x_0x%016"
|
|
+ PRIx64 "_0x%016" PRIx64 "}=\"%s\"\n",
|
|
+ internal_get_name(s->name),
|
|
+ node->id.fcp_dev.cssid,
|
|
+ node->id.fcp_dev.ssid,
|
|
+ node->id.fcp_dev.devno, node->id.wwpn,
|
|
+ node->id.lun, s->value);
|
|
+ } else {
|
|
+ fprintf(fd, "ATTR{[ccw/%s]0x%016" PRIx64
|
|
+ "/0x%016" PRIx64 "/%s}=\"%s\"\n",
|
|
+ hba_id, node->id.wwpn, node->id.lun,
|
|
+ s->name, s->value);
|
|
+ }
|
|
}
|
|
last_node = node;
|
|
}
|