mirror of
https://github.com/ibm-s390-linux/s390-tools.git
synced 2026-08-05 02:14:52 +00:00
zdev: Remove support for lcs device type
Kernel support for LCS devices was removed with commit 6cccb3bb0561
("s390/net: Remove LCS driver") in kernel v6.15. Remove the associated
zdev support for the lcs device type.
Signed-off-by: Vineeth Vijayan <vneethv@linux.ibm.com>
Reviewed-by: Peter Oberparleiter <oberpar@linux.ibm.com>
Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
This commit is contained in:
committed by
Jan Höppner
parent
bd0bb9dd5c
commit
b6bb87f377
@@ -55,7 +55,7 @@ cmdline() {
|
||||
installkernel() {
|
||||
# Add modules for all device types supported by chzdev (required for
|
||||
# auto-configuration)
|
||||
instmods ctcm lcs qeth qeth_l2 qeth_l3 dasd_mod dasd_eckd_mod dasd_fba_mod \
|
||||
instmods ctcm qeth qeth_l2 qeth_l3 dasd_mod dasd_eckd_mod dasd_fba_mod \
|
||||
dasd_diag_mod zfcp
|
||||
}
|
||||
|
||||
|
||||
@@ -61,7 +61,7 @@ installkernel() {
|
||||
# Add modules for all device types supported by chzdev (required for
|
||||
# auto-configuration)
|
||||
hostonly="$(optional_hostonly)" \
|
||||
instmods ctcm lcs qeth qeth_l2 qeth_l3 dasd_mod dasd_eckd_mod dasd_fba_mod \
|
||||
instmods ctcm qeth qeth_l2 qeth_l3 dasd_mod dasd_eckd_mod dasd_fba_mod \
|
||||
dasd_diag_mod zfcp
|
||||
}
|
||||
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef LCS_H
|
||||
#define LCS_H
|
||||
|
||||
#define LCS_MOD_NAME "lcs"
|
||||
#define LCS_CCWGROUPDRV_NAME "lcs"
|
||||
#define LCS_CCWDRV_NAME "lcs"
|
||||
#define LCS_ROOTDRV_NAME "lcs"
|
||||
#define LCS_NUM_DEVS 2
|
||||
|
||||
struct devtype;
|
||||
struct namespace;
|
||||
|
||||
extern struct devtype lcs_devtype;
|
||||
extern struct namespace lcs_namespace;
|
||||
|
||||
#endif /* LCS_H */
|
||||
@@ -1,24 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef LCS_AUTO_H
|
||||
#define LCS_AUTO_H
|
||||
|
||||
#include "misc.h"
|
||||
|
||||
struct util_list;
|
||||
struct ccwgroup_devid;
|
||||
struct ccw_devid;
|
||||
|
||||
void lcs_auto_add_ids(struct util_list *);
|
||||
exit_code_t lcs_auto_get_devid(struct ccwgroup_devid *, struct ccw_devid *,
|
||||
err_t);
|
||||
exit_code_t lcs_auto_is_possible(struct ccwgroup_devid *, err_t);
|
||||
|
||||
#endif /* LCS_AUTO_H */
|
||||
@@ -29,7 +29,7 @@ esac
|
||||
|
||||
# Add modules for all device types supported by chzdev (required for
|
||||
# auto-configuration)
|
||||
zdev_modules="lcs qeth qeth_l2 qeth_l3 dasd_mod dasd_eckd_mod dasd_fba_mod dasd_diag_mod zfcp"
|
||||
zdev_modules="qeth qeth_l2 qeth_l3 dasd_mod dasd_eckd_mod dasd_fba_mod dasd_diag_mod zfcp"
|
||||
|
||||
for x in $zdev_modules ; do
|
||||
manual_add_modules ${x}
|
||||
|
||||
@@ -61,7 +61,7 @@ chzdev - Configure z Systems specific devices
|
||||
.B chzdev
|
||||
is a tool for configuring devices and device drivers which are specific to the
|
||||
IBM z Systems platform. Supported device types include storage devices (DASD
|
||||
and zFCP) and networking devices (QETH, CTC and LCS).
|
||||
and zFCP) and networking devices (QETH and CTC).
|
||||
.PP
|
||||
.
|
||||
.SS "Configurations"
|
||||
|
||||
@@ -60,7 +60,7 @@ lszdev - Display configuration of z Systems specific devices
|
||||
.B lszdev
|
||||
displays the configuration of devices and device drivers that
|
||||
are specific to IBM z Systems. Supported device types include
|
||||
storage devices (DASD and zFCP) and networking devices (QETH, CTC and LCS).
|
||||
storage devices (DASD and zFCP) and networking devices (QETH and CTC).
|
||||
.PP
|
||||
.
|
||||
.PP
|
||||
|
||||
@@ -36,9 +36,6 @@ chzdev_objects += nic.o qeth.o qeth_auto.o
|
||||
# CTC devtype
|
||||
chzdev_objects += ctc.o ctc_auto.o
|
||||
|
||||
# LCS devtype
|
||||
chzdev_objects += lcs.o lcs_auto.o
|
||||
|
||||
# AP devtype
|
||||
chzdev_objects += ap.o
|
||||
|
||||
@@ -72,9 +69,6 @@ lszdev_objects += nic.o qeth.o qeth_auto.o
|
||||
# CTC devtype
|
||||
lszdev_objects += ctc.o ctc_auto.o
|
||||
|
||||
# LCS devtype
|
||||
lszdev_objects += lcs.o lcs_auto.o
|
||||
|
||||
# AP devtype
|
||||
lszdev_objects += ap.o
|
||||
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
#include "ccwgroup.h"
|
||||
#include "ctc.h"
|
||||
#include "ctc_auto.h"
|
||||
#include "lcs.h"
|
||||
#include "module.h"
|
||||
#include "path.h"
|
||||
|
||||
@@ -39,9 +38,7 @@ static struct cutype ctc_cutypes[] = {
|
||||
* 1. A CTC device can be grouped from 2 CCW devices
|
||||
* a) Read device
|
||||
* b) Write device
|
||||
* 2. All CCW devices must be bound to the CTC CCW device driver. Note that
|
||||
* due to an overlap in CU-Types, CCW device could also be bound to
|
||||
* the LCS device driver.
|
||||
* 2. All CCW devices must be bound to the CTC CCW device driver.
|
||||
* 3. The subchannel of all CCW devices must be defined with the same CHPID
|
||||
* 4. None of the CCW devices is part of an existing CCWGROUP device
|
||||
*/
|
||||
@@ -113,7 +110,7 @@ static exit_code_t add_cb(const char *path, const char *filename, void *data)
|
||||
}
|
||||
|
||||
/* Return a sorted ptrlist of struct ccw_devinfos for all CCW devices
|
||||
* bound to the ctc or lcs CCW device driver with matching CUTYPE.
|
||||
* bound to the ctc CCW device driver with matching CUTYPE.
|
||||
* The result must be freed using ptrlist_free(,1); */
|
||||
static struct util_list *read_sorted_ctc_devinfos(void)
|
||||
{
|
||||
@@ -130,12 +127,6 @@ static struct util_list *read_sorted_ctc_devinfos(void)
|
||||
path_for_each(path, add_cb, infos);
|
||||
free(path);
|
||||
|
||||
/* Add CCW devices bound to the LCS CCW device driver. */
|
||||
path = path_get_sys_bus_drv(CCW_BUS_NAME, LCS_CCWDRV_NAME);
|
||||
if (util_path_is_dir(path))
|
||||
path_for_each(path, add_cb, infos);
|
||||
free(path);
|
||||
|
||||
/* For each CHPID: Find groups. Add to result list. */
|
||||
util_list_sort(infos, info_cmp, NULL);
|
||||
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
#include "devnode.h"
|
||||
#include "devtype.h"
|
||||
#include "generic_ccw.h"
|
||||
#include "lcs.h"
|
||||
#include "misc.h"
|
||||
#include "module.h"
|
||||
#include "namespace.h"
|
||||
@@ -36,7 +35,6 @@ struct devtype *devtypes[] = {
|
||||
&zfcp_devtype,
|
||||
&qeth_devtype,
|
||||
&ctc_devtype,
|
||||
&lcs_devtype,
|
||||
&ap_devtype,
|
||||
&virtio_devtype,
|
||||
&generic_ccw_devtype, /* Generic types should come last. */
|
||||
|
||||
429
zdev/src/lcs.c
429
zdev/src/lcs.c
@@ -1,429 +0,0 @@
|
||||
/*
|
||||
* 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 <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "attrib.h"
|
||||
#include "ccw.h"
|
||||
#include "ccwgroup.h"
|
||||
#include "device.h"
|
||||
#include "devtype.h"
|
||||
#include "internal.h"
|
||||
#include "lcs.h"
|
||||
#include "lcs_auto.h"
|
||||
#include "misc.h"
|
||||
#include "namespace.h"
|
||||
#include "setting.h"
|
||||
|
||||
#define DEVNAME "LCS device"
|
||||
|
||||
/*
|
||||
* LCS device ID namespace methods.
|
||||
*/
|
||||
static exit_code_t lcs_parse_devid(struct ccwgroup_devid *devid_ptr,
|
||||
const char *id, err_t err)
|
||||
{
|
||||
struct ccwgroup_devid devid;
|
||||
const char *reason = NULL;
|
||||
exit_code_t rc;
|
||||
|
||||
rc = ccwgroup_parse_devid(&devid, id, err);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
if (devid.num > LCS_NUM_DEVS) {
|
||||
reason = "Too many CCW device IDs specified";
|
||||
rc = EXIT_INVALID_ID;
|
||||
} else if (devid_ptr)
|
||||
*devid_ptr = devid;
|
||||
|
||||
if (reason) {
|
||||
err_t_print(err, "Error in %s ID format: %s: %s\n", DEVNAME,
|
||||
reason, id);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static exit_code_t lcs_parse_devid_range(struct ccwgroup_devid *from_ptr,
|
||||
struct ccwgroup_devid *to_ptr,
|
||||
const char *range, err_t err)
|
||||
{
|
||||
char *from_str, *to_str;
|
||||
struct ccwgroup_devid from, to;
|
||||
exit_code_t rc;
|
||||
const char *reason = NULL;
|
||||
|
||||
/* Split range. */
|
||||
from_str = misc_strdup(range);
|
||||
to_str = strchr(from_str, '-');
|
||||
if (!to_str) {
|
||||
rc = EXIT_INVALID_ID;
|
||||
reason = "Missing hyphen";
|
||||
goto out;
|
||||
}
|
||||
*to_str = 0;
|
||||
to_str++;
|
||||
|
||||
/* Parse range start end end ID. */
|
||||
rc = lcs_parse_devid(&from, from_str, err);
|
||||
if (rc)
|
||||
goto out;
|
||||
|
||||
rc = lcs_parse_devid(&to, to_str, err);
|
||||
if (rc)
|
||||
goto out;
|
||||
|
||||
/* Only allow ranges on CCWGROUP devices specified as single ID. */
|
||||
if (from.num != 1 || to.num != 1) {
|
||||
rc = EXIT_INVALID_ID;
|
||||
reason = "Ranges only supported on single CCW device IDs";
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc = EXIT_OK;
|
||||
if (from_ptr)
|
||||
*from_ptr = from;
|
||||
if (to_ptr)
|
||||
*to_ptr = to;
|
||||
|
||||
out:
|
||||
free(from_str);
|
||||
|
||||
if (reason) {
|
||||
err_t_print(err, "Error in %s ID range format: %s: %s\n",
|
||||
DEVNAME, reason, range);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static bool lcs_parse_devid_range_simple(struct ccwgroup_devid *from,
|
||||
struct ccwgroup_devid *to,
|
||||
const char *range)
|
||||
{
|
||||
if (lcs_parse_devid_range(from, to, range, err_ignore) == EXIT_OK)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static exit_code_t lcs_ns_is_id_valid(const char *id, err_t err)
|
||||
{
|
||||
return lcs_parse_devid(NULL, id, err);
|
||||
}
|
||||
|
||||
static char *lcs_ns_normalize_id(const char *id)
|
||||
{
|
||||
struct ccwgroup_devid devid;
|
||||
|
||||
if (lcs_parse_devid(&devid, id, err_ignore) != EXIT_OK)
|
||||
return NULL;
|
||||
|
||||
return ccwgroup_devid_to_str(&devid);
|
||||
}
|
||||
|
||||
static void *lcs_ns_parse_id(const char *id, err_t err)
|
||||
{
|
||||
struct ccwgroup_devid *devid;
|
||||
|
||||
devid = misc_malloc(sizeof(struct ccwgroup_devid));
|
||||
if (lcs_parse_devid(devid, id, err) != EXIT_OK) {
|
||||
free(devid);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return devid;
|
||||
}
|
||||
|
||||
static exit_code_t lcs_ns_is_id_range_valid(const char *range, err_t err)
|
||||
{
|
||||
return lcs_parse_devid_range(NULL, NULL, range, err);
|
||||
}
|
||||
|
||||
static unsigned long lcs_ns_num_ids_in_range(const char *range)
|
||||
{
|
||||
struct ccwgroup_devid f, t;
|
||||
|
||||
if (!lcs_parse_devid_range_simple(&f, &t, range))
|
||||
return 0;
|
||||
|
||||
if (f.devid[0].cssid != t.devid[0].cssid ||
|
||||
f.devid[0].ssid != t.devid[0].ssid)
|
||||
return 0;
|
||||
|
||||
if (f.devid[0].devno > t.devid[0].devno)
|
||||
return 0;
|
||||
|
||||
return t.devid[0].devno - f.devid[0].devno + 1;
|
||||
}
|
||||
|
||||
static void lcs_ns_range_start(struct ns_range_iterator *it, const char *range)
|
||||
{
|
||||
struct ccwgroup_devid from, to;
|
||||
|
||||
if (!lcs_parse_devid_range_simple(&from, &to, range)) {
|
||||
memset(it, 0, sizeof(struct ns_range_iterator));
|
||||
return;
|
||||
}
|
||||
|
||||
it->devid = ccwgroup_copy_devid(&from);
|
||||
it->devid_last = ccwgroup_copy_devid(&to);
|
||||
it->id = ccwgroup_devid_to_str(it->devid);
|
||||
}
|
||||
|
||||
static bool lcs_ns_is_id_blacklisted(const char *id)
|
||||
{
|
||||
struct ccwgroup_devid devid;
|
||||
char *ccw_id;
|
||||
unsigned int i;
|
||||
bool result = false;
|
||||
|
||||
if (lcs_parse_devid(&devid, id, err_ignore) != EXIT_OK)
|
||||
return false;
|
||||
for (i = 0; i < devid.num; i++) {
|
||||
ccw_id = ccw_devid_to_str(&devid.devid[i]);
|
||||
result = ccw_is_id_blacklisted(ccw_id);
|
||||
free(ccw_id);
|
||||
if (result)
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static void lcs_ns_unblacklist_id(const char *id)
|
||||
{
|
||||
struct ccwgroup_devid devid;
|
||||
char *ccw_id;
|
||||
unsigned int i;
|
||||
|
||||
if (lcs_parse_devid(&devid, id, err_ignore) != EXIT_OK)
|
||||
return;
|
||||
for (i = 0; i < devid.num; i++) {
|
||||
ccw_id = ccw_devid_to_str(&devid.devid[i]);
|
||||
if (ccw_is_id_blacklisted(ccw_id))
|
||||
ccw_unblacklist_id(ccw_id);
|
||||
free(ccw_id);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* LCS device ID namespace.
|
||||
*/
|
||||
|
||||
struct namespace lcs_namespace = {
|
||||
.devname = DEVNAME,
|
||||
.is_id_valid = lcs_ns_is_id_valid,
|
||||
.is_id_similar = ccwgroup_is_id_similar,
|
||||
.cmp_ids = ccwgroup_cmp_ids,
|
||||
.normalize_id = lcs_ns_normalize_id,
|
||||
.parse_id = lcs_ns_parse_id,
|
||||
.cmp_parsed_ids = ccwgroup_cmp_parsed_ids,
|
||||
.qsort_cmp = ccwgroup_qsort_cmp,
|
||||
.is_id_range_valid = lcs_ns_is_id_range_valid,
|
||||
.num_ids_in_range = lcs_ns_num_ids_in_range,
|
||||
.is_id_in_range = ccwgroup_is_id_in_range,
|
||||
.range_start = lcs_ns_range_start,
|
||||
.range_next = ccwgroup_range_next,
|
||||
|
||||
/* Blacklist handling. */
|
||||
.is_blacklist_active = ccw_is_blacklist_active,
|
||||
.is_id_blacklisted = lcs_ns_is_id_blacklisted,
|
||||
.is_id_range_blacklisted = ccw_is_id_range_blacklisted,
|
||||
.unblacklist_id = lcs_ns_unblacklist_id,
|
||||
.unblacklist_id_range = ccw_unblacklist_id_range,
|
||||
.blacklist_persist = ccw_blacklist_persist,
|
||||
};
|
||||
|
||||
/*
|
||||
* LCS device attributes.
|
||||
*/
|
||||
|
||||
static struct attrib lcs_attr_lancmd_timeout = {
|
||||
.name = "lancmd_timeout",
|
||||
.title = "Modify LAN command timeout",
|
||||
.desc =
|
||||
"Specify the time in seconds that the LCS driver waits for a reply\n"
|
||||
"after issuing a LAN command to the LAN adapter.\n",
|
||||
.defval = "5",
|
||||
.accept = ACCEPT_ARRAY(ACCEPT_NUM_GE(1)),
|
||||
};
|
||||
|
||||
static struct attrib lcs_attr_recover = {
|
||||
.name = "recover",
|
||||
.title = "Trigger device recovery",
|
||||
.desc =
|
||||
"Write '1' to this attribute to restart the recovery process for the\n"
|
||||
"QETH device.\n",
|
||||
.accept = ACCEPT_ARRAY(ACCEPT_NUM(1)),
|
||||
.writeonly = 1,
|
||||
.activeonly = 1,
|
||||
};
|
||||
|
||||
/*
|
||||
* LCS subtype methods.
|
||||
*/
|
||||
|
||||
static exit_code_t lcs_st_is_definable(struct subtype *st, const char *id,
|
||||
err_t err)
|
||||
{
|
||||
struct ccwgroup_subtype_data *data = st->data;
|
||||
struct ccwgroup_devid devid;
|
||||
exit_code_t rc;
|
||||
|
||||
rc = ccwgroup_parse_devid(&devid, id, err);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
if (subtype_device_exists_active(st, id))
|
||||
return EXIT_OK;
|
||||
|
||||
if (devid.num == data->num_devs)
|
||||
return lcs_auto_is_possible(&devid, err);
|
||||
|
||||
if (devid.num == 1)
|
||||
return lcs_auto_get_devid(NULL, &devid.devid[0], err);
|
||||
|
||||
err_t_print(err, "Invalid number of CCW device IDs\n");
|
||||
|
||||
return EXIT_INVALID_ID;
|
||||
}
|
||||
|
||||
/**
|
||||
* device_detect_definable - Detect configuration of definable device
|
||||
* @st: Device subtype
|
||||
* @dev: Device
|
||||
*
|
||||
* Detect the full ID and default parameters for non-existing but definable
|
||||
* device @dev and update active.definable. Return %EXIT_OK on success, or an
|
||||
* error code otherwise.
|
||||
*/
|
||||
static exit_code_t lcs_st_detect_definable(struct subtype *st,
|
||||
struct device *dev)
|
||||
{
|
||||
struct ccwgroup_devid *devid;
|
||||
exit_code_t rc;
|
||||
|
||||
devid = dev->devid;
|
||||
if (devid->num == 1) {
|
||||
/* Detect possible group for this device. */
|
||||
rc = lcs_auto_get_devid(devid, &devid->devid[0],
|
||||
err_delayed_print);
|
||||
if (rc) {
|
||||
error("Auto-detection failed for %s %s\n"
|
||||
"Please be sure to specify full CCWGROUP ID!\n",
|
||||
st->devname, dev->id);
|
||||
return rc;
|
||||
}
|
||||
free(dev->id);
|
||||
dev->id = ccwgroup_devid_to_str(dev->devid);
|
||||
}
|
||||
|
||||
dev->active.definable = 1;
|
||||
|
||||
return EXIT_OK;
|
||||
}
|
||||
|
||||
static void lcs_st_add_definable_ids(struct subtype *st, struct util_list *ids)
|
||||
{
|
||||
lcs_auto_add_ids(ids);
|
||||
}
|
||||
|
||||
/*
|
||||
* LCS subtype.
|
||||
*/
|
||||
|
||||
static struct ccwgroup_subtype_data lcs_data = {
|
||||
.ccwgroupdrv = LCS_CCWGROUPDRV_NAME,
|
||||
.ccwdrv = LCS_CCWDRV_NAME,
|
||||
.rootdrv = LCS_ROOTDRV_NAME,
|
||||
.mod = LCS_MOD_NAME,
|
||||
.num_devs = LCS_NUM_DEVS,
|
||||
};
|
||||
|
||||
static struct subtype lcs_subtype = {
|
||||
.super = &ccwgroup_subtype,
|
||||
.devtype = &lcs_devtype,
|
||||
.name = "lcs",
|
||||
.title = "LAN-Channel-Station (LCS) network devices",
|
||||
.devname = DEVNAME,
|
||||
.modules = STRING_ARRAY(LCS_MOD_NAME),
|
||||
.namespace = &lcs_namespace,
|
||||
.data = &lcs_data,
|
||||
|
||||
.dev_attribs = ATTRIB_ARRAY(
|
||||
&ccw_attr_online,
|
||||
&lcs_attr_lancmd_timeout,
|
||||
&lcs_attr_recover,
|
||||
&internal_attr_early,
|
||||
),
|
||||
.unknown_dev_attribs = 1,
|
||||
.support_definable = 1,
|
||||
|
||||
.is_definable = &lcs_st_is_definable,
|
||||
.detect_definable = &lcs_st_detect_definable,
|
||||
.add_definable_ids = &lcs_st_add_definable_ids,
|
||||
};
|
||||
|
||||
/*
|
||||
* LCS devtype methods.
|
||||
*/
|
||||
|
||||
/* Clean up all resources used by devtype object. */
|
||||
static void lcs_devtype_exit(struct devtype *dt)
|
||||
{
|
||||
setting_list_free(dt->active_settings);
|
||||
setting_list_free(dt->persistent_settings);
|
||||
}
|
||||
|
||||
static exit_code_t lcs_devtype_read_settings(struct devtype *dt,
|
||||
config_t config)
|
||||
{
|
||||
/* No kernel or module parameters exist for the lcs device driver,
|
||||
* but at least determine module loaded state. */
|
||||
dt->active_settings = setting_list_new();
|
||||
dt->persistent_settings = setting_list_new();
|
||||
|
||||
if (SCOPE_ACTIVE(config))
|
||||
dt->active_exists = devtype_is_module_loaded(dt);
|
||||
|
||||
return EXIT_OK;
|
||||
}
|
||||
|
||||
static exit_code_t lcs_devtype_write_settings(struct devtype *dt,
|
||||
config_t config)
|
||||
{
|
||||
/* No kernel or module parameters exist for the lcs device driver. */
|
||||
|
||||
return EXIT_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* LCS devtype.
|
||||
*/
|
||||
|
||||
struct devtype lcs_devtype = {
|
||||
.name = "lcs",
|
||||
.title = "", /* Only use subtypes. */
|
||||
.devname = "LCS",
|
||||
|
||||
.subtypes = SUBTYPE_ARRAY(
|
||||
&lcs_subtype,
|
||||
),
|
||||
|
||||
.type_attribs = ATTRIB_ARRAY(
|
||||
),
|
||||
|
||||
.exit = &lcs_devtype_exit,
|
||||
|
||||
.read_settings = &lcs_devtype_read_settings,
|
||||
.write_settings = &lcs_devtype_write_settings,
|
||||
};
|
||||
@@ -1,348 +0,0 @@
|
||||
/*
|
||||
* 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 <string.h>
|
||||
|
||||
#include "lib/util_path.h"
|
||||
|
||||
#include "ccw.h"
|
||||
#include "ccwgroup.h"
|
||||
#include "ctc.h"
|
||||
#include "lcs.h"
|
||||
#include "lcs_auto.h"
|
||||
#include "module.h"
|
||||
#include "path.h"
|
||||
|
||||
struct cutype {
|
||||
unsigned int cutype:16;
|
||||
unsigned int cumodel:8;
|
||||
};
|
||||
|
||||
static struct cutype lcs_cutypes[] = {
|
||||
{ .cutype = 0x3088, .cumodel = 0x08, },
|
||||
{ .cutype = 0x3088, .cumodel = 0x1f, },
|
||||
{ .cutype = 0x3088, .cumodel = 0x60, },
|
||||
};
|
||||
|
||||
/*
|
||||
* LCS autodetection
|
||||
*
|
||||
* A LCS device must be grouped before it can be used. The following
|
||||
* rules apply to grouping:
|
||||
*
|
||||
* 1. A LCS device can be grouped from 2 CCW devices
|
||||
* a) Read device
|
||||
* b) Write device
|
||||
* 2. All CCW devices must be bound to the LCS CCW device driver. Note that
|
||||
* due to an overlap in CU-Types, CCW device could also be bound to
|
||||
* the LCS device driver.
|
||||
* 3. The subchannel of all CCW devices must be defined with the same CHPID
|
||||
* 4. None of the CCW devices is part of an existing CCWGROUP device
|
||||
*/
|
||||
|
||||
/* Compare by: 1. CHPID, 2. CUTYPE, 3. DEVTYPE, 4. CCW device ID
|
||||
* -1 = a < b 1 = a > b 0 = a == b. */
|
||||
static int info_cmp(void *a, void *b, void *data)
|
||||
{
|
||||
struct ptrlist_node *pa = a, *pb = b;
|
||||
struct ccw_devinfo *ia = pa->ptr, *ib = pb->ptr;
|
||||
int r;
|
||||
|
||||
r = ccw_devinfo_chpids_cmp(ia, ib);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
r = ccw_devinfo_cutype_cmp(ia, ib);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
r = ccw_devinfo_devtype_cmp(ia, ib);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
return ccw_cmp_devids(&ia->devid, &ib->devid);
|
||||
}
|
||||
|
||||
static bool is_compatible(struct ccw_devinfo *a, struct ccw_devinfo *b)
|
||||
{
|
||||
if (ccw_devinfo_chpids_cmp(a, b) == 0 &&
|
||||
ccw_devinfo_cutype_cmp(a, b) == 0 &&
|
||||
ccw_devinfo_devtype_cmp(a, b) == 0)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool is_lcs(struct ccw_devinfo *info)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
/* Rule out devices which can be confirmed to be CTC devices. */
|
||||
if (ctc_confirm(&info->devid))
|
||||
return false;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(lcs_cutypes); i++) {
|
||||
if (info->cutype == lcs_cutypes[i].cutype &&
|
||||
info->cumodel == lcs_cutypes[i].cumodel)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Add device info for all LCS CCW devices to ptrlist in data. */
|
||||
static exit_code_t add_cb(const char *path, const char *filename, void *data)
|
||||
{
|
||||
struct ccw_devid devid;
|
||||
struct util_list *infos = data;
|
||||
struct ccw_devinfo *devinfo;
|
||||
|
||||
if (!strchr(filename, '.'))
|
||||
return EXIT_OK;
|
||||
if (!ccw_parse_devid_simple(&devid, filename))
|
||||
return EXIT_OK;
|
||||
devinfo = ccw_devinfo_get(&devid, 0);
|
||||
if (devinfo->exists && is_lcs(devinfo))
|
||||
ptrlist_add(infos, devinfo);
|
||||
else
|
||||
free(devinfo);
|
||||
|
||||
return EXIT_OK;
|
||||
}
|
||||
|
||||
/* Return a sorted ptrlist of struct ccw_devinfos for all CCW devices
|
||||
* bound to the lcs or ctc CCW device driver with matching CUTYPE.
|
||||
* The result must be freed using ptrlist_free(,1); */
|
||||
static struct util_list *read_sorted_lcs_devinfos(void)
|
||||
{
|
||||
struct util_list *infos;
|
||||
char *path;
|
||||
|
||||
/* Get CHPID information for all devices handled by the LCS driver. */
|
||||
infos = ptrlist_new();
|
||||
|
||||
/* Add CCW devices bound to the LCS CCW device driver. */
|
||||
module_try_load_once(LCS_MOD_NAME, NULL);
|
||||
path = path_get_sys_bus_drv(CCW_BUS_NAME, LCS_CCWDRV_NAME);
|
||||
if (util_path_is_dir(path))
|
||||
path_for_each(path, add_cb, infos);
|
||||
free(path);
|
||||
|
||||
/* Add CCW devices bound to the CTC CCW device driver. */
|
||||
path = path_get_sys_bus_drv(CCW_BUS_NAME, CTC_CCWDRV_NAME);
|
||||
if (util_path_is_dir(path))
|
||||
path_for_each(path, add_cb, infos);
|
||||
free(path);
|
||||
|
||||
/* For each CHPID: Find groups. Add to result list. */
|
||||
util_list_sort(infos, info_cmp, NULL);
|
||||
|
||||
return infos;
|
||||
}
|
||||
|
||||
static void add_ccwgroup_devid(struct util_list *devids, struct ccw_devid *read,
|
||||
struct ccw_devid *write)
|
||||
{
|
||||
struct ccwgroup_devid devid;
|
||||
|
||||
devid.devid[0] = *read;
|
||||
devid.devid[1] = *write;
|
||||
devid.num = LCS_NUM_DEVS;
|
||||
|
||||
ptrlist_add(devids, ccwgroup_copy_devid(&devid));
|
||||
}
|
||||
|
||||
static void add_groupable_devids(struct util_list *devids,
|
||||
struct util_list *infos)
|
||||
{
|
||||
struct ptrlist_node *curr, *next;
|
||||
struct ccw_devinfo *r, *w;
|
||||
|
||||
/* For each CHPID: Find groups. Add to result list. */
|
||||
curr = util_list_start(infos);
|
||||
while (curr) {
|
||||
next = util_list_next(infos, curr);
|
||||
if (!next)
|
||||
break;
|
||||
r = curr->ptr;
|
||||
w = next->ptr;
|
||||
if (is_compatible(r, w) && EVEN(r->devid.devno) &&
|
||||
ccw_devid_distance(&r->devid, &w->devid) == 1) {
|
||||
add_ccwgroup_devid(devids, &r->devid, &w->devid);
|
||||
curr = util_list_next(infos, next);
|
||||
} else
|
||||
curr = next;
|
||||
}
|
||||
}
|
||||
|
||||
/* Add CCWGROUP IDs of lcs devices that can be grouped to strlist @ids. */
|
||||
void lcs_auto_add_ids(struct util_list *ids)
|
||||
{
|
||||
struct util_list *infos, *devids;
|
||||
struct ptrlist_node *p;
|
||||
char *id;
|
||||
|
||||
infos = read_sorted_lcs_devinfos();
|
||||
devids = ptrlist_new();
|
||||
add_groupable_devids(devids, infos);
|
||||
|
||||
util_list_iterate(devids, p) {
|
||||
id = ccwgroup_devid_to_str(p->ptr);
|
||||
strlist_add(ids, id);
|
||||
free(id);
|
||||
}
|
||||
|
||||
ptrlist_free(devids, 1);
|
||||
ptrlist_free(infos, 1);
|
||||
}
|
||||
|
||||
exit_code_t lcs_auto_get_devid(struct ccwgroup_devid *devid_ptr,
|
||||
struct ccw_devid *ccw_devid, err_t err)
|
||||
{
|
||||
struct util_list *devids, *infos;
|
||||
struct ptrlist_node *p, *read, *write;
|
||||
struct ccw_devinfo *r, *w;
|
||||
struct ccwgroup_devid *devid;
|
||||
exit_code_t rc;
|
||||
|
||||
infos = read_sorted_lcs_devinfos();
|
||||
|
||||
/* Try to find an ID from the canonical auto-generated list. */
|
||||
devids = ptrlist_new();
|
||||
add_groupable_devids(devids, infos);
|
||||
|
||||
util_list_iterate(devids, p) {
|
||||
devid = p->ptr;
|
||||
if (ccw_cmp_devids(ccw_devid, &devid->devid[0]) != 0)
|
||||
continue;
|
||||
rc = EXIT_OK;
|
||||
if (devid_ptr)
|
||||
*devid_ptr = *devid;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Try to create a CCWGROUP ID with the specified ID as read device. */
|
||||
|
||||
/* Get CCW device info for read device. */
|
||||
read = NULL;
|
||||
util_list_iterate(infos, read) {
|
||||
r = read->ptr;
|
||||
if (ccw_cmp_devids(&r->devid, ccw_devid) == 0)
|
||||
break;
|
||||
}
|
||||
if (!read) {
|
||||
err_t_print(err, "Read CCW device not found\n");
|
||||
rc = EXIT_GROUP_NOT_FOUND;
|
||||
goto out;
|
||||
}
|
||||
if (!EVEN(r->devid.devno)) {
|
||||
err_t_print(err, "Read CCW device number not even\n");
|
||||
rc = EXIT_GROUP_INVALID;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Get CCW device ID for write device. */
|
||||
write = util_list_next(infos, read);
|
||||
if (!write) {
|
||||
err_t_print(err, "Write CCW device not found\n");
|
||||
rc = EXIT_GROUP_NOT_FOUND;
|
||||
goto out;
|
||||
}
|
||||
w = write->ptr;
|
||||
if (!is_compatible(r, w)) {
|
||||
err_t_print(err, "No compatible write CCW device found\n");
|
||||
rc = EXIT_GROUP_INVALID;
|
||||
goto out;
|
||||
}
|
||||
if (ccw_devid_distance(&r->devid, &w->devid) != 1) {
|
||||
err_t_print(err, "Write CCW device ID must be read plus one\n");
|
||||
rc = EXIT_GROUP_INVALID;
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc = EXIT_OK;
|
||||
if (devid_ptr) {
|
||||
devid_ptr->devid[0] = r->devid;
|
||||
devid_ptr->devid[1] = w->devid;
|
||||
devid_ptr->num = LCS_NUM_DEVS;
|
||||
}
|
||||
|
||||
out:
|
||||
ptrlist_free(devids, 1);
|
||||
ptrlist_free(infos, 1);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
exit_code_t lcs_auto_is_possible(struct ccwgroup_devid *devid, err_t err)
|
||||
{
|
||||
struct ccw_devinfo *info[LCS_NUM_DEVS];
|
||||
unsigned int i;
|
||||
char *ccwid;
|
||||
const char *msg;
|
||||
exit_code_t rc;
|
||||
|
||||
if (devid->num < LCS_NUM_DEVS) {
|
||||
err_t_print(err, "Not enough CCW device IDs in LCS device "
|
||||
"ID\n");
|
||||
return EXIT_INCOMPLETE_ID;
|
||||
}
|
||||
if (devid->num > LCS_NUM_DEVS) {
|
||||
err_t_print(err, "LCS device ID contains too many CCW device "
|
||||
"IDs\n");
|
||||
return EXIT_INVALID_ID;
|
||||
}
|
||||
if (ccw_devid_distance(&devid->devid[0], &devid->devid[1]) != 1) {
|
||||
err_t_print(err, "Write device ID must be read plus one\n");
|
||||
return EXIT_GROUP_INVALID;
|
||||
}
|
||||
if (!EVEN(devid->devid[0].devno)) {
|
||||
err_t_print(err, "Device number of read device ID must be "
|
||||
"even\n");
|
||||
return EXIT_GROUP_INVALID;
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(info); i++)
|
||||
info[i] = ccw_devinfo_get(&devid->devid[i], 1);
|
||||
|
||||
rc = EXIT_OK;
|
||||
msg = NULL;
|
||||
for (i = 0; i < ARRAY_SIZE(info); i++) {
|
||||
if (!info[i]->exists) {
|
||||
msg = "CCW device %s does not exist\n";
|
||||
rc = EXIT_GROUP_NOT_FOUND;
|
||||
} else if (info[i]->grouped) {
|
||||
msg = "CCW device %s already grouped\n";
|
||||
rc = EXIT_GROUP_ALREADY;
|
||||
} else if (i > 0 &&
|
||||
ccw_devinfo_chpids_cmp(info[i - 1], info[i]) != 0) {
|
||||
msg = "CCW device %s is not on the same CHPID\n";
|
||||
rc = EXIT_GROUP_INVALID;
|
||||
} else if (i > 0 &&
|
||||
ccw_devinfo_cutype_cmp(info[i - 1], info[i]) != 0) {
|
||||
msg = "CUTYPE of CCW device %s differs\n";
|
||||
rc = EXIT_GROUP_INVALID;
|
||||
} else if (i > 0 &&
|
||||
ccw_devinfo_devtype_cmp(info[i - 1], info[i]) != 0) {
|
||||
msg = "DEVTYPE of CCW device %s differs\n";
|
||||
rc = EXIT_GROUP_INVALID;
|
||||
}
|
||||
if (!msg)
|
||||
continue;
|
||||
ccwid = ccw_devid_to_str(&devid->devid[i]);
|
||||
err_t_print(err, msg, ccwid);
|
||||
free(ccwid);
|
||||
break;
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(info); i++)
|
||||
free(info[i]);
|
||||
|
||||
return rc;
|
||||
}
|
||||
@@ -13,7 +13,6 @@
|
||||
#include "ccw.h"
|
||||
#include "ctc.h"
|
||||
#include "devtype.h"
|
||||
#include "lcs.h"
|
||||
#include "namespace.h"
|
||||
#include "qeth.h"
|
||||
#include "zfcp_lun.h"
|
||||
@@ -24,7 +23,6 @@ struct namespace *namespaces[] = {
|
||||
&zfcp_lun_namespace,
|
||||
&qeth_namespace,
|
||||
&ctc_namespace,
|
||||
&lcs_namespace,
|
||||
&ap_namespace,
|
||||
NULL,
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user