diff options
Diffstat (limited to 'drivers/s390/block')
-rw-r--r-- | drivers/s390/block/dasd.c | 22 | ||||
-rw-r--r-- | drivers/s390/block/dasd_devmap.c | 109 | ||||
-rw-r--r-- | drivers/s390/block/dasd_eckd.c | 175 | ||||
-rw-r--r-- | drivers/s390/block/dasd_fba.c | 2 | ||||
-rw-r--r-- | drivers/s390/block/dasd_int.h | 111 |
5 files changed, 352 insertions, 67 deletions
diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index 6efacadc8fcd..c7eb9a10c680 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c @@ -2084,19 +2084,24 @@ static void __dasd_device_start_head(struct dasd_device *device) static void __dasd_device_check_path_events(struct dasd_device *device) { + __u8 tbvpm, fcsecpm; int rc; - if (!dasd_path_get_tbvpm(device)) + tbvpm = dasd_path_get_tbvpm(device); + fcsecpm = dasd_path_get_fcsecpm(device); + + if (!tbvpm && !fcsecpm) return; if (device->stopped & ~(DASD_STOPPED_DC_WAIT)) return; - rc = device->discipline->verify_path(device, - dasd_path_get_tbvpm(device)); - if (rc) + rc = device->discipline->pe_handler(device, tbvpm, fcsecpm); + if (rc) { dasd_device_set_timer(device, 50); - else + } else { dasd_path_clear_all_verify(device); + dasd_path_clear_all_fcsec(device); + } }; /* @@ -3448,8 +3453,7 @@ static void dasd_generic_auto_online(void *data, async_cookie_t cookie) * Initial attempt at a probe function. this can be simplified once * the other detection code is gone. */ -int dasd_generic_probe(struct ccw_device *cdev, - struct dasd_discipline *discipline) +int dasd_generic_probe(struct ccw_device *cdev) { int ret; @@ -3847,6 +3851,10 @@ void dasd_generic_path_event(struct ccw_device *cdev, int *path_event) if (device->discipline->kick_validate) device->discipline->kick_validate(device); } + if (path_event[chp] & PE_PATH_FCES_EVENT) { + dasd_path_fcsec_update(device, chp); + dasd_schedule_device_bh(device); + } } hpfpm = dasd_path_get_hpfpm(device); ifccpm = dasd_path_get_ifccpm(device); diff --git a/drivers/s390/block/dasd_devmap.c b/drivers/s390/block/dasd_devmap.c index 32fc51341d99..16bb135c20aa 100644 --- a/drivers/s390/block/dasd_devmap.c +++ b/drivers/s390/block/dasd_devmap.c @@ -576,6 +576,11 @@ dasd_create_device(struct ccw_device *cdev) dev_set_drvdata(&cdev->dev, device); spin_unlock_irqrestore(get_ccwdev_lock(cdev), flags); + device->paths_info = kset_create_and_add("paths_info", NULL, + &device->cdev->dev.kobj); + if (!device->paths_info) + dev_warn(&cdev->dev, "Could not create paths_info kset\n"); + return device; } @@ -622,6 +627,9 @@ dasd_delete_device(struct dasd_device *device) wait_event(dasd_delete_wq, atomic_read(&device->ref_count) == 0); dasd_generic_free_discipline(device); + + kset_unregister(device->paths_info); + /* Disconnect dasd_device structure from ccw_device structure. */ cdev = device->cdev; device->cdev = NULL; @@ -1641,6 +1649,39 @@ dasd_path_interval_store(struct device *dev, struct device_attribute *attr, static DEVICE_ATTR(path_interval, 0644, dasd_path_interval_show, dasd_path_interval_store); +static ssize_t +dasd_device_fcs_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct dasd_device *device; + int fc_sec; + int rc; + + device = dasd_device_from_cdev(to_ccwdev(dev)); + if (IS_ERR(device)) + return -ENODEV; + fc_sec = dasd_path_get_fcs_device(device); + if (fc_sec == -EINVAL) + rc = snprintf(buf, PAGE_SIZE, "Inconsistent\n"); + else + rc = snprintf(buf, PAGE_SIZE, "%s\n", dasd_path_get_fcs_str(fc_sec)); + dasd_put_device(device); + + return rc; +} +static DEVICE_ATTR(fc_security, 0444, dasd_device_fcs_show, NULL); + +static ssize_t +dasd_path_fcs_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) +{ + struct dasd_path *path = to_dasd_path(kobj); + unsigned int fc_sec = path->fc_security; + + return snprintf(buf, PAGE_SIZE, "%s\n", dasd_path_get_fcs_str(fc_sec)); +} + +static struct kobj_attribute path_fcs_attribute = + __ATTR(fc_security, 0444, dasd_path_fcs_show, NULL); #define DASD_DEFINE_ATTR(_name, _func) \ static ssize_t dasd_##_name##_show(struct device *dev, \ @@ -1697,6 +1738,7 @@ static struct attribute * dasd_attrs[] = { &dev_attr_path_reset.attr, &dev_attr_hpf.attr, &dev_attr_ese.attr, + &dev_attr_fc_security.attr, NULL, }; @@ -1777,6 +1819,73 @@ dasd_set_feature(struct ccw_device *cdev, int feature, int flag) } EXPORT_SYMBOL(dasd_set_feature); +static struct attribute *paths_info_attrs[] = { + &path_fcs_attribute.attr, + NULL, +}; + +static struct kobj_type path_attr_type = { + .release = dasd_path_release, + .default_attrs = paths_info_attrs, + .sysfs_ops = &kobj_sysfs_ops, +}; + +static void dasd_path_init_kobj(struct dasd_device *device, int chp) +{ + device->path[chp].kobj.kset = device->paths_info; + kobject_init(&device->path[chp].kobj, &path_attr_type); +} + +void dasd_path_create_kobj(struct dasd_device *device, int chp) +{ + int rc; + + if (test_bit(DASD_FLAG_OFFLINE, &device->flags)) + return; + if (!device->paths_info) { + dev_warn(&device->cdev->dev, "Unable to create paths objects\n"); + return; + } + if (device->path[chp].in_sysfs) + return; + if (!device->path[chp].conf_data) + return; + + dasd_path_init_kobj(device, chp); + + rc = kobject_add(&device->path[chp].kobj, NULL, "%x.%02x", + device->path[chp].cssid, device->path[chp].chpid); + if (rc) + kobject_put(&device->path[chp].kobj); + device->path[chp].in_sysfs = true; +} +EXPORT_SYMBOL(dasd_path_create_kobj); + +void dasd_path_create_kobjects(struct dasd_device *device) +{ + u8 lpm, opm; + + opm = dasd_path_get_opm(device); + for (lpm = 0x80; lpm; lpm >>= 1) { + if (!(lpm & opm)) + continue; + dasd_path_create_kobj(device, pathmask_to_pos(lpm)); + } +} +EXPORT_SYMBOL(dasd_path_create_kobjects); + +/* + * As we keep kobjects for the lifetime of a device, this function must not be + * called anywhere but in the context of offlining a device. + */ +void dasd_path_remove_kobj(struct dasd_device *device, int chp) +{ + if (device->path[chp].in_sysfs) { + kobject_put(&device->path[chp].kobj); + device->path[chp].in_sysfs = false; + } +} +EXPORT_SYMBOL(dasd_path_remove_kobj); int dasd_add_sysfs_files(struct ccw_device *cdev) { diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c index 758ee4153ac1..3caa1ee5f4b0 100644 --- a/drivers/s390/block/dasd_eckd.c +++ b/drivers/s390/block/dasd_eckd.c @@ -103,7 +103,7 @@ struct ext_pool_exhaust_work_data { }; /* definitions for the path verification worker */ -struct path_verification_work_data { +struct pe_handler_work_data { struct work_struct worker; struct dasd_device *device; struct dasd_ccw_req cqr; @@ -111,9 +111,10 @@ struct path_verification_work_data { __u8 rcd_buffer[DASD_ECKD_RCD_DATA_SIZE]; int isglobal; __u8 tbvpm; + __u8 fcsecpm; }; -static struct path_verification_work_data *path_verification_worker; -static DEFINE_MUTEX(dasd_path_verification_mutex); +static struct pe_handler_work_data *pe_handler_worker; +static DEFINE_MUTEX(dasd_pe_handler_mutex); struct check_attention_work_data { struct work_struct worker; @@ -143,7 +144,7 @@ dasd_eckd_probe (struct ccw_device *cdev) "ccw-device options"); return ret; } - ret = dasd_generic_probe(cdev, &dasd_eckd_discipline); + ret = dasd_generic_probe(cdev); return ret; } @@ -1000,6 +1001,27 @@ static unsigned char dasd_eckd_path_access(void *conf_data, int conf_len) return 0; } +static void dasd_eckd_store_conf_data(struct dasd_device *device, + struct dasd_conf_data *conf_data, int chp) +{ + struct channel_path_desc_fmt0 *chp_desc; + struct subchannel_id sch_id; + + ccw_device_get_schid(device->cdev, &sch_id); + /* + * path handling and read_conf allocate data + * free it before replacing the pointer + */ + kfree(device->path[chp].conf_data); + device->path[chp].conf_data = conf_data; + device->path[chp].cssid = sch_id.cssid; + device->path[chp].ssid = sch_id.ssid; + chp_desc = ccw_device_get_chp_desc(device->cdev, chp); + if (chp_desc) + device->path[chp].chpid = chp_desc->chpid; + kfree(chp_desc); +} + static void dasd_eckd_clear_conf_data(struct dasd_device *device) { struct dasd_eckd_private *private = device->private; @@ -1013,9 +1035,33 @@ static void dasd_eckd_clear_conf_data(struct dasd_device *device) device->path[i].cssid = 0; device->path[i].ssid = 0; device->path[i].chpid = 0; + dasd_path_notoper(device, i); + dasd_path_remove_kobj(device, i); } } +static void dasd_eckd_read_fc_security(struct dasd_device *device) +{ + struct dasd_eckd_private *private = device->private; + u8 esm_valid; + u8 esm[8]; + int chp; + int rc; + + rc = chsc_scud(private->uid.ssid, (u64 *)esm, &esm_valid); + if (rc) { + for (chp = 0; chp < 8; chp++) + device->path[chp].fc_security = 0; + return; + } + + for (chp = 0; chp < 8; chp++) { + if (esm_valid & (0x80 >> chp)) + device->path[chp].fc_security = esm[chp]; + else + device->path[chp].fc_security = 0; + } +} static int dasd_eckd_read_conf(struct dasd_device *device) { @@ -1026,12 +1072,9 @@ static int dasd_eckd_read_conf(struct dasd_device *device) struct dasd_eckd_private *private, path_private; struct dasd_uid *uid; char print_path_uid[60], print_device_uid[60]; - struct channel_path_desc_fmt0 *chp_desc; - struct subchannel_id sch_id; private = device->private; opm = ccw_device_get_path_mask(device->cdev); - ccw_device_get_schid(device->cdev, &sch_id); conf_data_saved = 0; path_err = 0; /* get configuration data per operational path */ @@ -1066,15 +1109,6 @@ static int dasd_eckd_read_conf(struct dasd_device *device) kfree(conf_data); continue; } - pos = pathmask_to_pos(lpm); - /* store per path conf_data */ - device->path[pos].conf_data = conf_data; - device->path[pos].cssid = sch_id.cssid; - device->path[pos].ssid = sch_id.ssid; - chp_desc = ccw_device_get_chp_desc(device->cdev, pos); - if (chp_desc) - device->path[pos].chpid = chp_desc->chpid; - kfree(chp_desc); /* * build device UID that other path data * can be compared to it @@ -1132,18 +1166,13 @@ static int dasd_eckd_read_conf(struct dasd_device *device) dasd_path_add_cablepm(device, lpm); continue; } - pos = pathmask_to_pos(lpm); - /* store per path conf_data */ - device->path[pos].conf_data = conf_data; - device->path[pos].cssid = sch_id.cssid; - device->path[pos].ssid = sch_id.ssid; - chp_desc = ccw_device_get_chp_desc(device->cdev, pos); - if (chp_desc) - device->path[pos].chpid = chp_desc->chpid; - kfree(chp_desc); path_private.conf_data = NULL; path_private.conf_len = 0; } + + pos = pathmask_to_pos(lpm); + dasd_eckd_store_conf_data(device, conf_data, pos); + switch (dasd_eckd_path_access(conf_data, conf_len)) { case 0x02: dasd_path_add_nppm(device, lpm); @@ -1160,6 +1189,8 @@ static int dasd_eckd_read_conf(struct dasd_device *device) } } + dasd_eckd_read_fc_security(device); + return path_err; } @@ -1219,7 +1250,7 @@ static int verify_fcx_max_data(struct dasd_device *device, __u8 lpm) } static int rebuild_device_uid(struct dasd_device *device, - struct path_verification_work_data *data) + struct pe_handler_work_data *data) { struct dasd_eckd_private *private = device->private; __u8 lpm, opm = dasd_path_get_opm(device); @@ -1257,31 +1288,18 @@ static int rebuild_device_uid(struct dasd_device *device, return rc; } -static void do_path_verification_work(struct work_struct *work) +static void dasd_eckd_path_available_action(struct dasd_device *device, + struct pe_handler_work_data *data) { - struct path_verification_work_data *data; - struct dasd_device *device; struct dasd_eckd_private path_private; struct dasd_uid *uid; __u8 path_rcd_buf[DASD_ECKD_RCD_DATA_SIZE]; __u8 lpm, opm, npm, ppm, epm, hpfpm, cablepm; + struct dasd_conf_data *conf_data; unsigned long flags; char print_uid[60]; - int rc; - - data = container_of(work, struct path_verification_work_data, worker); - device = data->device; + int rc, pos; - /* delay path verification until device was resumed */ - if (test_bit(DASD_FLAG_SUSPENDED, &device->flags)) { - schedule_work(work); - return; - } - /* check if path verification already running and delay if so */ - if (test_and_set_bit(DASD_FLAG_PATH_VERIFY, &device->flags)) { - schedule_work(work); - return; - } opm = 0; npm = 0; ppm = 0; @@ -1397,6 +1415,14 @@ static void do_path_verification_work(struct work_struct *work) } } + conf_data = kzalloc(DASD_ECKD_RCD_DATA_SIZE, GFP_KERNEL); + if (conf_data) { + memcpy(conf_data, data->rcd_buffer, + DASD_ECKD_RCD_DATA_SIZE); + } + pos = pathmask_to_pos(lpm); + dasd_eckd_store_conf_data(device, conf_data, pos); + /* * There is a small chance that a path is lost again between * above path verification and the following modification of @@ -1417,34 +1443,65 @@ static void do_path_verification_work(struct work_struct *work) dasd_path_add_cablepm(device, cablepm); dasd_path_add_nohpfpm(device, hpfpm); spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags); + + dasd_path_create_kobj(device, pos); + } +} + +static void do_pe_handler_work(struct work_struct *work) +{ + struct pe_handler_work_data *data; + struct dasd_device *device; + + data = container_of(work, struct pe_handler_work_data, worker); + device = data->device; + + /* delay path verification until device was resumed */ + if (test_bit(DASD_FLAG_SUSPENDED, &device->flags)) { + schedule_work(work); + return; + } + /* check if path verification already running and delay if so */ + if (test_and_set_bit(DASD_FLAG_PATH_VERIFY, &device->flags)) { + schedule_work(work); + return; } + + if (data->tbvpm) + dasd_eckd_path_available_action(device, data); + if (data->fcsecpm) + dasd_eckd_read_fc_security(device); + clear_bit(DASD_FLAG_PATH_VERIFY, &device->flags); dasd_put_device(device); if (data->isglobal) - mutex_unlock(&dasd_path_verification_mutex); + mutex_unlock(&dasd_pe_handler_mutex); else kfree(data); } -static int dasd_eckd_verify_path(struct dasd_device *device, __u8 lpm) +static int dasd_eckd_pe_handler(struct dasd_device *device, + __u8 tbvpm, __u8 fcsecpm) { - struct path_verification_work_data *data; + struct pe_handler_work_data *data; data = kmalloc(sizeof(*data), GFP_ATOMIC | GFP_DMA); if (!data) { - if (mutex_trylock(&dasd_path_verification_mutex)) { - data = path_verification_worker; + if (mutex_trylock(&dasd_pe_handler_mutex)) { + data = pe_handler_worker; data->isglobal = 1; - } else + } else { return -ENOMEM; + } } else { memset(data, 0, sizeof(*data)); data->isglobal = 0; } - INIT_WORK(&data->worker, do_path_verification_work); + INIT_WORK(&data->worker, do_pe_handler_work); dasd_get_device(device); data->device = device; - data->tbvpm = lpm; + data->tbvpm = tbvpm; + data->fcsecpm = fcsecpm; schedule_work(&data->worker); return 0; } @@ -2056,6 +2113,8 @@ dasd_eckd_check_characteristics(struct dasd_device *device) if (rc) goto out_err3; + dasd_path_create_kobjects(device); + /* Read Feature Codes */ dasd_eckd_read_features(device); @@ -6590,7 +6649,7 @@ static struct dasd_discipline dasd_eckd_discipline = { .check_device = dasd_eckd_check_characteristics, .uncheck_device = dasd_eckd_uncheck_device, .do_analysis = dasd_eckd_do_analysis, - .verify_path = dasd_eckd_verify_path, + .pe_handler = dasd_eckd_pe_handler, .basic_to_ready = dasd_eckd_basic_to_ready, .online_to_ready = dasd_eckd_online_to_ready, .basic_to_known = dasd_eckd_basic_to_known, @@ -6649,16 +6708,16 @@ dasd_eckd_init(void) GFP_KERNEL | GFP_DMA); if (!dasd_vol_info_req) return -ENOMEM; - path_verification_worker = kmalloc(sizeof(*path_verification_worker), - GFP_KERNEL | GFP_DMA); - if (!path_verification_worker) { + pe_handler_worker = kmalloc(sizeof(*pe_handler_worker), + GFP_KERNEL | GFP_DMA); + if (!pe_handler_worker) { kfree(dasd_reserve_req); kfree(dasd_vol_info_req); return -ENOMEM; } rawpadpage = (void *)__get_free_page(GFP_KERNEL); if (!rawpadpage) { - kfree(path_verification_worker); + kfree(pe_handler_worker); kfree(dasd_reserve_req); kfree(dasd_vol_info_req); return -ENOMEM; @@ -6667,7 +6726,7 @@ dasd_eckd_init(void) if (!ret) wait_for_device_probe(); else { - kfree(path_verification_worker); + kfree(pe_handler_worker); kfree(dasd_reserve_req); kfree(dasd_vol_info_req); free_page((unsigned long)rawpadpage); @@ -6679,7 +6738,7 @@ static void __exit dasd_eckd_cleanup(void) { ccw_driver_unregister(&dasd_eckd_driver); - kfree(path_verification_worker); + kfree(pe_handler_worker); kfree(dasd_reserve_req); free_page((unsigned long)rawpadpage); } diff --git a/drivers/s390/block/dasd_fba.c b/drivers/s390/block/dasd_fba.c index c027344ee225..1aeb68794ce8 100644 --- a/drivers/s390/block/dasd_fba.c +++ b/drivers/s390/block/dasd_fba.c @@ -58,7 +58,7 @@ static struct ccw_driver dasd_fba_driver; /* see below */ static int dasd_fba_probe(struct ccw_device *cdev) { - return dasd_generic_probe(cdev, &dasd_fba_discipline); + return dasd_generic_probe(cdev); } static int diff --git a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h index 8ca077fbdf4f..3bc008f9136c 100644 --- a/drivers/s390/block/dasd_int.h +++ b/drivers/s390/block/dasd_int.h @@ -298,6 +298,7 @@ struct dasd_discipline { * configuration. */ int (*verify_path)(struct dasd_device *, __u8); + int (*pe_handler)(struct dasd_device *, __u8, __u8); /* * Last things to do when a device is set online, and first things @@ -418,10 +419,40 @@ extern struct dasd_discipline *dasd_diag_discipline_pointer; #define DASD_PATH_NOHPF 6 #define DASD_PATH_CUIR 7 #define DASD_PATH_IFCC 8 +#define DASD_PATH_FCSEC 9 #define DASD_THRHLD_MAX 4294967295U #define DASD_INTERVAL_MAX 4294967295U +/* FC Endpoint Security Capabilities */ +#define DASD_FC_SECURITY_UNSUP 0 +#define DASD_FC_SECURITY_AUTH 1 +#define DASD_FC_SECURITY_ENC_FCSP2 2 +#define DASD_FC_SECURITY_ENC_ERAS 3 + +#define DASD_FC_SECURITY_ENC_STR "Encryption" +static const struct { + u8 value; + char *name; +} dasd_path_fcs_mnemonics[] = { + { DASD_FC_SECURITY_UNSUP, "Unsupported" }, + { DASD_FC_SECURITY_AUTH, "Authentication" }, + { DASD_FC_SECURITY_ENC_FCSP2, DASD_FC_SECURITY_ENC_STR }, + { DASD_FC_SECURITY_ENC_ERAS, DASD_FC_SECURITY_ENC_STR }, +}; + +static inline char *dasd_path_get_fcs_str(int val) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(dasd_path_fcs_mnemonics); i++) { + if (dasd_path_fcs_mnemonics[i].value == val) + return dasd_path_fcs_mnemonics[i].name; + } + + return dasd_path_fcs_mnemonics[0].name; +} + struct dasd_path { unsigned long flags; u8 cssid; @@ -430,8 +461,18 @@ struct dasd_path { struct dasd_conf_data *conf_data; atomic_t error_count; unsigned long errorclk; + u8 fc_security; + struct kobject kobj; + bool in_sysfs; }; +#define to_dasd_path(path) container_of(path, struct dasd_path, kobj) + +static inline void dasd_path_release(struct kobject *kobj) +{ +/* Memory for the dasd_path kobject is freed when dasd_free_device() is called */ +} + struct dasd_profile_info { /* legacy part of profile data, as in dasd_profile_info_t */ @@ -542,6 +583,7 @@ struct dasd_device { struct dentry *hosts_dentry; struct dasd_profile profile; struct dasd_format_entry format_entry; + struct kset *paths_info; }; struct dasd_block { @@ -766,7 +808,7 @@ void dasd_block_set_timer(struct dasd_block *, int); void dasd_block_clear_timer(struct dasd_block *); int dasd_cancel_req(struct dasd_ccw_req *); int dasd_flush_device_queue(struct dasd_device *); -int dasd_generic_probe (struct ccw_device *, struct dasd_discipline *); +int dasd_generic_probe(struct ccw_device *); void dasd_generic_free_discipline(struct dasd_device *); void dasd_generic_remove (struct ccw_device *cdev); int dasd_generic_set_online(struct ccw_device *, struct dasd_discipline *); @@ -814,6 +856,9 @@ int dasd_set_feature(struct ccw_device *, int, int); int dasd_add_sysfs_files(struct ccw_device *); void dasd_remove_sysfs_files(struct ccw_device *); +void dasd_path_create_kobj(struct dasd_device *, int); +void dasd_path_create_kobjects(struct dasd_device *); +void dasd_path_remove_kobj(struct dasd_device *, int); struct dasd_device *dasd_device_from_cdev(struct ccw_device *); struct dasd_device *dasd_device_from_cdev_locked(struct ccw_device *); @@ -912,6 +957,29 @@ static inline void dasd_path_clear_all_verify(struct dasd_device *device) dasd_path_clear_verify(device, chp); } +static inline void dasd_path_fcsec(struct dasd_device *device, int chp) +{ + __set_bit(DASD_PATH_FCSEC, &device->path[chp].flags); +} + +static inline void dasd_path_clear_fcsec(struct dasd_device *device, int chp) +{ + __clear_bit(DASD_PATH_FCSEC, &device->path[chp].flags); +} + +static inline int dasd_path_need_fcsec(struct dasd_device *device, int chp) +{ + return test_bit(DASD_PATH_FCSEC, &device->path[chp].flags); +} + +static inline void dasd_path_clear_all_fcsec(struct dasd_device *device) +{ + int chp; + + for (chp = 0; chp < 8; chp++) + dasd_path_clear_fcsec(device, chp); +} + static inline void dasd_path_operational(struct dasd_device *device, int chp) { __set_bit(DASD_PATH_OPERATIONAL, &device->path[chp].flags); @@ -1037,6 +1105,17 @@ static inline __u8 dasd_path_get_tbvpm(struct dasd_device *device) return tbvpm; } +static inline int dasd_path_get_fcsecpm(struct dasd_device *device) +{ + int chp; + + for (chp = 0; chp < 8; chp++) + if (dasd_path_need_fcsec(device, chp)) + return 1; + + return 0; +} + static inline __u8 dasd_path_get_nppm(struct dasd_device *device) { int chp; @@ -1104,6 +1183,31 @@ static inline __u8 dasd_path_get_hpfpm(struct dasd_device *device) return hpfpm; } +static inline u8 dasd_path_get_fcs_path(struct dasd_device *device, int chp) +{ + return device->path[chp].fc_security; +} + +static inline int dasd_path_get_fcs_device(struct dasd_device *device) +{ + u8 fc_sec = 0; + int chp; + + for (chp = 0; chp < 8; chp++) { + if (device->opm & (0x80 >> chp)) { + fc_sec = device->path[chp].fc_security; + break; + } + } + for (; chp < 8; chp++) { + if (device->opm & (0x80 >> chp)) + if (device->path[chp].fc_security != fc_sec) + return -EINVAL; + } + + return fc_sec; +} + /* * add functions for path masks * the existing path mask will be extended by the given path mask @@ -1269,6 +1373,11 @@ static inline void dasd_path_notoper(struct dasd_device *device, int chp) dasd_path_clear_nonpreferred(device, chp); } +static inline void dasd_path_fcsec_update(struct dasd_device *device, int chp) +{ + dasd_path_fcsec(device, chp); +} + /* * remove all paths from normal operation */ |