Skip to content

Commit 19508b2

Browse files
hoeppnerjaxboe
authored andcommitted
s390/dasd: Display FC Endpoint Security information via sysfs
Add a new sysfs attribute (fc_security) per device and per operational channel path. The information of the current FC Endpoint Security state is received through the CIO layer. The state of the FC Endpoint Security can be either "Unsupported", "Authentication", or "Encryption". For example: $ cat /sys/bus/ccw/devices/0.0.c600/fc_security Encryption If any of the operational paths is in a state different from all others, the device sysfs attribute will display the additional state "Inconsistent". The sysfs attributes per paths are organised in a new directory called "paths_info" with subdirectories for each path. /sys/bus/ccw/devices/0.0.c600/paths_info/ ├── 0.38 │   └── fc_security ├── 0.39 │   └── fc_security ├── 0.3a │   └── fc_security └── 0.3b └── fc_security Signed-off-by: Jan Höppner <[email protected]> Signed-off-by: Stefan Haberland <[email protected]> Reviewed-by: Stefan Haberland <[email protected]> Reviewed-by: Cornelia Huck <[email protected]> Signed-off-by: Jens Axboe <[email protected]>
1 parent 9e34c8b commit 19508b2

File tree

3 files changed

+207
-0
lines changed

3 files changed

+207
-0
lines changed

drivers/s390/block/dasd_devmap.c

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -576,6 +576,11 @@ dasd_create_device(struct ccw_device *cdev)
576576
dev_set_drvdata(&cdev->dev, device);
577577
spin_unlock_irqrestore(get_ccwdev_lock(cdev), flags);
578578

579+
device->paths_info = kset_create_and_add("paths_info", NULL,
580+
&device->cdev->dev.kobj);
581+
if (!device->paths_info)
582+
dev_warn(&cdev->dev, "Could not create paths_info kset\n");
583+
579584
return device;
580585
}
581586

@@ -622,6 +627,9 @@ dasd_delete_device(struct dasd_device *device)
622627
wait_event(dasd_delete_wq, atomic_read(&device->ref_count) == 0);
623628

624629
dasd_generic_free_discipline(device);
630+
631+
kset_unregister(device->paths_info);
632+
625633
/* Disconnect dasd_device structure from ccw_device structure. */
626634
cdev = device->cdev;
627635
device->cdev = NULL;
@@ -1641,6 +1649,39 @@ dasd_path_interval_store(struct device *dev, struct device_attribute *attr,
16411649
static DEVICE_ATTR(path_interval, 0644, dasd_path_interval_show,
16421650
dasd_path_interval_store);
16431651

1652+
static ssize_t
1653+
dasd_device_fcs_show(struct device *dev, struct device_attribute *attr,
1654+
char *buf)
1655+
{
1656+
struct dasd_device *device;
1657+
int fc_sec;
1658+
int rc;
1659+
1660+
device = dasd_device_from_cdev(to_ccwdev(dev));
1661+
if (IS_ERR(device))
1662+
return -ENODEV;
1663+
fc_sec = dasd_path_get_fcs_device(device);
1664+
if (fc_sec == -EINVAL)
1665+
rc = snprintf(buf, PAGE_SIZE, "Inconsistent\n");
1666+
else
1667+
rc = snprintf(buf, PAGE_SIZE, "%s\n", dasd_path_get_fcs_str(fc_sec));
1668+
dasd_put_device(device);
1669+
1670+
return rc;
1671+
}
1672+
static DEVICE_ATTR(fc_security, 0444, dasd_device_fcs_show, NULL);
1673+
1674+
static ssize_t
1675+
dasd_path_fcs_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
1676+
{
1677+
struct dasd_path *path = to_dasd_path(kobj);
1678+
unsigned int fc_sec = path->fc_security;
1679+
1680+
return snprintf(buf, PAGE_SIZE, "%s\n", dasd_path_get_fcs_str(fc_sec));
1681+
}
1682+
1683+
static struct kobj_attribute path_fcs_attribute =
1684+
__ATTR(fc_security, 0444, dasd_path_fcs_show, NULL);
16441685

16451686
#define DASD_DEFINE_ATTR(_name, _func) \
16461687
static ssize_t dasd_##_name##_show(struct device *dev, \
@@ -1697,6 +1738,7 @@ static struct attribute * dasd_attrs[] = {
16971738
&dev_attr_path_reset.attr,
16981739
&dev_attr_hpf.attr,
16991740
&dev_attr_ese.attr,
1741+
&dev_attr_fc_security.attr,
17001742
NULL,
17011743
};
17021744

@@ -1777,6 +1819,73 @@ dasd_set_feature(struct ccw_device *cdev, int feature, int flag)
17771819
}
17781820
EXPORT_SYMBOL(dasd_set_feature);
17791821

