mirror of
https://github.com/ibm-s390-linux/s390-tools.git
synced 2026-08-05 02:14:52 +00:00
zdev: Add option to select IPL device
Add new command-line option --ipldev. When specified and IPL was done from a supported device type, the IPL device is selected for the requested tool operation. Example to list IPL device information: $ lszdev --ipldev Example to create a persistent configuration for the IPL device: $ chzdev --enable --persistent --ipldev Reviewed-by: Vineeth Vijayan <vneethv@linux.ibm.com> Signed-off-by: Peter Oberparleiter <oberpar@linux.ibm.com> Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
This commit is contained in:
committed by
Jan Höppner
parent
cad4e9e15b
commit
d9a9bd8dcf
@@ -23,6 +23,7 @@
|
||||
#define PATH_MODPROBE "/sbin/modprobe"
|
||||
#define PATH_CCW_BUS "/sys/bus/ccw"
|
||||
#define PATH_CCWGROUP_BUS "/sys/bus/ccwgroup"
|
||||
#define PATH_IPL "/sys/firmware/ipl"
|
||||
#define PATH_UDEV_RULES "/etc/udev/rules.d"
|
||||
#define PATH_UDEV_RULES_VOLATILE "/run/udev/rules.d"
|
||||
#define PATH_PROC "/proc"
|
||||
|
||||
@@ -29,6 +29,7 @@ struct select_opts {
|
||||
unsigned int online:1;
|
||||
unsigned int offline:1;
|
||||
unsigned int failed:1;
|
||||
unsigned int ipldev:1;
|
||||
struct util_list devids; /* List of struct strlist_node */
|
||||
struct util_list by_path; /* List of struct strlist_node */
|
||||
struct util_list by_node; /* List of struct strlist_node */
|
||||
|
||||
@@ -127,6 +127,7 @@ typedef exit_code_t (*subtype_cb_t)(struct subtype *st, const char *id,
|
||||
* @device_undefine: Optional: Undefine a device
|
||||
* @add_definable_ids: Optional: Add IDs of all devices that can be defined to
|
||||
* specified strlist
|
||||
* @get_ipldev_id: Optional: If subtype provides IPL device, return its ID
|
||||
*/
|
||||
struct subtype {
|
||||
/* Static data. */
|
||||
@@ -222,6 +223,7 @@ struct subtype {
|
||||
exit_code_t (*device_undefine)(struct subtype *, struct device *);
|
||||
void (*add_definable_ids)(struct subtype *,
|
||||
struct util_list *);
|
||||
char *(*get_ipldev_id)(struct subtype *);
|
||||
};
|
||||
|
||||
/* Subtype method accessor functions. */
|
||||
@@ -287,6 +289,7 @@ exit_code_t subtype_detect_definable(struct subtype *, struct device *);
|
||||
exit_code_t subtype_device_define(struct subtype *, struct device *);
|
||||
exit_code_t subtype_device_undefine(struct subtype *, struct device *);
|
||||
void subtype_add_definable_ids(struct subtype *, struct util_list *);
|
||||
char *subtype_get_ipldev_id(struct subtype *);
|
||||
|
||||
/* Subtype helper functions. */
|
||||
bool subtype_device_exists(struct subtype *st, const char *id,
|
||||
@@ -308,6 +311,7 @@ struct subtype *subtype_find(const char *name);
|
||||
struct attrib *subtype_find_dev_attrib(struct subtype *st, const char *str);
|
||||
exit_code_t subtype_read_all_devices(struct subtype *st, config_t config,
|
||||
read_scope_t);
|
||||
bool subtypes_find_ipldev(struct subtype **st_ptr, char **id_ptr);
|
||||
bool subtypes_find_by_devnode(struct devnode *devnode,
|
||||
struct subtype **st_ptr, char **id_ptr);
|
||||
void subtype_devices_print_all(void);
|
||||
|
||||
@@ -345,6 +345,12 @@ errors.
|
||||
.CL lszdev \-\-failed \-\-info
|
||||
.PP
|
||||
.
|
||||
.OD ipldev "" ""
|
||||
Select IPL device
|
||||
|
||||
Select the device used for the most recent IPL operation.
|
||||
.PP
|
||||
.
|
||||
.
|
||||
.SH SETTINGS
|
||||
A
|
||||
|
||||
@@ -313,7 +313,12 @@ errors.
|
||||
.B Example:
|
||||
.CL lszdev \-\-failed \-\-info
|
||||
.PP
|
||||
.
|
||||
.OD ipldev "" ""
|
||||
Select IPL device
|
||||
|
||||
Select the device used for the most recent IPL operation.
|
||||
.PP
|
||||
.
|
||||
.
|
||||
.SH ACTIONS
|
||||
|
||||
@@ -1827,6 +1827,27 @@ static char *ccw_st_get_active_attrib_path(struct subtype *st,
|
||||
return path;
|
||||
}
|
||||
|
||||
/* Return a newly allocated character string containing the IPL device ID in
|
||||
* case of CCW IPL. */
|
||||
static char *ccw_st_get_ipldev_id(struct subtype *st)
|
||||
{
|
||||
char *type, *id = NULL;
|
||||
|
||||
type = path_read_text_file(1, err_ignore, PATH_IPL "/ipl_type");
|
||||
if (strcmp(type, "ccw") != 0)
|
||||
goto out;
|
||||
|
||||
id = path_read_text_file(1, err_ignore, PATH_IPL "/device");
|
||||
if (!ccw_st_exists_active(st, id)) {
|
||||
free(id);
|
||||
id = NULL;
|
||||
}
|
||||
out:
|
||||
free(type);
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
/* The methods of this subtype assume that @data points to a
|
||||
* struct ccw_subtype_data. */
|
||||
struct subtype ccw_subtype = {
|
||||
@@ -1864,4 +1885,6 @@ struct subtype ccw_subtype = {
|
||||
.add_devnodes = &ccw_st_add_devnodes,
|
||||
.resolve_devnode = &ccw_st_resolve_devnode,
|
||||
.get_active_attrib_path = &ccw_st_get_active_attrib_path,
|
||||
|
||||
.get_ipldev_id = &ccw_st_get_ipldev_id,
|
||||
};
|
||||
|
||||
@@ -124,6 +124,7 @@ enum {
|
||||
OPT_ONLINE = (OPT_ANONYMOUS_BASE+__COUNTER__),
|
||||
OPT_OFFLINE = (OPT_ANONYMOUS_BASE+__COUNTER__),
|
||||
OPT_FAILED = (OPT_ANONYMOUS_BASE+__COUNTER__),
|
||||
OPT_IPLDEV = (OPT_ANONYMOUS_BASE+__COUNTER__),
|
||||
OPT_BY_PATH = (OPT_ANONYMOUS_BASE+__COUNTER__),
|
||||
OPT_BY_NODE = (OPT_ANONYMOUS_BASE+__COUNTER__),
|
||||
OPT_BY_INTERFACE = (OPT_ANONYMOUS_BASE+__COUNTER__),
|
||||
@@ -173,14 +174,14 @@ static struct opts_conflict conflict_list[] = {
|
||||
OPT_REMOVE_ALL, OPT_CONFIGURED, OPT_EXISTING, OPT_ONLINE,
|
||||
OPT_OFFLINE, OPT_BY_PATH, OPT_BY_NODE, OPT_BY_INTERFACE,
|
||||
OPT_BY_ATTRIB, OPT_ACTIVE, OPT_PERSISTENT, OPT_FAILED,
|
||||
OPT_DECONFIGURE_ALL, 0),
|
||||
OPT_IPLDEV, OPT_DECONFIGURE_ALL, 0),
|
||||
OPTS_CONFLICT(OPT_LIST_TYPES,
|
||||
OPT_DECONFIGURE, OPT_LIST_ATTRIBS, OPT_HELP_ATTRIBS,
|
||||
OPT_EXPORT, OPT_IMPORT, OPT_APPLY, OPT_REMOVE,
|
||||
OPT_REMOVE_ALL, OPT_CONFIGURED, OPT_EXISTING, OPT_ONLINE,
|
||||
OPT_OFFLINE, OPT_BY_PATH, OPT_BY_NODE, OPT_BY_INTERFACE,
|
||||
OPT_BY_ATTRIB, OPT_ACTIVE, OPT_PERSISTENT, OPT_FAILED,
|
||||
OPT_DECONFIGURE_ALL, 0),
|
||||
OPT_IPLDEV, OPT_DECONFIGURE_ALL, 0),
|
||||
OPTS_CONFLICT(OPT_EXPORT,
|
||||
OPT_DECONFIGURE, OPT_LIST_ATTRIBS, OPT_HELP_ATTRIBS,
|
||||
OPT_LIST_TYPES, OPT_IMPORT, OPT_APPLY, OPT_REMOVE,
|
||||
@@ -197,7 +198,7 @@ static struct opts_conflict conflict_list[] = {
|
||||
OPT_REMOVE_ALL, OPT_CONFIGURED, OPT_EXISTING, OPT_ONLINE,
|
||||
OPT_OFFLINE, OPT_BY_PATH, OPT_BY_NODE, OPT_BY_INTERFACE,
|
||||
OPT_BY_ATTRIB, OPT_ACTIVE, OPT_PERSISTENT, OPT_FAILED,
|
||||
OPT_DECONFIGURE_ALL, 0),
|
||||
OPT_IPLDEV, OPT_DECONFIGURE_ALL, 0),
|
||||
OPTS_CONFLICT(OPT_APPLY,
|
||||
OPT_DECONFIGURE, OPT_LIST_ATTRIBS, OPT_HELP_ATTRIBS,
|
||||
OPT_LIST_TYPES, OPT_EXPORT, OPT_IMPORT, OPT_REMOVE,
|
||||
@@ -223,6 +224,7 @@ static const struct option opt_list[] = {
|
||||
{ "online", no_argument, NULL, OPT_ONLINE },
|
||||
{ "offline", no_argument, NULL, OPT_OFFLINE },
|
||||
{ "failed", no_argument, NULL, OPT_FAILED },
|
||||
{ "ipldev", no_argument, NULL, OPT_IPLDEV },
|
||||
{ "by-path", required_argument, NULL, OPT_BY_PATH },
|
||||
{ "by-node", required_argument, NULL, OPT_BY_NODE },
|
||||
{ "by-interface", required_argument, NULL, OPT_BY_INTERFACE },
|
||||
@@ -837,6 +839,11 @@ static exit_code_t parse_options(struct options *opts, int argc, char *argv[])
|
||||
opts->select->failed = 1;
|
||||
break;
|
||||
|
||||
case OPT_IPLDEV:
|
||||
/* --ipldev */
|
||||
opts->select->ipldev = 1;
|
||||
break;
|
||||
|
||||
case OPT_BY_PATH:
|
||||
/* --by-path MOUNTPOINT */
|
||||
strlist_add(&opts->select->by_path, "%s", optarg);
|
||||
|
||||
@@ -21,6 +21,7 @@ SELECTION
|
||||
--existing Select devices found in the active configuration
|
||||
--online/--offline Select devices that are online/offline
|
||||
--failed Select devices that are not functioning correctly
|
||||
--ipldev Select device used for IPL/boot
|
||||
--by-path PATH Select device providing file system path, e.g. /usr
|
||||
--by-node NODE Select device providing device node, e.g. /dev/sda
|
||||
--by-interface NAME Select device providing network interface, e.g. eth0
|
||||
|
||||
@@ -477,6 +477,26 @@ static void dasd_st_add_modules(struct subtype *st, struct device *dev,
|
||||
strlist_add_unique(modules, DASD_DIAG_MOD_NAME);
|
||||
}
|
||||
|
||||
static char *dasd_eckd_st_get_ipldev_id(struct subtype *st)
|
||||
{
|
||||
char *id, *type;
|
||||
|
||||
/* Handle CCW-type IPL first. */
|
||||
id = st->super->get_ipldev_id(st);
|
||||
if (id)
|
||||
return id;
|
||||
|
||||
/* Extra-handling for eckd LD-IPL. */
|
||||
type = path_read_text_file(1, err_ignore, PATH_IPL "/ipl_type");
|
||||
if (strcmp(type, "eckd") != 0)
|
||||
goto out;
|
||||
id = path_read_text_file(1, err_ignore, PATH_IPL "/ipl/device");
|
||||
|
||||
out:
|
||||
free(type);
|
||||
return id;
|
||||
}
|
||||
|
||||
/*
|
||||
* DASD methods.
|
||||
*/
|
||||
@@ -798,6 +818,7 @@ struct subtype dasd_subtype_eckd = {
|
||||
.configure_persistent = &dasd_st_configure_persistent,
|
||||
.check_pre_configure = &dasd_st_check_pre_configure,
|
||||
.add_modules = &dasd_st_add_modules,
|
||||
.get_ipldev_id = &dasd_eckd_st_get_ipldev_id,
|
||||
};
|
||||
|
||||
static struct ccw_subtype_data dasd_fba_data = {
|
||||
|
||||
@@ -89,6 +89,7 @@ enum {
|
||||
OPT_ONLINE = (OPT_ANONYMOUS_BASE+__COUNTER__),
|
||||
OPT_OFFLINE = (OPT_ANONYMOUS_BASE+__COUNTER__),
|
||||
OPT_FAILED = (OPT_ANONYMOUS_BASE+__COUNTER__),
|
||||
OPT_IPLDEV = (OPT_ANONYMOUS_BASE+__COUNTER__),
|
||||
OPT_BY_PATH = (OPT_ANONYMOUS_BASE+__COUNTER__),
|
||||
OPT_BY_NODE = (OPT_ANONYMOUS_BASE+__COUNTER__),
|
||||
OPT_BY_INTERFACE = (OPT_ANONYMOUS_BASE+__COUNTER__),
|
||||
@@ -129,6 +130,7 @@ static struct opts_conflict conflict_list[] = {
|
||||
OPTS_CONFLICT(OPT_TYPE,
|
||||
OPT_CONFIGURED, OPT_EXISTING, OPT_ONLINE, OPT_OFFLINE,
|
||||
OPT_BY_PATH, OPT_BY_NODE, OPT_BY_INTERFACE, OPT_FAILED,
|
||||
OPT_IPLDEV,
|
||||
0),
|
||||
OPTS_CONFLICT(OPT_SITE,
|
||||
OPT_TYPE),
|
||||
@@ -148,6 +150,7 @@ static const struct option opt_list[] = {
|
||||
{ "online", no_argument, NULL, OPT_ONLINE },
|
||||
{ "offline", no_argument, NULL, OPT_OFFLINE },
|
||||
{ "failed", no_argument, NULL, OPT_FAILED },
|
||||
{ "ipldev", no_argument, NULL, OPT_IPLDEV },
|
||||
{ "by-path", required_argument, NULL, OPT_BY_PATH },
|
||||
{ "by-node", required_argument, NULL, OPT_BY_NODE },
|
||||
{ "by-interface", required_argument, NULL, OPT_BY_INTERFACE },
|
||||
@@ -609,6 +612,11 @@ static exit_code_t parse_options(struct options *opts, int argc, char *argv[])
|
||||
opts->select->failed = 1;
|
||||
break;
|
||||
|
||||
case OPT_IPLDEV:
|
||||
/* --ipldev */
|
||||
opts->select->ipldev = 1;
|
||||
break;
|
||||
|
||||
case OPT_BY_PATH:
|
||||
/* --by-path MOUNTPOINT */
|
||||
strlist_add(&opts->select->by_path, "%s", optarg);
|
||||
|
||||
@@ -21,6 +21,7 @@ SELECTION
|
||||
--existing Select devices found in the active configuration
|
||||
--online/--offline Select devices that are online/offline
|
||||
--failed Select devices that are not functioning correctly
|
||||
--ipldev Select device used for IPL/boot
|
||||
--by-path PATH Select device providing file system path, e.g. /usr
|
||||
--by-node NODE Select device providing device node, e.g. /dev/sda
|
||||
--by-interface NAME Select device providing network interface, e.g. eth0
|
||||
|
||||
@@ -69,7 +69,8 @@ bool select_opts_dev_specified(struct select_opts *select)
|
||||
!util_list_is_empty(&select->by_if) ||
|
||||
!util_list_is_empty(&select->by_attr) ||
|
||||
select->all || select->configured || select->existing ||
|
||||
select->online || select->offline || select->failed)
|
||||
select->online || select->offline || select->failed ||
|
||||
select->ipldev)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
@@ -1207,6 +1208,19 @@ out:
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Select device that was used for IPL. */
|
||||
static void select_ipldev(struct util_list *selected)
|
||||
{
|
||||
struct subtype *st;
|
||||
char *id;
|
||||
|
||||
if (!subtypes_find_ipldev(&st, &id))
|
||||
return;
|
||||
|
||||
selected_dev_list_add(selected, st->devtype, st, id, NULL, 0);
|
||||
free(id);
|
||||
}
|
||||
|
||||
/* Determine list of IDs of selected devices based on selection options.
|
||||
* Results are stored as list of struct selected_dev_node in SELECTED.
|
||||
* If @existing is set, only return nodes for existing devices.
|
||||
@@ -1235,7 +1249,7 @@ exit_code_t select_devices(struct select_opts *select,
|
||||
!(util_list_is_empty(&select->by_path) &&
|
||||
util_list_is_empty(&select->by_node) &&
|
||||
util_list_is_empty(&select->by_if) &&
|
||||
util_list_is_empty(&select->by_attr)))
|
||||
util_list_is_empty(&select->by_attr) && !select->ipldev))
|
||||
goto by_function;
|
||||
|
||||
/* Convert device ID specifications to enable tracking of specifications
|
||||
@@ -1291,6 +1305,9 @@ by_function:
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (select->ipldev)
|
||||
select_ipldev(selected);
|
||||
|
||||
out:
|
||||
/* Release device ID specifications tracking list. */
|
||||
ptrlist_free(specs, 1);
|
||||
|
||||
@@ -96,6 +96,30 @@ static exit_code_t devnode_cb(struct subtype *st, const char *id,
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Find device which was used for IPL. Note that id_ptr will point to a newly
|
||||
* allocated string on success. */
|
||||
bool subtypes_find_ipldev(struct subtype **st_ptr, char **id_ptr)
|
||||
{
|
||||
int i, j;
|
||||
struct devtype *dt;
|
||||
struct subtype *st;
|
||||
char *id;
|
||||
|
||||
for (i = 0; (dt = devtypes[i]); i++) {
|
||||
for (j = 0; (st = dt->subtypes[j]); j++) {
|
||||
id = subtype_get_ipldev_id(st);
|
||||
if (id) {
|
||||
*st_ptr = st;
|
||||
*id_ptr = id;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Find a device which provides the specified devnode. Note that id_ptr will
|
||||
* point to a newly allocated string on success. */
|
||||
bool subtypes_find_by_devnode(struct devnode *devnode, struct subtype **st_ptr,
|
||||
@@ -520,6 +544,16 @@ void subtype_add_definable_ids(struct subtype *st, struct util_list *ids)
|
||||
super->add_definable_ids(st, ids);
|
||||
}
|
||||
|
||||
char *subtype_get_ipldev_id(struct subtype *st)
|
||||
{
|
||||
struct subtype *super = super_get(st, get_ipldev_id, 0);
|
||||
|
||||
if (super)
|
||||
return super->get_ipldev_id(st);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Subtype helpers. These functions combine some of the subtype methods
|
||||
* to implement more complex functions.
|
||||
|
||||
@@ -1105,6 +1105,28 @@ static exit_code_t zfcp_lun_st_detect_definable(struct subtype *st,
|
||||
return EXIT_OK;
|
||||
}
|
||||
|
||||
static char *zfcp_lun_st_get_ipldev_id(struct subtype *st)
|
||||
{
|
||||
char *type, *fcp_dev, *wwpn, *lun, *id = NULL;
|
||||
|
||||
type = path_read_text_file(1, err_ignore, PATH_IPL "/ipl_type");
|
||||
if (strcmp(type, "fcp") != 0)
|
||||
goto out;
|
||||
|
||||
fcp_dev = path_read_text_file(1, err_ignore, PATH_IPL "/device");
|
||||
wwpn = path_read_text_file(1, err_ignore, PATH_IPL "/wwpn");
|
||||
lun = path_read_text_file(1, err_ignore, PATH_IPL "/lun");
|
||||
if (fcp_dev && wwpn && lun)
|
||||
id = misc_asprintf("%s:%s:%s", fcp_dev, wwpn, lun);
|
||||
free(lun);
|
||||
free(wwpn);
|
||||
free(fcp_dev);
|
||||
|
||||
out:
|
||||
free(type);
|
||||
return id;
|
||||
}
|
||||
|
||||
/*
|
||||
* zfcp lun subtype.
|
||||
*/
|
||||
@@ -1168,4 +1190,6 @@ struct subtype zfcp_lun_subtype = {
|
||||
.detect_definable = &zfcp_lun_st_detect_definable,
|
||||
.device_define = &zfcp_lun_st_device_define,
|
||||
.device_undefine = &zfcp_lun_st_device_undefine,
|
||||
|
||||
.get_ipldev_id = &zfcp_lun_st_get_ipldev_id,
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user