mirror of
https://github.com/ibm-s390-linux/s390-tools.git
synced 2026-08-05 02:14:52 +00:00
Enable user to specify that a device should be configured early, that is during the initial RAM-disk boot phase. This may be necessary, e.g. to override auto-configuration for a device which is also applied during that boot phase. It may also be used to manually specify devices that are required to access the root file system, such as networking devices. Users can mark devices as requiring early configuration by specifying a value of 1 for the newly added internal attribute zdev:early: # chzdev dasd-eckd 0.0.1234 -p zdev:early=1 This can be changed back by removing the attribute setting, or by setting the attribute value to 0: # chzdev dasd-eckd 0.0.1234 -p -r zdev:early or # chzdev dasd-eckd 0.0.1234 -p zdev:early=0 Signed-off-by: Peter Oberparleiter <oberpar@linux.vnet.ibm.com> Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
258 lines
6.1 KiB
C
258 lines
6.1 KiB
C
/*
|
|
* zdev - Modify and display the persistent configuration of devices
|
|
*
|
|
* Copyright IBM Corp. 2016, 2017
|
|
*
|
|
* s390-tools is free software; you can redistribute it and/or modify
|
|
* it under the terms of the MIT license. See LICENSE for details.
|
|
*/
|
|
|
|
#include <inttypes.h>
|
|
#include <stdint.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include "attrib.h"
|
|
#include "ccw.h"
|
|
#include "device.h"
|
|
#include "devtype.h"
|
|
#include "internal.h"
|
|
#include "misc.h"
|
|
#include "path.h"
|
|
#include "setting.h"
|
|
#include "zfcp.h"
|
|
#include "zfcp_host.h"
|
|
|
|
/*
|
|
* zfcp host attributes.
|
|
*/
|
|
|
|
static struct attrib zfcp_host_attr_failed = {
|
|
.name = "failed",
|
|
.title = "Check and restart FCP device recovery",
|
|
.desc =
|
|
"This attribute shows if error recovery of an FCP device has failed:\n"
|
|
" 0: Error recovery has not failed or was not started\n"
|
|
" 1: Error recovery was started and failed to complete\n"
|
|
" successfully even after several automatic retries\n\n"
|
|
"Write the value 0 to this attribute to restart the error recovery\n"
|
|
"process after resolving the root cause of the failure.\n",
|
|
.activeonly = 1,
|
|
.rewrite = 1,
|
|
.unstable = 1,
|
|
.defval = "0",
|
|
.accept = ACCEPT_ARRAY(ACCEPT_NUM(0)),
|
|
};
|
|
|
|
static struct attrib zfcp_host_attr_port_remove = {
|
|
.name = "port_remove",
|
|
.title = "Unregister a remote port from the FCP device",
|
|
.desc =
|
|
"Unregister a remote port from the FCP device by writing its WWPN\n"
|
|
"to this attribute. The WWPN must be in a format with 16 hexadecimal\n"
|
|
"digits and 0x prefix and no manually configured FCP LUNs may be\n"
|
|
"registered with that remote port.\n\n"
|
|
"Note: The next port scan will register all available ports again,\n"
|
|
"including any previously removed ports. To prevent removed ports\n"
|
|
"from being registered automatically, use zoning.\n",
|
|
.writeonly = 1,
|
|
};
|
|
|
|
static struct attrib zfcp_host_attr_port_rescan = {
|
|
.name = "port_rescan",
|
|
.title = "Trigger a port rescan for the FCP device",
|
|
.desc =
|
|
"Rescan FCP device for available remote ports by writing the value 1\n"
|
|
"to this attribute\n",
|
|
.activeonly = 1,
|
|
.writeonly = 1,
|
|
.accept = ACCEPT_ARRAY(ACCEPT_NUM(1)),
|
|
};
|
|
|
|
/*
|
|
* zfcp host methods.
|
|
*/
|
|
|
|
static exit_code_t check_cmb_enable(struct subtype *st, struct device *dev,
|
|
config_t config)
|
|
{
|
|
struct setting *c, *o;
|
|
|
|
c = setting_list_find(dev->active.settings, ccw_attr_cmb_enable.name);
|
|
o = setting_list_find(dev->active.settings, ccw_attr_online.name);
|
|
|
|
if (!c || !o) {
|
|
/* Could not determine attribute states. */
|
|
return EXIT_OK;
|
|
}
|
|
|
|
if (c->modified && o->actual_value &&
|
|
strcmp(o->actual_value, "1") == 0 && strcmp(o->value, "0") != 0) {
|
|
delayed_forceable("Cannot modify cmb_enable setting while "
|
|
"device is online\n");
|
|
return EXIT_INVALID_CONFIG;
|
|
}
|
|
|
|
return EXIT_OK;
|
|
}
|
|
|
|
static exit_code_t zfcp_host_st_check_pre_configure(struct subtype *st,
|
|
struct device *dev,
|
|
int prereq, config_t config)
|
|
{
|
|
exit_code_t rc;
|
|
|
|
/* No need to check if device is deconfigured. */
|
|
if (dev->active.deconfigured)
|
|
return EXIT_OK;
|
|
|
|
rc = check_cmb_enable(st, dev, config);
|
|
if (rc)
|
|
return rc;
|
|
|
|
return EXIT_OK;
|
|
}
|
|
|
|
static char *get_port_type_path(const char *id)
|
|
{
|
|
char *devpath, *path = NULL;
|
|
struct util_list *files;
|
|
struct strlist_node *s;
|
|
|
|
devpath = path_get_ccw_device(ZFCP_CCWDRV_NAME, id);
|
|
files = strlist_new();
|
|
if (!misc_read_dir(devpath, files, NULL, NULL))
|
|
goto out;
|
|
util_list_iterate(files, s) {
|
|
if (!starts_with(s->str, "host"))
|
|
continue;
|
|
path = misc_asprintf("%s/%s/fc_host/%s/port_type", devpath,
|
|
s->str, s->str);
|
|
}
|
|
out:
|
|
free(devpath);
|
|
strlist_free(files);
|
|
|
|
return path;
|
|
}
|
|
|
|
exit_code_t zfcp_host_check_npiv(const char *id, int *enabled)
|
|
{
|
|
char *path, *type = NULL;
|
|
exit_code_t rc = EXIT_RUNTIME_ERROR;
|
|
|
|
path = get_port_type_path(id);
|
|
if (!path)
|
|
goto out;
|
|
|
|
type = misc_read_text_file(path, 1, err_ignore);
|
|
if (!type)
|
|
goto out;
|
|
|
|
/* Check FCP port type. */
|
|
if (strcmp(type, "NPIV VPORT") == 0)
|
|
*enabled = 1;
|
|
else
|
|
*enabled = 0;
|
|
rc = EXIT_OK;
|
|
|
|
out:
|
|
free(path);
|
|
free(type);
|
|
|
|
return rc;
|
|
}
|
|
|
|
static exit_code_t check_npiv(struct subtype *st, struct device *dev,
|
|
int prereq, config_t config)
|
|
{
|
|
int npiv, allow_lun_scan;
|
|
static int warn_done;
|
|
|
|
if (prereq) {
|
|
/* FCP device is configured as part of 3-tuple. */
|
|
return EXIT_OK;
|
|
}
|
|
|
|
if (subtype_online_get(st, dev, config) != 1) {
|
|
/* FCP device is set offline. */
|
|
return EXIT_OK;
|
|
}
|
|
|
|
/* Check FCP port type. */
|
|
if (zfcp_host_check_npiv(dev->id, &npiv)) {
|
|
/* Could not determine NPIV setting. */
|
|
return EXIT_OK;
|
|
}
|
|
if (!npiv) {
|
|
delayed_info("Note: NPIV mode disabled - LUNs must be "
|
|
"configured manually\n");
|
|
return EXIT_INVALID_CONFIG;
|
|
}
|
|
|
|
/* Check allow_lun_scan setting. */
|
|
if (zfcp_check_allow_lun_scan(&allow_lun_scan, config)) {
|
|
/* Could not determine allow_lun_scan setting. */
|
|
return EXIT_OK;
|
|
}
|
|
if (!allow_lun_scan && !warn_done) {
|
|
delayed_info("Note: Automatic LUN scan disabled - LUNs must "
|
|
"be configured manually\n");
|
|
return EXIT_INVALID_CONFIG;
|
|
}
|
|
|
|
return EXIT_OK;
|
|
}
|
|
|
|
/* Perform post-write checks specific to zfcp hosts. */
|
|
static exit_code_t zfcp_host_st_check_post_configure(struct subtype *st,
|
|
struct device *dev,
|
|
int prereq,
|
|
config_t config)
|
|
{
|
|
/* No need to check if device is deconfigured. */
|
|
if (dev->active.deconfigured)
|
|
return EXIT_OK;
|
|
|
|
/* Check for NPIV but don't route exit code to caller - we only
|
|
* want to show a warning. */
|
|
check_npiv(st, dev, prereq, config);
|
|
|
|
return EXIT_OK;
|
|
}
|
|
|
|
/*
|
|
* zfcp host sub-type.
|
|
*/
|
|
|
|
static struct ccw_subtype_data zfcp_host_data = {
|
|
.ccwdrv = ZFCP_CCWDRV_NAME,
|
|
.mod = ZFCP_MOD_NAME,
|
|
};
|
|
|
|
struct subtype zfcp_host_subtype = {
|
|
.super = &ccw_subtype,
|
|
|
|
.devtype = &zfcp_devtype,
|
|
.name = "zfcp-host",
|
|
.title = "FCP devices",
|
|
.devname = "FCP device",
|
|
.modules = STRING_ARRAY(ZFCP_MOD_NAME),
|
|
.namespace = &ccw_namespace,
|
|
.data = &zfcp_host_data,
|
|
|
|
.dev_attribs = ATTRIB_ARRAY(
|
|
&ccw_attr_online,
|
|
&ccw_attr_cmb_enable,
|
|
&zfcp_host_attr_failed,
|
|
&zfcp_host_attr_port_remove,
|
|
&zfcp_host_attr_port_rescan,
|
|
&internal_attr_early,
|
|
),
|
|
.unknown_dev_attribs = 1,
|
|
|
|
.check_pre_configure = &zfcp_host_st_check_pre_configure,
|
|
.check_post_configure = &zfcp_host_st_check_post_configure,
|
|
};
|