1822+
static struct attribute *paths_info_attrs[] = {
1823+
&path_fcs_attribute.attr,
1824+
NULL,
1825+
};
1826+
1827+
static struct kobj_type path_attr_type = {
1828+
.release = dasd_path_release,
1829+
.default_attrs = paths_info_attrs,
1830+
.sysfs_ops = &kobj_sysfs_ops,
1831+
};
1832+
1833+
static void dasd_path_init_kobj(struct dasd_device *device, int chp)
1834+
{
1835+
device->path[chp].kobj.kset = device->paths_info;
1836+
kobject_init(&device->path[chp].kobj, &path_attr_type);
1837+
}
1838+
1839+
void dasd_path_create_kobj(struct dasd_device *device, int chp)
1840+
{
1841+
int rc;
1842+
1843+
if (test_bit(DASD_FLAG_OFFLINE, &device->flags))
1844+
return;
1845+
if (!device->paths_info) {
1846+
dev_warn(&device->cdev->dev, "Unable to create paths objects\n");
1847+
return;
1848+
}
1849+
if (device->path[chp].in_sysfs)
1850+
return;
1851+
if (!device->path[chp].conf_data)
1852+
return;
1853+
1854+
dasd_path_init_kobj(device, chp);
1855+
1856+
rc = kobject_add(&device->path[chp].kobj, NULL, "%x.%02x",
1857+
device->path[chp].cssid, device->path[chp].chpid);
1858+
if (rc)
1859+
kobject_put(&device->path[chp].kobj);
1860+
device->path[chp].in_sysfs = true;
1861+
}
1862+
EXPORT_SYMBOL(dasd_path_create_kobj);
1863+
1864+
void dasd_path_create_kobjects(struct dasd_device *device)
1865+
{
1866+
u8 lpm, opm;
1867+
1868+
opm = dasd_path_get_opm(device);
1869+
for (lpm = 0x80; lpm; lpm >>= 1) {
1870+
if (!(lpm & opm))
1871+
continue;
1872+
dasd_path_create_kobj(device, pathmask_to_pos(lpm));
1873+
}
1874+
}
1875+
EXPORT_SYMBOL(dasd_path_create_kobjects);
1876+
1877+
/*
1878+
* As we keep kobjects for the lifetime of a device, this function must not be
1879+
* called anywhere but in the context of offlining a device.
1880+
*/
1881+
void dasd_path_remove_kobj(struct dasd_device *device, int chp)
1882+
{
1883+
if (device->path[chp].in_sysfs) {
1884+
kobject_put(&device->path[chp].kobj);
1885+
device->path[chp].in_sysfs = false;
1886+
}
1887+
}
1888+
EXPORT_SYMBOL(dasd_path_remove_kobj);
17801889

17811890
int dasd_add_sysfs_files(struct ccw_device *cdev)
17821891
{

drivers/s390/block/dasd_eckd.c

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1035,6 +1035,30 @@ static void dasd_eckd_clear_conf_data(struct dasd_device *device)
10351035
device->path[i].ssid = 0;
10361036
device->path[i].chpid = 0;
10371037
dasd_path_notoper(device, i);
1038+
dasd_path_remove_kobj(device, i);
1039+
}
1040+
}
1041+
1042+
static void dasd_eckd_read_fc_security(struct dasd_device *device)
1043+
{
1044+
struct dasd_eckd_private *private = device->private;
1045+
u8 esm_valid;
1046+
u8 esm[8];
1047+
int chp;
1048+
int rc;
1049+
1050+
rc = chsc_scud(private->uid.ssid, (u64 *)esm, &esm_valid);
1051+
if (rc) {
1052+
for (chp = 0; chp < 8; chp++)
1053+
device->path[chp].fc_security = 0;
1054+
return;
1055+
}
1056+
1057+
for (chp = 0; chp < 8; chp++) {
1058+
if (esm_valid & (0x80 >> chp))
1059+
device->path[chp].fc_security = esm[chp];
1060+
else
1061+
device->path[chp].fc_security = 0;
10381062
}
10391063
}
10401064

@@ -1164,6 +1188,8 @@ static int dasd_eckd_read_conf(struct dasd_device *device)
11641188
}
11651189
}
11661190

1191+
dasd_eckd_read_fc_security(device);
1192+
11671193
return path_err;
11681194
}
11691195

@@ -1430,6 +1456,8 @@ static void do_path_verification_work(struct work_struct *work)
14301456
dasd_path_add_cablepm(device, cablepm);
14311457
dasd_path_add_nohpfpm(device, hpfpm);
14321458
spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
1459+
1460+
dasd_path_create_kobj(device, pos);
14331461
}
14341462
clear_bit(DASD_FLAG_PATH_VERIFY, &device->flags);
14351463
dasd_put_device(device);
@@ -2069,6 +2097,8 @@ dasd_eckd_check_characteristics(struct dasd_device *device)
20692097
if (rc)
20702098
goto out_err3;
20712099

