File s390-tools-sles15sp1-06-zdev-Add-support-for-handling-auto-configuration-dat.patch of Package s390-tools.14411

Subject: zdev: Add support for handling auto-configuration data
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: fe68ec513dc1c73c1961f4e15b83d51291df20eb
Problem-ID:  LS1604

Upstream-Description:

             zdev: Add support for handling auto-configuration data

             Auto-configuration is the name of a new configuration target that is
             supported by chzdev and lszdev besides the existing active and
             persistent configuration targets. Directives created in this new
             configuration are stored as udev rules in the /run/udev/rules.d
             directory.

             Auto-configuration directives are only in effect if there are no
             directives for the same device in the user-provided persistent
             configuration. This allows users to override auto-configuration
             directives if necessary.

             Due to the volatile nature of the /run directory, auto-configuration
             directives are cleared on reboot. Therefore mechanisms that generate
             auto-configuration directives must recreate them on every boot.

             The lszdev tool displays auto-configuration data both in list view
             as well as in detail view. Users can specify the new option --auto-conf
             to only show data from this configuration target.

             Mechanisms that generate automated configuration directives can use
             chzdev together with the --auto-conf option to create the corresponding
             udev rules.

             Note: This change does not include a mechanism that generates
                   auto-configuration directives.

             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/device.h        |    4 
 zdev/include/misc.h          |   28 +++---
 zdev/include/path.h          |    5 -
 zdev/include/setting.h       |    3 
 zdev/include/subtype.h       |   22 ++++
 zdev/include/udev.h          |    5 -
 zdev/include/udev_ccw.h      |    8 -
 zdev/include/udev_ccwgroup.h |   12 +-
 zdev/include/udev_zfcp_lun.h |   10 +-
 zdev/man/chzdev.8            |   16 +++
 zdev/man/lszdev.8            |   22 +++-
 zdev/src/ccw.c               |   99 ++++++++++++++++++---
 zdev/src/ccwgroup.c          |   76 ++++++++++++++--
 zdev/src/chzdev.c            |  162 +++++++++++++++++++++++------------
 zdev/src/chzdev_usage.txt    |    1 
 zdev/src/dasd.c              |   48 +++++-----
 zdev/src/device.c            |   55 +++++++++++
 zdev/src/export.c            |   96 +++++++++++++++-----
 zdev/src/firmware.c          |    6 +
 zdev/src/lszdev.c            |  154 +++++++++++++++++++++++++--------
 zdev/src/lszdev_usage.txt    |    1 
 zdev/src/misc.c              |   25 +++--
 zdev/src/path.c              |   14 +--
 zdev/src/qeth.c              |   32 ++++++
 zdev/src/select.c            |   17 ++-
 zdev/src/setting.c           |   14 ++-
 zdev/src/subtype.c           |   83 +++++++++++++++++
 zdev/src/udev.c              |    9 +
 zdev/src/udev_ccw.c          |   30 +++---
 zdev/src/udev_ccwgroup.c     |   41 ++++----
 zdev/src/udev_zfcp_lun.c     |   46 +++++----
 zdev/src/zfcp_lun.c          |   51 +++++++++--
 32 files changed, 910 insertions(+), 285 deletions(-)

--- a/zdev/include/device.h
+++ b/zdev/include/device.h
@@ -45,6 +45,7 @@ struct device_state {
  * @node: Node for adding this device to a list
  * @active: Device state in the active configuration
  * @persistent: Device state in the persistent configuration
+ * @autoconf: Auto-configured device state
  * @errors: A strlist of error and warning messages issued for the device
  * @processed: Device has been processed
  */
@@ -59,6 +60,7 @@ struct device {
 
 	struct device_state active;
 	struct device_state persistent;
+	struct device_state autoconf;
 
 	unsigned int processed:1;
 };
@@ -97,4 +99,6 @@ void device_list_print(struct device_lis
 struct setting_list *device_get_setting_list(struct device *dev,
 					     config_t config);
 
+config_t device_get_config(struct device *dev);
+
 #endif /* DEVICE_H */
--- a/zdev/include/misc.h
+++ b/zdev/include/misc.h
@@ -19,9 +19,14 @@
 #include "exit_code.h"
 
 #define ARRAY_SIZE(x)	(sizeof(x) / sizeof((x)[0]))
-#define	SCOPE_ACTIVE(x)		(((x) == config_active) || ((x) == config_all))
-#define	SCOPE_PERSISTENT(x)	(((x) == config_persistent) || \
-				 ((x) == config_all))
+#define SCOPE_ACTIVE(x)		((x) & config_active ? 1 : 0)
+#define SCOPE_PERSISTENT(x)	((x) & config_persistent ? 1 : 0)
+#define SCOPE_AUTOCONF(x)	((x) & config_autoconf ? 1 : 0)
+#define SCOPE_ALL(x)		((x) == (config_active | config_persistent |\
+					 config_autoconf))
+#define SCOPE_SINGLE(x)		((x) == config_active || \
+				 (x) == config_persistent || \
+				 (x) == config_autoconf)
 
 #define DELAY_INDENT	4
 
@@ -34,12 +39,15 @@
 
 #define EVEN(x)		(((x) & 1) == 0)
 
