18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com> 48c2ecf20Sopenharmony_ci * Horst Hummel <Horst.Hummel@de.ibm.com> 58c2ecf20Sopenharmony_ci * Carsten Otte <Cotte@de.ibm.com> 68c2ecf20Sopenharmony_ci * Martin Schwidefsky <schwidefsky@de.ibm.com> 78c2ecf20Sopenharmony_ci * Bugreports.to..: <Linux390@de.ibm.com> 88c2ecf20Sopenharmony_ci * Copyright IBM Corp. 1999,2001 98c2ecf20Sopenharmony_ci * 108c2ecf20Sopenharmony_ci * Device mapping and dasd= parameter parsing functions. All devmap 118c2ecf20Sopenharmony_ci * functions may not be called from interrupt context. In particular 128c2ecf20Sopenharmony_ci * dasd_get_device is a no-no from interrupt context. 138c2ecf20Sopenharmony_ci * 148c2ecf20Sopenharmony_ci */ 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci#define KMSG_COMPONENT "dasd" 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#include <linux/ctype.h> 198c2ecf20Sopenharmony_ci#include <linux/init.h> 208c2ecf20Sopenharmony_ci#include <linux/module.h> 218c2ecf20Sopenharmony_ci#include <linux/slab.h> 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci#include <asm/debug.h> 248c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 258c2ecf20Sopenharmony_ci#include <asm/ipl.h> 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci/* This is ugly... */ 288c2ecf20Sopenharmony_ci#define PRINTK_HEADER "dasd_devmap:" 298c2ecf20Sopenharmony_ci#define DASD_BUS_ID_SIZE 20 308c2ecf20Sopenharmony_ci#define DASD_MAX_PARAMS 256 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci#include "dasd_int.h" 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_cistruct kmem_cache *dasd_page_cache; 358c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(dasd_page_cache); 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci/* 388c2ecf20Sopenharmony_ci * dasd_devmap_t is used to store the features and the relation 398c2ecf20Sopenharmony_ci * between device number and device index. To find a dasd_devmap_t 408c2ecf20Sopenharmony_ci * that corresponds to a device number of a device index each 418c2ecf20Sopenharmony_ci * dasd_devmap_t is added to two linked lists, one to search by 428c2ecf20Sopenharmony_ci * the device number and one to search by the device index. As 438c2ecf20Sopenharmony_ci * soon as big minor numbers are available the device index list 448c2ecf20Sopenharmony_ci * can be removed since the device number will then be identical 458c2ecf20Sopenharmony_ci * to the device index. 468c2ecf20Sopenharmony_ci */ 478c2ecf20Sopenharmony_cistruct dasd_devmap { 488c2ecf20Sopenharmony_ci struct list_head list; 498c2ecf20Sopenharmony_ci char bus_id[DASD_BUS_ID_SIZE]; 508c2ecf20Sopenharmony_ci unsigned int devindex; 518c2ecf20Sopenharmony_ci unsigned short features; 528c2ecf20Sopenharmony_ci struct dasd_device *device; 538c2ecf20Sopenharmony_ci}; 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci/* 568c2ecf20Sopenharmony_ci * Parameter parsing functions for dasd= parameter. The syntax is: 578c2ecf20Sopenharmony_ci * <devno> : (0x)?[0-9a-fA-F]+ 588c2ecf20Sopenharmony_ci * <busid> : [0-0a-f]\.[0-9a-f]\.(0x)?[0-9a-fA-F]+ 598c2ecf20Sopenharmony_ci * <feature> : ro 608c2ecf20Sopenharmony_ci * <feature_list> : \(<feature>(:<feature>)*\) 618c2ecf20Sopenharmony_ci * <devno-range> : <devno>(-<devno>)?<feature_list>? 628c2ecf20Sopenharmony_ci * <busid-range> : <busid>(-<busid>)?<feature_list>? 638c2ecf20Sopenharmony_ci * <devices> : <devno-range>|<busid-range> 648c2ecf20Sopenharmony_ci * <dasd_module> : dasd_diag_mod|dasd_eckd_mod|dasd_fba_mod 658c2ecf20Sopenharmony_ci * 668c2ecf20Sopenharmony_ci * <dasd> : autodetect|probeonly|<devices>(,<devices>)* 678c2ecf20Sopenharmony_ci */ 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ciint dasd_probeonly = 0; /* is true, when probeonly mode is active */ 708c2ecf20Sopenharmony_ciint dasd_autodetect = 0; /* is true, when autodetection is active */ 718c2ecf20Sopenharmony_ciint dasd_nopav = 0; /* is true, when PAV is disabled */ 728c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(dasd_nopav); 738c2ecf20Sopenharmony_ciint dasd_nofcx; /* disable High Performance Ficon */ 748c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(dasd_nofcx); 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci/* 778c2ecf20Sopenharmony_ci * char *dasd[] is intended to hold the ranges supplied by the dasd= statement 788c2ecf20Sopenharmony_ci * it is named 'dasd' to directly be filled by insmod with the comma separated 798c2ecf20Sopenharmony_ci * strings when running as a module. 808c2ecf20Sopenharmony_ci */ 818c2ecf20Sopenharmony_cistatic char *dasd[DASD_MAX_PARAMS]; 828c2ecf20Sopenharmony_cimodule_param_array(dasd, charp, NULL, S_IRUGO); 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci/* 858c2ecf20Sopenharmony_ci * Single spinlock to protect devmap and servermap structures and lists. 868c2ecf20Sopenharmony_ci */ 878c2ecf20Sopenharmony_cistatic DEFINE_SPINLOCK(dasd_devmap_lock); 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci/* 908c2ecf20Sopenharmony_ci * Hash lists for devmap structures. 918c2ecf20Sopenharmony_ci */ 928c2ecf20Sopenharmony_cistatic struct list_head dasd_hashlists[256]; 938c2ecf20Sopenharmony_ciint dasd_max_devindex; 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_cistatic struct dasd_devmap *dasd_add_busid(const char *, int); 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_cistatic inline int 988c2ecf20Sopenharmony_cidasd_hash_busid(const char *bus_id) 998c2ecf20Sopenharmony_ci{ 1008c2ecf20Sopenharmony_ci int hash, i; 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci hash = 0; 1038c2ecf20Sopenharmony_ci for (i = 0; (i < DASD_BUS_ID_SIZE) && *bus_id; i++, bus_id++) 1048c2ecf20Sopenharmony_ci hash += *bus_id; 1058c2ecf20Sopenharmony_ci return hash & 0xff; 1068c2ecf20Sopenharmony_ci} 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci#ifndef MODULE 1098c2ecf20Sopenharmony_cistatic int __init dasd_call_setup(char *opt) 1108c2ecf20Sopenharmony_ci{ 1118c2ecf20Sopenharmony_ci static int i __initdata; 1128c2ecf20Sopenharmony_ci char *tmp; 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci while (i < DASD_MAX_PARAMS) { 1158c2ecf20Sopenharmony_ci tmp = strsep(&opt, ","); 1168c2ecf20Sopenharmony_ci if (!tmp) 1178c2ecf20Sopenharmony_ci break; 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci dasd[i++] = tmp; 1208c2ecf20Sopenharmony_ci } 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci return 1; 1238c2ecf20Sopenharmony_ci} 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci__setup ("dasd=", dasd_call_setup); 1268c2ecf20Sopenharmony_ci#endif /* #ifndef MODULE */ 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci#define DASD_IPLDEV "ipldev" 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci/* 1318c2ecf20Sopenharmony_ci * Read a device busid/devno from a string. 1328c2ecf20Sopenharmony_ci */ 1338c2ecf20Sopenharmony_cistatic int __init dasd_busid(char *str, int *id0, int *id1, int *devno) 1348c2ecf20Sopenharmony_ci{ 1358c2ecf20Sopenharmony_ci unsigned int val; 1368c2ecf20Sopenharmony_ci char *tok; 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci /* Interpret ipldev busid */ 1398c2ecf20Sopenharmony_ci if (strncmp(DASD_IPLDEV, str, strlen(DASD_IPLDEV)) == 0) { 1408c2ecf20Sopenharmony_ci if (ipl_info.type != IPL_TYPE_CCW) { 1418c2ecf20Sopenharmony_ci pr_err("The IPL device is not a CCW device\n"); 1428c2ecf20Sopenharmony_ci return -EINVAL; 1438c2ecf20Sopenharmony_ci } 1448c2ecf20Sopenharmony_ci *id0 = 0; 1458c2ecf20Sopenharmony_ci *id1 = ipl_info.data.ccw.dev_id.ssid; 1468c2ecf20Sopenharmony_ci *devno = ipl_info.data.ccw.dev_id.devno; 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci return 0; 1498c2ecf20Sopenharmony_ci } 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci /* Old style 0xXXXX or XXXX */ 1528c2ecf20Sopenharmony_ci if (!kstrtouint(str, 16, &val)) { 1538c2ecf20Sopenharmony_ci *id0 = *id1 = 0; 1548c2ecf20Sopenharmony_ci if (val > 0xffff) 1558c2ecf20Sopenharmony_ci return -EINVAL; 1568c2ecf20Sopenharmony_ci *devno = val; 1578c2ecf20Sopenharmony_ci return 0; 1588c2ecf20Sopenharmony_ci } 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci /* New style x.y.z busid */ 1618c2ecf20Sopenharmony_ci tok = strsep(&str, "."); 1628c2ecf20Sopenharmony_ci if (kstrtouint(tok, 16, &val) || val > 0xff) 1638c2ecf20Sopenharmony_ci return -EINVAL; 1648c2ecf20Sopenharmony_ci *id0 = val; 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci tok = strsep(&str, "."); 1678c2ecf20Sopenharmony_ci if (kstrtouint(tok, 16, &val) || val > 0xff) 1688c2ecf20Sopenharmony_ci return -EINVAL; 1698c2ecf20Sopenharmony_ci *id1 = val; 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci tok = strsep(&str, "."); 1728c2ecf20Sopenharmony_ci if (kstrtouint(tok, 16, &val) || val > 0xffff) 1738c2ecf20Sopenharmony_ci return -EINVAL; 1748c2ecf20Sopenharmony_ci *devno = val; 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci return 0; 1778c2ecf20Sopenharmony_ci} 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci/* 1808c2ecf20Sopenharmony_ci * Read colon separated list of dasd features. 1818c2ecf20Sopenharmony_ci */ 1828c2ecf20Sopenharmony_cistatic int __init dasd_feature_list(char *str) 1838c2ecf20Sopenharmony_ci{ 1848c2ecf20Sopenharmony_ci int features, len, rc; 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci features = 0; 1878c2ecf20Sopenharmony_ci rc = 0; 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci if (!str) 1908c2ecf20Sopenharmony_ci return DASD_FEATURE_DEFAULT; 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci while (1) { 1938c2ecf20Sopenharmony_ci for (len = 0; 1948c2ecf20Sopenharmony_ci str[len] && str[len] != ':' && str[len] != ')'; len++); 1958c2ecf20Sopenharmony_ci if (len == 2 && !strncmp(str, "ro", 2)) 1968c2ecf20Sopenharmony_ci features |= DASD_FEATURE_READONLY; 1978c2ecf20Sopenharmony_ci else if (len == 4 && !strncmp(str, "diag", 4)) 1988c2ecf20Sopenharmony_ci features |= DASD_FEATURE_USEDIAG; 1998c2ecf20Sopenharmony_ci else if (len == 3 && !strncmp(str, "raw", 3)) 2008c2ecf20Sopenharmony_ci features |= DASD_FEATURE_USERAW; 2018c2ecf20Sopenharmony_ci else if (len == 6 && !strncmp(str, "erplog", 6)) 2028c2ecf20Sopenharmony_ci features |= DASD_FEATURE_ERPLOG; 2038c2ecf20Sopenharmony_ci else if (len == 8 && !strncmp(str, "failfast", 8)) 2048c2ecf20Sopenharmony_ci features |= DASD_FEATURE_FAILFAST; 2058c2ecf20Sopenharmony_ci else { 2068c2ecf20Sopenharmony_ci pr_warn("%.*s is not a supported device option\n", 2078c2ecf20Sopenharmony_ci len, str); 2088c2ecf20Sopenharmony_ci rc = -EINVAL; 2098c2ecf20Sopenharmony_ci } 2108c2ecf20Sopenharmony_ci str += len; 2118c2ecf20Sopenharmony_ci if (*str != ':') 2128c2ecf20Sopenharmony_ci break; 2138c2ecf20Sopenharmony_ci str++; 2148c2ecf20Sopenharmony_ci } 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci return rc ? : features; 2178c2ecf20Sopenharmony_ci} 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci/* 2208c2ecf20Sopenharmony_ci * Try to match the first element on the comma separated parse string 2218c2ecf20Sopenharmony_ci * with one of the known keywords. If a keyword is found, take the approprate 2228c2ecf20Sopenharmony_ci * action and return a pointer to the residual string. If the first element 2238c2ecf20Sopenharmony_ci * could not be matched to any keyword then return an error code. 2248c2ecf20Sopenharmony_ci */ 2258c2ecf20Sopenharmony_cistatic int __init dasd_parse_keyword(char *keyword) 2268c2ecf20Sopenharmony_ci{ 2278c2ecf20Sopenharmony_ci int length = strlen(keyword); 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci if (strncmp("autodetect", keyword, length) == 0) { 2308c2ecf20Sopenharmony_ci dasd_autodetect = 1; 2318c2ecf20Sopenharmony_ci pr_info("The autodetection mode has been activated\n"); 2328c2ecf20Sopenharmony_ci return 0; 2338c2ecf20Sopenharmony_ci } 2348c2ecf20Sopenharmony_ci if (strncmp("probeonly", keyword, length) == 0) { 2358c2ecf20Sopenharmony_ci dasd_probeonly = 1; 2368c2ecf20Sopenharmony_ci pr_info("The probeonly mode has been activated\n"); 2378c2ecf20Sopenharmony_ci return 0; 2388c2ecf20Sopenharmony_ci } 2398c2ecf20Sopenharmony_ci if (strncmp("nopav", keyword, length) == 0) { 2408c2ecf20Sopenharmony_ci if (MACHINE_IS_VM) 2418c2ecf20Sopenharmony_ci pr_info("'nopav' is not supported on z/VM\n"); 2428c2ecf20Sopenharmony_ci else { 2438c2ecf20Sopenharmony_ci dasd_nopav = 1; 2448c2ecf20Sopenharmony_ci pr_info("PAV support has be deactivated\n"); 2458c2ecf20Sopenharmony_ci } 2468c2ecf20Sopenharmony_ci return 0; 2478c2ecf20Sopenharmony_ci } 2488c2ecf20Sopenharmony_ci if (strncmp("nofcx", keyword, length) == 0) { 2498c2ecf20Sopenharmony_ci dasd_nofcx = 1; 2508c2ecf20Sopenharmony_ci pr_info("High Performance FICON support has been " 2518c2ecf20Sopenharmony_ci "deactivated\n"); 2528c2ecf20Sopenharmony_ci return 0; 2538c2ecf20Sopenharmony_ci } 2548c2ecf20Sopenharmony_ci if (strncmp("fixedbuffers", keyword, length) == 0) { 2558c2ecf20Sopenharmony_ci if (dasd_page_cache) 2568c2ecf20Sopenharmony_ci return 0; 2578c2ecf20Sopenharmony_ci dasd_page_cache = 2588c2ecf20Sopenharmony_ci kmem_cache_create("dasd_page_cache", PAGE_SIZE, 2598c2ecf20Sopenharmony_ci PAGE_SIZE, SLAB_CACHE_DMA, 2608c2ecf20Sopenharmony_ci NULL); 2618c2ecf20Sopenharmony_ci if (!dasd_page_cache) 2628c2ecf20Sopenharmony_ci DBF_EVENT(DBF_WARNING, "%s", "Failed to create slab, " 2638c2ecf20Sopenharmony_ci "fixed buffer mode disabled."); 2648c2ecf20Sopenharmony_ci else 2658c2ecf20Sopenharmony_ci DBF_EVENT(DBF_INFO, "%s", 2668c2ecf20Sopenharmony_ci "turning on fixed buffer mode"); 2678c2ecf20Sopenharmony_ci return 0; 2688c2ecf20Sopenharmony_ci } 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci return -EINVAL; 2718c2ecf20Sopenharmony_ci} 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci/* 2748c2ecf20Sopenharmony_ci * Split a string of a device range into its pieces and return the from, to, and 2758c2ecf20Sopenharmony_ci * feature parts separately. 2768c2ecf20Sopenharmony_ci * e.g.: 2778c2ecf20Sopenharmony_ci * 0.0.1234-0.0.5678(ro:erplog) -> from: 0.0.1234 to: 0.0.5678 features: ro:erplog 2788c2ecf20Sopenharmony_ci * 0.0.8765(raw) -> from: 0.0.8765 to: null features: raw 2798c2ecf20Sopenharmony_ci * 0x4321 -> from: 0x4321 to: null features: null 2808c2ecf20Sopenharmony_ci */ 2818c2ecf20Sopenharmony_cistatic int __init dasd_evaluate_range_param(char *range, char **from_str, 2828c2ecf20Sopenharmony_ci char **to_str, char **features_str) 2838c2ecf20Sopenharmony_ci{ 2848c2ecf20Sopenharmony_ci int rc = 0; 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci /* Do we have a range or a single device? */ 2878c2ecf20Sopenharmony_ci if (strchr(range, '-')) { 2888c2ecf20Sopenharmony_ci *from_str = strsep(&range, "-"); 2898c2ecf20Sopenharmony_ci *to_str = strsep(&range, "("); 2908c2ecf20Sopenharmony_ci *features_str = strsep(&range, ")"); 2918c2ecf20Sopenharmony_ci } else { 2928c2ecf20Sopenharmony_ci *from_str = strsep(&range, "("); 2938c2ecf20Sopenharmony_ci *features_str = strsep(&range, ")"); 2948c2ecf20Sopenharmony_ci } 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci if (*features_str && !range) { 2978c2ecf20Sopenharmony_ci pr_warn("A closing parenthesis ')' is missing in the dasd= parameter\n"); 2988c2ecf20Sopenharmony_ci rc = -EINVAL; 2998c2ecf20Sopenharmony_ci } 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci return rc; 3028c2ecf20Sopenharmony_ci} 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci/* 3058c2ecf20Sopenharmony_ci * Try to interprete the range string as a device number or a range of devices. 3068c2ecf20Sopenharmony_ci * If the interpretation is successful, create the matching dasd_devmap entries. 3078c2ecf20Sopenharmony_ci * If interpretation fails or in case of an error, return an error code. 3088c2ecf20Sopenharmony_ci */ 3098c2ecf20Sopenharmony_cistatic int __init dasd_parse_range(const char *range) 3108c2ecf20Sopenharmony_ci{ 3118c2ecf20Sopenharmony_ci struct dasd_devmap *devmap; 3128c2ecf20Sopenharmony_ci int from, from_id0, from_id1; 3138c2ecf20Sopenharmony_ci int to, to_id0, to_id1; 3148c2ecf20Sopenharmony_ci int features; 3158c2ecf20Sopenharmony_ci char bus_id[DASD_BUS_ID_SIZE + 1]; 3168c2ecf20Sopenharmony_ci char *features_str = NULL; 3178c2ecf20Sopenharmony_ci char *from_str = NULL; 3188c2ecf20Sopenharmony_ci char *to_str = NULL; 3198c2ecf20Sopenharmony_ci int rc = 0; 3208c2ecf20Sopenharmony_ci char *tmp; 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci tmp = kstrdup(range, GFP_KERNEL); 3238c2ecf20Sopenharmony_ci if (!tmp) 3248c2ecf20Sopenharmony_ci return -ENOMEM; 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci if (dasd_evaluate_range_param(tmp, &from_str, &to_str, &features_str)) { 3278c2ecf20Sopenharmony_ci rc = -EINVAL; 3288c2ecf20Sopenharmony_ci goto out; 3298c2ecf20Sopenharmony_ci } 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci if (dasd_busid(from_str, &from_id0, &from_id1, &from)) { 3328c2ecf20Sopenharmony_ci rc = -EINVAL; 3338c2ecf20Sopenharmony_ci goto out; 3348c2ecf20Sopenharmony_ci } 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci to = from; 3378c2ecf20Sopenharmony_ci to_id0 = from_id0; 3388c2ecf20Sopenharmony_ci to_id1 = from_id1; 3398c2ecf20Sopenharmony_ci if (to_str) { 3408c2ecf20Sopenharmony_ci if (dasd_busid(to_str, &to_id0, &to_id1, &to)) { 3418c2ecf20Sopenharmony_ci rc = -EINVAL; 3428c2ecf20Sopenharmony_ci goto out; 3438c2ecf20Sopenharmony_ci } 3448c2ecf20Sopenharmony_ci if (from_id0 != to_id0 || from_id1 != to_id1 || from > to) { 3458c2ecf20Sopenharmony_ci pr_err("%s is not a valid device range\n", range); 3468c2ecf20Sopenharmony_ci rc = -EINVAL; 3478c2ecf20Sopenharmony_ci goto out; 3488c2ecf20Sopenharmony_ci } 3498c2ecf20Sopenharmony_ci } 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci features = dasd_feature_list(features_str); 3528c2ecf20Sopenharmony_ci if (features < 0) { 3538c2ecf20Sopenharmony_ci rc = -EINVAL; 3548c2ecf20Sopenharmony_ci goto out; 3558c2ecf20Sopenharmony_ci } 3568c2ecf20Sopenharmony_ci /* each device in dasd= parameter should be set initially online */ 3578c2ecf20Sopenharmony_ci features |= DASD_FEATURE_INITIAL_ONLINE; 3588c2ecf20Sopenharmony_ci while (from <= to) { 3598c2ecf20Sopenharmony_ci sprintf(bus_id, "%01x.%01x.%04x", from_id0, from_id1, from++); 3608c2ecf20Sopenharmony_ci devmap = dasd_add_busid(bus_id, features); 3618c2ecf20Sopenharmony_ci if (IS_ERR(devmap)) { 3628c2ecf20Sopenharmony_ci rc = PTR_ERR(devmap); 3638c2ecf20Sopenharmony_ci goto out; 3648c2ecf20Sopenharmony_ci } 3658c2ecf20Sopenharmony_ci } 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ciout: 3688c2ecf20Sopenharmony_ci kfree(tmp); 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci return rc; 3718c2ecf20Sopenharmony_ci} 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci/* 3748c2ecf20Sopenharmony_ci * Parse parameters stored in dasd[] 3758c2ecf20Sopenharmony_ci * The 'dasd=...' parameter allows to specify a comma separated list of 3768c2ecf20Sopenharmony_ci * keywords and device ranges. The parameters in that list will be stored as 3778c2ecf20Sopenharmony_ci * separate elementes in dasd[]. 3788c2ecf20Sopenharmony_ci */ 3798c2ecf20Sopenharmony_ciint __init dasd_parse(void) 3808c2ecf20Sopenharmony_ci{ 3818c2ecf20Sopenharmony_ci int rc, i; 3828c2ecf20Sopenharmony_ci char *cur; 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci rc = 0; 3858c2ecf20Sopenharmony_ci for (i = 0; i < DASD_MAX_PARAMS; i++) { 3868c2ecf20Sopenharmony_ci cur = dasd[i]; 3878c2ecf20Sopenharmony_ci if (!cur) 3888c2ecf20Sopenharmony_ci break; 3898c2ecf20Sopenharmony_ci if (*cur == '\0') 3908c2ecf20Sopenharmony_ci continue; 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci rc = dasd_parse_keyword(cur); 3938c2ecf20Sopenharmony_ci if (rc) 3948c2ecf20Sopenharmony_ci rc = dasd_parse_range(cur); 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci if (rc) 3978c2ecf20Sopenharmony_ci break; 3988c2ecf20Sopenharmony_ci } 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci return rc; 4018c2ecf20Sopenharmony_ci} 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci/* 4048c2ecf20Sopenharmony_ci * Add a devmap for the device specified by busid. It is possible that 4058c2ecf20Sopenharmony_ci * the devmap already exists (dasd= parameter). The order of the devices 4068c2ecf20Sopenharmony_ci * added through this function will define the kdevs for the individual 4078c2ecf20Sopenharmony_ci * devices. 4088c2ecf20Sopenharmony_ci */ 4098c2ecf20Sopenharmony_cistatic struct dasd_devmap * 4108c2ecf20Sopenharmony_cidasd_add_busid(const char *bus_id, int features) 4118c2ecf20Sopenharmony_ci{ 4128c2ecf20Sopenharmony_ci struct dasd_devmap *devmap, *new, *tmp; 4138c2ecf20Sopenharmony_ci int hash; 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_ci new = kzalloc(sizeof(struct dasd_devmap), GFP_KERNEL); 4168c2ecf20Sopenharmony_ci if (!new) 4178c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 4188c2ecf20Sopenharmony_ci spin_lock(&dasd_devmap_lock); 4198c2ecf20Sopenharmony_ci devmap = NULL; 4208c2ecf20Sopenharmony_ci hash = dasd_hash_busid(bus_id); 4218c2ecf20Sopenharmony_ci list_for_each_entry(tmp, &dasd_hashlists[hash], list) 4228c2ecf20Sopenharmony_ci if (strncmp(tmp->bus_id, bus_id, DASD_BUS_ID_SIZE) == 0) { 4238c2ecf20Sopenharmony_ci devmap = tmp; 4248c2ecf20Sopenharmony_ci break; 4258c2ecf20Sopenharmony_ci } 4268c2ecf20Sopenharmony_ci if (!devmap) { 4278c2ecf20Sopenharmony_ci /* This bus_id is new. */ 4288c2ecf20Sopenharmony_ci new->devindex = dasd_max_devindex++; 4298c2ecf20Sopenharmony_ci strlcpy(new->bus_id, bus_id, DASD_BUS_ID_SIZE); 4308c2ecf20Sopenharmony_ci new->features = features; 4318c2ecf20Sopenharmony_ci new->device = NULL; 4328c2ecf20Sopenharmony_ci list_add(&new->list, &dasd_hashlists[hash]); 4338c2ecf20Sopenharmony_ci devmap = new; 4348c2ecf20Sopenharmony_ci new = NULL; 4358c2ecf20Sopenharmony_ci } 4368c2ecf20Sopenharmony_ci spin_unlock(&dasd_devmap_lock); 4378c2ecf20Sopenharmony_ci kfree(new); 4388c2ecf20Sopenharmony_ci return devmap; 4398c2ecf20Sopenharmony_ci} 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_ci/* 4428c2ecf20Sopenharmony_ci * Find devmap for device with given bus_id. 4438c2ecf20Sopenharmony_ci */ 4448c2ecf20Sopenharmony_cistatic struct dasd_devmap * 4458c2ecf20Sopenharmony_cidasd_find_busid(const char *bus_id) 4468c2ecf20Sopenharmony_ci{ 4478c2ecf20Sopenharmony_ci struct dasd_devmap *devmap, *tmp; 4488c2ecf20Sopenharmony_ci int hash; 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_ci spin_lock(&dasd_devmap_lock); 4518c2ecf20Sopenharmony_ci devmap = ERR_PTR(-ENODEV); 4528c2ecf20Sopenharmony_ci hash = dasd_hash_busid(bus_id); 4538c2ecf20Sopenharmony_ci list_for_each_entry(tmp, &dasd_hashlists[hash], list) { 4548c2ecf20Sopenharmony_ci if (strncmp(tmp->bus_id, bus_id, DASD_BUS_ID_SIZE) == 0) { 4558c2ecf20Sopenharmony_ci devmap = tmp; 4568c2ecf20Sopenharmony_ci break; 4578c2ecf20Sopenharmony_ci } 4588c2ecf20Sopenharmony_ci } 4598c2ecf20Sopenharmony_ci spin_unlock(&dasd_devmap_lock); 4608c2ecf20Sopenharmony_ci return devmap; 4618c2ecf20Sopenharmony_ci} 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci/* 4648c2ecf20Sopenharmony_ci * Check if busid has been added to the list of dasd ranges. 4658c2ecf20Sopenharmony_ci */ 4668c2ecf20Sopenharmony_ciint 4678c2ecf20Sopenharmony_cidasd_busid_known(const char *bus_id) 4688c2ecf20Sopenharmony_ci{ 4698c2ecf20Sopenharmony_ci return IS_ERR(dasd_find_busid(bus_id)) ? -ENOENT : 0; 4708c2ecf20Sopenharmony_ci} 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ci/* 4738c2ecf20Sopenharmony_ci * Forget all about the device numbers added so far. 4748c2ecf20Sopenharmony_ci * This may only be called at module unload or system shutdown. 4758c2ecf20Sopenharmony_ci */ 4768c2ecf20Sopenharmony_cistatic void 4778c2ecf20Sopenharmony_cidasd_forget_ranges(void) 4788c2ecf20Sopenharmony_ci{ 4798c2ecf20Sopenharmony_ci struct dasd_devmap *devmap, *n; 4808c2ecf20Sopenharmony_ci int i; 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_ci spin_lock(&dasd_devmap_lock); 4838c2ecf20Sopenharmony_ci for (i = 0; i < 256; i++) { 4848c2ecf20Sopenharmony_ci list_for_each_entry_safe(devmap, n, &dasd_hashlists[i], list) { 4858c2ecf20Sopenharmony_ci BUG_ON(devmap->device != NULL); 4868c2ecf20Sopenharmony_ci list_del(&devmap->list); 4878c2ecf20Sopenharmony_ci kfree(devmap); 4888c2ecf20Sopenharmony_ci } 4898c2ecf20Sopenharmony_ci } 4908c2ecf20Sopenharmony_ci spin_unlock(&dasd_devmap_lock); 4918c2ecf20Sopenharmony_ci} 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci/* 4948c2ecf20Sopenharmony_ci * Find the device struct by its device index. 4958c2ecf20Sopenharmony_ci */ 4968c2ecf20Sopenharmony_cistruct dasd_device * 4978c2ecf20Sopenharmony_cidasd_device_from_devindex(int devindex) 4988c2ecf20Sopenharmony_ci{ 4998c2ecf20Sopenharmony_ci struct dasd_devmap *devmap, *tmp; 5008c2ecf20Sopenharmony_ci struct dasd_device *device; 5018c2ecf20Sopenharmony_ci int i; 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_ci spin_lock(&dasd_devmap_lock); 5048c2ecf20Sopenharmony_ci devmap = NULL; 5058c2ecf20Sopenharmony_ci for (i = 0; (i < 256) && !devmap; i++) 5068c2ecf20Sopenharmony_ci list_for_each_entry(tmp, &dasd_hashlists[i], list) 5078c2ecf20Sopenharmony_ci if (tmp->devindex == devindex) { 5088c2ecf20Sopenharmony_ci /* Found the devmap for the device. */ 5098c2ecf20Sopenharmony_ci devmap = tmp; 5108c2ecf20Sopenharmony_ci break; 5118c2ecf20Sopenharmony_ci } 5128c2ecf20Sopenharmony_ci if (devmap && devmap->device) { 5138c2ecf20Sopenharmony_ci device = devmap->device; 5148c2ecf20Sopenharmony_ci dasd_get_device(device); 5158c2ecf20Sopenharmony_ci } else 5168c2ecf20Sopenharmony_ci device = ERR_PTR(-ENODEV); 5178c2ecf20Sopenharmony_ci spin_unlock(&dasd_devmap_lock); 5188c2ecf20Sopenharmony_ci return device; 5198c2ecf20Sopenharmony_ci} 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ci/* 5228c2ecf20Sopenharmony_ci * Return devmap for cdev. If no devmap exists yet, create one and 5238c2ecf20Sopenharmony_ci * connect it to the cdev. 5248c2ecf20Sopenharmony_ci */ 5258c2ecf20Sopenharmony_cistatic struct dasd_devmap * 5268c2ecf20Sopenharmony_cidasd_devmap_from_cdev(struct ccw_device *cdev) 5278c2ecf20Sopenharmony_ci{ 5288c2ecf20Sopenharmony_ci struct dasd_devmap *devmap; 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_ci devmap = dasd_find_busid(dev_name(&cdev->dev)); 5318c2ecf20Sopenharmony_ci if (IS_ERR(devmap)) 5328c2ecf20Sopenharmony_ci devmap = dasd_add_busid(dev_name(&cdev->dev), 5338c2ecf20Sopenharmony_ci DASD_FEATURE_DEFAULT); 5348c2ecf20Sopenharmony_ci return devmap; 5358c2ecf20Sopenharmony_ci} 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_ci/* 5388c2ecf20Sopenharmony_ci * Create a dasd device structure for cdev. 5398c2ecf20Sopenharmony_ci */ 5408c2ecf20Sopenharmony_cistruct dasd_device * 5418c2ecf20Sopenharmony_cidasd_create_device(struct ccw_device *cdev) 5428c2ecf20Sopenharmony_ci{ 5438c2ecf20Sopenharmony_ci struct dasd_devmap *devmap; 5448c2ecf20Sopenharmony_ci struct dasd_device *device; 5458c2ecf20Sopenharmony_ci unsigned long flags; 5468c2ecf20Sopenharmony_ci int rc; 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_ci devmap = dasd_devmap_from_cdev(cdev); 5498c2ecf20Sopenharmony_ci if (IS_ERR(devmap)) 5508c2ecf20Sopenharmony_ci return (void *) devmap; 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_ci device = dasd_alloc_device(); 5538c2ecf20Sopenharmony_ci if (IS_ERR(device)) 5548c2ecf20Sopenharmony_ci return device; 5558c2ecf20Sopenharmony_ci atomic_set(&device->ref_count, 3); 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_ci spin_lock(&dasd_devmap_lock); 5588c2ecf20Sopenharmony_ci if (!devmap->device) { 5598c2ecf20Sopenharmony_ci devmap->device = device; 5608c2ecf20Sopenharmony_ci device->devindex = devmap->devindex; 5618c2ecf20Sopenharmony_ci device->features = devmap->features; 5628c2ecf20Sopenharmony_ci get_device(&cdev->dev); 5638c2ecf20Sopenharmony_ci device->cdev = cdev; 5648c2ecf20Sopenharmony_ci rc = 0; 5658c2ecf20Sopenharmony_ci } else 5668c2ecf20Sopenharmony_ci /* Someone else was faster. */ 5678c2ecf20Sopenharmony_ci rc = -EBUSY; 5688c2ecf20Sopenharmony_ci spin_unlock(&dasd_devmap_lock); 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_ci if (rc) { 5718c2ecf20Sopenharmony_ci dasd_free_device(device); 5728c2ecf20Sopenharmony_ci return ERR_PTR(rc); 5738c2ecf20Sopenharmony_ci } 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_ci spin_lock_irqsave(get_ccwdev_lock(cdev), flags); 5768c2ecf20Sopenharmony_ci dev_set_drvdata(&cdev->dev, device); 5778c2ecf20Sopenharmony_ci spin_unlock_irqrestore(get_ccwdev_lock(cdev), flags); 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci return device; 5808c2ecf20Sopenharmony_ci} 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_ci/* 5838c2ecf20Sopenharmony_ci * Wait queue for dasd_delete_device waits. 5848c2ecf20Sopenharmony_ci */ 5858c2ecf20Sopenharmony_cistatic DECLARE_WAIT_QUEUE_HEAD(dasd_delete_wq); 5868c2ecf20Sopenharmony_ci 5878c2ecf20Sopenharmony_ci/* 5888c2ecf20Sopenharmony_ci * Remove a dasd device structure. The passed referenced 5898c2ecf20Sopenharmony_ci * is destroyed. 5908c2ecf20Sopenharmony_ci */ 5918c2ecf20Sopenharmony_civoid 5928c2ecf20Sopenharmony_cidasd_delete_device(struct dasd_device *device) 5938c2ecf20Sopenharmony_ci{ 5948c2ecf20Sopenharmony_ci struct ccw_device *cdev; 5958c2ecf20Sopenharmony_ci struct dasd_devmap *devmap; 5968c2ecf20Sopenharmony_ci unsigned long flags; 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_ci /* First remove device pointer from devmap. */ 5998c2ecf20Sopenharmony_ci devmap = dasd_find_busid(dev_name(&device->cdev->dev)); 6008c2ecf20Sopenharmony_ci BUG_ON(IS_ERR(devmap)); 6018c2ecf20Sopenharmony_ci spin_lock(&dasd_devmap_lock); 6028c2ecf20Sopenharmony_ci if (devmap->device != device) { 6038c2ecf20Sopenharmony_ci spin_unlock(&dasd_devmap_lock); 6048c2ecf20Sopenharmony_ci dasd_put_device(device); 6058c2ecf20Sopenharmony_ci return; 6068c2ecf20Sopenharmony_ci } 6078c2ecf20Sopenharmony_ci devmap->device = NULL; 6088c2ecf20Sopenharmony_ci spin_unlock(&dasd_devmap_lock); 6098c2ecf20Sopenharmony_ci 6108c2ecf20Sopenharmony_ci /* Disconnect dasd_device structure from ccw_device structure. */ 6118c2ecf20Sopenharmony_ci spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags); 6128c2ecf20Sopenharmony_ci dev_set_drvdata(&device->cdev->dev, NULL); 6138c2ecf20Sopenharmony_ci spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags); 6148c2ecf20Sopenharmony_ci 6158c2ecf20Sopenharmony_ci /* 6168c2ecf20Sopenharmony_ci * Drop ref_count by 3, one for the devmap reference, one for 6178c2ecf20Sopenharmony_ci * the cdev reference and one for the passed reference. 6188c2ecf20Sopenharmony_ci */ 6198c2ecf20Sopenharmony_ci atomic_sub(3, &device->ref_count); 6208c2ecf20Sopenharmony_ci 6218c2ecf20Sopenharmony_ci /* Wait for reference counter to drop to zero. */ 6228c2ecf20Sopenharmony_ci wait_event(dasd_delete_wq, atomic_read(&device->ref_count) == 0); 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_ci dasd_generic_free_discipline(device); 6258c2ecf20Sopenharmony_ci /* Disconnect dasd_device structure from ccw_device structure. */ 6268c2ecf20Sopenharmony_ci cdev = device->cdev; 6278c2ecf20Sopenharmony_ci device->cdev = NULL; 6288c2ecf20Sopenharmony_ci 6298c2ecf20Sopenharmony_ci /* Put ccw_device structure. */ 6308c2ecf20Sopenharmony_ci put_device(&cdev->dev); 6318c2ecf20Sopenharmony_ci 6328c2ecf20Sopenharmony_ci /* Now the device structure can be freed. */ 6338c2ecf20Sopenharmony_ci dasd_free_device(device); 6348c2ecf20Sopenharmony_ci} 6358c2ecf20Sopenharmony_ci 6368c2ecf20Sopenharmony_ci/* 6378c2ecf20Sopenharmony_ci * Reference counter dropped to zero. Wake up waiter 6388c2ecf20Sopenharmony_ci * in dasd_delete_device. 6398c2ecf20Sopenharmony_ci */ 6408c2ecf20Sopenharmony_civoid 6418c2ecf20Sopenharmony_cidasd_put_device_wake(struct dasd_device *device) 6428c2ecf20Sopenharmony_ci{ 6438c2ecf20Sopenharmony_ci wake_up(&dasd_delete_wq); 6448c2ecf20Sopenharmony_ci} 6458c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(dasd_put_device_wake); 6468c2ecf20Sopenharmony_ci 6478c2ecf20Sopenharmony_ci/* 6488c2ecf20Sopenharmony_ci * Return dasd_device structure associated with cdev. 6498c2ecf20Sopenharmony_ci * This function needs to be called with the ccw device 6508c2ecf20Sopenharmony_ci * lock held. It can be used from interrupt context. 6518c2ecf20Sopenharmony_ci */ 6528c2ecf20Sopenharmony_cistruct dasd_device * 6538c2ecf20Sopenharmony_cidasd_device_from_cdev_locked(struct ccw_device *cdev) 6548c2ecf20Sopenharmony_ci{ 6558c2ecf20Sopenharmony_ci struct dasd_device *device = dev_get_drvdata(&cdev->dev); 6568c2ecf20Sopenharmony_ci 6578c2ecf20Sopenharmony_ci if (!device) 6588c2ecf20Sopenharmony_ci return ERR_PTR(-ENODEV); 6598c2ecf20Sopenharmony_ci dasd_get_device(device); 6608c2ecf20Sopenharmony_ci return device; 6618c2ecf20Sopenharmony_ci} 6628c2ecf20Sopenharmony_ci 6638c2ecf20Sopenharmony_ci/* 6648c2ecf20Sopenharmony_ci * Return dasd_device structure associated with cdev. 6658c2ecf20Sopenharmony_ci */ 6668c2ecf20Sopenharmony_cistruct dasd_device * 6678c2ecf20Sopenharmony_cidasd_device_from_cdev(struct ccw_device *cdev) 6688c2ecf20Sopenharmony_ci{ 6698c2ecf20Sopenharmony_ci struct dasd_device *device; 6708c2ecf20Sopenharmony_ci unsigned long flags; 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_ci spin_lock_irqsave(get_ccwdev_lock(cdev), flags); 6738c2ecf20Sopenharmony_ci device = dasd_device_from_cdev_locked(cdev); 6748c2ecf20Sopenharmony_ci spin_unlock_irqrestore(get_ccwdev_lock(cdev), flags); 6758c2ecf20Sopenharmony_ci return device; 6768c2ecf20Sopenharmony_ci} 6778c2ecf20Sopenharmony_ci 6788c2ecf20Sopenharmony_civoid dasd_add_link_to_gendisk(struct gendisk *gdp, struct dasd_device *device) 6798c2ecf20Sopenharmony_ci{ 6808c2ecf20Sopenharmony_ci struct dasd_devmap *devmap; 6818c2ecf20Sopenharmony_ci 6828c2ecf20Sopenharmony_ci devmap = dasd_find_busid(dev_name(&device->cdev->dev)); 6838c2ecf20Sopenharmony_ci if (IS_ERR(devmap)) 6848c2ecf20Sopenharmony_ci return; 6858c2ecf20Sopenharmony_ci spin_lock(&dasd_devmap_lock); 6868c2ecf20Sopenharmony_ci gdp->private_data = devmap; 6878c2ecf20Sopenharmony_ci spin_unlock(&dasd_devmap_lock); 6888c2ecf20Sopenharmony_ci} 6898c2ecf20Sopenharmony_ci 6908c2ecf20Sopenharmony_cistruct dasd_device *dasd_device_from_gendisk(struct gendisk *gdp) 6918c2ecf20Sopenharmony_ci{ 6928c2ecf20Sopenharmony_ci struct dasd_device *device; 6938c2ecf20Sopenharmony_ci struct dasd_devmap *devmap; 6948c2ecf20Sopenharmony_ci 6958c2ecf20Sopenharmony_ci if (!gdp->private_data) 6968c2ecf20Sopenharmony_ci return NULL; 6978c2ecf20Sopenharmony_ci device = NULL; 6988c2ecf20Sopenharmony_ci spin_lock(&dasd_devmap_lock); 6998c2ecf20Sopenharmony_ci devmap = gdp->private_data; 7008c2ecf20Sopenharmony_ci if (devmap && devmap->device) { 7018c2ecf20Sopenharmony_ci device = devmap->device; 7028c2ecf20Sopenharmony_ci dasd_get_device(device); 7038c2ecf20Sopenharmony_ci } 7048c2ecf20Sopenharmony_ci spin_unlock(&dasd_devmap_lock); 7058c2ecf20Sopenharmony_ci return device; 7068c2ecf20Sopenharmony_ci} 7078c2ecf20Sopenharmony_ci 7088c2ecf20Sopenharmony_ci/* 7098c2ecf20Sopenharmony_ci * SECTION: files in sysfs 7108c2ecf20Sopenharmony_ci */ 7118c2ecf20Sopenharmony_ci 7128c2ecf20Sopenharmony_ci/* 7138c2ecf20Sopenharmony_ci * failfast controls the behaviour, if no path is available 7148c2ecf20Sopenharmony_ci */ 7158c2ecf20Sopenharmony_cistatic ssize_t dasd_ff_show(struct device *dev, struct device_attribute *attr, 7168c2ecf20Sopenharmony_ci char *buf) 7178c2ecf20Sopenharmony_ci{ 7188c2ecf20Sopenharmony_ci struct dasd_devmap *devmap; 7198c2ecf20Sopenharmony_ci int ff_flag; 7208c2ecf20Sopenharmony_ci 7218c2ecf20Sopenharmony_ci devmap = dasd_find_busid(dev_name(dev)); 7228c2ecf20Sopenharmony_ci if (!IS_ERR(devmap)) 7238c2ecf20Sopenharmony_ci ff_flag = (devmap->features & DASD_FEATURE_FAILFAST) != 0; 7248c2ecf20Sopenharmony_ci else 7258c2ecf20Sopenharmony_ci ff_flag = (DASD_FEATURE_DEFAULT & DASD_FEATURE_FAILFAST) != 0; 7268c2ecf20Sopenharmony_ci return snprintf(buf, PAGE_SIZE, ff_flag ? "1\n" : "0\n"); 7278c2ecf20Sopenharmony_ci} 7288c2ecf20Sopenharmony_ci 7298c2ecf20Sopenharmony_cistatic ssize_t dasd_ff_store(struct device *dev, struct device_attribute *attr, 7308c2ecf20Sopenharmony_ci const char *buf, size_t count) 7318c2ecf20Sopenharmony_ci{ 7328c2ecf20Sopenharmony_ci unsigned int val; 7338c2ecf20Sopenharmony_ci int rc; 7348c2ecf20Sopenharmony_ci 7358c2ecf20Sopenharmony_ci if (kstrtouint(buf, 0, &val) || val > 1) 7368c2ecf20Sopenharmony_ci return -EINVAL; 7378c2ecf20Sopenharmony_ci 7388c2ecf20Sopenharmony_ci rc = dasd_set_feature(to_ccwdev(dev), DASD_FEATURE_FAILFAST, val); 7398c2ecf20Sopenharmony_ci 7408c2ecf20Sopenharmony_ci return rc ? : count; 7418c2ecf20Sopenharmony_ci} 7428c2ecf20Sopenharmony_ci 7438c2ecf20Sopenharmony_cistatic DEVICE_ATTR(failfast, 0644, dasd_ff_show, dasd_ff_store); 7448c2ecf20Sopenharmony_ci 7458c2ecf20Sopenharmony_ci/* 7468c2ecf20Sopenharmony_ci * readonly controls the readonly status of a dasd 7478c2ecf20Sopenharmony_ci */ 7488c2ecf20Sopenharmony_cistatic ssize_t 7498c2ecf20Sopenharmony_cidasd_ro_show(struct device *dev, struct device_attribute *attr, char *buf) 7508c2ecf20Sopenharmony_ci{ 7518c2ecf20Sopenharmony_ci struct dasd_devmap *devmap; 7528c2ecf20Sopenharmony_ci struct dasd_device *device; 7538c2ecf20Sopenharmony_ci int ro_flag = 0; 7548c2ecf20Sopenharmony_ci 7558c2ecf20Sopenharmony_ci devmap = dasd_find_busid(dev_name(dev)); 7568c2ecf20Sopenharmony_ci if (IS_ERR(devmap)) 7578c2ecf20Sopenharmony_ci goto out; 7588c2ecf20Sopenharmony_ci 7598c2ecf20Sopenharmony_ci ro_flag = !!(devmap->features & DASD_FEATURE_READONLY); 7608c2ecf20Sopenharmony_ci 7618c2ecf20Sopenharmony_ci spin_lock(&dasd_devmap_lock); 7628c2ecf20Sopenharmony_ci device = devmap->device; 7638c2ecf20Sopenharmony_ci if (device) 7648c2ecf20Sopenharmony_ci ro_flag |= test_bit(DASD_FLAG_DEVICE_RO, &device->flags); 7658c2ecf20Sopenharmony_ci spin_unlock(&dasd_devmap_lock); 7668c2ecf20Sopenharmony_ci 7678c2ecf20Sopenharmony_ciout: 7688c2ecf20Sopenharmony_ci return snprintf(buf, PAGE_SIZE, ro_flag ? "1\n" : "0\n"); 7698c2ecf20Sopenharmony_ci} 7708c2ecf20Sopenharmony_ci 7718c2ecf20Sopenharmony_cistatic ssize_t 7728c2ecf20Sopenharmony_cidasd_ro_store(struct device *dev, struct device_attribute *attr, 7738c2ecf20Sopenharmony_ci const char *buf, size_t count) 7748c2ecf20Sopenharmony_ci{ 7758c2ecf20Sopenharmony_ci struct ccw_device *cdev = to_ccwdev(dev); 7768c2ecf20Sopenharmony_ci struct dasd_device *device; 7778c2ecf20Sopenharmony_ci unsigned long flags; 7788c2ecf20Sopenharmony_ci unsigned int val; 7798c2ecf20Sopenharmony_ci int rc; 7808c2ecf20Sopenharmony_ci 7818c2ecf20Sopenharmony_ci if (kstrtouint(buf, 0, &val) || val > 1) 7828c2ecf20Sopenharmony_ci return -EINVAL; 7838c2ecf20Sopenharmony_ci 7848c2ecf20Sopenharmony_ci rc = dasd_set_feature(cdev, DASD_FEATURE_READONLY, val); 7858c2ecf20Sopenharmony_ci if (rc) 7868c2ecf20Sopenharmony_ci return rc; 7878c2ecf20Sopenharmony_ci 7888c2ecf20Sopenharmony_ci device = dasd_device_from_cdev(cdev); 7898c2ecf20Sopenharmony_ci if (IS_ERR(device)) 7908c2ecf20Sopenharmony_ci return count; 7918c2ecf20Sopenharmony_ci 7928c2ecf20Sopenharmony_ci spin_lock_irqsave(get_ccwdev_lock(cdev), flags); 7938c2ecf20Sopenharmony_ci val = val || test_bit(DASD_FLAG_DEVICE_RO, &device->flags); 7948c2ecf20Sopenharmony_ci 7958c2ecf20Sopenharmony_ci if (!device->block || !device->block->gdp || 7968c2ecf20Sopenharmony_ci test_bit(DASD_FLAG_OFFLINE, &device->flags)) { 7978c2ecf20Sopenharmony_ci spin_unlock_irqrestore(get_ccwdev_lock(cdev), flags); 7988c2ecf20Sopenharmony_ci goto out; 7998c2ecf20Sopenharmony_ci } 8008c2ecf20Sopenharmony_ci /* Increase open_count to avoid losing the block device */ 8018c2ecf20Sopenharmony_ci atomic_inc(&device->block->open_count); 8028c2ecf20Sopenharmony_ci spin_unlock_irqrestore(get_ccwdev_lock(cdev), flags); 8038c2ecf20Sopenharmony_ci 8048c2ecf20Sopenharmony_ci set_disk_ro(device->block->gdp, val); 8058c2ecf20Sopenharmony_ci atomic_dec(&device->block->open_count); 8068c2ecf20Sopenharmony_ci 8078c2ecf20Sopenharmony_ciout: 8088c2ecf20Sopenharmony_ci dasd_put_device(device); 8098c2ecf20Sopenharmony_ci 8108c2ecf20Sopenharmony_ci return count; 8118c2ecf20Sopenharmony_ci} 8128c2ecf20Sopenharmony_ci 8138c2ecf20Sopenharmony_cistatic DEVICE_ATTR(readonly, 0644, dasd_ro_show, dasd_ro_store); 8148c2ecf20Sopenharmony_ci/* 8158c2ecf20Sopenharmony_ci * erplog controls the logging of ERP related data 8168c2ecf20Sopenharmony_ci * (e.g. failing channel programs). 8178c2ecf20Sopenharmony_ci */ 8188c2ecf20Sopenharmony_cistatic ssize_t 8198c2ecf20Sopenharmony_cidasd_erplog_show(struct device *dev, struct device_attribute *attr, char *buf) 8208c2ecf20Sopenharmony_ci{ 8218c2ecf20Sopenharmony_ci struct dasd_devmap *devmap; 8228c2ecf20Sopenharmony_ci int erplog; 8238c2ecf20Sopenharmony_ci 8248c2ecf20Sopenharmony_ci devmap = dasd_find_busid(dev_name(dev)); 8258c2ecf20Sopenharmony_ci if (!IS_ERR(devmap)) 8268c2ecf20Sopenharmony_ci erplog = (devmap->features & DASD_FEATURE_ERPLOG) != 0; 8278c2ecf20Sopenharmony_ci else 8288c2ecf20Sopenharmony_ci erplog = (DASD_FEATURE_DEFAULT & DASD_FEATURE_ERPLOG) != 0; 8298c2ecf20Sopenharmony_ci return snprintf(buf, PAGE_SIZE, erplog ? "1\n" : "0\n"); 8308c2ecf20Sopenharmony_ci} 8318c2ecf20Sopenharmony_ci 8328c2ecf20Sopenharmony_cistatic ssize_t 8338c2ecf20Sopenharmony_cidasd_erplog_store(struct device *dev, struct device_attribute *attr, 8348c2ecf20Sopenharmony_ci const char *buf, size_t count) 8358c2ecf20Sopenharmony_ci{ 8368c2ecf20Sopenharmony_ci unsigned int val; 8378c2ecf20Sopenharmony_ci int rc; 8388c2ecf20Sopenharmony_ci 8398c2ecf20Sopenharmony_ci if (kstrtouint(buf, 0, &val) || val > 1) 8408c2ecf20Sopenharmony_ci return -EINVAL; 8418c2ecf20Sopenharmony_ci 8428c2ecf20Sopenharmony_ci rc = dasd_set_feature(to_ccwdev(dev), DASD_FEATURE_ERPLOG, val); 8438c2ecf20Sopenharmony_ci 8448c2ecf20Sopenharmony_ci return rc ? : count; 8458c2ecf20Sopenharmony_ci} 8468c2ecf20Sopenharmony_ci 8478c2ecf20Sopenharmony_cistatic DEVICE_ATTR(erplog, 0644, dasd_erplog_show, dasd_erplog_store); 8488c2ecf20Sopenharmony_ci 8498c2ecf20Sopenharmony_ci/* 8508c2ecf20Sopenharmony_ci * use_diag controls whether the driver should use diag rather than ssch 8518c2ecf20Sopenharmony_ci * to talk to the device 8528c2ecf20Sopenharmony_ci */ 8538c2ecf20Sopenharmony_cistatic ssize_t 8548c2ecf20Sopenharmony_cidasd_use_diag_show(struct device *dev, struct device_attribute *attr, char *buf) 8558c2ecf20Sopenharmony_ci{ 8568c2ecf20Sopenharmony_ci struct dasd_devmap *devmap; 8578c2ecf20Sopenharmony_ci int use_diag; 8588c2ecf20Sopenharmony_ci 8598c2ecf20Sopenharmony_ci devmap = dasd_find_busid(dev_name(dev)); 8608c2ecf20Sopenharmony_ci if (!IS_ERR(devmap)) 8618c2ecf20Sopenharmony_ci use_diag = (devmap->features & DASD_FEATURE_USEDIAG) != 0; 8628c2ecf20Sopenharmony_ci else 8638c2ecf20Sopenharmony_ci use_diag = (DASD_FEATURE_DEFAULT & DASD_FEATURE_USEDIAG) != 0; 8648c2ecf20Sopenharmony_ci return sprintf(buf, use_diag ? "1\n" : "0\n"); 8658c2ecf20Sopenharmony_ci} 8668c2ecf20Sopenharmony_ci 8678c2ecf20Sopenharmony_cistatic ssize_t 8688c2ecf20Sopenharmony_cidasd_use_diag_store(struct device *dev, struct device_attribute *attr, 8698c2ecf20Sopenharmony_ci const char *buf, size_t count) 8708c2ecf20Sopenharmony_ci{ 8718c2ecf20Sopenharmony_ci struct dasd_devmap *devmap; 8728c2ecf20Sopenharmony_ci unsigned int val; 8738c2ecf20Sopenharmony_ci ssize_t rc; 8748c2ecf20Sopenharmony_ci 8758c2ecf20Sopenharmony_ci devmap = dasd_devmap_from_cdev(to_ccwdev(dev)); 8768c2ecf20Sopenharmony_ci if (IS_ERR(devmap)) 8778c2ecf20Sopenharmony_ci return PTR_ERR(devmap); 8788c2ecf20Sopenharmony_ci 8798c2ecf20Sopenharmony_ci if (kstrtouint(buf, 0, &val) || val > 1) 8808c2ecf20Sopenharmony_ci return -EINVAL; 8818c2ecf20Sopenharmony_ci 8828c2ecf20Sopenharmony_ci spin_lock(&dasd_devmap_lock); 8838c2ecf20Sopenharmony_ci /* Changing diag discipline flag is only allowed in offline state. */ 8848c2ecf20Sopenharmony_ci rc = count; 8858c2ecf20Sopenharmony_ci if (!devmap->device && !(devmap->features & DASD_FEATURE_USERAW)) { 8868c2ecf20Sopenharmony_ci if (val) 8878c2ecf20Sopenharmony_ci devmap->features |= DASD_FEATURE_USEDIAG; 8888c2ecf20Sopenharmony_ci else 8898c2ecf20Sopenharmony_ci devmap->features &= ~DASD_FEATURE_USEDIAG; 8908c2ecf20Sopenharmony_ci } else 8918c2ecf20Sopenharmony_ci rc = -EPERM; 8928c2ecf20Sopenharmony_ci spin_unlock(&dasd_devmap_lock); 8938c2ecf20Sopenharmony_ci return rc; 8948c2ecf20Sopenharmony_ci} 8958c2ecf20Sopenharmony_ci 8968c2ecf20Sopenharmony_cistatic DEVICE_ATTR(use_diag, 0644, dasd_use_diag_show, dasd_use_diag_store); 8978c2ecf20Sopenharmony_ci 8988c2ecf20Sopenharmony_ci/* 8998c2ecf20Sopenharmony_ci * use_raw controls whether the driver should give access to raw eckd data or 9008c2ecf20Sopenharmony_ci * operate in standard mode 9018c2ecf20Sopenharmony_ci */ 9028c2ecf20Sopenharmony_cistatic ssize_t 9038c2ecf20Sopenharmony_cidasd_use_raw_show(struct device *dev, struct device_attribute *attr, char *buf) 9048c2ecf20Sopenharmony_ci{ 9058c2ecf20Sopenharmony_ci struct dasd_devmap *devmap; 9068c2ecf20Sopenharmony_ci int use_raw; 9078c2ecf20Sopenharmony_ci 9088c2ecf20Sopenharmony_ci devmap = dasd_find_busid(dev_name(dev)); 9098c2ecf20Sopenharmony_ci if (!IS_ERR(devmap)) 9108c2ecf20Sopenharmony_ci use_raw = (devmap->features & DASD_FEATURE_USERAW) != 0; 9118c2ecf20Sopenharmony_ci else 9128c2ecf20Sopenharmony_ci use_raw = (DASD_FEATURE_DEFAULT & DASD_FEATURE_USERAW) != 0; 9138c2ecf20Sopenharmony_ci return sprintf(buf, use_raw ? "1\n" : "0\n"); 9148c2ecf20Sopenharmony_ci} 9158c2ecf20Sopenharmony_ci 9168c2ecf20Sopenharmony_cistatic ssize_t 9178c2ecf20Sopenharmony_cidasd_use_raw_store(struct device *dev, struct device_attribute *attr, 9188c2ecf20Sopenharmony_ci const char *buf, size_t count) 9198c2ecf20Sopenharmony_ci{ 9208c2ecf20Sopenharmony_ci struct dasd_devmap *devmap; 9218c2ecf20Sopenharmony_ci ssize_t rc; 9228c2ecf20Sopenharmony_ci unsigned long val; 9238c2ecf20Sopenharmony_ci 9248c2ecf20Sopenharmony_ci devmap = dasd_devmap_from_cdev(to_ccwdev(dev)); 9258c2ecf20Sopenharmony_ci if (IS_ERR(devmap)) 9268c2ecf20Sopenharmony_ci return PTR_ERR(devmap); 9278c2ecf20Sopenharmony_ci 9288c2ecf20Sopenharmony_ci if ((kstrtoul(buf, 10, &val) != 0) || val > 1) 9298c2ecf20Sopenharmony_ci return -EINVAL; 9308c2ecf20Sopenharmony_ci 9318c2ecf20Sopenharmony_ci spin_lock(&dasd_devmap_lock); 9328c2ecf20Sopenharmony_ci /* Changing diag discipline flag is only allowed in offline state. */ 9338c2ecf20Sopenharmony_ci rc = count; 9348c2ecf20Sopenharmony_ci if (!devmap->device && !(devmap->features & DASD_FEATURE_USEDIAG)) { 9358c2ecf20Sopenharmony_ci if (val) 9368c2ecf20Sopenharmony_ci devmap->features |= DASD_FEATURE_USERAW; 9378c2ecf20Sopenharmony_ci else 9388c2ecf20Sopenharmony_ci devmap->features &= ~DASD_FEATURE_USERAW; 9398c2ecf20Sopenharmony_ci } else 9408c2ecf20Sopenharmony_ci rc = -EPERM; 9418c2ecf20Sopenharmony_ci spin_unlock(&dasd_devmap_lock); 9428c2ecf20Sopenharmony_ci return rc; 9438c2ecf20Sopenharmony_ci} 9448c2ecf20Sopenharmony_ci 9458c2ecf20Sopenharmony_cistatic DEVICE_ATTR(raw_track_access, 0644, dasd_use_raw_show, 9468c2ecf20Sopenharmony_ci dasd_use_raw_store); 9478c2ecf20Sopenharmony_ci 9488c2ecf20Sopenharmony_cistatic ssize_t 9498c2ecf20Sopenharmony_cidasd_safe_offline_store(struct device *dev, struct device_attribute *attr, 9508c2ecf20Sopenharmony_ci const char *buf, size_t count) 9518c2ecf20Sopenharmony_ci{ 9528c2ecf20Sopenharmony_ci struct ccw_device *cdev = to_ccwdev(dev); 9538c2ecf20Sopenharmony_ci struct dasd_device *device; 9548c2ecf20Sopenharmony_ci unsigned long flags; 9558c2ecf20Sopenharmony_ci int rc; 9568c2ecf20Sopenharmony_ci 9578c2ecf20Sopenharmony_ci spin_lock_irqsave(get_ccwdev_lock(cdev), flags); 9588c2ecf20Sopenharmony_ci device = dasd_device_from_cdev_locked(cdev); 9598c2ecf20Sopenharmony_ci if (IS_ERR(device)) { 9608c2ecf20Sopenharmony_ci rc = PTR_ERR(device); 9618c2ecf20Sopenharmony_ci spin_unlock_irqrestore(get_ccwdev_lock(cdev), flags); 9628c2ecf20Sopenharmony_ci goto out; 9638c2ecf20Sopenharmony_ci } 9648c2ecf20Sopenharmony_ci 9658c2ecf20Sopenharmony_ci if (test_bit(DASD_FLAG_OFFLINE, &device->flags) || 9668c2ecf20Sopenharmony_ci test_bit(DASD_FLAG_SAFE_OFFLINE_RUNNING, &device->flags)) { 9678c2ecf20Sopenharmony_ci /* Already doing offline processing */ 9688c2ecf20Sopenharmony_ci dasd_put_device(device); 9698c2ecf20Sopenharmony_ci spin_unlock_irqrestore(get_ccwdev_lock(cdev), flags); 9708c2ecf20Sopenharmony_ci rc = -EBUSY; 9718c2ecf20Sopenharmony_ci goto out; 9728c2ecf20Sopenharmony_ci } 9738c2ecf20Sopenharmony_ci 9748c2ecf20Sopenharmony_ci set_bit(DASD_FLAG_SAFE_OFFLINE, &device->flags); 9758c2ecf20Sopenharmony_ci dasd_put_device(device); 9768c2ecf20Sopenharmony_ci spin_unlock_irqrestore(get_ccwdev_lock(cdev), flags); 9778c2ecf20Sopenharmony_ci 9788c2ecf20Sopenharmony_ci rc = ccw_device_set_offline(cdev); 9798c2ecf20Sopenharmony_ci 9808c2ecf20Sopenharmony_ciout: 9818c2ecf20Sopenharmony_ci return rc ? rc : count; 9828c2ecf20Sopenharmony_ci} 9838c2ecf20Sopenharmony_ci 9848c2ecf20Sopenharmony_cistatic DEVICE_ATTR(safe_offline, 0200, NULL, dasd_safe_offline_store); 9858c2ecf20Sopenharmony_ci 9868c2ecf20Sopenharmony_cistatic ssize_t 9878c2ecf20Sopenharmony_cidasd_access_show(struct device *dev, struct device_attribute *attr, 9888c2ecf20Sopenharmony_ci char *buf) 9898c2ecf20Sopenharmony_ci{ 9908c2ecf20Sopenharmony_ci struct ccw_device *cdev = to_ccwdev(dev); 9918c2ecf20Sopenharmony_ci struct dasd_device *device; 9928c2ecf20Sopenharmony_ci int count; 9938c2ecf20Sopenharmony_ci 9948c2ecf20Sopenharmony_ci device = dasd_device_from_cdev(cdev); 9958c2ecf20Sopenharmony_ci if (IS_ERR(device)) 9968c2ecf20Sopenharmony_ci return PTR_ERR(device); 9978c2ecf20Sopenharmony_ci 9988c2ecf20Sopenharmony_ci if (!device->discipline) 9998c2ecf20Sopenharmony_ci count = -ENODEV; 10008c2ecf20Sopenharmony_ci else if (!device->discipline->host_access_count) 10018c2ecf20Sopenharmony_ci count = -EOPNOTSUPP; 10028c2ecf20Sopenharmony_ci else 10038c2ecf20Sopenharmony_ci count = device->discipline->host_access_count(device); 10048c2ecf20Sopenharmony_ci 10058c2ecf20Sopenharmony_ci dasd_put_device(device); 10068c2ecf20Sopenharmony_ci if (count < 0) 10078c2ecf20Sopenharmony_ci return count; 10088c2ecf20Sopenharmony_ci 10098c2ecf20Sopenharmony_ci return sprintf(buf, "%d\n", count); 10108c2ecf20Sopenharmony_ci} 10118c2ecf20Sopenharmony_ci 10128c2ecf20Sopenharmony_cistatic DEVICE_ATTR(host_access_count, 0444, dasd_access_show, NULL); 10138c2ecf20Sopenharmony_ci 10148c2ecf20Sopenharmony_cistatic ssize_t 10158c2ecf20Sopenharmony_cidasd_discipline_show(struct device *dev, struct device_attribute *attr, 10168c2ecf20Sopenharmony_ci char *buf) 10178c2ecf20Sopenharmony_ci{ 10188c2ecf20Sopenharmony_ci struct dasd_device *device; 10198c2ecf20Sopenharmony_ci ssize_t len; 10208c2ecf20Sopenharmony_ci 10218c2ecf20Sopenharmony_ci device = dasd_device_from_cdev(to_ccwdev(dev)); 10228c2ecf20Sopenharmony_ci if (IS_ERR(device)) 10238c2ecf20Sopenharmony_ci goto out; 10248c2ecf20Sopenharmony_ci else if (!device->discipline) { 10258c2ecf20Sopenharmony_ci dasd_put_device(device); 10268c2ecf20Sopenharmony_ci goto out; 10278c2ecf20Sopenharmony_ci } else { 10288c2ecf20Sopenharmony_ci len = snprintf(buf, PAGE_SIZE, "%s\n", 10298c2ecf20Sopenharmony_ci device->discipline->name); 10308c2ecf20Sopenharmony_ci dasd_put_device(device); 10318c2ecf20Sopenharmony_ci return len; 10328c2ecf20Sopenharmony_ci } 10338c2ecf20Sopenharmony_ciout: 10348c2ecf20Sopenharmony_ci len = snprintf(buf, PAGE_SIZE, "none\n"); 10358c2ecf20Sopenharmony_ci return len; 10368c2ecf20Sopenharmony_ci} 10378c2ecf20Sopenharmony_ci 10388c2ecf20Sopenharmony_cistatic DEVICE_ATTR(discipline, 0444, dasd_discipline_show, NULL); 10398c2ecf20Sopenharmony_ci 10408c2ecf20Sopenharmony_cistatic ssize_t 10418c2ecf20Sopenharmony_cidasd_device_status_show(struct device *dev, struct device_attribute *attr, 10428c2ecf20Sopenharmony_ci char *buf) 10438c2ecf20Sopenharmony_ci{ 10448c2ecf20Sopenharmony_ci struct dasd_device *device; 10458c2ecf20Sopenharmony_ci ssize_t len; 10468c2ecf20Sopenharmony_ci 10478c2ecf20Sopenharmony_ci device = dasd_device_from_cdev(to_ccwdev(dev)); 10488c2ecf20Sopenharmony_ci if (!IS_ERR(device)) { 10498c2ecf20Sopenharmony_ci switch (device->state) { 10508c2ecf20Sopenharmony_ci case DASD_STATE_NEW: 10518c2ecf20Sopenharmony_ci len = snprintf(buf, PAGE_SIZE, "new\n"); 10528c2ecf20Sopenharmony_ci break; 10538c2ecf20Sopenharmony_ci case DASD_STATE_KNOWN: 10548c2ecf20Sopenharmony_ci len = snprintf(buf, PAGE_SIZE, "detected\n"); 10558c2ecf20Sopenharmony_ci break; 10568c2ecf20Sopenharmony_ci case DASD_STATE_BASIC: 10578c2ecf20Sopenharmony_ci len = snprintf(buf, PAGE_SIZE, "basic\n"); 10588c2ecf20Sopenharmony_ci break; 10598c2ecf20Sopenharmony_ci case DASD_STATE_UNFMT: 10608c2ecf20Sopenharmony_ci len = snprintf(buf, PAGE_SIZE, "unformatted\n"); 10618c2ecf20Sopenharmony_ci break; 10628c2ecf20Sopenharmony_ci case DASD_STATE_READY: 10638c2ecf20Sopenharmony_ci len = snprintf(buf, PAGE_SIZE, "ready\n"); 10648c2ecf20Sopenharmony_ci break; 10658c2ecf20Sopenharmony_ci case DASD_STATE_ONLINE: 10668c2ecf20Sopenharmony_ci len = snprintf(buf, PAGE_SIZE, "online\n"); 10678c2ecf20Sopenharmony_ci break; 10688c2ecf20Sopenharmony_ci default: 10698c2ecf20Sopenharmony_ci len = snprintf(buf, PAGE_SIZE, "no stat\n"); 10708c2ecf20Sopenharmony_ci break; 10718c2ecf20Sopenharmony_ci } 10728c2ecf20Sopenharmony_ci dasd_put_device(device); 10738c2ecf20Sopenharmony_ci } else 10748c2ecf20Sopenharmony_ci len = snprintf(buf, PAGE_SIZE, "unknown\n"); 10758c2ecf20Sopenharmony_ci return len; 10768c2ecf20Sopenharmony_ci} 10778c2ecf20Sopenharmony_ci 10788c2ecf20Sopenharmony_cistatic DEVICE_ATTR(status, 0444, dasd_device_status_show, NULL); 10798c2ecf20Sopenharmony_ci 10808c2ecf20Sopenharmony_cistatic ssize_t dasd_alias_show(struct device *dev, 10818c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 10828c2ecf20Sopenharmony_ci{ 10838c2ecf20Sopenharmony_ci struct dasd_device *device; 10848c2ecf20Sopenharmony_ci struct dasd_uid uid; 10858c2ecf20Sopenharmony_ci 10868c2ecf20Sopenharmony_ci device = dasd_device_from_cdev(to_ccwdev(dev)); 10878c2ecf20Sopenharmony_ci if (IS_ERR(device)) 10888c2ecf20Sopenharmony_ci return sprintf(buf, "0\n"); 10898c2ecf20Sopenharmony_ci 10908c2ecf20Sopenharmony_ci if (device->discipline && device->discipline->get_uid && 10918c2ecf20Sopenharmony_ci !device->discipline->get_uid(device, &uid)) { 10928c2ecf20Sopenharmony_ci if (uid.type == UA_BASE_PAV_ALIAS || 10938c2ecf20Sopenharmony_ci uid.type == UA_HYPER_PAV_ALIAS) { 10948c2ecf20Sopenharmony_ci dasd_put_device(device); 10958c2ecf20Sopenharmony_ci return sprintf(buf, "1\n"); 10968c2ecf20Sopenharmony_ci } 10978c2ecf20Sopenharmony_ci } 10988c2ecf20Sopenharmony_ci dasd_put_device(device); 10998c2ecf20Sopenharmony_ci 11008c2ecf20Sopenharmony_ci return sprintf(buf, "0\n"); 11018c2ecf20Sopenharmony_ci} 11028c2ecf20Sopenharmony_ci 11038c2ecf20Sopenharmony_cistatic DEVICE_ATTR(alias, 0444, dasd_alias_show, NULL); 11048c2ecf20Sopenharmony_ci 11058c2ecf20Sopenharmony_cistatic ssize_t dasd_vendor_show(struct device *dev, 11068c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 11078c2ecf20Sopenharmony_ci{ 11088c2ecf20Sopenharmony_ci struct dasd_device *device; 11098c2ecf20Sopenharmony_ci struct dasd_uid uid; 11108c2ecf20Sopenharmony_ci char *vendor; 11118c2ecf20Sopenharmony_ci 11128c2ecf20Sopenharmony_ci device = dasd_device_from_cdev(to_ccwdev(dev)); 11138c2ecf20Sopenharmony_ci vendor = ""; 11148c2ecf20Sopenharmony_ci if (IS_ERR(device)) 11158c2ecf20Sopenharmony_ci return snprintf(buf, PAGE_SIZE, "%s\n", vendor); 11168c2ecf20Sopenharmony_ci 11178c2ecf20Sopenharmony_ci if (device->discipline && device->discipline->get_uid && 11188c2ecf20Sopenharmony_ci !device->discipline->get_uid(device, &uid)) 11198c2ecf20Sopenharmony_ci vendor = uid.vendor; 11208c2ecf20Sopenharmony_ci 11218c2ecf20Sopenharmony_ci dasd_put_device(device); 11228c2ecf20Sopenharmony_ci 11238c2ecf20Sopenharmony_ci return snprintf(buf, PAGE_SIZE, "%s\n", vendor); 11248c2ecf20Sopenharmony_ci} 11258c2ecf20Sopenharmony_ci 11268c2ecf20Sopenharmony_cistatic DEVICE_ATTR(vendor, 0444, dasd_vendor_show, NULL); 11278c2ecf20Sopenharmony_ci 11288c2ecf20Sopenharmony_ci#define UID_STRLEN ( /* vendor */ 3 + 1 + /* serial */ 14 + 1 +\ 11298c2ecf20Sopenharmony_ci /* SSID */ 4 + 1 + /* unit addr */ 2 + 1 +\ 11308c2ecf20Sopenharmony_ci /* vduit */ 32 + 1) 11318c2ecf20Sopenharmony_ci 11328c2ecf20Sopenharmony_cistatic ssize_t 11338c2ecf20Sopenharmony_cidasd_uid_show(struct device *dev, struct device_attribute *attr, char *buf) 11348c2ecf20Sopenharmony_ci{ 11358c2ecf20Sopenharmony_ci struct dasd_device *device; 11368c2ecf20Sopenharmony_ci struct dasd_uid uid; 11378c2ecf20Sopenharmony_ci char uid_string[UID_STRLEN]; 11388c2ecf20Sopenharmony_ci char ua_string[3]; 11398c2ecf20Sopenharmony_ci 11408c2ecf20Sopenharmony_ci device = dasd_device_from_cdev(to_ccwdev(dev)); 11418c2ecf20Sopenharmony_ci uid_string[0] = 0; 11428c2ecf20Sopenharmony_ci if (IS_ERR(device)) 11438c2ecf20Sopenharmony_ci return snprintf(buf, PAGE_SIZE, "%s\n", uid_string); 11448c2ecf20Sopenharmony_ci 11458c2ecf20Sopenharmony_ci if (device->discipline && device->discipline->get_uid && 11468c2ecf20Sopenharmony_ci !device->discipline->get_uid(device, &uid)) { 11478c2ecf20Sopenharmony_ci switch (uid.type) { 11488c2ecf20Sopenharmony_ci case UA_BASE_DEVICE: 11498c2ecf20Sopenharmony_ci snprintf(ua_string, sizeof(ua_string), "%02x", 11508c2ecf20Sopenharmony_ci uid.real_unit_addr); 11518c2ecf20Sopenharmony_ci break; 11528c2ecf20Sopenharmony_ci case UA_BASE_PAV_ALIAS: 11538c2ecf20Sopenharmony_ci snprintf(ua_string, sizeof(ua_string), "%02x", 11548c2ecf20Sopenharmony_ci uid.base_unit_addr); 11558c2ecf20Sopenharmony_ci break; 11568c2ecf20Sopenharmony_ci case UA_HYPER_PAV_ALIAS: 11578c2ecf20Sopenharmony_ci snprintf(ua_string, sizeof(ua_string), "xx"); 11588c2ecf20Sopenharmony_ci break; 11598c2ecf20Sopenharmony_ci default: 11608c2ecf20Sopenharmony_ci /* should not happen, treat like base device */ 11618c2ecf20Sopenharmony_ci snprintf(ua_string, sizeof(ua_string), "%02x", 11628c2ecf20Sopenharmony_ci uid.real_unit_addr); 11638c2ecf20Sopenharmony_ci break; 11648c2ecf20Sopenharmony_ci } 11658c2ecf20Sopenharmony_ci 11668c2ecf20Sopenharmony_ci if (strlen(uid.vduit) > 0) 11678c2ecf20Sopenharmony_ci snprintf(uid_string, sizeof(uid_string), 11688c2ecf20Sopenharmony_ci "%s.%s.%04x.%s.%s", 11698c2ecf20Sopenharmony_ci uid.vendor, uid.serial, uid.ssid, ua_string, 11708c2ecf20Sopenharmony_ci uid.vduit); 11718c2ecf20Sopenharmony_ci else 11728c2ecf20Sopenharmony_ci snprintf(uid_string, sizeof(uid_string), 11738c2ecf20Sopenharmony_ci "%s.%s.%04x.%s", 11748c2ecf20Sopenharmony_ci uid.vendor, uid.serial, uid.ssid, ua_string); 11758c2ecf20Sopenharmony_ci } 11768c2ecf20Sopenharmony_ci dasd_put_device(device); 11778c2ecf20Sopenharmony_ci 11788c2ecf20Sopenharmony_ci return snprintf(buf, PAGE_SIZE, "%s\n", uid_string); 11798c2ecf20Sopenharmony_ci} 11808c2ecf20Sopenharmony_cistatic DEVICE_ATTR(uid, 0444, dasd_uid_show, NULL); 11818c2ecf20Sopenharmony_ci 11828c2ecf20Sopenharmony_ci/* 11838c2ecf20Sopenharmony_ci * extended error-reporting 11848c2ecf20Sopenharmony_ci */ 11858c2ecf20Sopenharmony_cistatic ssize_t 11868c2ecf20Sopenharmony_cidasd_eer_show(struct device *dev, struct device_attribute *attr, char *buf) 11878c2ecf20Sopenharmony_ci{ 11888c2ecf20Sopenharmony_ci struct dasd_devmap *devmap; 11898c2ecf20Sopenharmony_ci int eer_flag; 11908c2ecf20Sopenharmony_ci 11918c2ecf20Sopenharmony_ci devmap = dasd_find_busid(dev_name(dev)); 11928c2ecf20Sopenharmony_ci if (!IS_ERR(devmap) && devmap->device) 11938c2ecf20Sopenharmony_ci eer_flag = dasd_eer_enabled(devmap->device); 11948c2ecf20Sopenharmony_ci else 11958c2ecf20Sopenharmony_ci eer_flag = 0; 11968c2ecf20Sopenharmony_ci return snprintf(buf, PAGE_SIZE, eer_flag ? "1\n" : "0\n"); 11978c2ecf20Sopenharmony_ci} 11988c2ecf20Sopenharmony_ci 11998c2ecf20Sopenharmony_cistatic ssize_t 12008c2ecf20Sopenharmony_cidasd_eer_store(struct device *dev, struct device_attribute *attr, 12018c2ecf20Sopenharmony_ci const char *buf, size_t count) 12028c2ecf20Sopenharmony_ci{ 12038c2ecf20Sopenharmony_ci struct dasd_device *device; 12048c2ecf20Sopenharmony_ci unsigned int val; 12058c2ecf20Sopenharmony_ci int rc = 0; 12068c2ecf20Sopenharmony_ci 12078c2ecf20Sopenharmony_ci device = dasd_device_from_cdev(to_ccwdev(dev)); 12088c2ecf20Sopenharmony_ci if (IS_ERR(device)) 12098c2ecf20Sopenharmony_ci return PTR_ERR(device); 12108c2ecf20Sopenharmony_ci 12118c2ecf20Sopenharmony_ci if (kstrtouint(buf, 0, &val) || val > 1) 12128c2ecf20Sopenharmony_ci return -EINVAL; 12138c2ecf20Sopenharmony_ci 12148c2ecf20Sopenharmony_ci if (val) 12158c2ecf20Sopenharmony_ci rc = dasd_eer_enable(device); 12168c2ecf20Sopenharmony_ci else 12178c2ecf20Sopenharmony_ci dasd_eer_disable(device); 12188c2ecf20Sopenharmony_ci 12198c2ecf20Sopenharmony_ci dasd_put_device(device); 12208c2ecf20Sopenharmony_ci 12218c2ecf20Sopenharmony_ci return rc ? : count; 12228c2ecf20Sopenharmony_ci} 12238c2ecf20Sopenharmony_ci 12248c2ecf20Sopenharmony_cistatic DEVICE_ATTR(eer_enabled, 0644, dasd_eer_show, dasd_eer_store); 12258c2ecf20Sopenharmony_ci 12268c2ecf20Sopenharmony_ci/* 12278c2ecf20Sopenharmony_ci * expiration time for default requests 12288c2ecf20Sopenharmony_ci */ 12298c2ecf20Sopenharmony_cistatic ssize_t 12308c2ecf20Sopenharmony_cidasd_expires_show(struct device *dev, struct device_attribute *attr, char *buf) 12318c2ecf20Sopenharmony_ci{ 12328c2ecf20Sopenharmony_ci struct dasd_device *device; 12338c2ecf20Sopenharmony_ci int len; 12348c2ecf20Sopenharmony_ci 12358c2ecf20Sopenharmony_ci device = dasd_device_from_cdev(to_ccwdev(dev)); 12368c2ecf20Sopenharmony_ci if (IS_ERR(device)) 12378c2ecf20Sopenharmony_ci return -ENODEV; 12388c2ecf20Sopenharmony_ci len = snprintf(buf, PAGE_SIZE, "%lu\n", device->default_expires); 12398c2ecf20Sopenharmony_ci dasd_put_device(device); 12408c2ecf20Sopenharmony_ci return len; 12418c2ecf20Sopenharmony_ci} 12428c2ecf20Sopenharmony_ci 12438c2ecf20Sopenharmony_cistatic ssize_t 12448c2ecf20Sopenharmony_cidasd_expires_store(struct device *dev, struct device_attribute *attr, 12458c2ecf20Sopenharmony_ci const char *buf, size_t count) 12468c2ecf20Sopenharmony_ci{ 12478c2ecf20Sopenharmony_ci struct dasd_device *device; 12488c2ecf20Sopenharmony_ci unsigned long val; 12498c2ecf20Sopenharmony_ci 12508c2ecf20Sopenharmony_ci device = dasd_device_from_cdev(to_ccwdev(dev)); 12518c2ecf20Sopenharmony_ci if (IS_ERR(device)) 12528c2ecf20Sopenharmony_ci return -ENODEV; 12538c2ecf20Sopenharmony_ci 12548c2ecf20Sopenharmony_ci if ((kstrtoul(buf, 10, &val) != 0) || 12558c2ecf20Sopenharmony_ci (val > DASD_EXPIRES_MAX) || val == 0) { 12568c2ecf20Sopenharmony_ci dasd_put_device(device); 12578c2ecf20Sopenharmony_ci return -EINVAL; 12588c2ecf20Sopenharmony_ci } 12598c2ecf20Sopenharmony_ci 12608c2ecf20Sopenharmony_ci if (val) 12618c2ecf20Sopenharmony_ci device->default_expires = val; 12628c2ecf20Sopenharmony_ci 12638c2ecf20Sopenharmony_ci dasd_put_device(device); 12648c2ecf20Sopenharmony_ci return count; 12658c2ecf20Sopenharmony_ci} 12668c2ecf20Sopenharmony_ci 12678c2ecf20Sopenharmony_cistatic DEVICE_ATTR(expires, 0644, dasd_expires_show, dasd_expires_store); 12688c2ecf20Sopenharmony_ci 12698c2ecf20Sopenharmony_cistatic ssize_t 12708c2ecf20Sopenharmony_cidasd_retries_show(struct device *dev, struct device_attribute *attr, char *buf) 12718c2ecf20Sopenharmony_ci{ 12728c2ecf20Sopenharmony_ci struct dasd_device *device; 12738c2ecf20Sopenharmony_ci int len; 12748c2ecf20Sopenharmony_ci 12758c2ecf20Sopenharmony_ci device = dasd_device_from_cdev(to_ccwdev(dev)); 12768c2ecf20Sopenharmony_ci if (IS_ERR(device)) 12778c2ecf20Sopenharmony_ci return -ENODEV; 12788c2ecf20Sopenharmony_ci len = snprintf(buf, PAGE_SIZE, "%lu\n", device->default_retries); 12798c2ecf20Sopenharmony_ci dasd_put_device(device); 12808c2ecf20Sopenharmony_ci return len; 12818c2ecf20Sopenharmony_ci} 12828c2ecf20Sopenharmony_ci 12838c2ecf20Sopenharmony_cistatic ssize_t 12848c2ecf20Sopenharmony_cidasd_retries_store(struct device *dev, struct device_attribute *attr, 12858c2ecf20Sopenharmony_ci const char *buf, size_t count) 12868c2ecf20Sopenharmony_ci{ 12878c2ecf20Sopenharmony_ci struct dasd_device *device; 12888c2ecf20Sopenharmony_ci unsigned long val; 12898c2ecf20Sopenharmony_ci 12908c2ecf20Sopenharmony_ci device = dasd_device_from_cdev(to_ccwdev(dev)); 12918c2ecf20Sopenharmony_ci if (IS_ERR(device)) 12928c2ecf20Sopenharmony_ci return -ENODEV; 12938c2ecf20Sopenharmony_ci 12948c2ecf20Sopenharmony_ci if ((kstrtoul(buf, 10, &val) != 0) || 12958c2ecf20Sopenharmony_ci (val > DASD_RETRIES_MAX)) { 12968c2ecf20Sopenharmony_ci dasd_put_device(device); 12978c2ecf20Sopenharmony_ci return -EINVAL; 12988c2ecf20Sopenharmony_ci } 12998c2ecf20Sopenharmony_ci 13008c2ecf20Sopenharmony_ci if (val) 13018c2ecf20Sopenharmony_ci device->default_retries = val; 13028c2ecf20Sopenharmony_ci 13038c2ecf20Sopenharmony_ci dasd_put_device(device); 13048c2ecf20Sopenharmony_ci return count; 13058c2ecf20Sopenharmony_ci} 13068c2ecf20Sopenharmony_ci 13078c2ecf20Sopenharmony_cistatic DEVICE_ATTR(retries, 0644, dasd_retries_show, dasd_retries_store); 13088c2ecf20Sopenharmony_ci 13098c2ecf20Sopenharmony_cistatic ssize_t 13108c2ecf20Sopenharmony_cidasd_timeout_show(struct device *dev, struct device_attribute *attr, 13118c2ecf20Sopenharmony_ci char *buf) 13128c2ecf20Sopenharmony_ci{ 13138c2ecf20Sopenharmony_ci struct dasd_device *device; 13148c2ecf20Sopenharmony_ci int len; 13158c2ecf20Sopenharmony_ci 13168c2ecf20Sopenharmony_ci device = dasd_device_from_cdev(to_ccwdev(dev)); 13178c2ecf20Sopenharmony_ci if (IS_ERR(device)) 13188c2ecf20Sopenharmony_ci return -ENODEV; 13198c2ecf20Sopenharmony_ci len = snprintf(buf, PAGE_SIZE, "%lu\n", device->blk_timeout); 13208c2ecf20Sopenharmony_ci dasd_put_device(device); 13218c2ecf20Sopenharmony_ci return len; 13228c2ecf20Sopenharmony_ci} 13238c2ecf20Sopenharmony_ci 13248c2ecf20Sopenharmony_cistatic ssize_t 13258c2ecf20Sopenharmony_cidasd_timeout_store(struct device *dev, struct device_attribute *attr, 13268c2ecf20Sopenharmony_ci const char *buf, size_t count) 13278c2ecf20Sopenharmony_ci{ 13288c2ecf20Sopenharmony_ci struct dasd_device *device; 13298c2ecf20Sopenharmony_ci struct request_queue *q; 13308c2ecf20Sopenharmony_ci unsigned long val; 13318c2ecf20Sopenharmony_ci 13328c2ecf20Sopenharmony_ci device = dasd_device_from_cdev(to_ccwdev(dev)); 13338c2ecf20Sopenharmony_ci if (IS_ERR(device) || !device->block) 13348c2ecf20Sopenharmony_ci return -ENODEV; 13358c2ecf20Sopenharmony_ci 13368c2ecf20Sopenharmony_ci if ((kstrtoul(buf, 10, &val) != 0) || 13378c2ecf20Sopenharmony_ci val > UINT_MAX / HZ) { 13388c2ecf20Sopenharmony_ci dasd_put_device(device); 13398c2ecf20Sopenharmony_ci return -EINVAL; 13408c2ecf20Sopenharmony_ci } 13418c2ecf20Sopenharmony_ci q = device->block->request_queue; 13428c2ecf20Sopenharmony_ci if (!q) { 13438c2ecf20Sopenharmony_ci dasd_put_device(device); 13448c2ecf20Sopenharmony_ci return -ENODEV; 13458c2ecf20Sopenharmony_ci } 13468c2ecf20Sopenharmony_ci 13478c2ecf20Sopenharmony_ci device->blk_timeout = val; 13488c2ecf20Sopenharmony_ci 13498c2ecf20Sopenharmony_ci blk_queue_rq_timeout(q, device->blk_timeout * HZ); 13508c2ecf20Sopenharmony_ci 13518c2ecf20Sopenharmony_ci dasd_put_device(device); 13528c2ecf20Sopenharmony_ci return count; 13538c2ecf20Sopenharmony_ci} 13548c2ecf20Sopenharmony_ci 13558c2ecf20Sopenharmony_cistatic DEVICE_ATTR(timeout, 0644, 13568c2ecf20Sopenharmony_ci dasd_timeout_show, dasd_timeout_store); 13578c2ecf20Sopenharmony_ci 13588c2ecf20Sopenharmony_ci 13598c2ecf20Sopenharmony_cistatic ssize_t 13608c2ecf20Sopenharmony_cidasd_path_reset_store(struct device *dev, struct device_attribute *attr, 13618c2ecf20Sopenharmony_ci const char *buf, size_t count) 13628c2ecf20Sopenharmony_ci{ 13638c2ecf20Sopenharmony_ci struct dasd_device *device; 13648c2ecf20Sopenharmony_ci unsigned int val; 13658c2ecf20Sopenharmony_ci 13668c2ecf20Sopenharmony_ci device = dasd_device_from_cdev(to_ccwdev(dev)); 13678c2ecf20Sopenharmony_ci if (IS_ERR(device)) 13688c2ecf20Sopenharmony_ci return -ENODEV; 13698c2ecf20Sopenharmony_ci 13708c2ecf20Sopenharmony_ci if ((kstrtouint(buf, 16, &val) != 0) || val > 0xff) 13718c2ecf20Sopenharmony_ci val = 0; 13728c2ecf20Sopenharmony_ci 13738c2ecf20Sopenharmony_ci if (device->discipline && device->discipline->reset_path) 13748c2ecf20Sopenharmony_ci device->discipline->reset_path(device, (__u8) val); 13758c2ecf20Sopenharmony_ci 13768c2ecf20Sopenharmony_ci dasd_put_device(device); 13778c2ecf20Sopenharmony_ci return count; 13788c2ecf20Sopenharmony_ci} 13798c2ecf20Sopenharmony_ci 13808c2ecf20Sopenharmony_cistatic DEVICE_ATTR(path_reset, 0200, NULL, dasd_path_reset_store); 13818c2ecf20Sopenharmony_ci 13828c2ecf20Sopenharmony_cistatic ssize_t dasd_hpf_show(struct device *dev, struct device_attribute *attr, 13838c2ecf20Sopenharmony_ci char *buf) 13848c2ecf20Sopenharmony_ci{ 13858c2ecf20Sopenharmony_ci struct dasd_device *device; 13868c2ecf20Sopenharmony_ci int hpf; 13878c2ecf20Sopenharmony_ci 13888c2ecf20Sopenharmony_ci device = dasd_device_from_cdev(to_ccwdev(dev)); 13898c2ecf20Sopenharmony_ci if (IS_ERR(device)) 13908c2ecf20Sopenharmony_ci return -ENODEV; 13918c2ecf20Sopenharmony_ci if (!device->discipline || !device->discipline->hpf_enabled) { 13928c2ecf20Sopenharmony_ci dasd_put_device(device); 13938c2ecf20Sopenharmony_ci return snprintf(buf, PAGE_SIZE, "%d\n", dasd_nofcx); 13948c2ecf20Sopenharmony_ci } 13958c2ecf20Sopenharmony_ci hpf = device->discipline->hpf_enabled(device); 13968c2ecf20Sopenharmony_ci dasd_put_device(device); 13978c2ecf20Sopenharmony_ci return snprintf(buf, PAGE_SIZE, "%d\n", hpf); 13988c2ecf20Sopenharmony_ci} 13998c2ecf20Sopenharmony_ci 14008c2ecf20Sopenharmony_cistatic DEVICE_ATTR(hpf, 0444, dasd_hpf_show, NULL); 14018c2ecf20Sopenharmony_ci 14028c2ecf20Sopenharmony_cistatic ssize_t dasd_reservation_policy_show(struct device *dev, 14038c2ecf20Sopenharmony_ci struct device_attribute *attr, 14048c2ecf20Sopenharmony_ci char *buf) 14058c2ecf20Sopenharmony_ci{ 14068c2ecf20Sopenharmony_ci struct dasd_devmap *devmap; 14078c2ecf20Sopenharmony_ci int rc = 0; 14088c2ecf20Sopenharmony_ci 14098c2ecf20Sopenharmony_ci devmap = dasd_find_busid(dev_name(dev)); 14108c2ecf20Sopenharmony_ci if (IS_ERR(devmap)) { 14118c2ecf20Sopenharmony_ci rc = snprintf(buf, PAGE_SIZE, "ignore\n"); 14128c2ecf20Sopenharmony_ci } else { 14138c2ecf20Sopenharmony_ci spin_lock(&dasd_devmap_lock); 14148c2ecf20Sopenharmony_ci if (devmap->features & DASD_FEATURE_FAILONSLCK) 14158c2ecf20Sopenharmony_ci rc = snprintf(buf, PAGE_SIZE, "fail\n"); 14168c2ecf20Sopenharmony_ci else 14178c2ecf20Sopenharmony_ci rc = snprintf(buf, PAGE_SIZE, "ignore\n"); 14188c2ecf20Sopenharmony_ci spin_unlock(&dasd_devmap_lock); 14198c2ecf20Sopenharmony_ci } 14208c2ecf20Sopenharmony_ci return rc; 14218c2ecf20Sopenharmony_ci} 14228c2ecf20Sopenharmony_ci 14238c2ecf20Sopenharmony_cistatic ssize_t dasd_reservation_policy_store(struct device *dev, 14248c2ecf20Sopenharmony_ci struct device_attribute *attr, 14258c2ecf20Sopenharmony_ci const char *buf, size_t count) 14268c2ecf20Sopenharmony_ci{ 14278c2ecf20Sopenharmony_ci struct ccw_device *cdev = to_ccwdev(dev); 14288c2ecf20Sopenharmony_ci int rc; 14298c2ecf20Sopenharmony_ci 14308c2ecf20Sopenharmony_ci if (sysfs_streq("ignore", buf)) 14318c2ecf20Sopenharmony_ci rc = dasd_set_feature(cdev, DASD_FEATURE_FAILONSLCK, 0); 14328c2ecf20Sopenharmony_ci else if (sysfs_streq("fail", buf)) 14338c2ecf20Sopenharmony_ci rc = dasd_set_feature(cdev, DASD_FEATURE_FAILONSLCK, 1); 14348c2ecf20Sopenharmony_ci else 14358c2ecf20Sopenharmony_ci rc = -EINVAL; 14368c2ecf20Sopenharmony_ci 14378c2ecf20Sopenharmony_ci return rc ? : count; 14388c2ecf20Sopenharmony_ci} 14398c2ecf20Sopenharmony_ci 14408c2ecf20Sopenharmony_cistatic DEVICE_ATTR(reservation_policy, 0644, 14418c2ecf20Sopenharmony_ci dasd_reservation_policy_show, dasd_reservation_policy_store); 14428c2ecf20Sopenharmony_ci 14438c2ecf20Sopenharmony_cistatic ssize_t dasd_reservation_state_show(struct device *dev, 14448c2ecf20Sopenharmony_ci struct device_attribute *attr, 14458c2ecf20Sopenharmony_ci char *buf) 14468c2ecf20Sopenharmony_ci{ 14478c2ecf20Sopenharmony_ci struct dasd_device *device; 14488c2ecf20Sopenharmony_ci int rc = 0; 14498c2ecf20Sopenharmony_ci 14508c2ecf20Sopenharmony_ci device = dasd_device_from_cdev(to_ccwdev(dev)); 14518c2ecf20Sopenharmony_ci if (IS_ERR(device)) 14528c2ecf20Sopenharmony_ci return snprintf(buf, PAGE_SIZE, "none\n"); 14538c2ecf20Sopenharmony_ci 14548c2ecf20Sopenharmony_ci if (test_bit(DASD_FLAG_IS_RESERVED, &device->flags)) 14558c2ecf20Sopenharmony_ci rc = snprintf(buf, PAGE_SIZE, "reserved\n"); 14568c2ecf20Sopenharmony_ci else if (test_bit(DASD_FLAG_LOCK_STOLEN, &device->flags)) 14578c2ecf20Sopenharmony_ci rc = snprintf(buf, PAGE_SIZE, "lost\n"); 14588c2ecf20Sopenharmony_ci else 14598c2ecf20Sopenharmony_ci rc = snprintf(buf, PAGE_SIZE, "none\n"); 14608c2ecf20Sopenharmony_ci dasd_put_device(device); 14618c2ecf20Sopenharmony_ci return rc; 14628c2ecf20Sopenharmony_ci} 14638c2ecf20Sopenharmony_ci 14648c2ecf20Sopenharmony_cistatic ssize_t dasd_reservation_state_store(struct device *dev, 14658c2ecf20Sopenharmony_ci struct device_attribute *attr, 14668c2ecf20Sopenharmony_ci const char *buf, size_t count) 14678c2ecf20Sopenharmony_ci{ 14688c2ecf20Sopenharmony_ci struct dasd_device *device; 14698c2ecf20Sopenharmony_ci int rc = 0; 14708c2ecf20Sopenharmony_ci 14718c2ecf20Sopenharmony_ci device = dasd_device_from_cdev(to_ccwdev(dev)); 14728c2ecf20Sopenharmony_ci if (IS_ERR(device)) 14738c2ecf20Sopenharmony_ci return -ENODEV; 14748c2ecf20Sopenharmony_ci if (sysfs_streq("reset", buf)) 14758c2ecf20Sopenharmony_ci clear_bit(DASD_FLAG_LOCK_STOLEN, &device->flags); 14768c2ecf20Sopenharmony_ci else 14778c2ecf20Sopenharmony_ci rc = -EINVAL; 14788c2ecf20Sopenharmony_ci dasd_put_device(device); 14798c2ecf20Sopenharmony_ci 14808c2ecf20Sopenharmony_ci if (rc) 14818c2ecf20Sopenharmony_ci return rc; 14828c2ecf20Sopenharmony_ci else 14838c2ecf20Sopenharmony_ci return count; 14848c2ecf20Sopenharmony_ci} 14858c2ecf20Sopenharmony_ci 14868c2ecf20Sopenharmony_cistatic DEVICE_ATTR(last_known_reservation_state, 0644, 14878c2ecf20Sopenharmony_ci dasd_reservation_state_show, dasd_reservation_state_store); 14888c2ecf20Sopenharmony_ci 14898c2ecf20Sopenharmony_cistatic ssize_t dasd_pm_show(struct device *dev, 14908c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 14918c2ecf20Sopenharmony_ci{ 14928c2ecf20Sopenharmony_ci struct dasd_device *device; 14938c2ecf20Sopenharmony_ci u8 opm, nppm, cablepm, cuirpm, hpfpm, ifccpm; 14948c2ecf20Sopenharmony_ci 14958c2ecf20Sopenharmony_ci device = dasd_device_from_cdev(to_ccwdev(dev)); 14968c2ecf20Sopenharmony_ci if (IS_ERR(device)) 14978c2ecf20Sopenharmony_ci return sprintf(buf, "0\n"); 14988c2ecf20Sopenharmony_ci 14998c2ecf20Sopenharmony_ci opm = dasd_path_get_opm(device); 15008c2ecf20Sopenharmony_ci nppm = dasd_path_get_nppm(device); 15018c2ecf20Sopenharmony_ci cablepm = dasd_path_get_cablepm(device); 15028c2ecf20Sopenharmony_ci cuirpm = dasd_path_get_cuirpm(device); 15038c2ecf20Sopenharmony_ci hpfpm = dasd_path_get_hpfpm(device); 15048c2ecf20Sopenharmony_ci ifccpm = dasd_path_get_ifccpm(device); 15058c2ecf20Sopenharmony_ci dasd_put_device(device); 15068c2ecf20Sopenharmony_ci 15078c2ecf20Sopenharmony_ci return sprintf(buf, "%02x %02x %02x %02x %02x %02x\n", opm, nppm, 15088c2ecf20Sopenharmony_ci cablepm, cuirpm, hpfpm, ifccpm); 15098c2ecf20Sopenharmony_ci} 15108c2ecf20Sopenharmony_ci 15118c2ecf20Sopenharmony_cistatic DEVICE_ATTR(path_masks, 0444, dasd_pm_show, NULL); 15128c2ecf20Sopenharmony_ci 15138c2ecf20Sopenharmony_ci/* 15148c2ecf20Sopenharmony_ci * threshold value for IFCC/CCC errors 15158c2ecf20Sopenharmony_ci */ 15168c2ecf20Sopenharmony_cistatic ssize_t 15178c2ecf20Sopenharmony_cidasd_path_threshold_show(struct device *dev, 15188c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 15198c2ecf20Sopenharmony_ci{ 15208c2ecf20Sopenharmony_ci struct dasd_device *device; 15218c2ecf20Sopenharmony_ci int len; 15228c2ecf20Sopenharmony_ci 15238c2ecf20Sopenharmony_ci device = dasd_device_from_cdev(to_ccwdev(dev)); 15248c2ecf20Sopenharmony_ci if (IS_ERR(device)) 15258c2ecf20Sopenharmony_ci return -ENODEV; 15268c2ecf20Sopenharmony_ci len = snprintf(buf, PAGE_SIZE, "%lu\n", device->path_thrhld); 15278c2ecf20Sopenharmony_ci dasd_put_device(device); 15288c2ecf20Sopenharmony_ci return len; 15298c2ecf20Sopenharmony_ci} 15308c2ecf20Sopenharmony_ci 15318c2ecf20Sopenharmony_cistatic ssize_t 15328c2ecf20Sopenharmony_cidasd_path_threshold_store(struct device *dev, struct device_attribute *attr, 15338c2ecf20Sopenharmony_ci const char *buf, size_t count) 15348c2ecf20Sopenharmony_ci{ 15358c2ecf20Sopenharmony_ci struct dasd_device *device; 15368c2ecf20Sopenharmony_ci unsigned long flags; 15378c2ecf20Sopenharmony_ci unsigned long val; 15388c2ecf20Sopenharmony_ci 15398c2ecf20Sopenharmony_ci device = dasd_device_from_cdev(to_ccwdev(dev)); 15408c2ecf20Sopenharmony_ci if (IS_ERR(device)) 15418c2ecf20Sopenharmony_ci return -ENODEV; 15428c2ecf20Sopenharmony_ci 15438c2ecf20Sopenharmony_ci if (kstrtoul(buf, 10, &val) != 0 || val > DASD_THRHLD_MAX) { 15448c2ecf20Sopenharmony_ci dasd_put_device(device); 15458c2ecf20Sopenharmony_ci return -EINVAL; 15468c2ecf20Sopenharmony_ci } 15478c2ecf20Sopenharmony_ci spin_lock_irqsave(get_ccwdev_lock(to_ccwdev(dev)), flags); 15488c2ecf20Sopenharmony_ci device->path_thrhld = val; 15498c2ecf20Sopenharmony_ci spin_unlock_irqrestore(get_ccwdev_lock(to_ccwdev(dev)), flags); 15508c2ecf20Sopenharmony_ci dasd_put_device(device); 15518c2ecf20Sopenharmony_ci return count; 15528c2ecf20Sopenharmony_ci} 15538c2ecf20Sopenharmony_cistatic DEVICE_ATTR(path_threshold, 0644, dasd_path_threshold_show, 15548c2ecf20Sopenharmony_ci dasd_path_threshold_store); 15558c2ecf20Sopenharmony_ci 15568c2ecf20Sopenharmony_ci/* 15578c2ecf20Sopenharmony_ci * configure if path is disabled after IFCC/CCC error threshold is 15588c2ecf20Sopenharmony_ci * exceeded 15598c2ecf20Sopenharmony_ci */ 15608c2ecf20Sopenharmony_cistatic ssize_t 15618c2ecf20Sopenharmony_cidasd_path_autodisable_show(struct device *dev, 15628c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 15638c2ecf20Sopenharmony_ci{ 15648c2ecf20Sopenharmony_ci struct dasd_devmap *devmap; 15658c2ecf20Sopenharmony_ci int flag; 15668c2ecf20Sopenharmony_ci 15678c2ecf20Sopenharmony_ci devmap = dasd_find_busid(dev_name(dev)); 15688c2ecf20Sopenharmony_ci if (!IS_ERR(devmap)) 15698c2ecf20Sopenharmony_ci flag = (devmap->features & DASD_FEATURE_PATH_AUTODISABLE) != 0; 15708c2ecf20Sopenharmony_ci else 15718c2ecf20Sopenharmony_ci flag = (DASD_FEATURE_DEFAULT & 15728c2ecf20Sopenharmony_ci DASD_FEATURE_PATH_AUTODISABLE) != 0; 15738c2ecf20Sopenharmony_ci return snprintf(buf, PAGE_SIZE, flag ? "1\n" : "0\n"); 15748c2ecf20Sopenharmony_ci} 15758c2ecf20Sopenharmony_ci 15768c2ecf20Sopenharmony_cistatic ssize_t 15778c2ecf20Sopenharmony_cidasd_path_autodisable_store(struct device *dev, 15788c2ecf20Sopenharmony_ci struct device_attribute *attr, 15798c2ecf20Sopenharmony_ci const char *buf, size_t count) 15808c2ecf20Sopenharmony_ci{ 15818c2ecf20Sopenharmony_ci unsigned int val; 15828c2ecf20Sopenharmony_ci int rc; 15838c2ecf20Sopenharmony_ci 15848c2ecf20Sopenharmony_ci if (kstrtouint(buf, 0, &val) || val > 1) 15858c2ecf20Sopenharmony_ci return -EINVAL; 15868c2ecf20Sopenharmony_ci 15878c2ecf20Sopenharmony_ci rc = dasd_set_feature(to_ccwdev(dev), 15888c2ecf20Sopenharmony_ci DASD_FEATURE_PATH_AUTODISABLE, val); 15898c2ecf20Sopenharmony_ci 15908c2ecf20Sopenharmony_ci return rc ? : count; 15918c2ecf20Sopenharmony_ci} 15928c2ecf20Sopenharmony_ci 15938c2ecf20Sopenharmony_cistatic DEVICE_ATTR(path_autodisable, 0644, 15948c2ecf20Sopenharmony_ci dasd_path_autodisable_show, 15958c2ecf20Sopenharmony_ci dasd_path_autodisable_store); 15968c2ecf20Sopenharmony_ci/* 15978c2ecf20Sopenharmony_ci * interval for IFCC/CCC checks 15988c2ecf20Sopenharmony_ci * meaning time with no IFCC/CCC error before the error counter 15998c2ecf20Sopenharmony_ci * gets reset 16008c2ecf20Sopenharmony_ci */ 16018c2ecf20Sopenharmony_cistatic ssize_t 16028c2ecf20Sopenharmony_cidasd_path_interval_show(struct device *dev, 16038c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 16048c2ecf20Sopenharmony_ci{ 16058c2ecf20Sopenharmony_ci struct dasd_device *device; 16068c2ecf20Sopenharmony_ci int len; 16078c2ecf20Sopenharmony_ci 16088c2ecf20Sopenharmony_ci device = dasd_device_from_cdev(to_ccwdev(dev)); 16098c2ecf20Sopenharmony_ci if (IS_ERR(device)) 16108c2ecf20Sopenharmony_ci return -ENODEV; 16118c2ecf20Sopenharmony_ci len = snprintf(buf, PAGE_SIZE, "%lu\n", device->path_interval); 16128c2ecf20Sopenharmony_ci dasd_put_device(device); 16138c2ecf20Sopenharmony_ci return len; 16148c2ecf20Sopenharmony_ci} 16158c2ecf20Sopenharmony_ci 16168c2ecf20Sopenharmony_cistatic ssize_t 16178c2ecf20Sopenharmony_cidasd_path_interval_store(struct device *dev, struct device_attribute *attr, 16188c2ecf20Sopenharmony_ci const char *buf, size_t count) 16198c2ecf20Sopenharmony_ci{ 16208c2ecf20Sopenharmony_ci struct dasd_device *device; 16218c2ecf20Sopenharmony_ci unsigned long flags; 16228c2ecf20Sopenharmony_ci unsigned long val; 16238c2ecf20Sopenharmony_ci 16248c2ecf20Sopenharmony_ci device = dasd_device_from_cdev(to_ccwdev(dev)); 16258c2ecf20Sopenharmony_ci if (IS_ERR(device)) 16268c2ecf20Sopenharmony_ci return -ENODEV; 16278c2ecf20Sopenharmony_ci 16288c2ecf20Sopenharmony_ci if ((kstrtoul(buf, 10, &val) != 0) || 16298c2ecf20Sopenharmony_ci (val > DASD_INTERVAL_MAX) || val == 0) { 16308c2ecf20Sopenharmony_ci dasd_put_device(device); 16318c2ecf20Sopenharmony_ci return -EINVAL; 16328c2ecf20Sopenharmony_ci } 16338c2ecf20Sopenharmony_ci spin_lock_irqsave(get_ccwdev_lock(to_ccwdev(dev)), flags); 16348c2ecf20Sopenharmony_ci if (val) 16358c2ecf20Sopenharmony_ci device->path_interval = val; 16368c2ecf20Sopenharmony_ci spin_unlock_irqrestore(get_ccwdev_lock(to_ccwdev(dev)), flags); 16378c2ecf20Sopenharmony_ci dasd_put_device(device); 16388c2ecf20Sopenharmony_ci return count; 16398c2ecf20Sopenharmony_ci} 16408c2ecf20Sopenharmony_ci 16418c2ecf20Sopenharmony_cistatic DEVICE_ATTR(path_interval, 0644, dasd_path_interval_show, 16428c2ecf20Sopenharmony_ci dasd_path_interval_store); 16438c2ecf20Sopenharmony_ci 16448c2ecf20Sopenharmony_ci 16458c2ecf20Sopenharmony_ci#define DASD_DEFINE_ATTR(_name, _func) \ 16468c2ecf20Sopenharmony_cistatic ssize_t dasd_##_name##_show(struct device *dev, \ 16478c2ecf20Sopenharmony_ci struct device_attribute *attr, \ 16488c2ecf20Sopenharmony_ci char *buf) \ 16498c2ecf20Sopenharmony_ci{ \ 16508c2ecf20Sopenharmony_ci struct ccw_device *cdev = to_ccwdev(dev); \ 16518c2ecf20Sopenharmony_ci struct dasd_device *device = dasd_device_from_cdev(cdev); \ 16528c2ecf20Sopenharmony_ci int val = 0; \ 16538c2ecf20Sopenharmony_ci \ 16548c2ecf20Sopenharmony_ci if (IS_ERR(device)) \ 16558c2ecf20Sopenharmony_ci return -ENODEV; \ 16568c2ecf20Sopenharmony_ci if (device->discipline && _func) \ 16578c2ecf20Sopenharmony_ci val = _func(device); \ 16588c2ecf20Sopenharmony_ci dasd_put_device(device); \ 16598c2ecf20Sopenharmony_ci \ 16608c2ecf20Sopenharmony_ci return snprintf(buf, PAGE_SIZE, "%d\n", val); \ 16618c2ecf20Sopenharmony_ci} \ 16628c2ecf20Sopenharmony_cistatic DEVICE_ATTR(_name, 0444, dasd_##_name##_show, NULL); \ 16638c2ecf20Sopenharmony_ci 16648c2ecf20Sopenharmony_ciDASD_DEFINE_ATTR(ese, device->discipline->is_ese); 16658c2ecf20Sopenharmony_ciDASD_DEFINE_ATTR(extent_size, device->discipline->ext_size); 16668c2ecf20Sopenharmony_ciDASD_DEFINE_ATTR(pool_id, device->discipline->ext_pool_id); 16678c2ecf20Sopenharmony_ciDASD_DEFINE_ATTR(space_configured, device->discipline->space_configured); 16688c2ecf20Sopenharmony_ciDASD_DEFINE_ATTR(space_allocated, device->discipline->space_allocated); 16698c2ecf20Sopenharmony_ciDASD_DEFINE_ATTR(logical_capacity, device->discipline->logical_capacity); 16708c2ecf20Sopenharmony_ciDASD_DEFINE_ATTR(warn_threshold, device->discipline->ext_pool_warn_thrshld); 16718c2ecf20Sopenharmony_ciDASD_DEFINE_ATTR(cap_at_warnlevel, device->discipline->ext_pool_cap_at_warnlevel); 16728c2ecf20Sopenharmony_ciDASD_DEFINE_ATTR(pool_oos, device->discipline->ext_pool_oos); 16738c2ecf20Sopenharmony_ci 16748c2ecf20Sopenharmony_cistatic struct attribute * dasd_attrs[] = { 16758c2ecf20Sopenharmony_ci &dev_attr_readonly.attr, 16768c2ecf20Sopenharmony_ci &dev_attr_discipline.attr, 16778c2ecf20Sopenharmony_ci &dev_attr_status.attr, 16788c2ecf20Sopenharmony_ci &dev_attr_alias.attr, 16798c2ecf20Sopenharmony_ci &dev_attr_vendor.attr, 16808c2ecf20Sopenharmony_ci &dev_attr_uid.attr, 16818c2ecf20Sopenharmony_ci &dev_attr_use_diag.attr, 16828c2ecf20Sopenharmony_ci &dev_attr_raw_track_access.attr, 16838c2ecf20Sopenharmony_ci &dev_attr_eer_enabled.attr, 16848c2ecf20Sopenharmony_ci &dev_attr_erplog.attr, 16858c2ecf20Sopenharmony_ci &dev_attr_failfast.attr, 16868c2ecf20Sopenharmony_ci &dev_attr_expires.attr, 16878c2ecf20Sopenharmony_ci &dev_attr_retries.attr, 16888c2ecf20Sopenharmony_ci &dev_attr_timeout.attr, 16898c2ecf20Sopenharmony_ci &dev_attr_reservation_policy.attr, 16908c2ecf20Sopenharmony_ci &dev_attr_last_known_reservation_state.attr, 16918c2ecf20Sopenharmony_ci &dev_attr_safe_offline.attr, 16928c2ecf20Sopenharmony_ci &dev_attr_host_access_count.attr, 16938c2ecf20Sopenharmony_ci &dev_attr_path_masks.attr, 16948c2ecf20Sopenharmony_ci &dev_attr_path_threshold.attr, 16958c2ecf20Sopenharmony_ci &dev_attr_path_autodisable.attr, 16968c2ecf20Sopenharmony_ci &dev_attr_path_interval.attr, 16978c2ecf20Sopenharmony_ci &dev_attr_path_reset.attr, 16988c2ecf20Sopenharmony_ci &dev_attr_hpf.attr, 16998c2ecf20Sopenharmony_ci &dev_attr_ese.attr, 17008c2ecf20Sopenharmony_ci NULL, 17018c2ecf20Sopenharmony_ci}; 17028c2ecf20Sopenharmony_ci 17038c2ecf20Sopenharmony_cistatic const struct attribute_group dasd_attr_group = { 17048c2ecf20Sopenharmony_ci .attrs = dasd_attrs, 17058c2ecf20Sopenharmony_ci}; 17068c2ecf20Sopenharmony_ci 17078c2ecf20Sopenharmony_cistatic struct attribute *capacity_attrs[] = { 17088c2ecf20Sopenharmony_ci &dev_attr_space_configured.attr, 17098c2ecf20Sopenharmony_ci &dev_attr_space_allocated.attr, 17108c2ecf20Sopenharmony_ci &dev_attr_logical_capacity.attr, 17118c2ecf20Sopenharmony_ci NULL, 17128c2ecf20Sopenharmony_ci}; 17138c2ecf20Sopenharmony_ci 17148c2ecf20Sopenharmony_cistatic const struct attribute_group capacity_attr_group = { 17158c2ecf20Sopenharmony_ci .name = "capacity", 17168c2ecf20Sopenharmony_ci .attrs = capacity_attrs, 17178c2ecf20Sopenharmony_ci}; 17188c2ecf20Sopenharmony_ci 17198c2ecf20Sopenharmony_cistatic struct attribute *ext_pool_attrs[] = { 17208c2ecf20Sopenharmony_ci &dev_attr_pool_id.attr, 17218c2ecf20Sopenharmony_ci &dev_attr_extent_size.attr, 17228c2ecf20Sopenharmony_ci &dev_attr_warn_threshold.attr, 17238c2ecf20Sopenharmony_ci &dev_attr_cap_at_warnlevel.attr, 17248c2ecf20Sopenharmony_ci &dev_attr_pool_oos.attr, 17258c2ecf20Sopenharmony_ci NULL, 17268c2ecf20Sopenharmony_ci}; 17278c2ecf20Sopenharmony_ci 17288c2ecf20Sopenharmony_cistatic const struct attribute_group ext_pool_attr_group = { 17298c2ecf20Sopenharmony_ci .name = "extent_pool", 17308c2ecf20Sopenharmony_ci .attrs = ext_pool_attrs, 17318c2ecf20Sopenharmony_ci}; 17328c2ecf20Sopenharmony_ci 17338c2ecf20Sopenharmony_cistatic const struct attribute_group *dasd_attr_groups[] = { 17348c2ecf20Sopenharmony_ci &dasd_attr_group, 17358c2ecf20Sopenharmony_ci &capacity_attr_group, 17368c2ecf20Sopenharmony_ci &ext_pool_attr_group, 17378c2ecf20Sopenharmony_ci NULL, 17388c2ecf20Sopenharmony_ci}; 17398c2ecf20Sopenharmony_ci 17408c2ecf20Sopenharmony_ci/* 17418c2ecf20Sopenharmony_ci * Return value of the specified feature. 17428c2ecf20Sopenharmony_ci */ 17438c2ecf20Sopenharmony_ciint 17448c2ecf20Sopenharmony_cidasd_get_feature(struct ccw_device *cdev, int feature) 17458c2ecf20Sopenharmony_ci{ 17468c2ecf20Sopenharmony_ci struct dasd_devmap *devmap; 17478c2ecf20Sopenharmony_ci 17488c2ecf20Sopenharmony_ci devmap = dasd_find_busid(dev_name(&cdev->dev)); 17498c2ecf20Sopenharmony_ci if (IS_ERR(devmap)) 17508c2ecf20Sopenharmony_ci return PTR_ERR(devmap); 17518c2ecf20Sopenharmony_ci 17528c2ecf20Sopenharmony_ci return ((devmap->features & feature) != 0); 17538c2ecf20Sopenharmony_ci} 17548c2ecf20Sopenharmony_ci 17558c2ecf20Sopenharmony_ci/* 17568c2ecf20Sopenharmony_ci * Set / reset given feature. 17578c2ecf20Sopenharmony_ci * Flag indicates whether to set (!=0) or the reset (=0) the feature. 17588c2ecf20Sopenharmony_ci */ 17598c2ecf20Sopenharmony_ciint 17608c2ecf20Sopenharmony_cidasd_set_feature(struct ccw_device *cdev, int feature, int flag) 17618c2ecf20Sopenharmony_ci{ 17628c2ecf20Sopenharmony_ci struct dasd_devmap *devmap; 17638c2ecf20Sopenharmony_ci 17648c2ecf20Sopenharmony_ci devmap = dasd_devmap_from_cdev(cdev); 17658c2ecf20Sopenharmony_ci if (IS_ERR(devmap)) 17668c2ecf20Sopenharmony_ci return PTR_ERR(devmap); 17678c2ecf20Sopenharmony_ci 17688c2ecf20Sopenharmony_ci spin_lock(&dasd_devmap_lock); 17698c2ecf20Sopenharmony_ci if (flag) 17708c2ecf20Sopenharmony_ci devmap->features |= feature; 17718c2ecf20Sopenharmony_ci else 17728c2ecf20Sopenharmony_ci devmap->features &= ~feature; 17738c2ecf20Sopenharmony_ci if (devmap->device) 17748c2ecf20Sopenharmony_ci devmap->device->features = devmap->features; 17758c2ecf20Sopenharmony_ci spin_unlock(&dasd_devmap_lock); 17768c2ecf20Sopenharmony_ci return 0; 17778c2ecf20Sopenharmony_ci} 17788c2ecf20Sopenharmony_ciEXPORT_SYMBOL(dasd_set_feature); 17798c2ecf20Sopenharmony_ci 17808c2ecf20Sopenharmony_ci 17818c2ecf20Sopenharmony_ciint dasd_add_sysfs_files(struct ccw_device *cdev) 17828c2ecf20Sopenharmony_ci{ 17838c2ecf20Sopenharmony_ci return sysfs_create_groups(&cdev->dev.kobj, dasd_attr_groups); 17848c2ecf20Sopenharmony_ci} 17858c2ecf20Sopenharmony_ci 17868c2ecf20Sopenharmony_civoid 17878c2ecf20Sopenharmony_cidasd_remove_sysfs_files(struct ccw_device *cdev) 17888c2ecf20Sopenharmony_ci{ 17898c2ecf20Sopenharmony_ci sysfs_remove_groups(&cdev->dev.kobj, dasd_attr_groups); 17908c2ecf20Sopenharmony_ci} 17918c2ecf20Sopenharmony_ci 17928c2ecf20Sopenharmony_ci 17938c2ecf20Sopenharmony_ciint 17948c2ecf20Sopenharmony_cidasd_devmap_init(void) 17958c2ecf20Sopenharmony_ci{ 17968c2ecf20Sopenharmony_ci int i; 17978c2ecf20Sopenharmony_ci 17988c2ecf20Sopenharmony_ci /* Initialize devmap structures. */ 17998c2ecf20Sopenharmony_ci dasd_max_devindex = 0; 18008c2ecf20Sopenharmony_ci for (i = 0; i < 256; i++) 18018c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&dasd_hashlists[i]); 18028c2ecf20Sopenharmony_ci return 0; 18038c2ecf20Sopenharmony_ci} 18048c2ecf20Sopenharmony_ci 18058c2ecf20Sopenharmony_civoid 18068c2ecf20Sopenharmony_cidasd_devmap_exit(void) 18078c2ecf20Sopenharmony_ci{ 18088c2ecf20Sopenharmony_ci dasd_forget_ranges(); 18098c2ecf20Sopenharmony_ci} 1810