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:
Vineeth Vijayan
2025-12-15 17:25:04 +01:00
committed by Jan Höppner
parent bd0bb9dd5c
commit b6bb87f377
13 changed files with 7 additions and 852 deletions

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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 */

View File

@@ -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 */

View File

@@ -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}

View File

@@ -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"

View File

@@ -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

View File

@@ -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

View File

@@ -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);

View File

@@ -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. */

View File

@@ -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,
};

View File

@@ -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;
}

View File

@@ -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,
};