-/* Enumeration of configuration sets. */
-typedef enum {
-	config_active,
-	config_persistent,
-	config_all,
-} config_t;
+/* Enumeration of configuration sets. Multiple configuration sets can be
+ * combined using bit-wise or. */
+enum {
+	config_active = 1,
+	config_persistent = 2,
+	config_autoconf = 4,
+	config_all = 7,
+};
+typedef int config_t;
 
 typedef enum {
 	err_ignore,
@@ -167,7 +175,7 @@ exit_code_t misc_write_text_file(const c
 exit_code_t misc_write_text_file_retry(const char *, const char *, err_t);
 exit_code_t misc_mktemp(char **, int *);
 char *misc_readlink(const char *path);
-config_t get_config(int, int);
+config_t get_config(int act, int pers, int ac);
 bool is_zvm(void);
 bool is_terminal(void);
 const char *config_to_str(config_t);
--- a/zdev/include/path.h
+++ b/zdev/include/path.h
@@ -24,6 +24,7 @@
 #define PATH_CCW_BUS		"/sys/bus/ccw"
 #define PATH_CCWGROUP_BUS	"/sys/bus/ccwgroup"
 #define PATH_UDEV_RULES		"/etc/udev/rules.d"
+#define PATH_UDEV_RULES_VOLATILE "/run/udev/rules.d"
 #define	PATH_PROC		"/proc"
 
 #define PATH_UDEVADM		"udevadm"
@@ -55,8 +56,8 @@ char *path_get_ccw_device(const char *,
 char *path_get_ccw_devices(const char *);
 char *path_get_ccwgroup_device(const char *, const char *);
 char *path_get_ccwgroup_devices(const char *);
-char *path_get_udev_rule(const char *, const char *);
-char *path_get_udev_rules(void);
+char *path_get_udev_rule(const char *type, const char *id, bool vol);
+char *path_get_udev_rules(bool vol);
 char *path_get_proc(const char *);
 char *path_get_sys_bus_dev(const char *, const char *);
 char *path_get_sys_bus_drv(const char *, const char *);
--- a/zdev/include/setting.h
+++ b/zdev/include/setting.h
@@ -94,7 +94,8 @@ void setting_list_map_values(struct sett
 void setting_list_mark_default_derived(struct setting_list *);
 int setting_list_count_set(struct setting_list *);
 void setting_list_remove_derived(struct setting_list *);
-char *setting_get_changes(struct setting_list *, struct setting_list *);
+char *setting_get_changes(struct setting_list *act, struct setting_list *pers,
+			  struct setting_list *ac);
 bool setting_match_value(struct setting *, const char *);
 
 #endif /* SETTING_H */
--- a/zdev/include/subtype.h
+++ b/zdev/include/subtype.h
@@ -67,17 +67,22 @@ typedef exit_code_t (*subtype_cb_t)(stru
  *
  * @exists_active: Check if device exists in active configuration
  * @exists_persistent: Check if device exists in persistent configuration
+ * @exists_autoconf: Check if device exists in autoconf configuration
  *
  * @add_active_ids: Add IDs of all devices existing in active configuration to
  *                  specified strlist
  * @add_persistent_ids: Add IDs of all devices existing in persistent
  *                      configuration to specified strlist
+ * @add_autoconf_ids: Add IDs of all devices existing in autoconf
+ *                    configuration to specified strlist
  *
  * @read_active: Read device configuration from active configuration
  * @read_persistent: Read device configuration from persistent configuration
+ * @read_autoconf: Read device configuration from autoconf configuration
  *
  * @configure_active: Apply configuration to active configuration
  * @configure_persistent: Apply configuration to persistent configuration
+ * @configure_autoconf: Apply configuration to autoconf configuration
  *
  * @check_pre_write: Optional: Determine if the given configuration is valid
  *                   for the specified device. If not, emit warning messages
@@ -150,24 +155,33 @@ struct subtype {
 
 	bool		(*exists_active)(struct subtype *, const char *);
 	bool		(*exists_persistent)(struct subtype *, const char *);
+	bool		(*exists_autoconf)(struct subtype *, const char *);
 
 	void		(*add_active_ids)(struct subtype *, struct util_list *);
 	void		(*add_persistent_ids)(struct subtype *,
 					      struct util_list *);
+	void		(*add_autoconf_ids)(struct subtype *,
+					    struct util_list *);
 
 	exit_code_t	(*read_active)(struct subtype *, struct device *,
 				       read_scope_t);
 	exit_code_t	(*read_persistent)(struct subtype *, struct device *,
 					   read_scope_t);
+	exit_code_t	(*read_autoconf)(struct subtype *, struct device *,
+					 read_scope_t);
 
 	exit_code_t	(*configure_active)(struct subtype *, struct device *);
 	exit_code_t	(*configure_persistent)(struct subtype *,
 						struct device *);
+	exit_code_t	(*configure_autoconf)(struct subtype *,
+					      struct device *);
 
 	exit_code_t	(*deconfigure_active)(struct subtype *,
 					      struct device *);
 	exit_code_t	(*deconfigure_persistent)(struct subtype *,
 						  struct device *);
+	exit_code_t	(*deconfigure_autoconf)(struct subtype *,
+						struct device *);
 
 	exit_code_t	(*check_pre_configure)(struct subtype *,
 					       struct device *, int, config_t);
@@ -217,23 +231,31 @@ void subtype_exit(struct subtype *);
 
 bool subtype_device_exists_active(struct subtype *, const char *);
 bool subtype_device_exists_persistent(struct subtype *, const char *);
+bool subtype_device_exists_autoconf(struct subtype *st, const char *id);
 
 void subtype_add_active_ids(struct subtype *, struct util_list *);
 void subtype_add_persistent_ids(struct subtype *, struct util_list *);
+void subtype_add_autoconf_ids(struct subtype *st, struct util_list *ids);
 
 exit_code_t subtype_device_read_active(struct subtype *, struct device *,
 				       read_scope_t);
 exit_code_t subtype_device_read_persistent(struct subtype *, struct device *,
 					   read_scope_t);
+exit_code_t subtype_device_read_autoconf(struct subtype *st, struct device *dev,
+					 read_scope_t scope);
 
 exit_code_t subtype_device_configure_active(struct subtype *, struct device *);
 exit_code_t subtype_device_configure_persistent(struct subtype *,
 						struct device *);
+exit_code_t subtype_device_configure_autoconf(struct subtype *st,
+					      struct device *dev);
 
 exit_code_t subtype_device_deconfigure_active(struct subtype *,
 					      struct device *);
 exit_code_t subtype_device_deconfigure_persistent(struct subtype *st,
 						  struct device *);
+exit_code_t subtype_device_deconfigure_autoconf(struct subtype *st,
+						struct device *dev);
 
 exit_code_t subtype_check_pre_configure(struct subtype *, struct device *, int,
 					config_t);
--- a/zdev/include/udev.h
+++ b/zdev/include/udev.h
@@ -40,8 +40,9 @@ exit_code_t udev_read_file(const char *,
 void udev_free_file(struct udev_file *);
 void udev_file_print(struct udev_file *);
 
-void udev_get_device_ids(const char *, struct util_list *);
-exit_code_t udev_remove_rule(const char *, const char *);
+void udev_get_device_ids(const char *type, struct util_list *list,
+			 bool autoconf);
+exit_code_t udev_remove_rule(const char *type, const char *id, bool autoconf);
 
 void udev_settle(void);
 
--- a/zdev/include/udev_ccw.h
+++ b/zdev/include/udev_ccw.h
@@ -15,9 +15,9 @@
 
 struct device;
 
-bool udev_ccw_exists(const char *, const char *);
-exit_code_t udev_ccw_read_device(struct device *);
-exit_code_t udev_ccw_write_device(struct device *);
-exit_code_t udev_ccw_write_cio_ignore(const char *);
+bool udev_ccw_exists(const char *type, const char *id, bool autoconf);
+exit_code_t udev_ccw_read_device(struct device *dev, bool autoconf);
+exit_code_t udev_ccw_write_device(struct device *dev, bool autoconf);
+exit_code_t udev_ccw_write_cio_ignore(const char *id_list, bool autoconf);
 
 #endif /* UDEV_CCW_H */
--- a/zdev/include/udev_ccwgroup.h
+++ b/zdev/include/udev_ccwgroup.h
@@ -16,10 +16,12 @@
 struct device;
 struct util_list;
 
-bool udev_ccwgroup_exists(const char *, const char *);
-exit_code_t udev_ccwgroup_read_device(struct device *);
-exit_code_t udev_ccwgroup_write_device(struct device *);
-void udev_ccwgroup_add_device_ids(const char *, struct util_list *);
-exit_code_t udev_ccwgroup_remove_rule(const char *, const char *);
+bool udev_ccwgroup_exists(const char *type, const char *id, bool autoconf);
+exit_code_t udev_ccwgroup_read_device(struct device *dev, bool autoconf);
+exit_code_t udev_ccwgroup_write_device(struct device *dev, bool autoconf);
+void udev_ccwgroup_add_device_ids(const char *type, struct util_list *list,
+				  bool autoconf);
+exit_code_t udev_ccwgroup_remove_rule(const char *type, const char *id,
+				      bool autoconf);
 
 #endif /* UDEV_CCWGROUP_H */
--- a/zdev/include/udev_zfcp_lun.h
+++ b/zdev/include/udev_zfcp_lun.h
@@ -15,10 +15,10 @@
 
 struct device;
 
-void udev_zfcp_lun_add_device_ids(struct util_list *);
-bool udev_zfcp_lun_exists(const char *);
-exit_code_t udev_zfcp_lun_read_device(struct device *);
-exit_code_t udev_zfcp_lun_write_device(struct device *);
-exit_code_t udev_zfcp_lun_remove_rule(const char *);
+void udev_zfcp_lun_add_device_ids(struct util_list *list, bool autoconf);
+bool udev_zfcp_lun_exists(const char *id, bool autoconf);
+exit_code_t udev_zfcp_lun_read_device(struct device *dev, bool autoconf);
+exit_code_t udev_zfcp_lun_write_device(struct device *dev, bool autoconf);
+exit_code_t udev_zfcp_lun_remove_rule(const char *id, bool autoconf);
 
 #endif /* UDEV_ZFCP_LUN_H */
--- a/zdev/man/chzdev.8
+++ b/zdev/man/chzdev.8
@@ -428,8 +428,8 @@ using the \-\-import action like in the
 .B Note:
 By default all configuration data that is read is also applied. To reduce the
 scope of imported configuration data, you can select specific devices, a device
-type, or define whether only data for the active or persistent configuration
-should be imported.
+type, or define whether only data for the active, persistent or
+auto-configuration should be imported.
 .PP
 .
 .OD list-attributes "l" ""
@@ -472,6 +472,18 @@ on reboot, or when a device becomes unav
 unloaded.
 .PP
 .
+.OD auto-conf "" ""
+Apply changes to the auto-configuration only.
+
+This option is used internally to apply machine-provided I/O configuration data
+to a Linux system.
+
+.B Note:
+There is typically no need for users to specify this option directly.
+In particular, user-initiated changes to this configuration will be lost
+the next time that machine-provided data is obtained (i.e. during boot).
+.PP
+.
 .OD base "" "PATH" | "KEY" = "VALUE"
 Change file system paths used to access files.
 
--- a/zdev/man/lszdev.8
+++ b/zdev/man/lszdev.8
@@ -69,12 +69,13 @@ With no further options specified, the o
 .
 .
 .SS "Configurations"
-There are two sources for configuration information: the active configuration
-of the currently running system, and the persistent configuration stored in
-configuration files.
+There are three sources for configuration information: the active configuration
+of the currently running system, the persistent configuration stored in
+configuration files, and the auto-configuration that is provided by some
+machine types to automatically enable I/O devices.
 .PP
 By default lszdev displays information from both the active and the persistent
-configuration.
+configuration, and, if available, from the auto-configuration.
 .PP
 .
 .
@@ -319,6 +320,19 @@ Restricts output to information obtained
 is information from the running system.
 .PP
 .
+.OD auto-conf "" ""
+List information from the auto-configuration only.
+
+Restricts output to information obtained from the auto-configuration.
+The auto-configuration is the collection of configuration data obtained
+automatically on some machine models during boot.
+
+.B Note:
+This data is refreshed during each boot. Also configuration directives in
+the auto-configuration only take effect if there is no directive for the
+same device in the persistent configuration.
+.PP
+.
 .OD base "" "PATH" | "KEY" = "VALUE"
 Change file system paths used to access files.
 
--- a/zdev/src/ccw.c
+++ b/zdev/src/ccw.c
@@ -892,12 +892,13 @@ static exit_code_t collect_group_cb(stru
 }
 
 /* Set bits for all persistently configured CCW devices. */
-static char ***id_bitmap_collect(void)
+static char ***id_bitmap_collect(bool autoconf)
 {
 	char ***id_bitmap;
 	int i, j;
 	struct devtype *dt;
 	struct subtype *st;
+	config_t config = autoconf ? config_autoconf : config_persistent;
 
 	id_bitmap = id_bitmap_new();
 
@@ -906,14 +907,14 @@ static char ***id_bitmap_collect(void)
 		for (j = 0; (st = dt->subtypes[j]); j++) {
 			/* Collect CCW device IDs. */
 			if (st->namespace == &ccw_namespace) {
-				subtype_for_each_id(st, config_persistent,
+				subtype_for_each_id(st, config,
 						    collect_cb, id_bitmap);
 			}
 			/* Collect CCWGROUP device IDs. Since there may be
 			 * multiple namespaces, we need to make use of this
 			 * hack. */
 			if (ccwgroup_compatible_namespace(st->namespace)) {
-				subtype_for_each_id(st, config_persistent,
+				subtype_for_each_id(st, config,
 						    collect_group_cb,
 						    id_bitmap);
 			}
@@ -952,7 +953,7 @@ static void range_add(struct util_list *
 	free(f_str);
 }
 
-static struct util_list *cio_ignore_get_ranges(void)
+static struct util_list *cio_ignore_get_ranges(bool autoconf)
 {
 	char ***id_bitmap;
 	unsigned int cssid, ssid, devno;
@@ -962,7 +963,7 @@ static struct util_list *cio_ignore_get_
 
 	ranges = strlist_new();
 
-	id_bitmap = id_bitmap_collect();
+	id_bitmap = id_bitmap_collect(autoconf);
 	for (cssid = 0; cssid < CSSID_MAX; cssid++) {
 		if (!id_bitmap[cssid])
 			continue;
@@ -1003,24 +1004,34 @@ static struct util_list *cio_ignore_get_
 }
 
 /* Persistently configure cio_ignore. */
-exit_code_t ccw_blacklist_persist(void)
+static exit_code_t _ccw_blacklist_persist(bool autoconf)
 {
 	struct util_list *ranges;
 	char *id_list;
 	exit_code_t rc;
 
 	/* Get string to write to /proc/cio_ignore. */
-	ranges = cio_ignore_get_ranges();
+	ranges = cio_ignore_get_ranges(autoconf);
 	id_list = strlist_flatten(ranges, ",");
 	strlist_free(ranges);
 
 	/* Write udev rule to automatically write cio_ignore. */
-	rc = udev_ccw_write_cio_ignore(id_list);
+	rc = udev_ccw_write_cio_ignore(id_list, autoconf);
 	free(id_list);
 
 	return rc;
 }
 
+exit_code_t ccw_blacklist_persist(void)
+{
+	exit_code_t rc1, rc2;
+
+	rc1 = _ccw_blacklist_persist(false);
+	rc2 = _ccw_blacklist_persist(true);
+
+	return rc1 ? rc1 : rc2;
+}
+
 /*
  * CCW device ID namespace.
  */
@@ -1368,7 +1379,13 @@ static bool ccw_st_exists_active(struct
 /* Check if a configuration exists for a CCW device with the specified @id. */
 static bool ccw_st_exists_persistent(struct subtype *st, const char *id)
 {
-	return udev_ccw_exists(st->name, id);
+	return udev_ccw_exists(st->name, id, false);
+}
+
+/* Check if a configuration exists for a CCW device with the specified @id. */
+static bool ccw_st_exists_autoconf(struct subtype *st, const char *id)
+{
+	return udev_ccw_exists(st->name, id, true);
 }
 
 static bool get_ids_cb(const char *file, void *data)
@@ -1404,7 +1421,14 @@ static void ccw_st_add_active_ids(struct
  * to strlist @ids. */
 static void ccw_st_add_persistent_ids(struct subtype *st, struct util_list *ids)
 {
-	udev_get_device_ids(st->name, ids);
+	udev_get_device_ids(st->name, ids, false);
+}
+
+/* Add the IDs of all CCW devices for which a autoconf configuration exists
+ * to strlist @ids. */
+static void ccw_st_add_autoconf_ids(struct subtype *st, struct util_list *ids)
+{
+	udev_get_device_ids(st->name, ids, true);
 }
 
 /* Read the configuration of the CCW device with the specified @id from the
@@ -1440,7 +1464,16 @@ static exit_code_t ccw_st_read_persisten
 					  struct device *dev,
 					  read_scope_t scope)
 {
-	return udev_ccw_read_device(dev);
+	return udev_ccw_read_device(dev, false);
+}
+
+/* Read the configuration of the CCW device with the specified @id from the
+ * autoconf configuration and add the resulting data to @dev. */
+static exit_code_t ccw_st_read_autoconf(struct subtype *st,
+					  struct device *dev,
+					  read_scope_t scope)
+{
+	return udev_ccw_read_device(dev, true);
 }
 
 static int get_online(struct setting_list *list)
@@ -1505,7 +1538,14 @@ static exit_code_t ccw_st_configure_acti
 static exit_code_t ccw_st_configure_persistent(struct subtype *st,
 					       struct device *dev)
 {
-	return udev_ccw_write_device(dev);
+	return udev_ccw_write_device(dev, false);
+}
+
+/* Create a autoconf configuration for the specified device @dev. */
+static exit_code_t ccw_st_configure_autoconf(struct subtype *st,
+					       struct device *dev)
+{
+	return udev_ccw_write_device(dev, true);
 }
 
 
@@ -1552,7 +1592,22 @@ static exit_code_t ccw_st_deconfigure_ac
 static exit_code_t ccw_st_deconfigure_persistent(struct subtype *st,
 						 struct device *dev)
 {
-	return udev_remove_rule(st->name, dev->id);
+	return udev_remove_rule(st->name, dev->id, false);
+}
+
+/**
+ * ccw_st_deconfigure_autoconf - Deconfigure device in autoconf
+ *                               configuration set
+ * @st: Subtype of target device
+ * @dev: Target device
+ *
+ * Deconfigure device @dev in the autoconf configuration set. Return %EXIT_OK
+ * on success, an error code otherwise.
+ */
+static exit_code_t ccw_st_deconfigure_autoconf(struct subtype *st,
+						 struct device *dev)
+{
+	return udev_remove_rule(st->name, dev->id, true);
 }
 
 /* Perform basic sanity checks. */
@@ -1589,6 +1644,8 @@ static void ccw_st_online_set(struct sub
 		setting_list_apply(dev->active.settings, a, name, value);
 	if (SCOPE_PERSISTENT(config))
 		setting_list_apply(dev->persistent.settings, a, name, value);
+	if (SCOPE_AUTOCONF(config))
+		setting_list_apply(dev->autoconf.settings, a, name, value);
 }
 
 /* Determine the online state of the specified CCW device (0=offline, 1=online,
@@ -1596,14 +1653,16 @@ static void ccw_st_online_set(struct sub
 static int ccw_st_online_get(struct subtype *st, struct device *dev,
 			     config_t config)
 {
-	int act_online = 1, pers_online = 1;
+	int act_online = 1, pers_online = 1, auto_online = 1;
 
 	if (SCOPE_ACTIVE(config))
 		act_online = get_online(dev->active.settings);
 	if (SCOPE_PERSISTENT(config))
 		pers_online = get_online(dev->persistent.settings);
+	if (SCOPE_AUTOCONF(config))
+		auto_online = get_online(dev->autoconf.settings);
 
-	return MIN(act_online, pers_online);
+	return MIN(MIN(act_online, pers_online), auto_online);
 }
 
 /* Determine if the online state of the specified CCW device was specified */
@@ -1622,6 +1681,11 @@ static bool ccw_st_online_specified(stru
 		if (s && s->specified)
 			return true;
 	}
+	if (SCOPE_AUTOCONF(config) && dev->autoconf.settings) {
+		s = setting_list_find(dev->autoconf.settings, "online");
+		if (s && s->specified)
+			return true;
+	}
 
 	return false;
 }
@@ -1769,18 +1833,23 @@ struct subtype ccw_subtype = {
 
 	.exists_active		= &ccw_st_exists_active,
 	.exists_persistent	= &ccw_st_exists_persistent,
+	.exists_autoconf	= &ccw_st_exists_autoconf,
 
 	.add_active_ids		= &ccw_st_add_active_ids,
 	.add_persistent_ids	= &ccw_st_add_persistent_ids,
+	.add_autoconf_ids	= &ccw_st_add_autoconf_ids,
 
 	.read_active		= &ccw_st_read_active,
 	.read_persistent	= &ccw_st_read_persistent,
+	.read_autoconf		= &ccw_st_read_autoconf,
 
 	.configure_active	= &ccw_st_configure_active,
 	.configure_persistent	= &ccw_st_configure_persistent,
+	.configure_autoconf	= &ccw_st_configure_autoconf,
 
 	.deconfigure_active	= &ccw_st_deconfigure_active,
 	.deconfigure_persistent	= &ccw_st_deconfigure_persistent,
+	.deconfigure_autoconf	= &ccw_st_deconfigure_autoconf,
 
 	.check_pre_configure	= &ccw_st_check_pre_configure,
 
--- a/zdev/src/ccwgroup.c
+++ b/zdev/src/ccwgroup.c
@@ -426,6 +426,8 @@ static void ccwgroup_st_online_set(struc
 	}
 	if (SCOPE_PERSISTENT(config))
 		setting_list_apply(dev->persistent.settings, a, name, value);
+	if (SCOPE_AUTOCONF(config))
+		setting_list_apply(dev->autoconf.settings, a, name, value);
 }
 
 static int get_online(struct setting_list *list)
@@ -446,18 +448,20 @@ static int get_online(struct setting_lis
 }
 
 /* Return -1 if online state is not configured, 0 for offline and 1 for online.
- * If multiple configurations are specified, return the minimum of both. */
+ * If multiple configurations are specified, return the minimum of all. */
 static int ccwgroup_st_online_get(struct subtype *st, struct device *dev,
 				  config_t config)
 {
-	int act_online = 1, pers_online = 1;
+	int act_online = 1, pers_online = 1, auto_online = 1;
 
 	if (SCOPE_ACTIVE(config))
 		act_online = get_online(dev->active.settings);
 	if (SCOPE_PERSISTENT(config))
 		pers_online = get_online(dev->persistent.settings);
+	if (SCOPE_AUTOCONF(config))
+		auto_online = get_online(dev->autoconf.settings);
 
-	return MIN(act_online, pers_online);
+	return MIN(MIN(act_online, pers_online), auto_online);
 }
 
 /* Determine if the online state of the specified device was modified. */
@@ -476,6 +480,11 @@ static bool ccwgroup_st_online_specified
 		if (s && s->specified)
 			return true;
 	}
+	if (SCOPE_AUTOCONF(config) && dev->autoconf.settings) {
+		s = setting_list_find(dev->autoconf.settings, "online");
+		if (s && s->specified)
+			return true;
+	}
 
 	return false;
 }
@@ -682,7 +691,18 @@ static exit_code_t ccwgroup_st_read_pers
 
 	expand_id(data->ccwgroupdrv, dev);
 
-	return udev_ccwgroup_read_device(dev);
+	return udev_ccwgroup_read_device(dev, false);
+}
+
+static exit_code_t ccwgroup_st_read_autoconf(struct subtype *st,
+					     struct device *dev,
+					     read_scope_t scope)
+{
+	struct ccwgroup_subtype_data *data = st->data;
+
+	expand_id(data->ccwgroupdrv, dev);
+
+	return udev_ccwgroup_read_device(dev, true);
 }
 
 static exit_code_t ccwgroup_st_configure_active(struct subtype *st,
@@ -693,8 +713,9 @@ static exit_code_t ccwgroup_st_configure
 	return device_write_active_settings(dev);
 }
 
-static exit_code_t ccwgroup_st_configure_persistent(struct subtype *st,
-						    struct device *dev)
+static exit_code_t _ccwgroup_st_configure_persistent(struct subtype *st,
+						     struct device *dev,
+						     bool autoconf)
 {
 	struct ccwgroup_subtype_data *data = st->data;
 	struct ccwgroup_devid *devid = dev->devid;
@@ -703,9 +724,22 @@ static exit_code_t ccwgroup_st_configure
 		delayed_err("Incomplete device ID specified\n");
 		return EXIT_INCOMPLETE_ID;
 	}
-	return udev_ccwgroup_write_device(dev);
+	return udev_ccwgroup_write_device(dev, autoconf);
+}
+
+static exit_code_t ccwgroup_st_configure_persistent(struct subtype *st,
+						    struct device *dev)
+{
+	return _ccwgroup_st_configure_persistent(st, dev, false);
+}
+
+static exit_code_t ccwgroup_st_configure_autoconf(struct subtype *st,
+						    struct device *dev)
+{
+	return _ccwgroup_st_configure_persistent(st, dev, true);
 }
 
+
 static char *ccwgroup_st_get_active_attrib_path(struct subtype *,
 						struct device *, const char *);
 
@@ -733,7 +767,13 @@ static exit_code_t ccwgroup_st_deconfigu
 static exit_code_t ccwgroup_st_deconfigure_persistent(struct subtype *st,
 						      struct device *dev)
 {
-	return udev_ccwgroup_remove_rule(st->name, dev->id);
+	return udev_ccwgroup_remove_rule(st->name, dev->id, false);
+}
+
+static exit_code_t ccwgroup_st_deconfigure_autoconf(struct subtype *st,
+						    struct device *dev)
+{
+	return udev_ccwgroup_remove_rule(st->name, dev->id, true);
 }
 
 /* Check if a CCWGROUP device with the specified ID exists. */
@@ -774,7 +814,12 @@ static bool ccwgroup_st_exists_active(st
 
 static bool ccwgroup_st_exists_persistent(struct subtype *st, const char *id)
 {
-	return udev_ccwgroup_exists(st->name, id);
+	return udev_ccwgroup_exists(st->name, id, false);
+}
+
+static bool ccwgroup_st_exists_autoconf(struct subtype *st, const char *id)
+{
+	return udev_ccwgroup_exists(st->name, id, true);
 }
 
 int ccwgroup_qsort_cmp(const void *a_ptr, const void *b_ptr)
@@ -796,7 +841,13 @@ static void ccwgroup_st_add_active_ids(s
 static void ccwgroup_st_add_persistent_ids(struct subtype *st,
 					   struct util_list *ids)
 {
-	udev_ccwgroup_add_device_ids(st->name, ids);
+	udev_ccwgroup_add_device_ids(st->name, ids, false);
+}
+
+static void ccwgroup_st_add_autoconf_ids(struct subtype *st,
+					 struct util_list *ids)
+{
+	udev_ccwgroup_add_device_ids(st->name, ids, true);
 }
 
 /* Check if CCW device ID @b is part of CCW group device ID @a. */
@@ -1185,18 +1236,23 @@ struct subtype ccwgroup_subtype = {
 
 	.exists_active		= &ccwgroup_st_exists_active,
 	.exists_persistent	= &ccwgroup_st_exists_persistent,
+	.exists_autoconf	= &ccwgroup_st_exists_autoconf,
 
 	.add_active_ids		= &ccwgroup_st_add_active_ids,
 	.add_persistent_ids	= &ccwgroup_st_add_persistent_ids,
+	.add_autoconf_ids	= &ccwgroup_st_add_autoconf_ids,
 
 	.read_active		= &ccwgroup_st_read_active,
 	.read_persistent	= &ccwgroup_st_read_persistent,
+	.read_autoconf		= &ccwgroup_st_read_autoconf,
 
 	.configure_active	= &ccwgroup_st_configure_active,
 	.configure_persistent	= &ccwgroup_st_configure_persistent,
+	.configure_autoconf	= &ccwgroup_st_configure_autoconf,
 
 	.deconfigure_active	= &ccwgroup_st_deconfigure_active,
 	.deconfigure_persistent	= &ccwgroup_st_deconfigure_persistent,
+	.deconfigure_autoconf	= &ccwgroup_st_deconfigure_autoconf,
 
 	.online_set		= &ccwgroup_st_online_set,
 	.online_get		= &ccwgroup_st_online_get,
--- a/zdev/src/chzdev.c
+++ b/zdev/src/chzdev.c
@@ -86,6 +86,7 @@ struct options {
 	config_t config;
 	unsigned int active:1;
 	unsigned int persistent:1;
+	unsigned int auto_conf:1;
 	struct util_list *remove;	/* List of struct strlist_node */
 	unsigned int remove_all:1;
 	unsigned int force:1;
@@ -138,6 +139,7 @@ enum {
 	OPT_VERBOSE		= 'V',
 	OPT_QUIET		= 'q',
 	OPT_NO_SETTLE		= (OPT_ANONYMOUS_BASE+__COUNTER__),
+	OPT_AUTO_CONF		= (OPT_ANONYMOUS_BASE+__COUNTER__),
 };
 
 static struct opts_conflict conflict_list[] = {
@@ -172,11 +174,13 @@ static struct opts_conflict conflict_lis
 	OPTS_CONFLICT(OPT_APPLY,
 		      OPT_DECONFIGURE, OPT_LIST_ATTRIBS, OPT_HELP_ATTRIBS,
 		      OPT_LIST_TYPES, OPT_EXPORT, OPT_IMPORT, OPT_REMOVE,
-		      OPT_REMOVE_ALL, OPT_ACTIVE, OPT_PERSISTENT, 0),
+		      OPT_REMOVE_ALL, OPT_ACTIVE, 0),
 	OPTS_CONFLICT(OPT_ONLINE,
 		      OPT_OFFLINE),
 	OPTS_CONFLICT(OPT_QUIET,
 		      OPT_VERBOSE),
+	OPTS_CONFLICT(OPT_AUTO_CONF,
+		      OPT_TYPE, OPT_LIST_ATTRIBS, OPT_LIST_TYPES),
 	OPTS_CONFLICT(0, 0),
 };
 
@@ -210,6 +214,7 @@ static const struct option opt_list[] =
 	/* Options. */
 	{ "active",		no_argument,	NULL, OPT_ACTIVE },
 	{ "persistent",		no_argument,	NULL, OPT_PERSISTENT },
+	{ "auto-conf",		no_argument,	NULL, OPT_AUTO_CONF },
 	{ "remove",		required_argument, NULL, OPT_REMOVE },
 	{ "remove-all",		no_argument,	NULL, OPT_REMOVE_ALL },
 	{ "force",		no_argument,	NULL, OPT_FORCE },
@@ -883,6 +888,11 @@ static exit_code_t parse_options(struct
 			opts->persistent = 1;
 			break;
 
+		case OPT_AUTO_CONF:
+			/* --auto-conf */
+			opts->auto_conf = 1;
+			break;
+
 		case OPT_REMOVE:
 			/* --remove ATTRIB */
 			strlist_add(opts->remove, "%s", optarg);
@@ -977,7 +987,13 @@ static exit_code_t parse_options(struct
 		goto out;
 
 	/* Determine configuration set. */
-	opts->config = get_config(opts->active, opts->persistent);
+	if (!opts->active && !opts->persistent && !opts->auto_conf) {
+		/* Default configuration targets are active + persistent */
+		opts->config = config_active | config_persistent;
+	} else {
+		opts->config = get_config(opts->active, opts->persistent,
+					  opts->auto_conf);
+	}
 
 	/* Handle positional parameters. */
 	rc = parse_positional(opts, argc, argv, optind);
@@ -1049,13 +1065,15 @@ static void remove_all_settings(struct s
 /* Perform --remove-all operation for specified config on device. */
 static exit_code_t device_remove_all(struct device *dev, config_t config)
 {
-	int active, persistent;
+	int active, persistent, autoconf;
 
 	active = SCOPE_ACTIVE(config) ?
 			count_removable(dev->active.settings, 1) : 0;
 	persistent = SCOPE_PERSISTENT(config) ?
 			count_removable(dev->persistent.settings, 0) : 0;
-	if (active == 0 && persistent == 0) {
+	autoconf = SCOPE_AUTOCONF(config) ?
+			count_removable(dev->autoconf.settings, 0) : 0;
+	if (active == 0 && persistent == 0 && autoconf == 0) {
 		delayed_err("No removable settings found\n");
 		return EXIT_SETTING_NOT_FOUND;
 	}
@@ -1063,6 +1081,8 @@ static exit_code_t device_remove_all(str
 		remove_all_settings(dev->active.settings, 1);
 	if (persistent)
 		remove_all_settings(dev->persistent.settings, 0);
+	if (autoconf)
+		remove_all_settings(dev->autoconf.settings, 0);
 
 	return EXIT_OK;
 }
@@ -1132,6 +1152,13 @@ static exit_code_t device_remove_setting
 			goto out;
 	}
 
+	if (SCOPE_AUTOCONF(config)) {
+		rc = remove_settings(dev->autoconf.settings, names, found,
+				     notfound, 0);
+		if (rc)
+			goto out;
+	}
+
 	if (!util_list_is_empty(notfound)) {
 		flat = strlist_flatten(notfound, " ");
 		delayed_err("Setting not found: %s\n", flat);
@@ -1199,7 +1226,8 @@ static void print_dev_config_info(struct
 
 	changes = setting_get_changes(
 		  SCOPE_ACTIVE(config) ? dev->active.settings : NULL,
-		  SCOPE_PERSISTENT(config) ? dev->persistent.settings : NULL);
+		  SCOPE_PERSISTENT(config) ? dev->persistent.settings : NULL,
+		  SCOPE_AUTOCONF(config) ? dev->autoconf.settings : NULL);
 	if (changes)
 		info("    Changes: %s\n", changes);
 	free(changes);
@@ -1257,6 +1285,12 @@ static exit_code_t cfg_mod_existence(str
 		dev->persistent.modified = 1;
 	}
 
+	/* Create autoconf config if necessary. */
+	if (SCOPE_AUTOCONF(config) && !dev->autoconf.exists) {
+		dev->autoconf.exists = 1;
+		dev->autoconf.modified = 1;
+	}
+
 	return EXIT_OK;
 }
 
@@ -1296,11 +1330,14 @@ online:
 	/* Make sure there's an online attribute. */
 	ensure_online(dev, config_active);
 	ensure_online(dev, config_persistent);
+	ensure_online(dev, config_autoconf);
 
 mand:
 	/* Ensure default values for mandatory attributes. */
 	setting_list_apply_defaults(dev->persistent.settings,
 				    dev->subtype->dev_attribs, true);
+	setting_list_apply_defaults(dev->autoconf.settings,
+				    dev->subtype->dev_attribs, true);
 
 	return EXIT_OK;
 }
@@ -1336,7 +1373,8 @@ static exit_code_t cfg_write(struct devi
 	if (!device_needs_writing(dev, config) && !force)
 		goto out;
 
-	if (check_active && config == config_persistent &&
+	if (check_active && !SCOPE_ACTIVE(config) &&
+	    (SCOPE_PERSISTENT(config) || SCOPE_AUTOCONF(config)) &&
 	    (!dev->active.exists && !dev->active.definable)) {
 		rc = handle_nonexistent(dev);
 		if (rc)
@@ -1377,7 +1415,7 @@ static exit_code_t cfg_configure(struct
 	if (proc_ptr)
 		*proc_ptr = 0;
 
-	/* Read current device data. Note that we read data from both
+	/* Read current device data. Note that we read data from all
 	 * configurations to enable QETH autodetection and subtype
 	 * detection (e.g. dasd -> dasd_fba).*/
 	dev = NULL;
@@ -1398,23 +1436,17 @@ static exit_code_t cfg_configure(struct
 
 	/* Exit here if we're only trying and device cannot be configured. */
 	if (try && !(dev->active.exists || dev->active.definable ||
-		     dev->persistent.exists)) {
+		     dev->persistent.exists || dev->autoconf.exists)) {
 		return EXIT_DEVICE_NOT_FOUND;
 	}
 
-	if (config == config_persistent) {
-		/* Abort if a modification action is triggered for a
-		 * non-existing persistent device. */
-		if (!dev->persistent.exists &&
-		    (!util_list_is_empty(opts->remove) || opts->remove_all))
-			return EXIT_DEVICE_NOT_FOUND;
+	/* Create device if needed by action. */
+	if (opts->enable || !util_list_is_empty(opts->settings)) {
+		rc = cfg_mod_existence(dev, config);
+		if (rc)
+			return rc;
 	}
 
-	/* Apply changes to device existence. */
-	rc = cfg_mod_existence(dev, config);
-	if (rc)
-		return rc;
-
 	/* Apply changes to device settings. */
 	rc = cfg_mod_settings(dev, opts, prereq);
 	if (rc)
@@ -1426,10 +1458,12 @@ static exit_code_t cfg_configure(struct
 
 /* Apply persistent configuration to active configuration. */
 static exit_code_t cfg_apply(struct subtype *st, const char *id, int prereq,
-			     struct device **dev_ptr, int *proc_ptr)
+			     struct device **dev_ptr, int *proc_ptr,
+			     bool autoconf)
 {
 	exit_code_t rc;
 	struct device *dev;
+	struct device_state *state;
 
 	/* Reset processed flag. */
 	if (proc_ptr)
@@ -1452,8 +1486,9 @@ static exit_code_t cfg_apply(struct subt
 		*proc_ptr = 1;
 	dev->processed = 1;
 
+	state = autoconf ? &dev->autoconf : &dev->persistent;
 	/* Exit here if there is no persistent configuration. */
-	if (!dev->persistent.exists)
+	if (!state->exists)
 		return EXIT_NO_DATA;
 
 	/* Apply changes to device existence. */
@@ -1462,8 +1497,7 @@ static exit_code_t cfg_apply(struct subt
 		return rc;
 
 	/* Copy persistent settings to active configuration. */
-	rc = device_apply_settings(dev, config_active,
-				   &dev->persistent.settings->list);
+	rc = device_apply_settings(dev, config_active, &state->settings->list);
 	if (rc)
 		return rc;
 
@@ -1477,7 +1511,8 @@ static exit_code_t cfg_import(struct sub
 			      struct device **dev_ptr, int *proc_ptr)
 {
 	exit_code_t rc;
-	struct setting_list *active = NULL, *persistent = NULL;
+	struct setting_list *active = NULL, *persistent = NULL,
+			    *autoconf = NULL;
 	struct device *dev;
 
 	/* Reset processed flag. */
@@ -1495,6 +1530,7 @@ static exit_code_t cfg_import(struct sub
 			return EXIT_OK;
 		active = setting_list_copy(dev->active.settings);
 		persistent = setting_list_copy(dev->persistent.settings);
+		autoconf = setting_list_copy(dev->autoconf.settings);
 	} else if (!prereq) {
 		/* Should not happen. */
 		return EXIT_OK;
@@ -1524,14 +1560,20 @@ static exit_code_t cfg_import(struct sub
 					   &persistent->list);
 		if (rc)
 			goto out;
+		rc = device_apply_settings(dev, config_autoconf,
+					   &autoconf->list);
+		if (rc)
+			goto out;
 	}
 	ensure_online(dev, config_active);
 	ensure_online(dev, config_persistent);
+	ensure_online(dev, config_autoconf);
 
 	/* Write resulting device data. */
 	rc = cfg_write(dev, prereq, config, 0);
 
 out:
+	setting_list_free(autoconf);
 	setting_list_free(persistent);
 	setting_list_free(active);
 
@@ -1609,11 +1651,13 @@ static exit_code_t print_config_result(s
 	if (opts->deconfigure) {
 		op = "deconfigure";
 		verb = "deconfigured";
-		if (dev)
+		if (dev) {
 			already = !dev->active.modified &&
-				  !dev->persistent.modified;
-		else if (rc == EXIT_DEVICE_NOT_FOUND &&
-			 config == config_persistent) {
+				  !dev->persistent.modified &&
+				  !dev->autoconf.modified;
+		} else if (rc == EXIT_DEVICE_NOT_FOUND &&
+			 (!SCOPE_ACTIVE(config) && (SCOPE_PERSISTENT(config) ||
+			  SCOPE_AUTOCONF(config)))) {
 			rc = EXIT_OK;
 			already = 1;
 		}
@@ -1685,9 +1729,10 @@ static exit_code_t cfg_prereqs(struct su
 	prereqs = selected_dev_list_new();
 	subtype_add_prereqs(st, id, prereqs);
 	util_list_iterate(prereqs, sel) {
-		if (opts->apply)
-			rc = cfg_apply(sel->st, sel->id, 1, &dev, &proc);
-		else if (opts->import) {
+		if (opts->apply) {
+			rc = cfg_apply(sel->st, sel->id, 1, &dev, &proc,
+				       opts->auto_conf);
+		} else if (opts->import) {
 			rc = cfg_import(sel->st, sel->id, config, 1, &dev,
 					&proc);
 		} else {
@@ -1760,9 +1805,11 @@ static exit_code_t configure_devices(str
 	struct namespace *ns;
 	const char *param;
 	struct device *dev;
+	config_t config = opts->config;
 
 	/* Determine list of selected devices. */
-	if (opts->config == config_persistent ||
+	if ((!SCOPE_ACTIVE(config) &&
+	    (SCOPE_PERSISTENT(config) || SCOPE_AUTOCONF(config))) ||
 	    (opts->select->subtype && opts->select->subtype->support_definable))
 		existing = 0;
 	else
@@ -1808,9 +1855,10 @@ static exit_code_t configure_devices(str
 			goto next;
 
 		/* Configure actual target device. */
-		if (opts->apply)
-			rc = cfg_apply(sel->st, sel->id, 0, &dev, &proc);
-		else {
+		if (opts->apply) {
+			rc = cfg_apply(sel->st, sel->id, 0, &dev, &proc,
+				       opts->auto_conf);
+		} else {
 			rc = cfg_configure(sel->st, sel->id, opts, 0,
 					   0, &dev, &proc);
 		}
@@ -1906,7 +1954,7 @@ static exit_code_t deconfigure_one_devic
 	dev->processed = 1;
 
 	if (try && !(dev->active.exists || dev->active.definable ||
-		     dev->persistent.exists)) {
+		     dev->persistent.exists || dev->autoconf.exists)) {
 		/* Attempt to deconfigure this device will fail. */
 		return EXIT_DEVICE_NOT_FOUND;
 	}
@@ -1916,7 +1964,8 @@ static exit_code_t deconfigure_one_devic
 	 * dev. */
 	if (SCOPE_ACTIVE(config) &&
 	    !(dev->active.exists || dev->active.definable)) {
-		if (!SCOPE_PERSISTENT(config) || !dev->persistent.exists)
+		if (!((SCOPE_PERSISTENT(config) && dev->persistent.exists) ||
+		      (SCOPE_AUTOCONF(config) && dev->autoconf.exists)))
 			return EXIT_DEVICE_NOT_FOUND;
 	}
 
@@ -1940,7 +1989,12 @@ static exit_code_t deconfigure_one_devic
 		dev->persistent.deconfigured = 1;
 		dev->persistent.modified = 1;
 	}
-	if (!dev->active.modified && !dev->persistent.modified)
+	if (SCOPE_AUTOCONF(config) && dev->autoconf.exists) {
+		dev->autoconf.deconfigured = 1;
+		dev->autoconf.modified = 1;
+	}
+	if (!dev->active.modified && !dev->persistent.modified &&
+	    !dev->autoconf.modified)
 		return EXIT_OK;
 
 	/* Pre-write check. */
@@ -2084,7 +2138,8 @@ static void print_type_config_info(struc
 
 	changes = setting_get_changes(
 		  SCOPE_ACTIVE(config) ? dt->active_settings : NULL,
-		  SCOPE_PERSISTENT(config) ? dt->persistent_settings : NULL);
+		  SCOPE_PERSISTENT(config) ? dt->persistent_settings : NULL,
+		  NULL);
 	if (changes)
 		info("    %s: %s\n", title, changes);
 	free(changes);
@@ -2498,6 +2553,8 @@ static void action_note(const char *msg,
 		info("%s the active configuration only\n", msg);
 	else if (config == config_persistent)
 		info("%s the persistent configuration only\n", msg);
+	else if (config == config_autoconf)
+		info("%s the auto-configuration only\n", msg);
 }
 
 /* Export configuration of selected devices and/or device type to file. */
@@ -2619,7 +2676,7 @@ static exit_code_t import_device(struct
 	struct subtype *st = dev->subtype;
 	exit_code_t rc;
 	config_t config;
-	int proc = 0, active, persistent;
+	int proc = 0, active, persistent, autoconf;
 
 	if (SCOPE_ACTIVE(opts->config))
 		active = (dev->active.exists || dev->active.definable);
@@ -2629,7 +2686,16 @@ static exit_code_t import_device(struct
 		persistent = dev->persistent.exists;
 	else
 		persistent = 0;
-	config = get_config(active, persistent);
+	if (SCOPE_AUTOCONF(opts->config))
+		autoconf = dev->autoconf.exists;
+	else
+		autoconf = 0;
+
+	if (!active && !persistent && !autoconf) {
+		/* Nothing to import */
+		return EXIT_OK;
+	}
+	config = get_config(active, persistent, autoconf);
 
 	/* First check for prerequisite devices that need to be configured. */
 	rc = cfg_prereqs(st, dev->id, opts, config, 0);
@@ -2656,17 +2722,9 @@ static bool import_device_selected(struc
 	if (!select_opts_dev_specified(select))
 		return false;
 
-	/* --active */
-	if (opts->config == config_active) {
-		if (!dev->active.exists && !dev->active.definable)
-			return false;
-	}
-
-	/* --persistent */
-	if (opts->config == config_persistent) {
-		if (!dev->persistent.exists)
-			return false;
-	}
+	/* Target configuration */
+	if ((device_get_config(dev) & opts->config) == 0)
+		return false;
 
 	/* Devtype */
 	if (select->devtype && dt != select->devtype)
--- a/zdev/src/chzdev_usage.txt
+++ b/zdev/src/chzdev_usage.txt
@@ -55,5 +55,6 @@ OPTIONS
       --dry-run          Display changes without applying
       --base PATH        Use PATH as base for accessing files
       --no-settle        Do not wait for udev to settle
+      --auto-conf        Apply changes to auto-configuration only
   -V, --verbose          Print additional run-time information
   -q, --quiet            Print only minimal run-time information
--- a/zdev/src/dasd.c
+++ b/zdev/src/dasd.c
@@ -316,34 +316,34 @@ static struct attrib dasd_attr_safe_offl
  * DASD subtype methods.
  */
 
-/* Check if use_diag setting can be correctly applied. */
-static exit_code_t check_use_diag(struct device *dev, config_t config)
+static bool _check_use_diag(struct setting_list *list)
 {
 	struct setting *u;
-	int zvm = is_zvm();
 
-	if (SCOPE_ACTIVE(config)) {
-		u = setting_list_find(dev->active.settings,
-				      dasd_attr_use_diag.name);
-		if (u && u->modified) {
-			if (u->value && atoi(u->value) == 1 && !zvm) {
-				delayed_warn("Cannot set 'use_diag=1' on "
-					     "non-z/VM system\n");
-				return EXIT_INVALID_CONFIG;
-			}
-		}
-	}
-	if (SCOPE_PERSISTENT(config)) {
-		u = setting_list_find(dev->persistent.settings,
-				      dasd_attr_use_diag.name);
-		if (u && u->modified) {
-			if (u->value && atoi(u->value) == 1 && !zvm) {
-				delayed_warn("Cannot set 'use_diag=1' on "
-					     "non-z/VM system\n");
-				return EXIT_INVALID_CONFIG;
-			}
+	u = setting_list_find(list, dasd_attr_use_diag.name);
+	if (u && u->modified) {
+		if (u->value && atoi(u->value) == 1) {
+			delayed_warn("Cannot set 'use_diag=1' on non-z/VM system\n");
+			return false;
 		}
 	}
+	return true;
+}
+
+/* Check if use_diag setting can be correctly applied. */
+static exit_code_t check_use_diag(struct device *dev, config_t config)
+{
+	if (is_zvm())
+		return EXIT_OK;
+
+	if (SCOPE_ACTIVE(config) && !_check_use_diag(dev->active.settings))
+		return EXIT_INVALID_CONFIG;
+	if (SCOPE_PERSISTENT(config) &&
+	    !_check_use_diag(dev->persistent.settings))
+		return EXIT_INVALID_CONFIG;
+	if (SCOPE_AUTOCONF(config) &&
+	    !_check_use_diag(dev->autoconf.settings))
+		return EXIT_INVALID_CONFIG;
 
 	return EXIT_OK;
 }
@@ -376,6 +376,8 @@ static void dasd_st_add_modules(struct s
 				    dasd_attr_use_diag.name, &changed, &aset);
 	setting_list_get_bool_state(dev->persistent.settings,
 				    dasd_attr_use_diag.name, &changed, &pset);
+	setting_list_get_bool_state(dev->autoconf.settings,
+				    dasd_attr_use_diag.name, &changed, &pset);
 
 	if (aset || pset)
 		strlist_add_unique(modules, DASD_DIAG_MOD_NAME);
--- a/zdev/src/device.c
+++ b/zdev/src/device.c
@@ -40,6 +40,7 @@ struct device *device_new(struct subtype
 
 	dev->active.settings = setting_list_new();
 	dev->persistent.settings = setting_list_new();
+	dev->autoconf.settings = setting_list_new();
 
 	return dev;
 }
@@ -53,6 +54,7 @@ void device_free(struct device *dev)
 	free(dev->devid);
 	setting_list_free(dev->active.settings);
 	setting_list_free(dev->persistent.settings);
+	setting_list_free(dev->autoconf.settings);
 	free(dev);
 }
 
@@ -83,6 +85,15 @@ void device_print(struct device *dev, in
 		setting_list_print(dev->persistent.settings, level + 8);
 	else
 		printf("%*s<none>\n", level + 8, "");
+
+	printf("%*sautoconf:\n", level + 4, "");
+	printf("%*sexists=%d mod=%d deconf=%d\n",
+	       level + 8, "", dev->autoconf.exists, dev->autoconf.modified,
+	       dev->autoconf.deconfigured);
+	if (dev->autoconf.settings)
+		setting_list_print(dev->autoconf.settings, level + 8);
+	else
+		printf("%*s<none>\n", level + 8, "");
 }
 
 static const void *device_hash_get_id(void *dev_ptr)
@@ -182,6 +193,10 @@ bool device_needs_writing(struct device
 	    (dev->persistent.modified || dev->persistent.deconfigured ||
 	     setting_list_modified(dev->persistent.settings)))
 		return true;
+	if (SCOPE_AUTOCONF(config) &&
+	    (dev->autoconf.modified || dev->autoconf.deconfigured ||
+	     setting_list_modified(dev->autoconf.settings)))
+		return true;
 
 	return false;
 }
@@ -204,6 +219,8 @@ static exit_code_t apply_setting(struct
 		/* Check for activeonly. */
 		if (!force && SCOPE_PERSISTENT(config) && a->activeonly)
 			goto err_activeonly_forceable;
+		if (!force && SCOPE_AUTOCONF(config) && a->activeonly)
+			goto err_activeonly_forceable;
 		/* Check for multiple values. */
 		if (!force && !a->multi && strlist_find(processed, key))
 			goto err_multi_forceable;
@@ -231,8 +248,15 @@ static exit_code_t apply_setting(struct
 					     a, key, value);
 	}
 
+	/* Apply to autoconf config. */
+	if (SCOPE_AUTOCONF(config)) {
+		setting_list_apply_specified(dev->autoconf.settings,
+					     a, key, value);
+	}
+
 	/* Additional warning when trying to persist read-only setting. */
-	if (config == config_persistent) {
+	if (!SCOPE_ACTIVE(config) && (SCOPE_PERSISTENT(config) ||
+				      SCOPE_AUTOCONF(config))) {
 		s = setting_list_find(dev->active.settings, key);
 		if (s && s->readonly)
 			warn_readonly = true;
@@ -341,6 +365,8 @@ void device_reset(struct device *dev, co
 		reset_device_state(&dev->active);
 	if (SCOPE_PERSISTENT(config))
 		reset_device_state(&dev->persistent);
+	if (SCOPE_AUTOCONF(config))
+		reset_device_state(&dev->autoconf);
 	dev->processed = 0;
 }
 
@@ -567,6 +593,12 @@ exit_code_t device_check_settings(struct
 						 err))
 			return EXIT_INVALID_CONFIG;
 	}
+	if (SCOPE_AUTOCONF(config)) {
+		if (!setting_list_check_conflict(dev->autoconf.settings,
+						 config_autoconf,
+						 err))
+			return EXIT_INVALID_CONFIG;
+	}
 
 	return EXIT_OK;
 }
@@ -578,8 +610,27 @@ struct setting_list *device_get_setting_
 
 	if (config == config_active)
 		settings = dev->active.settings;
-	else
+	else if (config == config_persistent)
 		settings = dev->persistent.settings;
+	else if (config == config_autoconf)
+		settings = dev->autoconf.settings;
 
 	return settings;
 }
+
+/* Return configuration set in which device exists. */
+config_t device_get_config(struct device *dev)
+{
+	config_t config = 0;
+
+	if (dev->active.exists || dev->active.definable)
+		config |= config_active;
+
+	if (dev->persistent.exists)
+		config |= config_persistent;
+
+	if (dev->autoconf.exists)
+		config |= config_autoconf;
+
+	return config;
+}
--- a/zdev/src/export.c
+++ b/zdev/src/export.c
@@ -83,7 +83,7 @@ static bool is_exportable(struct setting
 			return true;
 		}
 	}
-	if (SCOPE_PERSISTENT(config)) {
+	if (SCOPE_PERSISTENT(config) || SCOPE_AUTOCONF(config)) {
 		if (setting_is_set(s))
 			return true;
 	}
@@ -148,10 +148,9 @@ static int count_exportable(struct devic
 	struct setting *s;
 	int count;
 
-	if (config == config_active)
-		list = dev->active.settings;
-	else
-		list = dev->persistent.settings;
+	list = device_get_setting_list(dev, config);
+	if (!list)
+		return 0;
 	count = 0;
 
 	util_list_iterate(&list->list, s) {
@@ -169,12 +168,26 @@ exit_code_t export_write_device(FILE *fd
 	exit_code_t rc;
 	struct setting_list *settings;
 
-	if (config == config_all) {
-		rc = export_write_device(fd, dev, config_active, first_ptr);
-		if (rc)
-			return rc;
-		return export_write_device(fd, dev, config_persistent,
-					   first_ptr);
+	if (!SCOPE_SINGLE(config)) {
+		if (SCOPE_ACTIVE(config)) {
+			rc = export_write_device(fd, dev, config_active,
+						 first_ptr);
+			if (rc)
+				return rc;
+		}
+		if (SCOPE_PERSISTENT(config)) {
+			rc = export_write_device(fd, dev, config_persistent,
+						 first_ptr);
+			if (rc)
+				return rc;
+		}
+		if (SCOPE_AUTOCONF(config)) {
+			rc = export_write_device(fd, dev, config_autoconf,
+						 first_ptr);
+			if (rc)
+				return rc;
+		}
+		return EXIT_OK;
 	}
 
 	if (config == config_active) {
@@ -185,10 +198,14 @@ exit_code_t export_write_device(FILE *fd
 		    !dev->subtype->support_definable)
 			return EXIT_OK;
 		settings = dev->active.settings;
-	} else {
+	} else if (config == config_persistent) {
 		if (!dev->persistent.exists)
 			return EXIT_OK;
 		settings = dev->persistent.settings;
+	} else {
+		if (!dev->autoconf.exists)
+			return EXIT_OK;
+		settings = dev->autoconf.settings;
 	}
 
 	write_header(fd, config, dev->subtype->name, dev->id, first_ptr);
@@ -204,12 +221,21 @@ exit_code_t export_write_devtype(FILE *f
 	exit_code_t rc;
 	struct setting_list *settings;
 
-	if (config == config_all) {
-		rc = export_write_devtype(fd, dt, config_active, first_ptr);
-		if (rc)
-			return rc;
-		return export_write_devtype(fd, dt, config_persistent,
-					    first_ptr);
+	if (!SCOPE_SINGLE(config)) {
+		if (SCOPE_ACTIVE(config)) {
+			rc = export_write_devtype(fd, dt, config_active,
+						  first_ptr);
+			if (rc)
+				return rc;
+		}
+		if (SCOPE_PERSISTENT(config)) {
+			rc = export_write_devtype(fd, dt, config_persistent,
+						  first_ptr);
+			if (rc)
+				return rc;
+		}
+		/* Scope autoconf not supported for devtype */
+		return EXIT_OK;
 	}
 
 	if (config == config_active)
@@ -379,6 +405,10 @@ static exit_code_t handle_header(const c
 			setting_list_clear(dev->persistent.settings);
 			dev->persistent.exists = 1;
 		}
+		if (SCOPE_AUTOCONF(hdr->config)) {
+			setting_list_clear(dev->autoconf.settings);
+			dev->autoconf.exists = 1;
+		}
 	}
 
 out:
@@ -397,13 +427,26 @@ static exit_code_t handle_setting(const
 	struct attrib **attribs, *a;
 	struct setting_list *list;
 
-	if (config == config_all) {
-		rc = handle_setting(filename, lineno, key, value, dt, dev,
-				    config_active);
-		if (rc)
-			return rc;
-		return handle_setting(filename, lineno, key, value, dt, dev,
-				      config_persistent);
+	if (!SCOPE_SINGLE(config)) {
+		if (SCOPE_ACTIVE(config)) {
+			rc = handle_setting(filename, lineno, key, value, dt,
+					    dev, config_active);
+			if (rc)
+				return rc;
+		}
+		if (SCOPE_PERSISTENT(config)) {
+			rc = handle_setting(filename, lineno, key, value, dt,
+					    dev, config_persistent);
+			if (rc)
+				return rc;
+		}
+		if (SCOPE_AUTOCONF(config)) {
+			rc = handle_setting(filename, lineno, key, value, dt,
+					    dev, config_autoconf);
+			if (rc)
+				return rc;
+		}
+		return EXIT_OK;
 	}
 
 	if (dt) {
@@ -452,7 +495,8 @@ static bool empty_device(struct device *
 	if (dev->subtype->support_definable)
 		return false;
 	if (util_list_is_empty(&dev->active.settings->list) &&
-	    util_list_is_empty(&dev->persistent.settings->list))
+	    util_list_is_empty(&dev->persistent.settings->list) &&
+	    util_list_is_empty(&dev->autoconf.settings->list))
 		return true;
 	return false;
 }
--- a/zdev/src/firmware.c
+++ b/zdev/src/firmware.c
@@ -360,6 +360,8 @@ static void add_setting(const char *file
 		_add_setting(filename, dev, config_active, key, value);
 	if (SCOPE_PERSISTENT(config))
 		_add_setting(filename, dev, config_persistent, key, value);
+	if (SCOPE_AUTOCONF(config))
+		_add_setting(filename, dev, config_autoconf, key, value);
 }
 
 /* Parse a single device setting in firmware format and apply it to the
@@ -477,6 +479,10 @@ static struct device *add_device(struct
 		setting_list_clear(dev->persistent.settings);
 		dev->persistent.exists = 1;
 	}
+	if (SCOPE_AUTOCONF(config)) {
+		setting_list_clear(dev->autoconf.settings);
+		dev->autoconf.exists = 1;
+	}
 
 	return dev;
 }
--- a/zdev/src/lszdev.c
+++ b/zdev/src/lszdev.c
@@ -59,6 +59,7 @@ struct options {
 	config_t config;
 	unsigned int active:1;
 	unsigned int persistent:1;
+	unsigned int auto_conf:1;
 	struct util_list *columns;	/* List of struct strlist_node */
 	unsigned int no_headings:1;
 	struct util_list *base;		/* List of struct strlist_node */
@@ -98,6 +99,7 @@ enum {
 	OPT_VERBOSE		= 'V',
 	OPT_QUIET		= 'q',
 	OPT_PAIRS		= 'P',
+	OPT_AUTO_CONF		= (OPT_ANONYMOUS_BASE+__COUNTER__),
 };
 
 static struct opts_conflict conflict_list[] = {
@@ -150,6 +152,7 @@ static const struct option opt_list[] =
 	/* Options. */
 	{ "active",		no_argument,	NULL, OPT_ACTIVE },
 	{ "persistent",		no_argument,	NULL, OPT_PERSISTENT },
+	{ "auto-conf",		no_argument,	NULL, OPT_AUTO_CONF },
 	{ "columns",		required_argument, NULL, OPT_COLUMNS },
 	{ "no-headings",	no_argument,	NULL, OPT_NO_HEADINGS },
 	{ "base",		required_argument, NULL, OPT_BASE },
@@ -623,6 +626,11 @@ static exit_code_t parse_options(struct
 			opts->persistent = 1;
 			break;
 
+		case OPT_AUTO_CONF:
+			/* --auto-conf */
+			opts->auto_conf = 1;
+			break;
+
 		case OPT_COLUMNS:
 			/* --columns COLUMN */
 			strlist_add_multi(opts->columns, optarg, ",", 0);
@@ -685,7 +693,15 @@ static exit_code_t parse_options(struct
 		goto out;
 
 	/* Determine configuration set. */
-	opts->config = get_config(opts->active, opts->persistent);
+	if (!opts->active && !opts->persistent && !opts->auto_conf) {
+		/* Default display targets are active + persistent - note that
+		 * autoconf data is still shown when available to make users
+		 * aware of this type of data. */
+		opts->config = config_active | config_persistent;
+	} else {
+		opts->config = get_config(opts->active, opts->persistent,
+					  opts->auto_conf);
+	}
 
 	/* Handle positional parameters. */
 	rc = parse_positional(opts, argc, argv, optind);
@@ -725,6 +741,7 @@ enum dev_table_id {
 	dev_netdevs,
 	dev_exists,
 	dev_pers,
+	dev_auto,
 	dev_online,
 	dev_failed,
 	dev_modules,
@@ -744,6 +761,8 @@ static struct column *dev_table = COLUMN
 	       "Device exists in the active configuration"),
 	COLUMN("PERS",		align_left, dev_pers, 1,
 	       "Device is configured persistently"),
+	COLUMN("AUTO",		align_left, dev_auto, 0,
+	       "Auto-configuration exists for device"),
 	COLUMN("FAILED",	align_left, dev_failed, 0,
 	       "Device is in error"),
 	COLUMN("NAMES",		align_left, dev_names, 1,
@@ -762,21 +781,34 @@ static struct column *dev_table = COLUMN
 	       "Path to specific attribute in active configuration")
 );
 
-static char *merge_str(const char *act, const char *pers)
+static char *merge_str(const char *act, const char *pers, const char *ac,
+		       config_t config)
 {
 	char *str;
+	size_t len;
 
-	if (act && pers) {
-		if (strcmp(act, pers) == 0)
-			str = misc_strdup(act);
-		else
-			str = misc_asprintf("%s/%s", act, pers);
-	} else if (act)
-		str = misc_strdup(act);
-	else if (pers)
-		str = misc_strdup(pers);
-	else
-		str = misc_strdup("-");
+	act	= act  ? act  : "-";
+	pers	= pers ? pers : "-";
+	ac	= ac   ? ac   : "-";
+
+	if (strcmp(act, pers) == 0 && strcmp(act, ac) == 0)
+		return misc_strdup(act);
+
+	len = strlen(act) + strlen(pers) + strlen(ac) + /* 3 * / + NUL */ 4;
+	str = misc_malloc(len);
+
+	if (SCOPE_ACTIVE(config))
+		strcat(str, act);
+	if (SCOPE_PERSISTENT(config)) {
+		if (*str)
+			strcat(str, "/");
+		strcat(str, pers);
+	}
+	if (SCOPE_AUTOCONF(config)) {
+		if (*str)
+			strcat(str, "/");
+		strcat(str, ac);
+	}
 
 	return str;
 }
@@ -821,10 +853,9 @@ static char *get_attr(struct device *dev
 	struct setting_list *list;
 	struct setting *s;
 
-	if (config == config_active)
-		list = dev->active.settings;
-	else
-		list = dev->persistent.settings;
+	list = device_get_setting_list(dev, config);
+	if (!list)
+		return NULL;
 	s = setting_list_find(list, name);
 	if (!s) {
 		if (config == config_active) {
@@ -841,7 +872,7 @@ static char *get_attr(struct device *dev
 static char *dev_table_get_attr(struct device *dev, const char *attr,
 				config_t config)
 {
-	char *act = NULL, *pers = NULL, *str;
+	char *act = NULL, *pers = NULL, *ac = NULL, *str;
 	const char *name;
 
 	name = strchr(attr, ':');
@@ -853,10 +884,13 @@ static char *dev_table_get_attr(struct d
 		act = get_attr(dev, name, config_active);
 	if (SCOPE_PERSISTENT(config))
 		pers = get_attr(dev, name, config_persistent);
+	if (SCOPE_AUTOCONF(config))
+		ac = get_attr(dev, name, config_autoconf);
 
-	str = merge_str(act, pers);
+	str = merge_str(act, pers, ac, config);
 	free(act);
 	free(pers);
+	free(ac);
 
 	return str;
 }
@@ -904,7 +938,11 @@ static char *dev_table_get_value(void *i
 		return misc_strdup(YESNO(dev->active.exists ||
 					 dev->active.definable));
 	case dev_pers:
+		if (!dev->persistent.exists && dev->autoconf.exists)
+			return misc_strdup("auto");
 		return misc_strdup(YESNO(dev->persistent.exists));
+	case dev_auto:
+		return misc_strdup(YESNO(dev->autoconf.exists));
 	case dev_online:
 		return dev_table_get_online(dev, config_active);
 	case dev_failed:
@@ -942,6 +980,7 @@ static read_scope_t get_scope(struct opt
 		case dev_netdevs:
 		case dev_exists:
 		case dev_pers:
+		case dev_auto:
 		case dev_online:
 		case dev_modules:
 			continue;
@@ -960,14 +999,21 @@ static struct util_list *dev_table_build
 	struct util_list *selected, *devices = NULL;
 	struct selected_dev_node *sel;
 	struct device *dev;
-	int active, persistent;
+	int active, persistent, autoconf;
 	read_scope_t scope;
 	exit_code_t rc;
+	config_t config = opts->config;
 
 	scope = get_scope(opts);
 	selected = selected_dev_list_new();
+
+	/* Read auto-config data when no configuration set was specified to
+	 * make user aware of auto-config data. */
+	if (!opts->active && !opts->persistent && !opts->auto_conf)
+		config |= config_autoconf;
+
 	rc = select_devices(opts->select, selected, 1, 0, opts->pairs,
-			    opts->config, scope, err_print);
+			    config, scope, err_print);
 	if (rc)
 		goto out;
 	devices = ptrlist_new();
@@ -987,7 +1033,8 @@ static struct util_list *dev_table_build
 		/* Only process existing devices. */
 		active = dev->active.exists || dev->active.definable;
 		persistent = dev->persistent.exists;
-		if (!active && !persistent)
+		autoconf = dev->autoconf.exists;
+		if (!active && !persistent && !autoconf)
 			continue;
 
 		ptrlist_add(devices, dev);
@@ -1025,9 +1072,11 @@ static exit_code_t do_list_devices(struc
 	if (!items)
 		return EXIT_EMPTY_SELECTION;
 
-	/* Adjust columns visible depending on --active and --persistent. */
+	/* Adjust columns visible depending on selected config set. */
 	table_set_default(dev_table, dev_online, SCOPE_ACTIVE(opts->config));
 	table_set_default(dev_table, dev_pers, SCOPE_PERSISTENT(opts->config));
+	table_set_default(dev_table, dev_auto, SCOPE_AUTOCONF(opts->config) &&
+					       !SCOPE_PERSISTENT(opts->config));
 	table_set_default(dev_table, dev_names, SCOPE_ACTIVE(opts->config));
 
 	/* Display table. */
@@ -1057,17 +1106,20 @@ enum settings_table_id {
 	settings_readonly,
 	settings_active,
 	settings_persistent,
+	settings_autoconf,
 };
 
 static struct column *settings_table = COLUMN_ARRAY(
 	COLUMN("ATTRIBUTE", align_left, settings_attribute, 1, ""),
 	COLUMN("READONLY", align_left, settings_readonly, 1, ""),
 	COLUMN("ACTIVE", align_left, settings_active, 1, ""),
-	COLUMN("PERSISTENT", align_left, settings_persistent, 1, "")
+	COLUMN("PERSISTENT", align_left, settings_persistent, 1, ""),
+	COLUMN("AUTOCONF", align_left, settings_autoconf, 0, "")
 );
 
 static struct util_list *settings_table_build(struct setting_list *active,
 					      struct setting_list *persistent,
+					      struct setting_list *autoconf,
 					      bool readonly)
 {
 	struct util_list *names, *items;
@@ -1088,6 +1140,10 @@ static struct util_list *settings_table_
 		util_list_iterate(&persistent->list, s)
 			strlist_add(names, s->name);
 	}
+	if (autoconf && !readonly) {
+		util_list_iterate(&autoconf->list, s)
+			strlist_add(names, s->name);
+	}
 	strlist_sort_unique(names, str_cmp);
 
 	/* Convert strlist to ptrlist. */
@@ -1102,6 +1158,7 @@ static struct util_list *settings_table_
 struct settings_table_data {
 	struct setting_list *active;
 	struct setting_list *persistent;
+	struct setting_list *autoconf;
 	int pairs;
 	bool readonly;
 };
@@ -1124,12 +1181,17 @@ static char *settings_table_get_value(vo
 	case settings_persistent:
 		list = stdata->persistent;
 		break;
+	case settings_autoconf:
+		list = stdata->autoconf;
+		break;
 	default:
 		break;
 	}
 	if (list) {
 		s = setting_list_find(list, name);
-		if (s && !(id == settings_persistent && s->derived)) {
+		if (s &&
+		    !((id == settings_persistent || id == settings_autoconf) &&
+		      s->derived)) {
 			if (stdata->pairs)
 				return misc_strdup(s->value);
 			else
@@ -1145,6 +1207,7 @@ static char *settings_table_get_value(vo
 
 static void settings_table_print(struct setting_list *active,
 				 struct setting_list *persistent,
+				 struct setting_list *autoconf,
 				 struct options *opts, int ind, bool readonly,
 				 bool neednl)
 {
@@ -1154,7 +1217,7 @@ static void settings_table_print(struct
 	items = settings_table_build(
 			SCOPE_ACTIVE(opts->config) ? active : NULL,
 			SCOPE_PERSISTENT(opts->config) ? persistent : NULL,
-			readonly);
+			autoconf, readonly);
 	if (util_list_is_empty(items)) {
 		if (!opts->pairs && !readonly)
 			indent(ind, "%sNo settings found\n",
@@ -1170,8 +1233,12 @@ static void settings_table_print(struct
 			  SCOPE_ACTIVE(opts->config));
 	table_set_default(settings_table, settings_persistent,
 			  SCOPE_PERSISTENT(opts->config) && !readonly ? 1 : 0);
+	table_set_default(settings_table, settings_autoconf,
+			  (SCOPE_AUTOCONF(opts->config) || autoconf) &&
+				!readonly ? 1 : 0);
 	data.active = active;
 	data.persistent = persistent;
+	data.autoconf = autoconf;
 	data.pairs = opts->pairs;
 	table_print(settings_table, settings_table_get_value, &data, items,
 		    NULL, 1, opts->pairs, ind, 0);
@@ -1253,7 +1320,7 @@ static exit_code_t do_info_type(struct o
 		}
 	} else {
 		settings_table_print(dt->active_settings,
-				     dt->persistent_settings, opts,
+				     dt->persistent_settings, NULL, opts,
 				     INFO_INDENT, false, false);
 	}
 
@@ -1280,7 +1347,7 @@ static void do_info_one_device(struct de
 {
 	struct subtype *st = dev->subtype;
 	char *names, *bdevs, *cdevs, *ndevs, *modules, *online, *path, *key;
-	const char *id, *type, *exists, *persist, *prefix;
+	const char *id, *type, *exists, *persist, *ac, *prefix;
 	struct util_list *resources, *errors;
 	struct strlist_node *s;
 	bool first;
@@ -1299,6 +1366,7 @@ static void do_info_one_device(struct de
 	errors	= subtype_get_errors(dev->subtype, dev->id);
 	exists	= YESNO(dev->active.exists || dev->active.definable);
 	persist	= YESNO(dev->persistent.exists);
+	ac	= YESNO(dev->autoconf.exists);
 
 	/* Print information. */
 	if (opts->pairs) {
@@ -1316,6 +1384,8 @@ static void do_info_one_device(struct de
 		print_pair("ONLINE", online);
 		print_pair("EXISTS", exists);
 		print_pair("PERSISTENT", persist);
+		if (SCOPE_AUTOCONF(opts->config) || dev->autoconf.exists)
+			print_pair("AUTOCONF", ac);
 		if (errors) {
 			util_list_iterate(errors, s)
 				print_pair("ERROR", s->str);
@@ -1341,6 +1411,8 @@ static void do_info_one_device(struct de
 		print_info("Online", online);
 		print_info("Exists", exists);
 		print_info("Persistent", persist);
+		if (SCOPE_AUTOCONF(opts->config) || dev->autoconf.exists)
+			print_info("Auto-configured", ac);
 		if (errors) {
 			first = true;
 			util_list_iterate(errors, s) {
@@ -1382,11 +1454,17 @@ static void do_info_one_device(struct de
 
 	settings_table_print(dev->active.exists ? dev->active.settings : NULL,
 			     dev->persistent.exists ? dev->persistent.settings :
-			     NULL, opts, INFO_INDENT, false, !opts->pairs);
+			     NULL,
+			     dev->autoconf.exists ? dev->autoconf.settings :
+			     NULL,
+			     opts, INFO_INDENT, false, !opts->pairs);
 
 	settings_table_print(dev->active.exists ? dev->active.settings : NULL,
 			     dev->persistent.exists ? dev->persistent.settings :
-			     NULL, opts, INFO_INDENT, true, !opts->pairs);
+			     NULL,
+			     dev->autoconf.exists ? dev->autoconf.settings :
+			     NULL,
+			     opts, INFO_INDENT, true, !opts->pairs);
 
 	strlist_free(errors);
 	free(online);
@@ -1404,9 +1482,10 @@ static exit_code_t do_info_devices(struc
 	struct util_list *selected;
 	struct selected_dev_node *sel;
 	struct device *dev;
-	int found, active, persistent;
+	int found, active, persistent, autoconf;
 	exit_code_t rc, drc = EXIT_OK;
 	read_scope_t scope;
+	config_t config = opts->config;
 
 	if (opts->info > 1)
 		scope = scope_all;
@@ -1415,7 +1494,13 @@ static exit_code_t do_info_devices(struc
 
 	/* Get list of selected devices. */
 	selected = selected_dev_list_new();
-	select_devices(opts->select, selected, 1, 0, opts->pairs, opts->config,
+
+	/* Read auto-config data when no configuration set was specified to
+	 * make user aware of auto-config data. */
+	if (!opts->active && !opts->persistent && !opts->auto_conf)
+		config |= config_autoconf;
+
+	select_devices(opts->select, selected, 1, 0, opts->pairs, config,
 		       scope, err_print);
 
 	/* Process selected devices. */
@@ -1434,9 +1519,8 @@ static exit_code_t do_info_devices(struc
 		/* Only process existing devices. */
 		active = dev->active.exists || dev->active.definable;
 		persistent = dev->persistent.exists;
-		if ((opts->config == config_active && !active) ||
-		    (opts->config == config_persistent && !persistent) ||
-		    (opts->config == config_all && !active && !persistent))
+		autoconf = dev->autoconf.exists;
+		if (!active && !persistent && !autoconf)
 			continue;
 		if (found > 0)
 			printf("\n");
--- a/zdev/src/lszdev_usage.txt
+++ b/zdev/src/lszdev_usage.txt
@@ -41,5 +41,6 @@ OPTIONS
   -n, --no-headings      Do not print column headings
       --base PATH        Use PATH as base for accessing files
       --pairs            Produce output in KEY="VALUE" format
+      --auto-conf        Only show auto-configuration data
   -V, --verbose          Print additional run-time information
   -q, --quiet            Print only minimal run-time information
--- a/zdev/src/misc.c
+++ b/zdev/src/misc.c
@@ -1107,14 +1107,18 @@ char *misc_readlink(const char *path)
 }
 
 /* Determine configuration set. */
-config_t get_config(int active, int persistent)
+config_t get_config(int active, int persistent, int autoconf)
 {
-	if ((!active && !persistent) || (active && persistent))
-		return config_all;
-	else if (active)
-		return config_active;
-	else
-		return config_persistent;
+	config_t config = 0;
+
+	if (active)
+		config |= config_active;
+	if (persistent)
+		config |= config_persistent;
+	if (autoconf)
+		config |= config_autoconf;
+
+	return config;
 }
 
 /* Determine if program is running under z/VM. */
@@ -1248,11 +1252,12 @@ const char *config_to_str(config_t confi
 		return "active";
 	case config_persistent:
 		return "persistent";
+	case config_autoconf:
+		return "autoconf";
 	case config_all:
 		return "all";
 	}
-	/* Should not happen. */
-	return "";
+	return "multiple";
 }
 
 /* Convert textual config representation to config_t. */
@@ -1262,6 +1267,8 @@ bool str_to_config(const char *str, conf
 		*config_ptr = config_active;
 	else if (strcasecmp(str, "persistent") == 0)
 		*config_ptr = config_persistent;
+	else if (strcasecmp(str, "autoconf") == 0)
+		*config_ptr = config_autoconf;
 	else if (strcasecmp(str, "all") == 0)
 		*config_ptr = config_all;
 	else
--- a/zdev/src/path.c
+++ b/zdev/src/path.c
@@ -297,21 +297,25 @@ char *path_get_ccwgroup_devices(const ch
 }
 
 /* Return path to udev rule. */
-char *path_get_udev_rule(const char *type, const char *id)
+char *path_get_udev_rule(const char *type, const char *id, bool vol)
 {
+	const char *path = vol ? PATH_UDEV_RULES_VOLATILE : PATH_UDEV_RULES;
+
 	if (id) {
-		return path_get("%s/%s-%s-%s%s", PATH_UDEV_RULES,
+		return path_get("%s/%s-%s-%s%s", path,
 				UDEV_PREFIX, type, id, UDEV_SUFFIX);
 	}
 
-	return path_get("%s/%s-%s%s", PATH_UDEV_RULES,
+	return path_get("%s/%s-%s%s", path,
 			UDEV_PREFIX, type, UDEV_SUFFIX);
 }
 
 /* Return path to directory containing all udev rules. */
-char *path_get_udev_rules(void)
+char *path_get_udev_rules(bool vol)
 {
-	return path_get("%s", PATH_UDEV_RULES);
+	const char *path = vol ? PATH_UDEV_RULES_VOLATILE : PATH_UDEV_RULES;
+
+	return path_get("%s", path);
 }
 
 /* Return path to the specified file in the proc file system. */
--- a/zdev/src/qeth.c
+++ b/zdev/src/qeth.c
@@ -1207,7 +1207,7 @@ static exit_code_t check_layer2(struct d
 {
 	struct setting *l;
 	int layer2_detected, layer2_active = -1, layer2_persistent = -1,
-	    layer2_modified = 0;
+	    layer2_autoconf = -1, layer2_modified = 0;
 	exit_code_t rc = EXIT_OK;
 
 	layer2_detected = detect_layer2(dev);
@@ -1231,13 +1231,25 @@ static exit_code_t check_layer2(struct d
 		if (rc)
 			goto out;
 	}
+	l = setting_list_find(dev->autoconf.settings, qeth_attr_layer2.name);
+	if (l) {
+		layer2_autoconf = atoi(l->value);
+		layer2_modified |= l->modified;
+	} else if (SCOPE_AUTOCONF(config)) {
+		rc = generate_layer2("autoconf", dev->autoconf.settings,
+				     &layer2_autoconf, &layer2_modified);
+		if (rc)
+			goto out;
+	}
 
 	/* Check correct layer2 setting. */
 	if (layer2_detected != -1) {
 		if ((SCOPE_ACTIVE(config) && layer2_active != -1 &&
 		     layer2_active != layer2_detected) ||
 		    (SCOPE_PERSISTENT(config) && layer2_persistent != -1 &&
-		     layer2_persistent != layer2_detected)) {
+		     layer2_persistent != layer2_detected) ||
+		    (SCOPE_AUTOCONF(config) && layer2_autoconf != -1 &&
+		     layer2_autoconf != layer2_detected)) {
 			rc = layer2_mismatch(layer2_detected, layer2_modified);
 			if (rc)
 				goto out;
@@ -1256,14 +1268,25 @@ static exit_code_t check_layer2(struct d
 		if (rc)
 			goto out;
 	}
+	if (SCOPE_AUTOCONF(config)) {
+		rc = check_ineffective_settings(dev->autoconf.settings,
+						layer2_autoconf);
+		if (rc)
+			goto out;
+	}
 	/* check for conflicting layer2 attribute groups */
 	if (SCOPE_ACTIVE(config)) {
 		rc = check_conflicting_settings(dev->active.settings);
 		if (rc)
 			goto out;
 	}
-	if (SCOPE_PERSISTENT(config))
+	if (SCOPE_PERSISTENT(config)) {
 		rc = check_conflicting_settings(dev->persistent.settings);
+		if (rc)
+			goto out;
+	}
+	if (SCOPE_AUTOCONF(config))
+		rc = check_conflicting_settings(dev->autoconf.settings);
 
 out:
 	return rc;
@@ -1277,7 +1300,8 @@ static exit_code_t qeth_st_check_pre_con
 
 	/* No need to check if device is deconfigured. */
 	if ((SCOPE_ACTIVE(config) && dev->active.deconfigured) ||
-	    (SCOPE_PERSISTENT(config) && dev->persistent.deconfigured))
+	    (SCOPE_PERSISTENT(config) && dev->persistent.deconfigured) ||
+	    (SCOPE_AUTOCONF(config) && dev->autoconf.deconfigured))
 		return EXIT_OK;
 
 	rc = check_layer2(dev, config);
--- a/zdev/src/select.c
+++ b/zdev/src/select.c
@@ -248,12 +248,13 @@ static void unblacklist_devices(struct s
 bool select_match_state(struct device *dev, struct select_opts *select)
 {
 	struct subtype *st = dev->subtype;
-	int exists, configured, online;
+	int exists, configured, autoconf, online;
 	struct util_list *errors;
 
 	exists = dev->active.exists || dev->active.definable;
 	configured = dev->persistent.exists;
-	if (select->all && !(exists || configured))
+	autoconf = dev->autoconf.exists;
+	if (select->all && !(exists || configured || autoconf))
 		return false;
 	if (select->existing && !exists)
 		return false;
@@ -862,7 +863,8 @@ static exit_code_t select_nocreate(struc
 			       select->offline || select->online ||
 			       SCOPE_ACTIVE(config),
 			       select->configured || select->all ||
-			       SCOPE_PERSISTENT(config));
+			       SCOPE_PERSISTENT(config),
+			       select->all || SCOPE_AUTOCONF(config));
 
 	longrun_total = 0;
 	if (quiet)
@@ -870,7 +872,7 @@ static exit_code_t select_nocreate(struc
 
 	/* Count devices. */
 	verb("Scanning for devices in %s configuration%s:\n",
-	     config_to_str(id_config), id_config == config_all ? "s" : "");
+	     config_to_str(id_config), !SCOPE_SINGLE(id_config) ? "s" : "");
 	for (i = 0; (dt = devtypes[i]); i++) {
 		if (select->devtype && dt != select->devtype)
 			continue;
@@ -1128,6 +1130,13 @@ static exit_code_t by_attr_cb(struct sub
 
 	/* Check for attribute value in persistent configuration. */
 	s = setting_list_find(dev->persistent.settings, cb_data->key);
+	if (s) {
+		match = setting_match_value(s, cb_data->value);
+		if (match)
+			goto out;
+	}
+	/* Check for attribute value in autoconf configuration. */
+	s = setting_list_find(dev->autoconf.settings, cb_data->key);
 	if (s)
 		match = setting_match_value(s, cb_data->value);
 
--- a/zdev/src/setting.c
+++ b/zdev/src/setting.c
@@ -646,7 +646,8 @@ static void add_changes(struct util_list
 
 /* Return a newly allocated string containing the setting changes found
  * in PERS and ACT or NULL if no change was found. */
-char *setting_get_changes(struct setting_list *act, struct setting_list *pers)
+char *setting_get_changes(struct setting_list *act, struct setting_list *pers,
+			  struct setting_list *ac)
 {
 	struct util_list *out;
 	struct util_list *processed;
@@ -662,6 +663,17 @@ char *setting_get_changes(struct setting
 			if (s->removed)
 				strlist_add(out, "-%s", s->name);
 			else if (s->modified)
+				add_changes(out, s);
+			else
+				continue;
+			strlist_add(processed, s->name);
+		}
+	}
+	if (ac) {
+		util_list_iterate(&ac->list, s) {
+			if (s->removed)
+				strlist_add(out, "-%s", s->name);
+			else if (s->modified)
 				add_changes(out, s);
 			else
 				continue;
--- a/zdev/src/subtype.c
+++ b/zdev/src/subtype.c
@@ -195,6 +195,13 @@ bool subtype_device_exists_persistent(st
 	return super->exists_persistent(st, id);
 }
 
+bool subtype_device_exists_autoconf(struct subtype *st, const char *id)
+{
+	struct subtype *super = super_get(st, exists_autoconf, 1);
+
+	return super->exists_autoconf(st, id);
+}
+
 void subtype_add_active_ids(struct subtype *st, struct util_list *ids)
 {
 	struct subtype *super = super_get(st, add_active_ids, 1);
@@ -209,6 +216,13 @@ void subtype_add_persistent_ids(struct s
 	super->add_persistent_ids(st, ids);
 }
 
+void subtype_add_autoconf_ids(struct subtype *st, struct util_list *ids)
+{
+	struct subtype *super = super_get(st, add_autoconf_ids, 1);
+
+	super->add_autoconf_ids(st, ids);
+}
+
 exit_code_t subtype_device_read_active(struct subtype *st, struct device *dev,
 				       read_scope_t scope)
 {
@@ -226,6 +240,15 @@ exit_code_t subtype_device_read_persiste
 	return super->read_persistent(st, dev, scope);
 }
 
+exit_code_t subtype_device_read_autoconf(struct subtype *st,
+					   struct device *dev,
+					   read_scope_t scope)
+{
+	struct subtype *super = super_get(st, read_autoconf, 1);
+
+	return super->read_autoconf(st, dev, scope);
+}
+
 exit_code_t subtype_device_configure_active(struct subtype *st,
 					    struct device *dev)
 {
@@ -242,6 +265,14 @@ exit_code_t subtype_device_configure_per
 	return super->configure_persistent(st, dev);
 }
 
+exit_code_t subtype_device_configure_autoconf(struct subtype *st,
+					      struct device *dev)
+{
+	struct subtype *super = super_get(st, configure_autoconf, 1);
+
+	return super->configure_autoconf(st, dev);
+}
+
 exit_code_t subtype_device_deconfigure_active(struct subtype *st,
 					      struct device *dev)
 {
@@ -258,6 +289,14 @@ exit_code_t subtype_device_deconfigure_p
 	return super->deconfigure_persistent(st, dev);
 }
 
+exit_code_t subtype_device_deconfigure_autoconf(struct subtype *st,
+						struct device *dev)
+{
+	struct subtype *super = super_get(st, deconfigure_autoconf, 1);
+
+	return super->deconfigure_autoconf(st, dev);
+}
+
 exit_code_t subtype_check_pre_configure(struct subtype *st, struct device *dev,
 					int prereq, config_t config)
 {
@@ -299,7 +338,7 @@ void subtype_online_set(struct subtype *
 int subtype_online_get(struct subtype *st, struct device *dev, config_t config)
 {
 	struct subtype *super = super_get(st, online_get, 0);
-	int act_online = 1, pers_online = 1;
+	int act_online = 1, pers_online = 1, auto_online = 1;
 
 	if (super)
 		return super->online_get(st, dev, config);
@@ -310,8 +349,10 @@ int subtype_online_get(struct subtype *s
 		act_online = dev->active.exists;
 	if (SCOPE_PERSISTENT(config))
 		pers_online = dev->persistent.exists;
+	if (SCOPE_AUTOCONF(config))
+		auto_online = dev->autoconf.exists;
 
-	return MIN(act_online, pers_online);
+	return MIN(MIN(act_online, pers_online), auto_online);
 }
 
 bool subtype_online_specified(struct subtype *st, struct device *dev,
@@ -495,6 +536,10 @@ bool subtype_device_exists(struct subtyp
 		if (!subtype_device_exists_persistent(st, id))
 			return false;
 	}
+	if (SCOPE_AUTOCONF(config)) {
+		if (!subtype_device_exists_autoconf(st, id))
+			return false;
+	}
 
 	return true;
 }
@@ -512,6 +557,8 @@ static struct util_list *get_ids(struct
 	}
 	if (SCOPE_PERSISTENT(config))
 		subtype_add_persistent_ids(st, ids);
+	if (SCOPE_AUTOCONF(config))
+		subtype_add_autoconf_ids(st, ids);
 
 	/* Provide a sorted view. */
 	strlist_sort_unique(ids, st->namespace->qsort_cmp);
@@ -683,6 +730,19 @@ static exit_code_t read_device(struct su
 			goto out;
 	}
 
+	if (SCOPE_AUTOCONF(config)) {
+		if (subtype_device_exists_autoconf(st, id))
+			rc = subtype_device_read_autoconf(st, dev, scope);
+		else if (defined) {
+			/* Need to copy detected settings to autoconf
+			 * config. */
+			setting_list_merge(dev->autoconf.settings,
+					   dev->active.settings, false, false);
+		}
+		if (rc)
+			goto out;
+	}
+
 	if (add)
 		device_list_add(st->devices, dev);
 
@@ -756,6 +816,25 @@ exit_code_t subtype_write_device(struct
 		if (!rc)
 			namespace_set_modified(dev->subtype->namespace);
 	}
+	if (SCOPE_AUTOCONF(config)) {
+		if (dev->autoconf.deconfigured) {
+			/* Deconfigure device. */
+			if (dev->autoconf.exists) {
+				rc = subtype_device_deconfigure_autoconf(st,
+									 dev);
+				if (rc)
+					return rc;
+			}
+		} else if (dev->autoconf.exists) {
+			/* Configure device. */
+			rc = subtype_device_configure_autoconf(st, dev);
+			if (rc)
+				return rc;
+		}
+		if (!rc)
+			namespace_set_modified(dev->subtype->namespace);
+	}
+
 
 	return EXIT_OK;
 }
--- a/zdev/src/udev.c
+++ b/zdev/src/udev.c
@@ -360,7 +360,8 @@ static bool get_ids_cb(const char *filen
 
 /* Add the IDs for all devices of the specified subtype name for which a
  * udev rule exists to strlist LIST. */
-void udev_get_device_ids(const char *type, struct util_list *list)
+void udev_get_device_ids(const char *type, struct util_list *list,
+			 bool autoconf)
 {
 	char *path, *prefix;
 	struct util_list *files;
@@ -369,7 +370,7 @@ void udev_get_device_ids(const char *typ
 
 	prefix = misc_asprintf("%s-%s-", UDEV_PREFIX, type);
 	plen = strlen(prefix);
-	path = path_get_udev_rules();
+	path = path_get_udev_rules(autoconf);
 	files = strlist_new();
 	if (!misc_read_dir(path, files, get_ids_cb, prefix))
 		goto out;
@@ -388,12 +389,12 @@ out:
 }
 
 /* Remove UDEV rule for device. */
-exit_code_t udev_remove_rule(const char *type, const char *id)
+exit_code_t udev_remove_rule(const char *type, const char *id, bool autoconf)
 {
 	char *path;
 	exit_code_t rc = EXIT_OK;
 
-	path = path_get_udev_rule(type, id);
+	path = path_get_udev_rule(type, id, autoconf);
 	if (util_path_is_reg_file(path))
 		rc = remove_file(path);
 	free(path);
--- a/zdev/src/udev_ccw.c
+++ b/zdev/src/udev_ccw.c
@@ -25,7 +25,7 @@
 #include "udev_ccw.h"
 
 /* Check if a udev rule for the specified ccw device exists. */
-bool udev_ccw_exists(const char *type, const char *id)
+bool udev_ccw_exists(const char *type, const char *id, bool autoconf)
 {
 	char *path, *normid;
 	bool rc;
@@ -34,7 +34,7 @@ bool udev_ccw_exists(const char *type, c
 	if (!normid)
 		return false;
 
-	path = path_get_udev_rule(type, normid);
+	path = path_get_udev_rule(type, normid, autoconf);
 	rc = util_path_is_reg_file(path);
 	free(path);
 	free(normid);
@@ -88,15 +88,16 @@ static void udev_file_get_settings(struc
 }
 
 /* Read the persistent configuration of a CCW device from a udev rule. */
-exit_code_t udev_ccw_read_device(struct device *dev)
+exit_code_t udev_ccw_read_device(struct device *dev, bool autoconf)
 {
 	struct subtype *st = dev->subtype;
-	struct device_state *state = &dev->persistent;
+	struct device_state *state = autoconf ? &dev->autoconf :
+						&dev->persistent;
 	struct udev_file *file = NULL;
 	exit_code_t rc;
 	char *path;
 
-	path = path_get_udev_rule(st->name, dev->id);
+	path = path_get_udev_rule(st->name, dev->id, autoconf);
 	rc = udev_read_file(path, &file);
 	if (rc)
 		goto out;
@@ -128,12 +129,13 @@ static char *get_label_id(const char *pr
 }
 
 /* Write the persistent configuration of a CCW device to a udev rule. */
-exit_code_t udev_ccw_write_device(struct device *dev)
+exit_code_t udev_ccw_write_device(struct device *dev, bool autoconf)
 {
 	struct subtype *st = dev->subtype;
 	struct ccw_subtype_data *data = st->data;
 	const char *type = st->name, *drv = data->ccwdrv, *id = dev->id;
-	struct device_state *state = &dev->persistent;
+	struct device_state *state = autoconf ? &dev->autoconf :
+						&dev->persistent;
 	char *path, *cfg_label = NULL, *end_label = NULL;
 	struct util_list *list;
 	struct ptrlist_node *p;
@@ -142,7 +144,7 @@ exit_code_t udev_ccw_write_device(struct
 	FILE *fd;
 
 	if (!state->exists)
-		return udev_remove_rule(type, id);
+		return udev_remove_rule(type, id, autoconf);
 
 	cfg_label = get_label_id("cfg", type, id);
 	end_label = get_label_id("end", type, id);
@@ -150,7 +152,7 @@ exit_code_t udev_ccw_write_device(struct
 	/* Apply attributes in correct order. */
 	list = setting_list_get_sorted(state->settings);
 
-	path = path_get_udev_rule(type, id);
+	path = path_get_udev_rule(type, id, autoconf);
 	debug("Writing %s udev rule file %s\n", type, path);
 	if (!util_path_exists(path)) {
 		rc = path_create(path);
@@ -234,14 +236,18 @@ out:
 }
 
 /* Write a udev rule to free devices from the cio-ignore blacklist. */
-exit_code_t udev_ccw_write_cio_ignore(const char *id_list)
+exit_code_t udev_ccw_write_cio_ignore(const char *id_list, bool autoconf)
 {
-	char *path, *curr = NULL;
+	char *path, *prefix, *curr = NULL;
 	FILE *fd;
 	exit_code_t rc = EXIT_OK;
 
+	/* Ensure that autoconf version of cio-ignore is not masked
+	 * by normal one. */
+	prefix = autoconf ? "cio-ignore-autoconf" : "cio-ignore";
+
 	/* Create file. */
-	path = path_get_udev_rule("cio-ignore", NULL);
+	path = path_get_udev_rule(prefix, NULL, autoconf);
 
 	if (!*id_list) {
 		/* Empty id_list string - remove file. */
--- a/zdev/src/udev_ccwgroup.c
+++ b/zdev/src/udev_ccwgroup.c
@@ -25,34 +25,34 @@
 #include "udev_ccwgroup.h"
 
 static char *get_rule_path_by_devid(const char *type,
-				    struct ccwgroup_devid *devid)
+				    struct ccwgroup_devid *devid, bool autoconf)
 {
 	char *ccw_id, *path;
 
 	ccw_id = ccw_devid_to_str(&devid->devid[0]);
-	path = path_get_udev_rule(type, ccw_id);
+	path = path_get_udev_rule(type, ccw_id, autoconf);
 	free(ccw_id);
 
 	return path;
 }
 
-static char *get_rule_path(const char *type, const char *id)
+static char *get_rule_path(const char *type, const char *id, bool autoconf)
 {
 	struct ccwgroup_devid devid;
 
 	if (ccwgroup_parse_devid(&devid, id, err_ignore) != EXIT_OK)
 		return NULL;
 
-	return get_rule_path_by_devid(type, &devid);
+	return get_rule_path_by_devid(type, &devid, autoconf);
 }
 
 /* Check if a udev rule for the specified CCWGROUP device exists. */
-bool udev_ccwgroup_exists(const char *type, const char *id)
+bool udev_ccwgroup_exists(const char *type, const char *id, bool autoconf)
 {
 	char *path;
 	bool rc;
 
-	path = get_rule_path(type, id);
+	path = get_rule_path(type, id, autoconf);
 	if (!path)
 		return false;
 	rc = util_path_is_reg_file(path);
@@ -143,15 +143,16 @@ static void expand_id(struct device *dev
 }
 
 /* Read the persistent configuration of a CCWGROUP device from a udev rule. */
-exit_code_t udev_ccwgroup_read_device(struct device *dev)
+exit_code_t udev_ccwgroup_read_device(struct device *dev, bool autoconf)
 {
 	struct subtype *st = dev->subtype;
-	struct device_state *state = &dev->persistent;
+	struct device_state *state = autoconf ? &dev->autoconf :
+						&dev->persistent;
 	struct udev_file *file = NULL;
 	exit_code_t rc;
 	char *path;
 
-	path = get_rule_path_by_devid(st->name, dev->devid);
+	path = get_rule_path_by_devid(st->name, dev->devid, autoconf);
 	rc = udev_read_file(path, &file);
 	if (rc)
 		goto out;
@@ -184,9 +185,11 @@ static char *get_label_id(const char *pr
 }
 
 /* Write the persistent configuration of a CCWGROUP device to a udev rule. */
-exit_code_t udev_ccwgroup_write_device(struct device *dev)
+exit_code_t udev_ccwgroup_write_device(struct device *dev, bool autoconf)
 {
 	struct subtype *st = dev->subtype;
+	struct device_state *state = autoconf ? &dev->autoconf :
+						&dev->persistent;
 	struct ccwgroup_subtype_data *data = st->data;
 	const char *type = st->name, *drv = data->ccwgroupdrv, *id = dev->id;
 	struct ccwgroup_devid devid;
@@ -200,21 +203,21 @@ exit_code_t udev_ccwgroup_write_device(s
 	FILE *fd;
 	unsigned int i;
 
-	if (!dev->persistent.exists)
-		return udev_ccwgroup_remove_rule(type, id);
+	if (!state->exists)
+		return udev_ccwgroup_remove_rule(type, id, autoconf);
 
 	if (ccwgroup_parse_devid(&devid, id, err_ignore) != EXIT_OK)
 		return EXIT_INVALID_ID;
 
 	ccw_id = ccw_devid_to_str(&devid.devid[0]);
-	path = get_rule_path(type, ccw_id);
+	path = get_rule_path(type, ccw_id, autoconf);
 
 	group_label = get_label_id("group", type, ccw_id);
 	cfg_label = get_label_id("cfg", type, ccw_id);
 	end_label = get_label_id("end", type, ccw_id);
 
 	/* Apply attributes in correct order. */
-	list = setting_list_get_sorted(dev->persistent.settings);
+	list = setting_list_get_sorted(state->settings);
 
 	debug("Writing %s udev rule file %s\n", type, path);
 	if (!util_path_exists(path)) {
@@ -357,12 +360,13 @@ static exit_code_t get_ids_cb(const char
 
 /* Add the IDs for all devices of the specified subtype name for which a
  * udev rule exists to strlist LIST. */
-void udev_ccwgroup_add_device_ids(const char *type, struct util_list *list)
+void udev_ccwgroup_add_device_ids(const char *type, struct util_list *list,
+				  bool autoconf)
 {
 	struct get_ids_cb_data cb_data;
 	char *path;
 
-	path = path_get_udev_rules();
+	path = path_get_udev_rules(autoconf);
 	cb_data.prefix = misc_asprintf("%s-%s-", UDEV_PREFIX, type);
 	cb_data.ids = list;
 
@@ -374,7 +378,8 @@ void udev_ccwgroup_add_device_ids(const
 }
 
 /* Remove UDEV rule for CCWGROUP device. */
-exit_code_t udev_ccwgroup_remove_rule(const char *type, const char *id)
+exit_code_t udev_ccwgroup_remove_rule(const char *type, const char *id,
+				      bool autoconf)
 {
 	char *partial_id, *path;
 	exit_code_t rc = EXIT_OK;
@@ -383,7 +388,7 @@ exit_code_t udev_ccwgroup_remove_rule(co
 	if (!partial_id)
 		return EXIT_INVALID_ID;
 
-	path = path_get_udev_rule(type, partial_id);
+	path = path_get_udev_rule(type, partial_id, autoconf);
 	if (util_path_is_reg_file(path))
 		rc = remove_file(path);
 	free(path);
--- a/zdev/src/udev_zfcp_lun.c
+++ b/zdev/src/udev_zfcp_lun.c
@@ -369,14 +369,14 @@ static exit_code_t lun_cb(const char *pa
 
 /* Add the IDs for all zfcp lun devices for which a configuration exists to
  * LIST. */
-void udev_zfcp_lun_add_device_ids(struct util_list *list)
+void udev_zfcp_lun_add_device_ids(struct util_list *list, bool autoconf)
 {
 	struct lun_cb_data cb_data;
 	char *path;
 
 	cb_data.prefix = misc_asprintf("%s-%s-", UDEV_PREFIX, ZFCP_LUN_NAME);
 	cb_data.list = list;
-	path = path_get_udev_rules();
+	path = path_get_udev_rules(autoconf);
 
 	if (util_path_is_dir(path))
 		path_for_each(path, lun_cb, &cb_data);
@@ -387,7 +387,7 @@ void udev_zfcp_lun_add_device_ids(struct
 
 /* Return path to zfcp lun udev rule file containing configuration data for
  * all LUNs of a zfcp device. */
-static char *get_zfcp_lun_path(const char *id)
+static char *get_zfcp_lun_path(const char *id, bool autoconf)
 {
 	char *copy, *e, *path;
 
@@ -395,7 +395,7 @@ static char *get_zfcp_lun_path(const cha
 	e = strchr(copy, ':');
 	if (e)
 		*e = 0;
-	path = path_get_udev_rule(ZFCP_LUN_NAME, copy);
+	path = path_get_udev_rule(ZFCP_LUN_NAME, copy, autoconf);
 	free(copy);
 
 	return path;
@@ -403,9 +403,9 @@ static char *get_zfcp_lun_path(const cha
 
 /* Return path to zfcp lun udev rule file containing configuration data for
  * a single LUN. */
-static char *get_single_zfcp_lun_path(const char *id)
+static char *get_single_zfcp_lun_path(const char *id, bool autoconf)
 {
-	return path_get_udev_rule(ZFCP_LUN_NAME, id);
+	return path_get_udev_rule(ZFCP_LUN_NAME, id, autoconf);
 }
 
 /* Apply the settings found in NODE to STATE. */
@@ -437,20 +437,21 @@ static void zfcp_lun_node_to_state(struc
 }
 
 /* Read the persistent configuration of a zfcp lun from a udev rule. */
-exit_code_t udev_zfcp_lun_read_device(struct device *dev)
+exit_code_t udev_zfcp_lun_read_device(struct device *dev, bool autoconf)
 {
 	struct subtype *st = dev->subtype;
-	struct device_state *state = &dev->persistent;
+	struct device_state *state = autoconf ? &dev->autoconf :
+						&dev->persistent;
 	struct util_list *luns;
 	struct zfcp_lun_node *node;
 	exit_code_t rc = EXIT_OK;
 	char *path;
 
 	/* Check for single lun file first then try multi lun file. */
-	path = get_single_zfcp_lun_path(dev->id);
+	path = get_single_zfcp_lun_path(dev->id, autoconf);
 	if (!util_path_exists(path)) {
 		free(path);
-		path = get_zfcp_lun_path(dev->id);
+		path = get_zfcp_lun_path(dev->id, autoconf);
 	}
 
 	/* Get previous rule data. */
@@ -616,7 +617,7 @@ out:
  * applies the corresponding parameters. If @single is set, update a single
  * lun rule file, otherwise update a multi lun rule file. */
 static exit_code_t update_lun_rule(const char *id, struct device_state *state,
-				   bool single)
+				   bool single, bool autoconf)
 {
 	struct zfcp_lun_devid devid;
 	struct util_list *luns;
@@ -628,7 +629,8 @@ static exit_code_t update_lun_rule(const
 	rc = zfcp_lun_parse_devid(&devid, id, err_delayed_print);
 	if (rc)
 		return rc;
-	path = single ? get_single_zfcp_lun_path(id) : get_zfcp_lun_path(id);
+	path = single ? get_single_zfcp_lun_path(id, autoconf) :
+			get_zfcp_lun_path(id, autoconf);
 
 	/* Get previous rule data. */
 	luns = zfcp_lun_node_list_new();
@@ -664,26 +666,28 @@ static exit_code_t update_lun_rule(const
 
 /* Write a udev-rule to configure the specified zfcp lun and associated
  * device state. */
-exit_code_t udev_zfcp_lun_write_device(struct device *dev)
+exit_code_t udev_zfcp_lun_write_device(struct device *dev, bool autoconf)
 {
 	exit_code_t rc;
+	struct device_state *state = autoconf ? &dev->autoconf :
+						&dev->persistent;
 
-	rc = update_lun_rule(dev->id, &dev->persistent, true);
+	rc = update_lun_rule(dev->id, state, true, autoconf);
 
 	/* We only want single lun rule files so remove any remaining
 	 * references in multi lun rule files. */
-	update_lun_rule(dev->id, NULL, false);
+	update_lun_rule(dev->id, NULL, false, autoconf);
 
 	return rc;
 }
 
 /* Remove the UDEV rule used to configure the zfcp lun with the specified ID. */
-exit_code_t udev_zfcp_lun_remove_rule(const char *id)
+exit_code_t udev_zfcp_lun_remove_rule(const char *id, bool autoconf)
 {
 	exit_code_t rc, rc2;
 
-	rc = update_lun_rule(id, NULL, true);
-	rc2 = update_lun_rule(id, NULL, false);
+	rc = update_lun_rule(id, NULL, true, autoconf);
+	rc2 = update_lun_rule(id, NULL, false, autoconf);
 
 	if (rc)
 		return rc;
@@ -692,7 +696,7 @@ exit_code_t udev_zfcp_lun_remove_rule(co
 }
 
 /* Determine if a udev rule exists for configuring the specified zfcp lun. */
-bool udev_zfcp_lun_exists(const char *id)
+bool udev_zfcp_lun_exists(const char *id, bool autoconf)
 {
 	struct zfcp_lun_devid devid;
 	char *path, *rule = NULL, *pattern = NULL;
@@ -702,7 +706,7 @@ bool udev_zfcp_lun_exists(const char *id
 		return false;
 
 	/* Check for single lun rule file first. */
-	path = get_single_zfcp_lun_path(id);
+	path = get_single_zfcp_lun_path(id, autoconf);
 	if (util_path_exists(path)) {
 		rc = true;
 		goto out;
@@ -710,7 +714,7 @@ bool udev_zfcp_lun_exists(const char *id
 	free(path);
 
 	/* Check multi lun rule file next. */
-	path = get_zfcp_lun_path(id);
+	path = get_zfcp_lun_path(id, autoconf);
 	rule = misc_read_text_file(path, 1, err_ignore);
 	if (!rule)
 		goto out;
--- a/zdev/src/zfcp_lun.c
+++ b/zdev/src/zfcp_lun.c
@@ -467,7 +467,14 @@ static exit_code_t zfcp_lun_st_read_pers
 					       struct device *dev,
 					       read_scope_t scope)
 {
-	return udev_zfcp_lun_read_device(dev);
+	return udev_zfcp_lun_read_device(dev, false);
+}
+
+static exit_code_t zfcp_lun_st_read_autoconf(struct subtype *st,
+					     struct device *dev,
+					     read_scope_t scope)
+{
+	return udev_zfcp_lun_read_device(dev, true);
 }
 
 static exit_code_t zfcp_lun_add(struct device *dev)
@@ -564,7 +571,13 @@ static exit_code_t zfcp_lun_st_configure
 static exit_code_t zfcp_lun_st_configure_persistent(struct subtype *st,
 						    struct device *dev)
 {
-	return udev_zfcp_lun_write_device(dev);
+	return udev_zfcp_lun_write_device(dev, false);
+}
+
+static exit_code_t zfcp_lun_st_configure_autoconf(struct subtype *st,
+						  struct device *dev)
+{
+	return udev_zfcp_lun_write_device(dev, true);
 }
 
 static exit_code_t zfcp_lun_st_deconfigure_active(struct subtype *st,
@@ -578,7 +591,13 @@ static exit_code_t zfcp_lun_st_deconfigu
 static exit_code_t zfcp_lun_st_deconfigure_persistent(struct subtype *st,
 						      struct device *dev)
 {
-	return udev_zfcp_lun_remove_rule(dev->id);
+	return udev_zfcp_lun_remove_rule(dev->id, false);
+}
+
+static exit_code_t zfcp_lun_st_deconfigure_autoconf(struct subtype *st,
+						    struct device *dev)
+{
+	return udev_zfcp_lun_remove_rule(dev->id, true);
 }
 
 static exit_code_t check_npiv(struct subtype *st, struct device *dev,
@@ -606,7 +625,8 @@ static exit_code_t check_npiv(struct sub
 	if (!allow_lun_scan)
 		goto out;
 
-	if (!(dev->active.deconfigured || dev->persistent.deconfigured)) {
+	if (!(dev->active.deconfigured || dev->persistent.deconfigured ||
+	      dev->autoconf.deconfigured)) {
 		delayed_info("Note: Auto LUN scan enabled - manual LUN "
 			     "configuration is redundant for %s %s\n",
 			     zfcp_host_subtype.devname, fcp_dev_id);
@@ -643,7 +663,8 @@ static exit_code_t zfcp_lun_st_check_pos
 
 	/* Don't show note when an attribute was modified. */
 	if (setting_list_modified(dev->active.settings) ||
-	    setting_list_modified(dev->persistent.settings))
+	    setting_list_modified(dev->persistent.settings) ||
+	    setting_list_modified(dev->autoconf.settings))
 		return EXIT_OK;
 
 	/* Check for NPIV but don't route exit code to caller - we only
@@ -795,7 +816,12 @@ static bool zfcp_lun_st_exists_active(st
 
 static bool zfcp_lun_st_exists_persistent(struct subtype *st, const char *id)
 {
-	return udev_zfcp_lun_exists(id);
+	return udev_zfcp_lun_exists(id, false);
+}
+
+static bool zfcp_lun_st_exists_autoconf(struct subtype *st, const char *id)
+{
+	return udev_zfcp_lun_exists(id, true);
 }
 
 static exit_code_t zfcp_lun_st_is_definable(struct subtype *st, const char *id,
@@ -889,7 +915,13 @@ static void zfcp_lun_st_add_active_ids(s
 static void zfcp_lun_st_add_persistent_ids(struct subtype *st,
 					   struct util_list *ids)
 {
-	udev_zfcp_lun_add_device_ids(ids);
+	udev_zfcp_lun_add_device_ids(ids, false);
+}
+
+static void zfcp_lun_st_add_autoconf_ids(struct subtype *st,
+					 struct util_list *ids)
+{
+	udev_zfcp_lun_add_device_ids(ids, true);
 }
 
 static exit_code_t add_sg_cb(const char *path, const char *filename, void *data)
@@ -1072,18 +1104,23 @@ struct subtype zfcp_lun_subtype = {
 
 	.exists_active		= &zfcp_lun_st_exists_active,
 	.exists_persistent	= &zfcp_lun_st_exists_persistent,
+	.exists_autoconf	= &zfcp_lun_st_exists_autoconf,
 
 	.add_active_ids		= &zfcp_lun_st_add_active_ids,
 	.add_persistent_ids	= &zfcp_lun_st_add_persistent_ids,
+	.add_autoconf_ids	= &zfcp_lun_st_add_autoconf_ids,
 
 	.read_active		= &zfcp_lun_st_read_active,
 	.read_persistent	= &zfcp_lun_st_read_persistent,
+	.read_autoconf		= &zfcp_lun_st_read_autoconf,
 
 	.configure_active	= &zfcp_lun_st_configure_active,
 	.configure_persistent	= &zfcp_lun_st_configure_persistent,
+	.configure_autoconf	= &zfcp_lun_st_configure_autoconf,
 
 	.deconfigure_active	= &zfcp_lun_st_deconfigure_active,
 	.deconfigure_persistent	= &zfcp_lun_st_deconfigure_persistent,
+	.deconfigure_autoconf	= &zfcp_lun_st_deconfigure_autoconf,
 
 	.check_pre_configure	= &zfcp_lun_st_check_pre_configure,
 	.check_post_configure	= &zfcp_lun_st_check_post_configure,
openSUSE Build Service is sponsored by