2100+
dasd_path_create_kobjects(device);
2101+
20722102
/* Read Feature Codes */
20732103
dasd_eckd_read_features(device);
20742104

drivers/s390/block/dasd_int.h

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -426,6 +426,35 @@ extern struct dasd_discipline *dasd_diag_discipline_pointer;
426426
#define DASD_THRHLD_MAX 4294967295U
427427
#define DASD_INTERVAL_MAX 4294967295U
428428

429+
/* FC Endpoint Security Capabilities */
430+
#define DASD_FC_SECURITY_UNSUP 0
431+
#define DASD_FC_SECURITY_AUTH 1
432+
#define DASD_FC_SECURITY_ENC_FCSP2 2
433+
#define DASD_FC_SECURITY_ENC_ERAS 3
434+
435+
#define DASD_FC_SECURITY_ENC_STR "Encryption"
436+
static const struct {
437+
u8 value;
438+
char *name;
439+
} dasd_path_fcs_mnemonics[] = {
440+
{ DASD_FC_SECURITY_UNSUP, "Unsupported" },
441+
{ DASD_FC_SECURITY_AUTH, "Authentication" },
442+
{ DASD_FC_SECURITY_ENC_FCSP2, DASD_FC_SECURITY_ENC_STR },
443+
{ DASD_FC_SECURITY_ENC_ERAS, DASD_FC_SECURITY_ENC_STR },
444+
};
445+
446+
static inline char *dasd_path_get_fcs_str(int val)
447+
{
448+
int i;
449+
450+
for (i = 0; i < ARRAY_SIZE(dasd_path_fcs_mnemonics); i++) {
451+
if (dasd_path_fcs_mnemonics[i].value == val)
452+
return dasd_path_fcs_mnemonics[i].name;
453+
}
454+
455+
return dasd_path_fcs_mnemonics[0].name;
456+
}
457+
429458
struct dasd_path {
430459
unsigned long flags;
431460
u8 cssid;
@@ -434,8 +463,18 @@ struct dasd_path {
434463
struct dasd_conf_data *conf_data;
435464
atomic_t error_count;
436465
unsigned long errorclk;
466+
u8 fc_security;
467+
struct kobject kobj;
468+
bool in_sysfs;
437469
};
438470

471+
#define to_dasd_path(path) container_of(path, struct dasd_path, kobj)
472+
473+
static inline void dasd_path_release(struct kobject *kobj)
474+
{
475+
/* Memory for the dasd_path kobject is freed when dasd_free_device() is called */
476+
}
477+
439478

440479
struct dasd_profile_info {
441480
/* legacy part of profile data, as in dasd_profile_info_t */
@@ -547,6 +586,7 @@ struct dasd_device {
547586
struct dentry *hosts_dentry;
548587
struct dasd_profile profile;
549588
struct dasd_format_entry format_entry;
589+
struct kset *paths_info;
550590
};
551591

552592
struct dasd_block {
@@ -824,6 +864,9 @@ int dasd_set_feature(struct ccw_device *, int, int);
824864

825865
int dasd_add_sysfs_files(struct ccw_device *);
826866
void dasd_remove_sysfs_files(struct ccw_device *);
867+
void dasd_path_create_kobj(struct dasd_device *, int);
868+
void dasd_path_create_kobjects(struct dasd_device *);
869+
void dasd_path_remove_kobj(struct dasd_device *, int);
827870

828871
struct dasd_device *dasd_device_from_cdev(struct ccw_device *);
829872
struct dasd_device *dasd_device_from_cdev_locked(struct ccw_device *);
@@ -1114,6 +1157,31 @@ static inline __u8 dasd_path_get_hpfpm(struct dasd_device *device)
11141157
return hpfpm;
11151158
}
11161159

1160+
static inline u8 dasd_path_get_fcs_path(struct dasd_device *device, int chp)
1161+
{
1162+
return device->path[chp].fc_security;
1163+
}
1164+
1165+
static inline int dasd_path_get_fcs_device(struct dasd_device *device)
1166+
{
1167+
u8 fc_sec = 0;
1168+
int chp;
1169+
1170+
for (chp = 0; chp < 8; chp++) {
1171+
if (device->opm & (0x80 >> chp)) {
1172+
fc_sec = device->path[chp].fc_security;
1173+
break;
1174+
}
1175+
}
1176+
for (; chp < 8; chp++) {
1177+
if (device->opm & (0x80 >> chp))
1178+
if (device->path[chp].fc_security != fc_sec)
1179+
return -EINVAL;
1180+
}
1181+
1182+
return fc_sec;
1183+
}
1184+
11171185
/*
11181186
* add functions for path masks
11191187
* the existing path mask will be extended by the given path mask

0 commit comments

Comments
 (0)