1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com> |
4 | * Horst Hummel <Horst.Hummel@de.ibm.com> |
5 | * Carsten Otte <Cotte@de.ibm.com> |
6 | * Martin Schwidefsky <schwidefsky@de.ibm.com> |
7 | * Bugreports.to..: <Linux390@de.ibm.com> |
8 | * Copyright IBM Corp. 1999,2001 |
9 | * |
10 | * Device mapping and dasd= parameter parsing functions. All devmap |
11 | * functions may not be called from interrupt context. In particular |
12 | * dasd_get_device is a no-no from interrupt context. |
13 | * |
14 | */ |
15 | |
16 | #include <linux/ctype.h> |
17 | #include <linux/init.h> |
18 | #include <linux/module.h> |
19 | #include <linux/slab.h> |
20 | |
21 | #include <asm/debug.h> |
22 | #include <linux/uaccess.h> |
23 | #include <asm/ipl.h> |
24 | |
25 | #define DASD_MAX_PARAMS 256 |
26 | |
27 | #include "dasd_int.h" |
28 | |
29 | struct kmem_cache *dasd_page_cache; |
30 | EXPORT_SYMBOL_GPL(dasd_page_cache); |
31 | |
32 | /* |
33 | * dasd_devmap_t is used to store the features and the relation |
34 | * between device number and device index. To find a dasd_devmap_t |
35 | * that corresponds to a device number of a device index each |
36 | * dasd_devmap_t is added to two linked lists, one to search by |
37 | * the device number and one to search by the device index. As |
38 | * soon as big minor numbers are available the device index list |
39 | * can be removed since the device number will then be identical |
40 | * to the device index. |
41 | */ |
42 | struct dasd_devmap { |
43 | struct list_head list; |
44 | char bus_id[DASD_BUS_ID_SIZE]; |
45 | unsigned int devindex; |
46 | unsigned short features; |
47 | struct dasd_device *device; |
48 | struct dasd_copy_relation *copy; |
49 | unsigned int aq_mask; |
50 | }; |
51 | |
52 | /* |
53 | * Parameter parsing functions for dasd= parameter. The syntax is: |
54 | * <devno> : (0x)?[0-9a-fA-F]+ |
55 | * <busid> : [0-0a-f]\.[0-9a-f]\.(0x)?[0-9a-fA-F]+ |
56 | * <feature> : ro |
57 | * <feature_list> : \(<feature>(:<feature>)*\) |
58 | * <devno-range> : <devno>(-<devno>)?<feature_list>? |
59 | * <busid-range> : <busid>(-<busid>)?<feature_list>? |
60 | * <devices> : <devno-range>|<busid-range> |
61 | * <dasd_module> : dasd_diag_mod|dasd_eckd_mod|dasd_fba_mod |
62 | * |
63 | * <dasd> : autodetect|probeonly|<devices>(,<devices>)* |
64 | */ |
65 | |
66 | int dasd_probeonly = 0; /* is true, when probeonly mode is active */ |
67 | int dasd_autodetect = 0; /* is true, when autodetection is active */ |
68 | int dasd_nopav = 0; /* is true, when PAV is disabled */ |
69 | EXPORT_SYMBOL_GPL(dasd_nopav); |
70 | int dasd_nofcx; /* disable High Performance Ficon */ |
71 | EXPORT_SYMBOL_GPL(dasd_nofcx); |
72 | |
73 | /* |
74 | * char *dasd[] is intended to hold the ranges supplied by the dasd= statement |
75 | * it is named 'dasd' to directly be filled by insmod with the comma separated |
76 | * strings when running as a module. |
77 | */ |
78 | static char *dasd[DASD_MAX_PARAMS]; |
79 | module_param_array(dasd, charp, NULL, S_IRUGO); |
80 | |
81 | /* |
82 | * Single spinlock to protect devmap and servermap structures and lists. |
83 | */ |
84 | static DEFINE_SPINLOCK(dasd_devmap_lock); |
85 | |
86 | /* |
87 | * Hash lists for devmap structures. |
88 | */ |
89 | static struct list_head dasd_hashlists[256]; |
90 | int dasd_max_devindex; |
91 | |
92 | static struct dasd_devmap *dasd_add_busid(const char *, int); |
93 | |
94 | static inline int |
95 | dasd_hash_busid(const char *bus_id) |
96 | { |
97 | int hash, i; |
98 | |
99 | hash = 0; |
100 | for (i = 0; (i < DASD_BUS_ID_SIZE) && *bus_id; i++, bus_id++) |
101 | hash += *bus_id; |
102 | return hash & 0xff; |
103 | } |
104 | |
105 | #ifndef MODULE |
106 | static int __init dasd_call_setup(char *opt) |
107 | { |
108 | static int i __initdata; |
109 | char *tmp; |
110 | |
111 | while (i < DASD_MAX_PARAMS) { |
112 | tmp = strsep(&opt, "," ); |
113 | if (!tmp) |
114 | break; |
115 | |
116 | dasd[i++] = tmp; |
117 | } |
118 | |
119 | return 1; |
120 | } |
121 | |
122 | __setup ("dasd=" , dasd_call_setup); |
123 | #endif /* #ifndef MODULE */ |
124 | |
125 | #define DASD_IPLDEV "ipldev" |
126 | |
127 | /* |
128 | * Read a device busid/devno from a string. |
129 | */ |
130 | static int dasd_busid(char *str, int *id0, int *id1, int *devno) |
131 | { |
132 | unsigned int val; |
133 | char *tok; |
134 | |
135 | /* Interpret ipldev busid */ |
136 | if (strncmp(DASD_IPLDEV, str, strlen(DASD_IPLDEV)) == 0) { |
137 | if (ipl_info.type != IPL_TYPE_CCW) { |
138 | pr_err("The IPL device is not a CCW device\n" ); |
139 | return -EINVAL; |
140 | } |
141 | *id0 = 0; |
142 | *id1 = ipl_info.data.ccw.dev_id.ssid; |
143 | *devno = ipl_info.data.ccw.dev_id.devno; |
144 | |
145 | return 0; |
146 | } |
147 | |
148 | /* Old style 0xXXXX or XXXX */ |
149 | if (!kstrtouint(s: str, base: 16, res: &val)) { |
150 | *id0 = *id1 = 0; |
151 | if (val > 0xffff) |
152 | return -EINVAL; |
153 | *devno = val; |
154 | return 0; |
155 | } |
156 | |
157 | /* New style x.y.z busid */ |
158 | tok = strsep(&str, "." ); |
159 | if (kstrtouint(s: tok, base: 16, res: &val) || val > 0xff) |
160 | return -EINVAL; |
161 | *id0 = val; |
162 | |
163 | tok = strsep(&str, "." ); |
164 | if (kstrtouint(s: tok, base: 16, res: &val) || val > 0xff) |
165 | return -EINVAL; |
166 | *id1 = val; |
167 | |
168 | tok = strsep(&str, "." ); |
169 | if (kstrtouint(s: tok, base: 16, res: &val) || val > 0xffff) |
170 | return -EINVAL; |
171 | *devno = val; |
172 | |
173 | return 0; |
174 | } |
175 | |
176 | /* |
177 | * Read colon separated list of dasd features. |
178 | */ |
179 | static int __init dasd_feature_list(char *str) |
180 | { |
181 | int features, len, rc; |
182 | |
183 | features = 0; |
184 | rc = 0; |
185 | |
186 | if (!str) |
187 | return DASD_FEATURE_DEFAULT; |
188 | |
189 | while (1) { |
190 | for (len = 0; |
191 | str[len] && str[len] != ':' && str[len] != ')'; len++); |
192 | if (len == 2 && !strncmp(str, "ro" , 2)) |
193 | features |= DASD_FEATURE_READONLY; |
194 | else if (len == 4 && !strncmp(str, "diag" , 4)) |
195 | features |= DASD_FEATURE_USEDIAG; |
196 | else if (len == 3 && !strncmp(str, "raw" , 3)) |
197 | features |= DASD_FEATURE_USERAW; |
198 | else if (len == 6 && !strncmp(str, "erplog" , 6)) |
199 | features |= DASD_FEATURE_ERPLOG; |
200 | else if (len == 8 && !strncmp(str, "failfast" , 8)) |
201 | features |= DASD_FEATURE_FAILFAST; |
202 | else { |
203 | pr_warn("%.*s is not a supported device option\n" , |
204 | len, str); |
205 | rc = -EINVAL; |
206 | } |
207 | str += len; |
208 | if (*str != ':') |
209 | break; |
210 | str++; |
211 | } |
212 | |
213 | return rc ? : features; |
214 | } |
215 | |
216 | /* |
217 | * Try to match the first element on the comma separated parse string |
218 | * with one of the known keywords. If a keyword is found, take the approprate |
219 | * action and return a pointer to the residual string. If the first element |
220 | * could not be matched to any keyword then return an error code. |
221 | */ |
222 | static int __init dasd_parse_keyword(char *keyword) |
223 | { |
224 | int length = strlen(keyword); |
225 | |
226 | if (strncmp("autodetect" , keyword, length) == 0) { |
227 | dasd_autodetect = 1; |
228 | pr_info("The autodetection mode has been activated\n" ); |
229 | return 0; |
230 | } |
231 | if (strncmp("probeonly" , keyword, length) == 0) { |
232 | dasd_probeonly = 1; |
233 | pr_info("The probeonly mode has been activated\n" ); |
234 | return 0; |
235 | } |
236 | if (strncmp("nopav" , keyword, length) == 0) { |
237 | if (MACHINE_IS_VM) |
238 | pr_info("'nopav' is not supported on z/VM\n" ); |
239 | else { |
240 | dasd_nopav = 1; |
241 | pr_info("PAV support has be deactivated\n" ); |
242 | } |
243 | return 0; |
244 | } |
245 | if (strncmp("nofcx" , keyword, length) == 0) { |
246 | dasd_nofcx = 1; |
247 | pr_info("High Performance FICON support has been " |
248 | "deactivated\n" ); |
249 | return 0; |
250 | } |
251 | if (strncmp("fixedbuffers" , keyword, length) == 0) { |
252 | if (dasd_page_cache) |
253 | return 0; |
254 | dasd_page_cache = |
255 | kmem_cache_create(name: "dasd_page_cache" , PAGE_SIZE, |
256 | PAGE_SIZE, SLAB_CACHE_DMA, |
257 | NULL); |
258 | if (!dasd_page_cache) |
259 | DBF_EVENT(DBF_WARNING, "%s" , "Failed to create slab, " |
260 | "fixed buffer mode disabled." ); |
261 | else |
262 | DBF_EVENT(DBF_INFO, "%s" , |
263 | "turning on fixed buffer mode" ); |
264 | return 0; |
265 | } |
266 | |
267 | return -EINVAL; |
268 | } |
269 | |
270 | /* |
271 | * Split a string of a device range into its pieces and return the from, to, and |
272 | * feature parts separately. |
273 | * e.g.: |
274 | * 0.0.1234-0.0.5678(ro:erplog) -> from: 0.0.1234 to: 0.0.5678 features: ro:erplog |
275 | * 0.0.8765(raw) -> from: 0.0.8765 to: null features: raw |
276 | * 0x4321 -> from: 0x4321 to: null features: null |
277 | */ |
278 | static int __init dasd_evaluate_range_param(char *range, char **from_str, |
279 | char **to_str, char **features_str) |
280 | { |
281 | int rc = 0; |
282 | |
283 | /* Do we have a range or a single device? */ |
284 | if (strchr(range, '-')) { |
285 | *from_str = strsep(&range, "-" ); |
286 | *to_str = strsep(&range, "(" ); |
287 | *features_str = strsep(&range, ")" ); |
288 | } else { |
289 | *from_str = strsep(&range, "(" ); |
290 | *features_str = strsep(&range, ")" ); |
291 | } |
292 | |
293 | if (*features_str && !range) { |
294 | pr_warn("A closing parenthesis ')' is missing in the dasd= parameter\n" ); |
295 | rc = -EINVAL; |
296 | } |
297 | |
298 | return rc; |
299 | } |
300 | |
301 | /* |
302 | * Try to interprete the range string as a device number or a range of devices. |
303 | * If the interpretation is successful, create the matching dasd_devmap entries. |
304 | * If interpretation fails or in case of an error, return an error code. |
305 | */ |
306 | static int __init dasd_parse_range(const char *range) |
307 | { |
308 | struct dasd_devmap *devmap; |
309 | int from, from_id0, from_id1; |
310 | int to, to_id0, to_id1; |
311 | int features; |
312 | char bus_id[DASD_BUS_ID_SIZE + 1]; |
313 | char *features_str = NULL; |
314 | char *from_str = NULL; |
315 | char *to_str = NULL; |
316 | int rc = 0; |
317 | char *tmp; |
318 | |
319 | tmp = kstrdup(s: range, GFP_KERNEL); |
320 | if (!tmp) |
321 | return -ENOMEM; |
322 | |
323 | if (dasd_evaluate_range_param(range: tmp, from_str: &from_str, to_str: &to_str, features_str: &features_str)) { |
324 | rc = -EINVAL; |
325 | goto out; |
326 | } |
327 | |
328 | if (dasd_busid(str: from_str, id0: &from_id0, id1: &from_id1, devno: &from)) { |
329 | rc = -EINVAL; |
330 | goto out; |
331 | } |
332 | |
333 | to = from; |
334 | to_id0 = from_id0; |
335 | to_id1 = from_id1; |
336 | if (to_str) { |
337 | if (dasd_busid(str: to_str, id0: &to_id0, id1: &to_id1, devno: &to)) { |
338 | rc = -EINVAL; |
339 | goto out; |
340 | } |
341 | if (from_id0 != to_id0 || from_id1 != to_id1 || from > to) { |
342 | pr_err("%s is not a valid device range\n" , range); |
343 | rc = -EINVAL; |
344 | goto out; |
345 | } |
346 | } |
347 | |
348 | features = dasd_feature_list(str: features_str); |
349 | if (features < 0) { |
350 | rc = -EINVAL; |
351 | goto out; |
352 | } |
353 | /* each device in dasd= parameter should be set initially online */ |
354 | features |= DASD_FEATURE_INITIAL_ONLINE; |
355 | while (from <= to) { |
356 | sprintf(buf: bus_id, fmt: "%01x.%01x.%04x" , from_id0, from_id1, from++); |
357 | devmap = dasd_add_busid(bus_id, features); |
358 | if (IS_ERR(ptr: devmap)) { |
359 | rc = PTR_ERR(ptr: devmap); |
360 | goto out; |
361 | } |
362 | } |
363 | |
364 | out: |
365 | kfree(objp: tmp); |
366 | |
367 | return rc; |
368 | } |
369 | |
370 | /* |
371 | * Parse parameters stored in dasd[] |
372 | * The 'dasd=...' parameter allows to specify a comma separated list of |
373 | * keywords and device ranges. The parameters in that list will be stored as |
374 | * separate elementes in dasd[]. |
375 | */ |
376 | int __init dasd_parse(void) |
377 | { |
378 | int rc, i; |
379 | char *cur; |
380 | |
381 | rc = 0; |
382 | for (i = 0; i < DASD_MAX_PARAMS; i++) { |
383 | cur = dasd[i]; |
384 | if (!cur) |
385 | break; |
386 | if (*cur == '\0') |
387 | continue; |
388 | |
389 | rc = dasd_parse_keyword(keyword: cur); |
390 | if (rc) |
391 | rc = dasd_parse_range(range: cur); |
392 | |
393 | if (rc) |
394 | break; |
395 | } |
396 | |
397 | return rc; |
398 | } |
399 | |
400 | /* |
401 | * Add a devmap for the device specified by busid. It is possible that |
402 | * the devmap already exists (dasd= parameter). The order of the devices |
403 | * added through this function will define the kdevs for the individual |
404 | * devices. |
405 | */ |
406 | static struct dasd_devmap * |
407 | dasd_add_busid(const char *bus_id, int features) |
408 | { |
409 | struct dasd_devmap *devmap, *new, *tmp; |
410 | int hash; |
411 | |
412 | new = kzalloc(size: sizeof(struct dasd_devmap), GFP_KERNEL); |
413 | if (!new) |
414 | return ERR_PTR(error: -ENOMEM); |
415 | spin_lock(lock: &dasd_devmap_lock); |
416 | devmap = NULL; |
417 | hash = dasd_hash_busid(bus_id); |
418 | list_for_each_entry(tmp, &dasd_hashlists[hash], list) |
419 | if (strncmp(tmp->bus_id, bus_id, DASD_BUS_ID_SIZE) == 0) { |
420 | devmap = tmp; |
421 | break; |
422 | } |
423 | if (!devmap) { |
424 | /* This bus_id is new. */ |
425 | new->devindex = dasd_max_devindex++; |
426 | strscpy(new->bus_id, bus_id, DASD_BUS_ID_SIZE); |
427 | new->features = features; |
428 | new->device = NULL; |
429 | list_add(new: &new->list, head: &dasd_hashlists[hash]); |
430 | devmap = new; |
431 | new = NULL; |
432 | } |
433 | spin_unlock(lock: &dasd_devmap_lock); |
434 | kfree(objp: new); |
435 | return devmap; |
436 | } |
437 | |
438 | static struct dasd_devmap * |
439 | dasd_find_busid_locked(const char *bus_id) |
440 | { |
441 | struct dasd_devmap *devmap, *tmp; |
442 | int hash; |
443 | |
444 | devmap = ERR_PTR(error: -ENODEV); |
445 | hash = dasd_hash_busid(bus_id); |
446 | list_for_each_entry(tmp, &dasd_hashlists[hash], list) { |
447 | if (strncmp(tmp->bus_id, bus_id, DASD_BUS_ID_SIZE) == 0) { |
448 | devmap = tmp; |
449 | break; |
450 | } |
451 | } |
452 | return devmap; |
453 | } |
454 | |
455 | /* |
456 | * Find devmap for device with given bus_id. |
457 | */ |
458 | static struct dasd_devmap * |
459 | dasd_find_busid(const char *bus_id) |
460 | { |
461 | struct dasd_devmap *devmap; |
462 | |
463 | spin_lock(lock: &dasd_devmap_lock); |
464 | devmap = dasd_find_busid_locked(bus_id); |
465 | spin_unlock(lock: &dasd_devmap_lock); |
466 | return devmap; |
467 | } |
468 | |
469 | /* |
470 | * Check if busid has been added to the list of dasd ranges. |
471 | */ |
472 | int |
473 | dasd_busid_known(const char *bus_id) |
474 | { |
475 | return IS_ERR(ptr: dasd_find_busid(bus_id)) ? -ENOENT : 0; |
476 | } |
477 | |
478 | /* |
479 | * Forget all about the device numbers added so far. |
480 | * This may only be called at module unload or system shutdown. |
481 | */ |
482 | static void |
483 | dasd_forget_ranges(void) |
484 | { |
485 | struct dasd_devmap *devmap, *n; |
486 | int i; |
487 | |
488 | spin_lock(lock: &dasd_devmap_lock); |
489 | for (i = 0; i < 256; i++) { |
490 | list_for_each_entry_safe(devmap, n, &dasd_hashlists[i], list) { |
491 | BUG_ON(devmap->device != NULL); |
492 | list_del(entry: &devmap->list); |
493 | kfree(objp: devmap); |
494 | } |
495 | } |
496 | spin_unlock(lock: &dasd_devmap_lock); |
497 | } |
498 | |
499 | /* |
500 | * Find the device struct by its device index. |
501 | */ |
502 | struct dasd_device * |
503 | dasd_device_from_devindex(int devindex) |
504 | { |
505 | struct dasd_devmap *devmap, *tmp; |
506 | struct dasd_device *device; |
507 | int i; |
508 | |
509 | spin_lock(lock: &dasd_devmap_lock); |
510 | devmap = NULL; |
511 | for (i = 0; (i < 256) && !devmap; i++) |
512 | list_for_each_entry(tmp, &dasd_hashlists[i], list) |
513 | if (tmp->devindex == devindex) { |
514 | /* Found the devmap for the device. */ |
515 | devmap = tmp; |
516 | break; |
517 | } |
518 | if (devmap && devmap->device) { |
519 | device = devmap->device; |
520 | dasd_get_device(device); |
521 | } else |
522 | device = ERR_PTR(error: -ENODEV); |
523 | spin_unlock(lock: &dasd_devmap_lock); |
524 | return device; |
525 | } |
526 | |
527 | /* |
528 | * Return devmap for cdev. If no devmap exists yet, create one and |
529 | * connect it to the cdev. |
530 | */ |
531 | static struct dasd_devmap * |
532 | dasd_devmap_from_cdev(struct ccw_device *cdev) |
533 | { |
534 | struct dasd_devmap *devmap; |
535 | |
536 | devmap = dasd_find_busid(bus_id: dev_name(dev: &cdev->dev)); |
537 | if (IS_ERR(ptr: devmap)) |
538 | devmap = dasd_add_busid(bus_id: dev_name(dev: &cdev->dev), |
539 | features: DASD_FEATURE_DEFAULT); |
540 | return devmap; |
541 | } |
542 | |
543 | /* |
544 | * Create a dasd device structure for cdev. |
545 | */ |
546 | struct dasd_device * |
547 | dasd_create_device(struct ccw_device *cdev) |
548 | { |
549 | struct dasd_devmap *devmap; |
550 | struct dasd_device *device; |
551 | unsigned long flags; |
552 | int rc; |
553 | |
554 | devmap = dasd_devmap_from_cdev(cdev); |
555 | if (IS_ERR(ptr: devmap)) |
556 | return (void *) devmap; |
557 | |
558 | device = dasd_alloc_device(); |
559 | if (IS_ERR(ptr: device)) |
560 | return device; |
561 | atomic_set(v: &device->ref_count, i: 3); |
562 | |
563 | spin_lock(lock: &dasd_devmap_lock); |
564 | if (!devmap->device) { |
565 | devmap->device = device; |
566 | device->devindex = devmap->devindex; |
567 | device->features = devmap->features; |
568 | get_device(dev: &cdev->dev); |
569 | device->cdev = cdev; |
570 | rc = 0; |
571 | } else |
572 | /* Someone else was faster. */ |
573 | rc = -EBUSY; |
574 | spin_unlock(lock: &dasd_devmap_lock); |
575 | |
576 | if (rc) { |
577 | dasd_free_device(device); |
578 | return ERR_PTR(error: rc); |
579 | } |
580 | |
581 | spin_lock_irqsave(get_ccwdev_lock(cdev), flags); |
582 | dev_set_drvdata(dev: &cdev->dev, data: device); |
583 | spin_unlock_irqrestore(lock: get_ccwdev_lock(cdev), flags); |
584 | |
585 | device->paths_info = kset_create_and_add(name: "paths_info" , NULL, |
586 | parent_kobj: &device->cdev->dev.kobj); |
587 | if (!device->paths_info) |
588 | dev_warn(&cdev->dev, "Could not create paths_info kset\n" ); |
589 | |
590 | return device; |
591 | } |
592 | |
593 | /* |
594 | * allocate a PPRC data structure and call the discipline function to fill |
595 | */ |
596 | static int dasd_devmap_get_pprc_status(struct dasd_device *device, |
597 | struct dasd_pprc_data_sc4 **data) |
598 | { |
599 | struct dasd_pprc_data_sc4 *temp; |
600 | |
601 | if (!device->discipline || !device->discipline->pprc_status) { |
602 | dev_warn(&device->cdev->dev, "Unable to query copy relation status\n" ); |
603 | return -EOPNOTSUPP; |
604 | } |
605 | temp = kzalloc(size: sizeof(*temp), GFP_KERNEL); |
606 | if (!temp) |
607 | return -ENOMEM; |
608 | |
609 | /* get PPRC information from storage */ |
610 | if (device->discipline->pprc_status(device, temp)) { |
611 | dev_warn(&device->cdev->dev, "Error during copy relation status query\n" ); |
612 | kfree(objp: temp); |
613 | return -EINVAL; |
614 | } |
615 | *data = temp; |
616 | |
617 | return 0; |
618 | } |
619 | |
620 | /* |
621 | * find an entry in a PPRC device_info array by a given UID |
622 | * depending on the primary/secondary state of the device it has to be |
623 | * matched with the respective fields |
624 | */ |
625 | static int dasd_devmap_entry_from_pprc_data(struct dasd_pprc_data_sc4 *data, |
626 | struct dasd_uid uid, |
627 | bool primary) |
628 | { |
629 | int i; |
630 | |
631 | for (i = 0; i < DASD_CP_ENTRIES; i++) { |
632 | if (primary) { |
633 | if (data->dev_info[i].prim_cu_ssid == uid.ssid && |
634 | data->dev_info[i].primary == uid.real_unit_addr) |
635 | return i; |
636 | } else { |
637 | if (data->dev_info[i].sec_cu_ssid == uid.ssid && |
638 | data->dev_info[i].secondary == uid.real_unit_addr) |
639 | return i; |
640 | } |
641 | } |
642 | return -1; |
643 | } |
644 | |
645 | /* |
646 | * check the consistency of a specified copy relation by checking |
647 | * the following things: |
648 | * |
649 | * - is the given device part of a copy pair setup |
650 | * - does the state of the device match the state in the PPRC status data |
651 | * - does the device UID match with the UID in the PPRC status data |
652 | * - to prevent misrouted IO check if the given device is present in all |
653 | * related PPRC status data |
654 | */ |
655 | static int dasd_devmap_check_copy_relation(struct dasd_device *device, |
656 | struct dasd_copy_entry *entry, |
657 | struct dasd_pprc_data_sc4 *data, |
658 | struct dasd_copy_relation *copy) |
659 | { |
660 | struct dasd_pprc_data_sc4 *tmp_dat; |
661 | struct dasd_device *tmp_dev; |
662 | struct dasd_uid uid; |
663 | int i, j; |
664 | |
665 | if (!device->discipline || !device->discipline->get_uid || |
666 | device->discipline->get_uid(device, &uid)) |
667 | return 1; |
668 | |
669 | i = dasd_devmap_entry_from_pprc_data(data, uid, primary: entry->primary); |
670 | if (i < 0) { |
671 | dev_warn(&device->cdev->dev, "Device not part of a copy relation\n" ); |
672 | return 1; |
673 | } |
674 | |
675 | /* double check which role the current device has */ |
676 | if (entry->primary) { |
677 | if (data->dev_info[i].flags & 0x80) { |
678 | dev_warn(&device->cdev->dev, "Copy pair secondary is setup as primary\n" ); |
679 | return 1; |
680 | } |
681 | if (data->dev_info[i].prim_cu_ssid != uid.ssid || |
682 | data->dev_info[i].primary != uid.real_unit_addr) { |
683 | dev_warn(&device->cdev->dev, |
684 | "Primary device %s does not match copy pair status primary device %04x\n" , |
685 | dev_name(&device->cdev->dev), |
686 | data->dev_info[i].prim_cu_ssid | |
687 | data->dev_info[i].primary); |
688 | return 1; |
689 | } |
690 | } else { |
691 | if (!(data->dev_info[i].flags & 0x80)) { |
692 | dev_warn(&device->cdev->dev, "Copy pair primary is setup as secondary\n" ); |
693 | return 1; |
694 | } |
695 | if (data->dev_info[i].sec_cu_ssid != uid.ssid || |
696 | data->dev_info[i].secondary != uid.real_unit_addr) { |
697 | dev_warn(&device->cdev->dev, |
698 | "Secondary device %s does not match copy pair status secondary device %04x\n" , |
699 | dev_name(&device->cdev->dev), |
700 | data->dev_info[i].sec_cu_ssid | |
701 | data->dev_info[i].secondary); |
702 | return 1; |
703 | } |
704 | } |
705 | |
706 | /* |
707 | * the current device has to be part of the copy relation of all |
708 | * entries to prevent misrouted IO to another copy pair |
709 | */ |
710 | for (j = 0; j < DASD_CP_ENTRIES; j++) { |
711 | if (entry == ©->entry[j]) |
712 | tmp_dev = device; |
713 | else |
714 | tmp_dev = copy->entry[j].device; |
715 | |
716 | if (!tmp_dev) |
717 | continue; |
718 | |
719 | if (dasd_devmap_get_pprc_status(device: tmp_dev, data: &tmp_dat)) |
720 | return 1; |
721 | |
722 | if (dasd_devmap_entry_from_pprc_data(data: tmp_dat, uid, primary: entry->primary) < 0) { |
723 | dev_warn(&tmp_dev->cdev->dev, |
724 | "Copy pair relation does not contain device: %s\n" , |
725 | dev_name(&device->cdev->dev)); |
726 | kfree(objp: tmp_dat); |
727 | return 1; |
728 | } |
729 | kfree(objp: tmp_dat); |
730 | } |
731 | return 0; |
732 | } |
733 | |
734 | /* delete device from copy relation entry */ |
735 | static void dasd_devmap_delete_copy_relation_device(struct dasd_device *device) |
736 | { |
737 | struct dasd_copy_relation *copy; |
738 | int i; |
739 | |
740 | if (!device->copy) |
741 | return; |
742 | |
743 | copy = device->copy; |
744 | for (i = 0; i < DASD_CP_ENTRIES; i++) { |
745 | if (copy->entry[i].device == device) |
746 | copy->entry[i].device = NULL; |
747 | } |
748 | dasd_put_device(device); |
749 | device->copy = NULL; |
750 | } |
751 | |
752 | /* |
753 | * read all required information for a copy relation setup and setup the device |
754 | * accordingly |
755 | */ |
756 | int dasd_devmap_set_device_copy_relation(struct ccw_device *cdev, |
757 | bool pprc_enabled) |
758 | { |
759 | struct dasd_pprc_data_sc4 *data = NULL; |
760 | struct dasd_copy_entry *entry = NULL; |
761 | struct dasd_copy_relation *copy; |
762 | struct dasd_devmap *devmap; |
763 | struct dasd_device *device; |
764 | int i, rc = 0; |
765 | |
766 | devmap = dasd_devmap_from_cdev(cdev); |
767 | if (IS_ERR(ptr: devmap)) |
768 | return PTR_ERR(ptr: devmap); |
769 | |
770 | device = devmap->device; |
771 | if (!device) |
772 | return -ENODEV; |
773 | |
774 | copy = devmap->copy; |
775 | /* no copy pair setup for this device */ |
776 | if (!copy) |
777 | goto out; |
778 | |
779 | rc = dasd_devmap_get_pprc_status(device, data: &data); |
780 | if (rc) |
781 | return rc; |
782 | |
783 | /* print error if PPRC is requested but not enabled on storage server */ |
784 | if (!pprc_enabled) { |
785 | dev_err(&cdev->dev, "Copy relation not enabled on storage server\n" ); |
786 | rc = -EINVAL; |
787 | goto out; |
788 | } |
789 | |
790 | if (!data->dev_info[0].state) { |
791 | dev_warn(&device->cdev->dev, "Copy pair setup requested for device not in copy relation\n" ); |
792 | rc = -EINVAL; |
793 | goto out; |
794 | } |
795 | /* find entry */ |
796 | for (i = 0; i < DASD_CP_ENTRIES; i++) { |
797 | if (copy->entry[i].configured && |
798 | strncmp(dev_name(dev: &cdev->dev), |
799 | copy->entry[i].busid, DASD_BUS_ID_SIZE) == 0) { |
800 | entry = ©->entry[i]; |
801 | break; |
802 | } |
803 | } |
804 | if (!entry) { |
805 | dev_warn(&device->cdev->dev, "Copy relation entry not found\n" ); |
806 | rc = -EINVAL; |
807 | goto out; |
808 | } |
809 | /* check if the copy relation is valid */ |
810 | if (dasd_devmap_check_copy_relation(device, entry, data, copy)) { |
811 | dev_warn(&device->cdev->dev, "Copy relation faulty\n" ); |
812 | rc = -EINVAL; |
813 | goto out; |
814 | } |
815 | |
816 | dasd_get_device(device); |
817 | copy->entry[i].device = device; |
818 | device->copy = copy; |
819 | out: |
820 | kfree(objp: data); |
821 | return rc; |
822 | } |
823 | EXPORT_SYMBOL_GPL(dasd_devmap_set_device_copy_relation); |
824 | |
825 | /* |
826 | * Wait queue for dasd_delete_device waits. |
827 | */ |
828 | static DECLARE_WAIT_QUEUE_HEAD(dasd_delete_wq); |
829 | |
830 | /* |
831 | * Remove a dasd device structure. The passed referenced |
832 | * is destroyed. |
833 | */ |
834 | void |
835 | dasd_delete_device(struct dasd_device *device) |
836 | { |
837 | struct ccw_device *cdev; |
838 | struct dasd_devmap *devmap; |
839 | unsigned long flags; |
840 | |
841 | /* First remove device pointer from devmap. */ |
842 | devmap = dasd_find_busid(bus_id: dev_name(dev: &device->cdev->dev)); |
843 | BUG_ON(IS_ERR(devmap)); |
844 | spin_lock(lock: &dasd_devmap_lock); |
845 | if (devmap->device != device) { |
846 | spin_unlock(lock: &dasd_devmap_lock); |
847 | dasd_put_device(device); |
848 | return; |
849 | } |
850 | devmap->device = NULL; |
851 | spin_unlock(lock: &dasd_devmap_lock); |
852 | |
853 | /* Disconnect dasd_device structure from ccw_device structure. */ |
854 | spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags); |
855 | dev_set_drvdata(dev: &device->cdev->dev, NULL); |
856 | spin_unlock_irqrestore(lock: get_ccwdev_lock(device->cdev), flags); |
857 | |
858 | /* Removve copy relation */ |
859 | dasd_devmap_delete_copy_relation_device(device); |
860 | /* |
861 | * Drop ref_count by 3, one for the devmap reference, one for |
862 | * the cdev reference and one for the passed reference. |
863 | */ |
864 | atomic_sub(i: 3, v: &device->ref_count); |
865 | |
866 | /* Wait for reference counter to drop to zero. */ |
867 | wait_event(dasd_delete_wq, atomic_read(&device->ref_count) == 0); |
868 | |
869 | dasd_generic_free_discipline(device); |
870 | |
871 | kset_unregister(kset: device->paths_info); |
872 | |
873 | /* Disconnect dasd_device structure from ccw_device structure. */ |
874 | cdev = device->cdev; |
875 | device->cdev = NULL; |
876 | |
877 | /* Put ccw_device structure. */ |
878 | put_device(dev: &cdev->dev); |
879 | |
880 | /* Now the device structure can be freed. */ |
881 | dasd_free_device(device); |
882 | } |
883 | |
884 | /* |
885 | * Reference counter dropped to zero. Wake up waiter |
886 | * in dasd_delete_device. |
887 | */ |
888 | void |
889 | dasd_put_device_wake(struct dasd_device *device) |
890 | { |
891 | wake_up(&dasd_delete_wq); |
892 | } |
893 | EXPORT_SYMBOL_GPL(dasd_put_device_wake); |
894 | |
895 | /* |
896 | * Return dasd_device structure associated with cdev. |
897 | * This function needs to be called with the ccw device |
898 | * lock held. It can be used from interrupt context. |
899 | */ |
900 | struct dasd_device * |
901 | dasd_device_from_cdev_locked(struct ccw_device *cdev) |
902 | { |
903 | struct dasd_device *device = dev_get_drvdata(dev: &cdev->dev); |
904 | |
905 | if (!device) |
906 | return ERR_PTR(error: -ENODEV); |
907 | dasd_get_device(device); |
908 | return device; |
909 | } |
910 | |
911 | /* |
912 | * Return dasd_device structure associated with cdev. |
913 | */ |
914 | struct dasd_device * |
915 | dasd_device_from_cdev(struct ccw_device *cdev) |
916 | { |
917 | struct dasd_device *device; |
918 | unsigned long flags; |
919 | |
920 | spin_lock_irqsave(get_ccwdev_lock(cdev), flags); |
921 | device = dasd_device_from_cdev_locked(cdev); |
922 | spin_unlock_irqrestore(lock: get_ccwdev_lock(cdev), flags); |
923 | return device; |
924 | } |
925 | |
926 | void dasd_add_link_to_gendisk(struct gendisk *gdp, struct dasd_device *device) |
927 | { |
928 | struct dasd_devmap *devmap; |
929 | |
930 | devmap = dasd_find_busid(bus_id: dev_name(dev: &device->cdev->dev)); |
931 | if (IS_ERR(ptr: devmap)) |
932 | return; |
933 | spin_lock(lock: &dasd_devmap_lock); |
934 | gdp->private_data = devmap; |
935 | spin_unlock(lock: &dasd_devmap_lock); |
936 | } |
937 | EXPORT_SYMBOL(dasd_add_link_to_gendisk); |
938 | |
939 | struct dasd_device *dasd_device_from_gendisk(struct gendisk *gdp) |
940 | { |
941 | struct dasd_device *device; |
942 | struct dasd_devmap *devmap; |
943 | |
944 | if (!gdp->private_data) |
945 | return NULL; |
946 | device = NULL; |
947 | spin_lock(lock: &dasd_devmap_lock); |
948 | devmap = gdp->private_data; |
949 | if (devmap && devmap->device) { |
950 | device = devmap->device; |
951 | dasd_get_device(device); |
952 | } |
953 | spin_unlock(lock: &dasd_devmap_lock); |
954 | return device; |
955 | } |
956 | |
957 | /* |
958 | * SECTION: files in sysfs |
959 | */ |
960 | |
961 | /* |
962 | * failfast controls the behaviour, if no path is available |
963 | */ |
964 | static ssize_t dasd_ff_show(struct device *dev, struct device_attribute *attr, |
965 | char *buf) |
966 | { |
967 | struct dasd_devmap *devmap; |
968 | int ff_flag; |
969 | |
970 | devmap = dasd_find_busid(bus_id: dev_name(dev)); |
971 | if (!IS_ERR(devmap)) |
972 | ff_flag = (devmap->features & DASD_FEATURE_FAILFAST) != 0; |
973 | else |
974 | ff_flag = (DASD_FEATURE_DEFAULT & DASD_FEATURE_FAILFAST) != 0; |
975 | return sysfs_emit(buf, fmt: ff_flag ? "1\n" : "0\n" ); |
976 | } |
977 | |
978 | static ssize_t dasd_ff_store(struct device *dev, struct device_attribute *attr, |
979 | const char *buf, size_t count) |
980 | { |
981 | unsigned int val; |
982 | int rc; |
983 | |
984 | if (kstrtouint(s: buf, base: 0, res: &val) || val > 1) |
985 | return -EINVAL; |
986 | |
987 | rc = dasd_set_feature(to_ccwdev(dev), DASD_FEATURE_FAILFAST, val); |
988 | |
989 | return rc ? : count; |
990 | } |
991 | |
992 | static DEVICE_ATTR(failfast, 0644, dasd_ff_show, dasd_ff_store); |
993 | |
994 | /* |
995 | * readonly controls the readonly status of a dasd |
996 | */ |
997 | static ssize_t |
998 | dasd_ro_show(struct device *dev, struct device_attribute *attr, char *buf) |
999 | { |
1000 | struct dasd_devmap *devmap; |
1001 | struct dasd_device *device; |
1002 | int ro_flag = 0; |
1003 | |
1004 | devmap = dasd_find_busid(bus_id: dev_name(dev)); |
1005 | if (IS_ERR(ptr: devmap)) |
1006 | goto out; |
1007 | |
1008 | ro_flag = !!(devmap->features & DASD_FEATURE_READONLY); |
1009 | |
1010 | spin_lock(lock: &dasd_devmap_lock); |
1011 | device = devmap->device; |
1012 | if (device) |
1013 | ro_flag |= test_bit(DASD_FLAG_DEVICE_RO, &device->flags); |
1014 | spin_unlock(lock: &dasd_devmap_lock); |
1015 | |
1016 | out: |
1017 | return sysfs_emit(buf, fmt: ro_flag ? "1\n" : "0\n" ); |
1018 | } |
1019 | |
1020 | static ssize_t |
1021 | dasd_ro_store(struct device *dev, struct device_attribute *attr, |
1022 | const char *buf, size_t count) |
1023 | { |
1024 | struct ccw_device *cdev = to_ccwdev(dev); |
1025 | struct dasd_device *device; |
1026 | unsigned long flags; |
1027 | unsigned int val; |
1028 | int rc; |
1029 | |
1030 | if (kstrtouint(s: buf, base: 0, res: &val) || val > 1) |
1031 | return -EINVAL; |
1032 | |
1033 | rc = dasd_set_feature(cdev, DASD_FEATURE_READONLY, val); |
1034 | if (rc) |
1035 | return rc; |
1036 | |
1037 | device = dasd_device_from_cdev(cdev); |
1038 | if (IS_ERR(ptr: device)) |
1039 | return count; |
1040 | |
1041 | spin_lock_irqsave(get_ccwdev_lock(cdev), flags); |
1042 | val = val || test_bit(DASD_FLAG_DEVICE_RO, &device->flags); |
1043 | |
1044 | if (!device->block || !device->block->gdp || |
1045 | test_bit(DASD_FLAG_OFFLINE, &device->flags)) { |
1046 | spin_unlock_irqrestore(lock: get_ccwdev_lock(cdev), flags); |
1047 | goto out; |
1048 | } |
1049 | /* Increase open_count to avoid losing the block device */ |
1050 | atomic_inc(v: &device->block->open_count); |
1051 | spin_unlock_irqrestore(lock: get_ccwdev_lock(cdev), flags); |
1052 | |
1053 | set_disk_ro(disk: device->block->gdp, read_only: val); |
1054 | atomic_dec(v: &device->block->open_count); |
1055 | |
1056 | out: |
1057 | dasd_put_device(device); |
1058 | |
1059 | return count; |
1060 | } |
1061 | |
1062 | static DEVICE_ATTR(readonly, 0644, dasd_ro_show, dasd_ro_store); |
1063 | /* |
1064 | * erplog controls the logging of ERP related data |
1065 | * (e.g. failing channel programs). |
1066 | */ |
1067 | static ssize_t |
1068 | dasd_erplog_show(struct device *dev, struct device_attribute *attr, char *buf) |
1069 | { |
1070 | struct dasd_devmap *devmap; |
1071 | int erplog; |
1072 | |
1073 | devmap = dasd_find_busid(bus_id: dev_name(dev)); |
1074 | if (!IS_ERR(devmap)) |
1075 | erplog = (devmap->features & DASD_FEATURE_ERPLOG) != 0; |
1076 | else |
1077 | erplog = (DASD_FEATURE_DEFAULT & DASD_FEATURE_ERPLOG) != 0; |
1078 | return sysfs_emit(buf, fmt: erplog ? "1\n" : "0\n" ); |
1079 | } |
1080 | |
1081 | static ssize_t |
1082 | dasd_erplog_store(struct device *dev, struct device_attribute *attr, |
1083 | const char *buf, size_t count) |
1084 | { |
1085 | unsigned int val; |
1086 | int rc; |
1087 | |
1088 | if (kstrtouint(s: buf, base: 0, res: &val) || val > 1) |
1089 | return -EINVAL; |
1090 | |
1091 | rc = dasd_set_feature(to_ccwdev(dev), DASD_FEATURE_ERPLOG, val); |
1092 | |
1093 | return rc ? : count; |
1094 | } |
1095 | |
1096 | static DEVICE_ATTR(erplog, 0644, dasd_erplog_show, dasd_erplog_store); |
1097 | |
1098 | /* |
1099 | * use_diag controls whether the driver should use diag rather than ssch |
1100 | * to talk to the device |
1101 | */ |
1102 | static ssize_t |
1103 | dasd_use_diag_show(struct device *dev, struct device_attribute *attr, char *buf) |
1104 | { |
1105 | struct dasd_devmap *devmap; |
1106 | int use_diag; |
1107 | |
1108 | devmap = dasd_find_busid(bus_id: dev_name(dev)); |
1109 | if (!IS_ERR(devmap)) |
1110 | use_diag = (devmap->features & DASD_FEATURE_USEDIAG) != 0; |
1111 | else |
1112 | use_diag = (DASD_FEATURE_DEFAULT & DASD_FEATURE_USEDIAG) != 0; |
1113 | return sysfs_emit(buf, fmt: use_diag ? "1\n" : "0\n" ); |
1114 | } |
1115 | |
1116 | static ssize_t |
1117 | dasd_use_diag_store(struct device *dev, struct device_attribute *attr, |
1118 | const char *buf, size_t count) |
1119 | { |
1120 | struct dasd_devmap *devmap; |
1121 | unsigned int val; |
1122 | ssize_t rc; |
1123 | |
1124 | devmap = dasd_devmap_from_cdev(cdev: to_ccwdev(dev)); |
1125 | if (IS_ERR(ptr: devmap)) |
1126 | return PTR_ERR(ptr: devmap); |
1127 | |
1128 | if (kstrtouint(s: buf, base: 0, res: &val) || val > 1) |
1129 | return -EINVAL; |
1130 | |
1131 | spin_lock(lock: &dasd_devmap_lock); |
1132 | /* Changing diag discipline flag is only allowed in offline state. */ |
1133 | rc = count; |
1134 | if (!devmap->device && !(devmap->features & DASD_FEATURE_USERAW)) { |
1135 | if (val) |
1136 | devmap->features |= DASD_FEATURE_USEDIAG; |
1137 | else |
1138 | devmap->features &= ~DASD_FEATURE_USEDIAG; |
1139 | } else |
1140 | rc = -EPERM; |
1141 | spin_unlock(lock: &dasd_devmap_lock); |
1142 | return rc; |
1143 | } |
1144 | |
1145 | static DEVICE_ATTR(use_diag, 0644, dasd_use_diag_show, dasd_use_diag_store); |
1146 | |
1147 | /* |
1148 | * use_raw controls whether the driver should give access to raw eckd data or |
1149 | * operate in standard mode |
1150 | */ |
1151 | static ssize_t |
1152 | dasd_use_raw_show(struct device *dev, struct device_attribute *attr, char *buf) |
1153 | { |
1154 | struct dasd_devmap *devmap; |
1155 | int use_raw; |
1156 | |
1157 | devmap = dasd_find_busid(bus_id: dev_name(dev)); |
1158 | if (!IS_ERR(devmap)) |
1159 | use_raw = (devmap->features & DASD_FEATURE_USERAW) != 0; |
1160 | else |
1161 | use_raw = (DASD_FEATURE_DEFAULT & DASD_FEATURE_USERAW) != 0; |
1162 | return sysfs_emit(buf, fmt: use_raw ? "1\n" : "0\n" ); |
1163 | } |
1164 | |
1165 | static ssize_t |
1166 | dasd_use_raw_store(struct device *dev, struct device_attribute *attr, |
1167 | const char *buf, size_t count) |
1168 | { |
1169 | struct dasd_devmap *devmap; |
1170 | ssize_t rc; |
1171 | unsigned long val; |
1172 | |
1173 | devmap = dasd_devmap_from_cdev(cdev: to_ccwdev(dev)); |
1174 | if (IS_ERR(ptr: devmap)) |
1175 | return PTR_ERR(ptr: devmap); |
1176 | |
1177 | if ((kstrtoul(s: buf, base: 10, res: &val) != 0) || val > 1) |
1178 | return -EINVAL; |
1179 | |
1180 | spin_lock(lock: &dasd_devmap_lock); |
1181 | /* Changing diag discipline flag is only allowed in offline state. */ |
1182 | rc = count; |
1183 | if (!devmap->device && !(devmap->features & DASD_FEATURE_USEDIAG)) { |
1184 | if (val) |
1185 | devmap->features |= DASD_FEATURE_USERAW; |
1186 | else |
1187 | devmap->features &= ~DASD_FEATURE_USERAW; |
1188 | } else |
1189 | rc = -EPERM; |
1190 | spin_unlock(lock: &dasd_devmap_lock); |
1191 | return rc; |
1192 | } |
1193 | |
1194 | static DEVICE_ATTR(raw_track_access, 0644, dasd_use_raw_show, |
1195 | dasd_use_raw_store); |
1196 | |
1197 | static ssize_t |
1198 | dasd_safe_offline_store(struct device *dev, struct device_attribute *attr, |
1199 | const char *buf, size_t count) |
1200 | { |
1201 | struct ccw_device *cdev = to_ccwdev(dev); |
1202 | struct dasd_device *device; |
1203 | unsigned long flags; |
1204 | int rc; |
1205 | |
1206 | spin_lock_irqsave(get_ccwdev_lock(cdev), flags); |
1207 | device = dasd_device_from_cdev_locked(cdev); |
1208 | if (IS_ERR(ptr: device)) { |
1209 | rc = PTR_ERR(ptr: device); |
1210 | spin_unlock_irqrestore(lock: get_ccwdev_lock(cdev), flags); |
1211 | goto out; |
1212 | } |
1213 | |
1214 | if (test_bit(DASD_FLAG_OFFLINE, &device->flags) || |
1215 | test_bit(DASD_FLAG_SAFE_OFFLINE_RUNNING, &device->flags)) { |
1216 | /* Already doing offline processing */ |
1217 | dasd_put_device(device); |
1218 | spin_unlock_irqrestore(lock: get_ccwdev_lock(cdev), flags); |
1219 | rc = -EBUSY; |
1220 | goto out; |
1221 | } |
1222 | |
1223 | set_bit(DASD_FLAG_SAFE_OFFLINE, addr: &device->flags); |
1224 | dasd_put_device(device); |
1225 | spin_unlock_irqrestore(lock: get_ccwdev_lock(cdev), flags); |
1226 | |
1227 | rc = ccw_device_set_offline(cdev); |
1228 | |
1229 | out: |
1230 | return rc ? rc : count; |
1231 | } |
1232 | |
1233 | static DEVICE_ATTR(safe_offline, 0200, NULL, dasd_safe_offline_store); |
1234 | |
1235 | static ssize_t |
1236 | dasd_access_show(struct device *dev, struct device_attribute *attr, |
1237 | char *buf) |
1238 | { |
1239 | struct ccw_device *cdev = to_ccwdev(dev); |
1240 | struct dasd_device *device; |
1241 | int count; |
1242 | |
1243 | device = dasd_device_from_cdev(cdev); |
1244 | if (IS_ERR(ptr: device)) |
1245 | return PTR_ERR(ptr: device); |
1246 | |
1247 | if (!device->discipline) |
1248 | count = -ENODEV; |
1249 | else if (!device->discipline->host_access_count) |
1250 | count = -EOPNOTSUPP; |
1251 | else |
1252 | count = device->discipline->host_access_count(device); |
1253 | |
1254 | dasd_put_device(device); |
1255 | if (count < 0) |
1256 | return count; |
1257 | |
1258 | return sysfs_emit(buf, fmt: "%d\n" , count); |
1259 | } |
1260 | |
1261 | static DEVICE_ATTR(host_access_count, 0444, dasd_access_show, NULL); |
1262 | |
1263 | static ssize_t |
1264 | dasd_discipline_show(struct device *dev, struct device_attribute *attr, |
1265 | char *buf) |
1266 | { |
1267 | struct dasd_device *device; |
1268 | ssize_t len; |
1269 | |
1270 | device = dasd_device_from_cdev(cdev: to_ccwdev(dev)); |
1271 | if (IS_ERR(ptr: device)) |
1272 | goto out; |
1273 | else if (!device->discipline) { |
1274 | dasd_put_device(device); |
1275 | goto out; |
1276 | } else { |
1277 | len = sysfs_emit(buf, fmt: "%s\n" , |
1278 | device->discipline->name); |
1279 | dasd_put_device(device); |
1280 | return len; |
1281 | } |
1282 | out: |
1283 | len = sysfs_emit(buf, fmt: "none\n" ); |
1284 | return len; |
1285 | } |
1286 | |
1287 | static DEVICE_ATTR(discipline, 0444, dasd_discipline_show, NULL); |
1288 | |
1289 | static ssize_t |
1290 | dasd_device_status_show(struct device *dev, struct device_attribute *attr, |
1291 | char *buf) |
1292 | { |
1293 | struct dasd_device *device; |
1294 | ssize_t len; |
1295 | |
1296 | device = dasd_device_from_cdev(cdev: to_ccwdev(dev)); |
1297 | if (!IS_ERR(ptr: device)) { |
1298 | switch (device->state) { |
1299 | case DASD_STATE_NEW: |
1300 | len = sysfs_emit(buf, fmt: "new\n" ); |
1301 | break; |
1302 | case DASD_STATE_KNOWN: |
1303 | len = sysfs_emit(buf, fmt: "detected\n" ); |
1304 | break; |
1305 | case DASD_STATE_BASIC: |
1306 | len = sysfs_emit(buf, fmt: "basic\n" ); |
1307 | break; |
1308 | case DASD_STATE_UNFMT: |
1309 | len = sysfs_emit(buf, fmt: "unformatted\n" ); |
1310 | break; |
1311 | case DASD_STATE_READY: |
1312 | len = sysfs_emit(buf, fmt: "ready\n" ); |
1313 | break; |
1314 | case DASD_STATE_ONLINE: |
1315 | len = sysfs_emit(buf, fmt: "online\n" ); |
1316 | break; |
1317 | default: |
1318 | len = sysfs_emit(buf, fmt: "no stat\n" ); |
1319 | break; |
1320 | } |
1321 | dasd_put_device(device); |
1322 | } else |
1323 | len = sysfs_emit(buf, fmt: "unknown\n" ); |
1324 | return len; |
1325 | } |
1326 | |
1327 | static DEVICE_ATTR(status, 0444, dasd_device_status_show, NULL); |
1328 | |
1329 | static ssize_t dasd_alias_show(struct device *dev, |
1330 | struct device_attribute *attr, char *buf) |
1331 | { |
1332 | struct dasd_device *device; |
1333 | struct dasd_uid uid; |
1334 | |
1335 | device = dasd_device_from_cdev(cdev: to_ccwdev(dev)); |
1336 | if (IS_ERR(ptr: device)) |
1337 | return sysfs_emit(buf, fmt: "0\n" ); |
1338 | |
1339 | if (device->discipline && device->discipline->get_uid && |
1340 | !device->discipline->get_uid(device, &uid)) { |
1341 | if (uid.type == UA_BASE_PAV_ALIAS || |
1342 | uid.type == UA_HYPER_PAV_ALIAS) { |
1343 | dasd_put_device(device); |
1344 | return sysfs_emit(buf, fmt: "1\n" ); |
1345 | } |
1346 | } |
1347 | dasd_put_device(device); |
1348 | |
1349 | return sysfs_emit(buf, fmt: "0\n" ); |
1350 | } |
1351 | |
1352 | static DEVICE_ATTR(alias, 0444, dasd_alias_show, NULL); |
1353 | |
1354 | static ssize_t dasd_vendor_show(struct device *dev, |
1355 | struct device_attribute *attr, char *buf) |
1356 | { |
1357 | struct dasd_device *device; |
1358 | struct dasd_uid uid; |
1359 | char *vendor; |
1360 | |
1361 | device = dasd_device_from_cdev(cdev: to_ccwdev(dev)); |
1362 | vendor = "" ; |
1363 | if (IS_ERR(ptr: device)) |
1364 | return sysfs_emit(buf, fmt: "%s\n" , vendor); |
1365 | |
1366 | if (device->discipline && device->discipline->get_uid && |
1367 | !device->discipline->get_uid(device, &uid)) |
1368 | vendor = uid.vendor; |
1369 | |
1370 | dasd_put_device(device); |
1371 | |
1372 | return sysfs_emit(buf, fmt: "%s\n" , vendor); |
1373 | } |
1374 | |
1375 | static DEVICE_ATTR(vendor, 0444, dasd_vendor_show, NULL); |
1376 | |
1377 | static ssize_t |
1378 | dasd_uid_show(struct device *dev, struct device_attribute *attr, char *buf) |
1379 | { |
1380 | char uid_string[DASD_UID_STRLEN]; |
1381 | struct dasd_device *device; |
1382 | struct dasd_uid uid; |
1383 | char ua_string[3]; |
1384 | |
1385 | device = dasd_device_from_cdev(cdev: to_ccwdev(dev)); |
1386 | uid_string[0] = 0; |
1387 | if (IS_ERR(ptr: device)) |
1388 | return sysfs_emit(buf, fmt: "%s\n" , uid_string); |
1389 | |
1390 | if (device->discipline && device->discipline->get_uid && |
1391 | !device->discipline->get_uid(device, &uid)) { |
1392 | switch (uid.type) { |
1393 | case UA_BASE_DEVICE: |
1394 | snprintf(buf: ua_string, size: sizeof(ua_string), fmt: "%02x" , |
1395 | uid.real_unit_addr); |
1396 | break; |
1397 | case UA_BASE_PAV_ALIAS: |
1398 | snprintf(buf: ua_string, size: sizeof(ua_string), fmt: "%02x" , |
1399 | uid.base_unit_addr); |
1400 | break; |
1401 | case UA_HYPER_PAV_ALIAS: |
1402 | snprintf(buf: ua_string, size: sizeof(ua_string), fmt: "xx" ); |
1403 | break; |
1404 | default: |
1405 | /* should not happen, treat like base device */ |
1406 | snprintf(buf: ua_string, size: sizeof(ua_string), fmt: "%02x" , |
1407 | uid.real_unit_addr); |
1408 | break; |
1409 | } |
1410 | |
1411 | snprintf(buf: uid_string, size: sizeof(uid_string), fmt: "%s.%s.%04x.%s%s%s" , |
1412 | uid.vendor, uid.serial, uid.ssid, ua_string, |
1413 | uid.vduit[0] ? "." : "" , uid.vduit); |
1414 | } |
1415 | dasd_put_device(device); |
1416 | |
1417 | return sysfs_emit(buf, fmt: "%s\n" , uid_string); |
1418 | } |
1419 | static DEVICE_ATTR(uid, 0444, dasd_uid_show, NULL); |
1420 | |
1421 | /* |
1422 | * extended error-reporting |
1423 | */ |
1424 | static ssize_t |
1425 | dasd_eer_show(struct device *dev, struct device_attribute *attr, char *buf) |
1426 | { |
1427 | struct dasd_devmap *devmap; |
1428 | int eer_flag; |
1429 | |
1430 | devmap = dasd_find_busid(bus_id: dev_name(dev)); |
1431 | if (!IS_ERR(ptr: devmap) && devmap->device) |
1432 | eer_flag = dasd_eer_enabled(devmap->device); |
1433 | else |
1434 | eer_flag = 0; |
1435 | return sysfs_emit(buf, fmt: eer_flag ? "1\n" : "0\n" ); |
1436 | } |
1437 | |
1438 | static ssize_t |
1439 | dasd_eer_store(struct device *dev, struct device_attribute *attr, |
1440 | const char *buf, size_t count) |
1441 | { |
1442 | struct dasd_device *device; |
1443 | unsigned int val; |
1444 | int rc = 0; |
1445 | |
1446 | device = dasd_device_from_cdev(cdev: to_ccwdev(dev)); |
1447 | if (IS_ERR(ptr: device)) |
1448 | return PTR_ERR(ptr: device); |
1449 | |
1450 | if (kstrtouint(s: buf, base: 0, res: &val) || val > 1) |
1451 | return -EINVAL; |
1452 | |
1453 | if (val) |
1454 | rc = dasd_eer_enable(device); |
1455 | else |
1456 | dasd_eer_disable(device); |
1457 | |
1458 | dasd_put_device(device); |
1459 | |
1460 | return rc ? : count; |
1461 | } |
1462 | |
1463 | static DEVICE_ATTR(eer_enabled, 0644, dasd_eer_show, dasd_eer_store); |
1464 | |
1465 | /* |
1466 | * aq_mask controls if the DASD should be quiesced on certain triggers |
1467 | * The aq_mask attribute is interpreted as bitmap of the DASD_EER_* triggers. |
1468 | */ |
1469 | static ssize_t dasd_aq_mask_show(struct device *dev, struct device_attribute *attr, |
1470 | char *buf) |
1471 | { |
1472 | struct dasd_devmap *devmap; |
1473 | unsigned int aq_mask = 0; |
1474 | |
1475 | devmap = dasd_find_busid(bus_id: dev_name(dev)); |
1476 | if (!IS_ERR(ptr: devmap)) |
1477 | aq_mask = devmap->aq_mask; |
1478 | |
1479 | return sysfs_emit(buf, fmt: "%d\n" , aq_mask); |
1480 | } |
1481 | |
1482 | static ssize_t dasd_aq_mask_store(struct device *dev, struct device_attribute *attr, |
1483 | const char *buf, size_t count) |
1484 | { |
1485 | struct dasd_devmap *devmap; |
1486 | unsigned int val; |
1487 | |
1488 | if (kstrtouint(s: buf, base: 0, res: &val) || val > DASD_EER_VALID) |
1489 | return -EINVAL; |
1490 | |
1491 | devmap = dasd_devmap_from_cdev(cdev: to_ccwdev(dev)); |
1492 | if (IS_ERR(ptr: devmap)) |
1493 | return PTR_ERR(ptr: devmap); |
1494 | |
1495 | spin_lock(lock: &dasd_devmap_lock); |
1496 | devmap->aq_mask = val; |
1497 | if (devmap->device) |
1498 | devmap->device->aq_mask = devmap->aq_mask; |
1499 | spin_unlock(lock: &dasd_devmap_lock); |
1500 | |
1501 | return count; |
1502 | } |
1503 | |
1504 | static DEVICE_ATTR(aq_mask, 0644, dasd_aq_mask_show, dasd_aq_mask_store); |
1505 | |
1506 | /* |
1507 | * aq_requeue controls if requests are returned to the blocklayer on quiesce |
1508 | * or if requests are only not started |
1509 | */ |
1510 | static ssize_t dasd_aqr_show(struct device *dev, struct device_attribute *attr, |
1511 | char *buf) |
1512 | { |
1513 | struct dasd_devmap *devmap; |
1514 | int flag; |
1515 | |
1516 | devmap = dasd_find_busid(bus_id: dev_name(dev)); |
1517 | if (!IS_ERR(devmap)) |
1518 | flag = (devmap->features & DASD_FEATURE_REQUEUEQUIESCE) != 0; |
1519 | else |
1520 | flag = (DASD_FEATURE_DEFAULT & |
1521 | DASD_FEATURE_REQUEUEQUIESCE) != 0; |
1522 | return sysfs_emit(buf, fmt: "%d\n" , flag); |
1523 | } |
1524 | |
1525 | static ssize_t dasd_aqr_store(struct device *dev, struct device_attribute *attr, |
1526 | const char *buf, size_t count) |
1527 | { |
1528 | bool val; |
1529 | int rc; |
1530 | |
1531 | if (kstrtobool(s: buf, res: &val)) |
1532 | return -EINVAL; |
1533 | |
1534 | rc = dasd_set_feature(to_ccwdev(dev), DASD_FEATURE_REQUEUEQUIESCE, val); |
1535 | |
1536 | return rc ? : count; |
1537 | } |
1538 | |
1539 | static DEVICE_ATTR(aq_requeue, 0644, dasd_aqr_show, dasd_aqr_store); |
1540 | |
1541 | /* |
1542 | * aq_timeouts controls how much retries have to time out until |
1543 | * a device gets autoquiesced |
1544 | */ |
1545 | static ssize_t |
1546 | dasd_aq_timeouts_show(struct device *dev, struct device_attribute *attr, |
1547 | char *buf) |
1548 | { |
1549 | struct dasd_device *device; |
1550 | int len; |
1551 | |
1552 | device = dasd_device_from_cdev(cdev: to_ccwdev(dev)); |
1553 | if (IS_ERR(ptr: device)) |
1554 | return -ENODEV; |
1555 | len = sysfs_emit(buf, fmt: "%u\n" , device->aq_timeouts); |
1556 | dasd_put_device(device); |
1557 | return len; |
1558 | } |
1559 | |
1560 | static ssize_t |
1561 | dasd_aq_timeouts_store(struct device *dev, struct device_attribute *attr, |
1562 | const char *buf, size_t count) |
1563 | { |
1564 | struct dasd_device *device; |
1565 | unsigned int val; |
1566 | |
1567 | device = dasd_device_from_cdev(cdev: to_ccwdev(dev)); |
1568 | if (IS_ERR(ptr: device)) |
1569 | return -ENODEV; |
1570 | |
1571 | if ((kstrtouint(s: buf, base: 10, res: &val) != 0) || |
1572 | val > DASD_RETRIES_MAX || val == 0) { |
1573 | dasd_put_device(device); |
1574 | return -EINVAL; |
1575 | } |
1576 | |
1577 | if (val) |
1578 | device->aq_timeouts = val; |
1579 | |
1580 | dasd_put_device(device); |
1581 | return count; |
1582 | } |
1583 | |
1584 | static DEVICE_ATTR(aq_timeouts, 0644, dasd_aq_timeouts_show, |
1585 | dasd_aq_timeouts_store); |
1586 | |
1587 | /* |
1588 | * expiration time for default requests |
1589 | */ |
1590 | static ssize_t |
1591 | dasd_expires_show(struct device *dev, struct device_attribute *attr, char *buf) |
1592 | { |
1593 | struct dasd_device *device; |
1594 | int len; |
1595 | |
1596 | device = dasd_device_from_cdev(cdev: to_ccwdev(dev)); |
1597 | if (IS_ERR(ptr: device)) |
1598 | return -ENODEV; |
1599 | len = sysfs_emit(buf, fmt: "%lu\n" , device->default_expires); |
1600 | dasd_put_device(device); |
1601 | return len; |
1602 | } |
1603 | |
1604 | static ssize_t |
1605 | dasd_expires_store(struct device *dev, struct device_attribute *attr, |
1606 | const char *buf, size_t count) |
1607 | { |
1608 | struct dasd_device *device; |
1609 | unsigned long val; |
1610 | |
1611 | device = dasd_device_from_cdev(cdev: to_ccwdev(dev)); |
1612 | if (IS_ERR(ptr: device)) |
1613 | return -ENODEV; |
1614 | |
1615 | if ((kstrtoul(s: buf, base: 10, res: &val) != 0) || |
1616 | (val > DASD_EXPIRES_MAX) || val == 0) { |
1617 | dasd_put_device(device); |
1618 | return -EINVAL; |
1619 | } |
1620 | |
1621 | if (val) |
1622 | device->default_expires = val; |
1623 | |
1624 | dasd_put_device(device); |
1625 | return count; |
1626 | } |
1627 | |
1628 | static DEVICE_ATTR(expires, 0644, dasd_expires_show, dasd_expires_store); |
1629 | |
1630 | static ssize_t |
1631 | dasd_retries_show(struct device *dev, struct device_attribute *attr, char *buf) |
1632 | { |
1633 | struct dasd_device *device; |
1634 | int len; |
1635 | |
1636 | device = dasd_device_from_cdev(cdev: to_ccwdev(dev)); |
1637 | if (IS_ERR(ptr: device)) |
1638 | return -ENODEV; |
1639 | len = sysfs_emit(buf, fmt: "%lu\n" , device->default_retries); |
1640 | dasd_put_device(device); |
1641 | return len; |
1642 | } |
1643 | |
1644 | static ssize_t |
1645 | dasd_retries_store(struct device *dev, struct device_attribute *attr, |
1646 | const char *buf, size_t count) |
1647 | { |
1648 | struct dasd_device *device; |
1649 | unsigned long val; |
1650 | |
1651 | device = dasd_device_from_cdev(cdev: to_ccwdev(dev)); |
1652 | if (IS_ERR(ptr: device)) |
1653 | return -ENODEV; |
1654 | |
1655 | if ((kstrtoul(s: buf, base: 10, res: &val) != 0) || |
1656 | (val > DASD_RETRIES_MAX)) { |
1657 | dasd_put_device(device); |
1658 | return -EINVAL; |
1659 | } |
1660 | |
1661 | if (val) |
1662 | device->default_retries = val; |
1663 | |
1664 | dasd_put_device(device); |
1665 | return count; |
1666 | } |
1667 | |
1668 | static DEVICE_ATTR(retries, 0644, dasd_retries_show, dasd_retries_store); |
1669 | |
1670 | static ssize_t |
1671 | dasd_timeout_show(struct device *dev, struct device_attribute *attr, |
1672 | char *buf) |
1673 | { |
1674 | struct dasd_device *device; |
1675 | int len; |
1676 | |
1677 | device = dasd_device_from_cdev(cdev: to_ccwdev(dev)); |
1678 | if (IS_ERR(ptr: device)) |
1679 | return -ENODEV; |
1680 | len = sysfs_emit(buf, fmt: "%lu\n" , device->blk_timeout); |
1681 | dasd_put_device(device); |
1682 | return len; |
1683 | } |
1684 | |
1685 | static ssize_t |
1686 | dasd_timeout_store(struct device *dev, struct device_attribute *attr, |
1687 | const char *buf, size_t count) |
1688 | { |
1689 | struct dasd_device *device; |
1690 | unsigned long val; |
1691 | |
1692 | device = dasd_device_from_cdev(cdev: to_ccwdev(dev)); |
1693 | if (IS_ERR(ptr: device) || !device->block) |
1694 | return -ENODEV; |
1695 | |
1696 | if ((kstrtoul(s: buf, base: 10, res: &val) != 0) || |
1697 | val > UINT_MAX / HZ) { |
1698 | dasd_put_device(device); |
1699 | return -EINVAL; |
1700 | } |
1701 | if (!device->block->gdp) { |
1702 | dasd_put_device(device); |
1703 | return -ENODEV; |
1704 | } |
1705 | |
1706 | device->blk_timeout = val; |
1707 | blk_queue_rq_timeout(device->block->gdp->queue, val * HZ); |
1708 | |
1709 | dasd_put_device(device); |
1710 | return count; |
1711 | } |
1712 | |
1713 | static DEVICE_ATTR(timeout, 0644, |
1714 | dasd_timeout_show, dasd_timeout_store); |
1715 | |
1716 | |
1717 | static ssize_t |
1718 | dasd_path_reset_store(struct device *dev, struct device_attribute *attr, |
1719 | const char *buf, size_t count) |
1720 | { |
1721 | struct dasd_device *device; |
1722 | unsigned int val; |
1723 | |
1724 | device = dasd_device_from_cdev(cdev: to_ccwdev(dev)); |
1725 | if (IS_ERR(ptr: device)) |
1726 | return -ENODEV; |
1727 | |
1728 | if ((kstrtouint(s: buf, base: 16, res: &val) != 0) || val > 0xff) |
1729 | val = 0; |
1730 | |
1731 | if (device->discipline && device->discipline->reset_path) |
1732 | device->discipline->reset_path(device, (__u8) val); |
1733 | |
1734 | dasd_put_device(device); |
1735 | return count; |
1736 | } |
1737 | |
1738 | static DEVICE_ATTR(path_reset, 0200, NULL, dasd_path_reset_store); |
1739 | |
1740 | static ssize_t dasd_hpf_show(struct device *dev, struct device_attribute *attr, |
1741 | char *buf) |
1742 | { |
1743 | struct dasd_device *device; |
1744 | int hpf; |
1745 | |
1746 | device = dasd_device_from_cdev(cdev: to_ccwdev(dev)); |
1747 | if (IS_ERR(ptr: device)) |
1748 | return -ENODEV; |
1749 | if (!device->discipline || !device->discipline->hpf_enabled) { |
1750 | dasd_put_device(device); |
1751 | return sysfs_emit(buf, fmt: "%d\n" , dasd_nofcx); |
1752 | } |
1753 | hpf = device->discipline->hpf_enabled(device); |
1754 | dasd_put_device(device); |
1755 | return sysfs_emit(buf, fmt: "%d\n" , hpf); |
1756 | } |
1757 | |
1758 | static DEVICE_ATTR(hpf, 0444, dasd_hpf_show, NULL); |
1759 | |
1760 | static ssize_t dasd_reservation_policy_show(struct device *dev, |
1761 | struct device_attribute *attr, |
1762 | char *buf) |
1763 | { |
1764 | struct dasd_devmap *devmap; |
1765 | int rc = 0; |
1766 | |
1767 | devmap = dasd_find_busid(bus_id: dev_name(dev)); |
1768 | if (IS_ERR(ptr: devmap)) { |
1769 | rc = sysfs_emit(buf, fmt: "ignore\n" ); |
1770 | } else { |
1771 | spin_lock(lock: &dasd_devmap_lock); |
1772 | if (devmap->features & DASD_FEATURE_FAILONSLCK) |
1773 | rc = sysfs_emit(buf, fmt: "fail\n" ); |
1774 | else |
1775 | rc = sysfs_emit(buf, fmt: "ignore\n" ); |
1776 | spin_unlock(lock: &dasd_devmap_lock); |
1777 | } |
1778 | return rc; |
1779 | } |
1780 | |
1781 | static ssize_t dasd_reservation_policy_store(struct device *dev, |
1782 | struct device_attribute *attr, |
1783 | const char *buf, size_t count) |
1784 | { |
1785 | struct ccw_device *cdev = to_ccwdev(dev); |
1786 | int rc; |
1787 | |
1788 | if (sysfs_streq(s1: "ignore" , s2: buf)) |
1789 | rc = dasd_set_feature(cdev, DASD_FEATURE_FAILONSLCK, 0); |
1790 | else if (sysfs_streq(s1: "fail" , s2: buf)) |
1791 | rc = dasd_set_feature(cdev, DASD_FEATURE_FAILONSLCK, 1); |
1792 | else |
1793 | rc = -EINVAL; |
1794 | |
1795 | return rc ? : count; |
1796 | } |
1797 | |
1798 | static DEVICE_ATTR(reservation_policy, 0644, |
1799 | dasd_reservation_policy_show, dasd_reservation_policy_store); |
1800 | |
1801 | static ssize_t dasd_reservation_state_show(struct device *dev, |
1802 | struct device_attribute *attr, |
1803 | char *buf) |
1804 | { |
1805 | struct dasd_device *device; |
1806 | int rc = 0; |
1807 | |
1808 | device = dasd_device_from_cdev(cdev: to_ccwdev(dev)); |
1809 | if (IS_ERR(ptr: device)) |
1810 | return sysfs_emit(buf, fmt: "none\n" ); |
1811 | |
1812 | if (test_bit(DASD_FLAG_IS_RESERVED, &device->flags)) |
1813 | rc = sysfs_emit(buf, fmt: "reserved\n" ); |
1814 | else if (test_bit(DASD_FLAG_LOCK_STOLEN, &device->flags)) |
1815 | rc = sysfs_emit(buf, fmt: "lost\n" ); |
1816 | else |
1817 | rc = sysfs_emit(buf, fmt: "none\n" ); |
1818 | dasd_put_device(device); |
1819 | return rc; |
1820 | } |
1821 | |
1822 | static ssize_t dasd_reservation_state_store(struct device *dev, |
1823 | struct device_attribute *attr, |
1824 | const char *buf, size_t count) |
1825 | { |
1826 | struct dasd_device *device; |
1827 | int rc = 0; |
1828 | |
1829 | device = dasd_device_from_cdev(cdev: to_ccwdev(dev)); |
1830 | if (IS_ERR(ptr: device)) |
1831 | return -ENODEV; |
1832 | if (sysfs_streq(s1: "reset" , s2: buf)) |
1833 | clear_bit(DASD_FLAG_LOCK_STOLEN, addr: &device->flags); |
1834 | else |
1835 | rc = -EINVAL; |
1836 | dasd_put_device(device); |
1837 | |
1838 | if (rc) |
1839 | return rc; |
1840 | else |
1841 | return count; |
1842 | } |
1843 | |
1844 | static DEVICE_ATTR(last_known_reservation_state, 0644, |
1845 | dasd_reservation_state_show, dasd_reservation_state_store); |
1846 | |
1847 | static ssize_t dasd_pm_show(struct device *dev, |
1848 | struct device_attribute *attr, char *buf) |
1849 | { |
1850 | struct dasd_device *device; |
1851 | u8 opm, nppm, cablepm, cuirpm, hpfpm, ifccpm; |
1852 | |
1853 | device = dasd_device_from_cdev(cdev: to_ccwdev(dev)); |
1854 | if (IS_ERR(ptr: device)) |
1855 | return sysfs_emit(buf, fmt: "0\n" ); |
1856 | |
1857 | opm = dasd_path_get_opm(device); |
1858 | nppm = dasd_path_get_nppm(device); |
1859 | cablepm = dasd_path_get_cablepm(device); |
1860 | cuirpm = dasd_path_get_cuirpm(device); |
1861 | hpfpm = dasd_path_get_hpfpm(device); |
1862 | ifccpm = dasd_path_get_ifccpm(device); |
1863 | dasd_put_device(device); |
1864 | |
1865 | return sysfs_emit(buf, fmt: "%02x %02x %02x %02x %02x %02x\n" , opm, nppm, |
1866 | cablepm, cuirpm, hpfpm, ifccpm); |
1867 | } |
1868 | |
1869 | static DEVICE_ATTR(path_masks, 0444, dasd_pm_show, NULL); |
1870 | |
1871 | /* |
1872 | * threshold value for IFCC/CCC errors |
1873 | */ |
1874 | static ssize_t |
1875 | dasd_path_threshold_show(struct device *dev, |
1876 | struct device_attribute *attr, char *buf) |
1877 | { |
1878 | struct dasd_device *device; |
1879 | int len; |
1880 | |
1881 | device = dasd_device_from_cdev(cdev: to_ccwdev(dev)); |
1882 | if (IS_ERR(ptr: device)) |
1883 | return -ENODEV; |
1884 | len = sysfs_emit(buf, fmt: "%lu\n" , device->path_thrhld); |
1885 | dasd_put_device(device); |
1886 | return len; |
1887 | } |
1888 | |
1889 | static ssize_t |
1890 | dasd_path_threshold_store(struct device *dev, struct device_attribute *attr, |
1891 | const char *buf, size_t count) |
1892 | { |
1893 | struct dasd_device *device; |
1894 | unsigned long flags; |
1895 | unsigned long val; |
1896 | |
1897 | device = dasd_device_from_cdev(cdev: to_ccwdev(dev)); |
1898 | if (IS_ERR(ptr: device)) |
1899 | return -ENODEV; |
1900 | |
1901 | if (kstrtoul(s: buf, base: 10, res: &val) != 0 || val > DASD_THRHLD_MAX) { |
1902 | dasd_put_device(device); |
1903 | return -EINVAL; |
1904 | } |
1905 | spin_lock_irqsave(get_ccwdev_lock(to_ccwdev(dev)), flags); |
1906 | device->path_thrhld = val; |
1907 | spin_unlock_irqrestore(lock: get_ccwdev_lock(to_ccwdev(dev)), flags); |
1908 | dasd_put_device(device); |
1909 | return count; |
1910 | } |
1911 | static DEVICE_ATTR(path_threshold, 0644, dasd_path_threshold_show, |
1912 | dasd_path_threshold_store); |
1913 | |
1914 | /* |
1915 | * configure if path is disabled after IFCC/CCC error threshold is |
1916 | * exceeded |
1917 | */ |
1918 | static ssize_t |
1919 | dasd_path_autodisable_show(struct device *dev, |
1920 | struct device_attribute *attr, char *buf) |
1921 | { |
1922 | struct dasd_devmap *devmap; |
1923 | int flag; |
1924 | |
1925 | devmap = dasd_find_busid(bus_id: dev_name(dev)); |
1926 | if (!IS_ERR(devmap)) |
1927 | flag = (devmap->features & DASD_FEATURE_PATH_AUTODISABLE) != 0; |
1928 | else |
1929 | flag = (DASD_FEATURE_DEFAULT & |
1930 | DASD_FEATURE_PATH_AUTODISABLE) != 0; |
1931 | return sysfs_emit(buf, fmt: flag ? "1\n" : "0\n" ); |
1932 | } |
1933 | |
1934 | static ssize_t |
1935 | dasd_path_autodisable_store(struct device *dev, |
1936 | struct device_attribute *attr, |
1937 | const char *buf, size_t count) |
1938 | { |
1939 | unsigned int val; |
1940 | int rc; |
1941 | |
1942 | if (kstrtouint(s: buf, base: 0, res: &val) || val > 1) |
1943 | return -EINVAL; |
1944 | |
1945 | rc = dasd_set_feature(to_ccwdev(dev), |
1946 | DASD_FEATURE_PATH_AUTODISABLE, val); |
1947 | |
1948 | return rc ? : count; |
1949 | } |
1950 | |
1951 | static DEVICE_ATTR(path_autodisable, 0644, |
1952 | dasd_path_autodisable_show, |
1953 | dasd_path_autodisable_store); |
1954 | /* |
1955 | * interval for IFCC/CCC checks |
1956 | * meaning time with no IFCC/CCC error before the error counter |
1957 | * gets reset |
1958 | */ |
1959 | static ssize_t |
1960 | dasd_path_interval_show(struct device *dev, |
1961 | struct device_attribute *attr, char *buf) |
1962 | { |
1963 | struct dasd_device *device; |
1964 | int len; |
1965 | |
1966 | device = dasd_device_from_cdev(cdev: to_ccwdev(dev)); |
1967 | if (IS_ERR(ptr: device)) |
1968 | return -ENODEV; |
1969 | len = sysfs_emit(buf, fmt: "%lu\n" , device->path_interval); |
1970 | dasd_put_device(device); |
1971 | return len; |
1972 | } |
1973 | |
1974 | static ssize_t |
1975 | dasd_path_interval_store(struct device *dev, struct device_attribute *attr, |
1976 | const char *buf, size_t count) |
1977 | { |
1978 | struct dasd_device *device; |
1979 | unsigned long flags; |
1980 | unsigned long val; |
1981 | |
1982 | device = dasd_device_from_cdev(cdev: to_ccwdev(dev)); |
1983 | if (IS_ERR(ptr: device)) |
1984 | return -ENODEV; |
1985 | |
1986 | if ((kstrtoul(s: buf, base: 10, res: &val) != 0) || |
1987 | (val > DASD_INTERVAL_MAX) || val == 0) { |
1988 | dasd_put_device(device); |
1989 | return -EINVAL; |
1990 | } |
1991 | spin_lock_irqsave(get_ccwdev_lock(to_ccwdev(dev)), flags); |
1992 | if (val) |
1993 | device->path_interval = val; |
1994 | spin_unlock_irqrestore(lock: get_ccwdev_lock(to_ccwdev(dev)), flags); |
1995 | dasd_put_device(device); |
1996 | return count; |
1997 | } |
1998 | |
1999 | static DEVICE_ATTR(path_interval, 0644, dasd_path_interval_show, |
2000 | dasd_path_interval_store); |
2001 | |
2002 | static ssize_t |
2003 | dasd_device_fcs_show(struct device *dev, struct device_attribute *attr, |
2004 | char *buf) |
2005 | { |
2006 | struct dasd_device *device; |
2007 | int fc_sec; |
2008 | int rc; |
2009 | |
2010 | device = dasd_device_from_cdev(cdev: to_ccwdev(dev)); |
2011 | if (IS_ERR(ptr: device)) |
2012 | return -ENODEV; |
2013 | fc_sec = dasd_path_get_fcs_device(device); |
2014 | if (fc_sec == -EINVAL) |
2015 | rc = sysfs_emit(buf, fmt: "Inconsistent\n" ); |
2016 | else |
2017 | rc = sysfs_emit(buf, fmt: "%s\n" , dasd_path_get_fcs_str(val: fc_sec)); |
2018 | dasd_put_device(device); |
2019 | |
2020 | return rc; |
2021 | } |
2022 | static DEVICE_ATTR(fc_security, 0444, dasd_device_fcs_show, NULL); |
2023 | |
2024 | static ssize_t |
2025 | dasd_path_fcs_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) |
2026 | { |
2027 | struct dasd_path *path = to_dasd_path(kobj); |
2028 | unsigned int fc_sec = path->fc_security; |
2029 | |
2030 | return sysfs_emit(buf, fmt: "%s\n" , dasd_path_get_fcs_str(val: fc_sec)); |
2031 | } |
2032 | |
2033 | static struct kobj_attribute path_fcs_attribute = |
2034 | __ATTR(fc_security, 0444, dasd_path_fcs_show, NULL); |
2035 | |
2036 | /* |
2037 | * print copy relation in the form |
2038 | * primary,secondary[1] primary,secondary[2], ... |
2039 | */ |
2040 | static ssize_t |
2041 | dasd_copy_pair_show(struct device *dev, |
2042 | struct device_attribute *attr, char *buf) |
2043 | { |
2044 | char prim_busid[DASD_BUS_ID_SIZE]; |
2045 | struct dasd_copy_relation *copy; |
2046 | struct dasd_devmap *devmap; |
2047 | int len = 0; |
2048 | int i; |
2049 | |
2050 | devmap = dasd_find_busid(bus_id: dev_name(dev)); |
2051 | if (IS_ERR(ptr: devmap)) |
2052 | return -ENODEV; |
2053 | |
2054 | if (!devmap->copy) |
2055 | return -ENODEV; |
2056 | |
2057 | copy = devmap->copy; |
2058 | /* find primary */ |
2059 | for (i = 0; i < DASD_CP_ENTRIES; i++) { |
2060 | if (copy->entry[i].configured && copy->entry[i].primary) { |
2061 | strscpy(prim_busid, copy->entry[i].busid, |
2062 | DASD_BUS_ID_SIZE); |
2063 | break; |
2064 | } |
2065 | } |
2066 | if (i == DASD_CP_ENTRIES) |
2067 | goto out; |
2068 | |
2069 | /* print all secondary */ |
2070 | for (i = 0; i < DASD_CP_ENTRIES; i++) { |
2071 | if (copy->entry[i].configured && !copy->entry[i].primary) |
2072 | len += sysfs_emit_at(buf, at: len, fmt: "%s,%s " , prim_busid, |
2073 | copy->entry[i].busid); |
2074 | } |
2075 | |
2076 | len += sysfs_emit_at(buf, at: len, fmt: "\n" ); |
2077 | out: |
2078 | return len; |
2079 | } |
2080 | |
2081 | static int dasd_devmap_set_copy_relation(struct dasd_devmap *devmap, |
2082 | struct dasd_copy_relation *copy, |
2083 | char *busid, bool primary) |
2084 | { |
2085 | int i; |
2086 | |
2087 | /* find free entry */ |
2088 | for (i = 0; i < DASD_CP_ENTRIES; i++) { |
2089 | /* current bus_id already included, nothing to do */ |
2090 | if (copy->entry[i].configured && |
2091 | strncmp(copy->entry[i].busid, busid, DASD_BUS_ID_SIZE) == 0) |
2092 | return 0; |
2093 | |
2094 | if (!copy->entry[i].configured) |
2095 | break; |
2096 | } |
2097 | if (i == DASD_CP_ENTRIES) |
2098 | return -EINVAL; |
2099 | |
2100 | copy->entry[i].configured = true; |
2101 | strscpy(copy->entry[i].busid, busid, DASD_BUS_ID_SIZE); |
2102 | if (primary) { |
2103 | copy->active = ©->entry[i]; |
2104 | copy->entry[i].primary = true; |
2105 | } |
2106 | if (!devmap->copy) |
2107 | devmap->copy = copy; |
2108 | |
2109 | return 0; |
2110 | } |
2111 | |
2112 | static void dasd_devmap_del_copy_relation(struct dasd_copy_relation *copy, |
2113 | char *busid) |
2114 | { |
2115 | int i; |
2116 | |
2117 | spin_lock(lock: &dasd_devmap_lock); |
2118 | /* find entry */ |
2119 | for (i = 0; i < DASD_CP_ENTRIES; i++) { |
2120 | if (copy->entry[i].configured && |
2121 | strncmp(copy->entry[i].busid, busid, DASD_BUS_ID_SIZE) == 0) |
2122 | break; |
2123 | } |
2124 | if (i == DASD_CP_ENTRIES || !copy->entry[i].configured) { |
2125 | spin_unlock(lock: &dasd_devmap_lock); |
2126 | return; |
2127 | } |
2128 | |
2129 | copy->entry[i].configured = false; |
2130 | memset(copy->entry[i].busid, 0, DASD_BUS_ID_SIZE); |
2131 | if (copy->active == ©->entry[i]) { |
2132 | copy->active = NULL; |
2133 | copy->entry[i].primary = false; |
2134 | } |
2135 | spin_unlock(lock: &dasd_devmap_lock); |
2136 | } |
2137 | |
2138 | static int dasd_devmap_clear_copy_relation(struct device *dev) |
2139 | { |
2140 | struct dasd_copy_relation *copy; |
2141 | struct dasd_devmap *devmap; |
2142 | int i, rc = 1; |
2143 | |
2144 | devmap = dasd_devmap_from_cdev(cdev: to_ccwdev(dev)); |
2145 | if (IS_ERR(ptr: devmap)) |
2146 | return 1; |
2147 | |
2148 | spin_lock(lock: &dasd_devmap_lock); |
2149 | if (!devmap->copy) |
2150 | goto out; |
2151 | |
2152 | copy = devmap->copy; |
2153 | /* first check if all secondary devices are offline*/ |
2154 | for (i = 0; i < DASD_CP_ENTRIES; i++) { |
2155 | if (!copy->entry[i].configured) |
2156 | continue; |
2157 | |
2158 | if (copy->entry[i].device == copy->active->device) |
2159 | continue; |
2160 | |
2161 | if (copy->entry[i].device) |
2162 | goto out; |
2163 | } |
2164 | /* clear all devmap entries */ |
2165 | for (i = 0; i < DASD_CP_ENTRIES; i++) { |
2166 | if (strlen(copy->entry[i].busid) == 0) |
2167 | continue; |
2168 | if (copy->entry[i].device) { |
2169 | dasd_put_device(device: copy->entry[i].device); |
2170 | copy->entry[i].device->copy = NULL; |
2171 | copy->entry[i].device = NULL; |
2172 | } |
2173 | devmap = dasd_find_busid_locked(bus_id: copy->entry[i].busid); |
2174 | devmap->copy = NULL; |
2175 | memset(copy->entry[i].busid, 0, DASD_BUS_ID_SIZE); |
2176 | } |
2177 | kfree(objp: copy); |
2178 | rc = 0; |
2179 | out: |
2180 | spin_unlock(lock: &dasd_devmap_lock); |
2181 | return rc; |
2182 | } |
2183 | |
2184 | /* |
2185 | * parse BUSIDs from a copy pair |
2186 | */ |
2187 | static int dasd_devmap_parse_busid(const char *buf, char *prim_busid, |
2188 | char *sec_busid) |
2189 | { |
2190 | char *primary, *secondary, *tmp, *pt; |
2191 | int id0, id1, id2; |
2192 | |
2193 | pt = kstrdup(s: buf, GFP_KERNEL); |
2194 | tmp = pt; |
2195 | if (!tmp) |
2196 | return -ENOMEM; |
2197 | |
2198 | primary = strsep(&tmp, "," ); |
2199 | if (!primary) { |
2200 | kfree(objp: pt); |
2201 | return -EINVAL; |
2202 | } |
2203 | secondary = strsep(&tmp, "," ); |
2204 | if (!secondary) { |
2205 | kfree(objp: pt); |
2206 | return -EINVAL; |
2207 | } |
2208 | if (dasd_busid(str: primary, id0: &id0, id1: &id1, devno: &id2)) { |
2209 | kfree(objp: pt); |
2210 | return -EINVAL; |
2211 | } |
2212 | sprintf(buf: prim_busid, fmt: "%01x.%01x.%04x" , id0, id1, id2); |
2213 | if (dasd_busid(str: secondary, id0: &id0, id1: &id1, devno: &id2)) { |
2214 | kfree(objp: pt); |
2215 | return -EINVAL; |
2216 | } |
2217 | sprintf(buf: sec_busid, fmt: "%01x.%01x.%04x" , id0, id1, id2); |
2218 | kfree(objp: pt); |
2219 | |
2220 | return 0; |
2221 | } |
2222 | |
2223 | static ssize_t dasd_copy_pair_store(struct device *dev, |
2224 | struct device_attribute *attr, |
2225 | const char *buf, size_t count) |
2226 | { |
2227 | struct dasd_devmap *prim_devmap, *sec_devmap; |
2228 | char prim_busid[DASD_BUS_ID_SIZE]; |
2229 | char sec_busid[DASD_BUS_ID_SIZE]; |
2230 | struct dasd_copy_relation *copy; |
2231 | struct dasd_device *device; |
2232 | bool pprc_enabled; |
2233 | int rc; |
2234 | |
2235 | if (strncmp(buf, "clear" , strlen("clear" )) == 0) { |
2236 | if (dasd_devmap_clear_copy_relation(dev)) |
2237 | return -EINVAL; |
2238 | return count; |
2239 | } |
2240 | |
2241 | rc = dasd_devmap_parse_busid(buf, prim_busid, sec_busid); |
2242 | if (rc) |
2243 | return rc; |
2244 | |
2245 | if (strncmp(dev_name(dev), prim_busid, DASD_BUS_ID_SIZE) != 0 && |
2246 | strncmp(dev_name(dev), sec_busid, DASD_BUS_ID_SIZE) != 0) |
2247 | return -EINVAL; |
2248 | |
2249 | /* allocate primary devmap if needed */ |
2250 | prim_devmap = dasd_find_busid(bus_id: prim_busid); |
2251 | if (IS_ERR(prim_devmap)) |
2252 | prim_devmap = dasd_add_busid(prim_busid, DASD_FEATURE_DEFAULT); |
2253 | |
2254 | /* allocate secondary devmap if needed */ |
2255 | sec_devmap = dasd_find_busid(bus_id: sec_busid); |
2256 | if (IS_ERR(sec_devmap)) |
2257 | sec_devmap = dasd_add_busid(sec_busid, DASD_FEATURE_DEFAULT); |
2258 | |
2259 | /* setting copy relation is only allowed for offline secondary */ |
2260 | if (sec_devmap->device) |
2261 | return -EINVAL; |
2262 | |
2263 | if (prim_devmap->copy) { |
2264 | copy = prim_devmap->copy; |
2265 | } else if (sec_devmap->copy) { |
2266 | copy = sec_devmap->copy; |
2267 | } else { |
2268 | copy = kzalloc(size: sizeof(*copy), GFP_KERNEL); |
2269 | if (!copy) |
2270 | return -ENOMEM; |
2271 | } |
2272 | spin_lock(lock: &dasd_devmap_lock); |
2273 | rc = dasd_devmap_set_copy_relation(devmap: prim_devmap, copy, busid: prim_busid, primary: true); |
2274 | if (rc) { |
2275 | spin_unlock(lock: &dasd_devmap_lock); |
2276 | return rc; |
2277 | } |
2278 | rc = dasd_devmap_set_copy_relation(devmap: sec_devmap, copy, busid: sec_busid, primary: false); |
2279 | if (rc) { |
2280 | spin_unlock(lock: &dasd_devmap_lock); |
2281 | return rc; |
2282 | } |
2283 | spin_unlock(lock: &dasd_devmap_lock); |
2284 | |
2285 | /* if primary device is already online call device setup directly */ |
2286 | if (prim_devmap->device && !prim_devmap->device->copy) { |
2287 | device = prim_devmap->device; |
2288 | if (device->discipline->pprc_enabled) { |
2289 | pprc_enabled = device->discipline->pprc_enabled(device); |
2290 | rc = dasd_devmap_set_device_copy_relation(device->cdev, |
2291 | pprc_enabled); |
2292 | } else { |
2293 | rc = -EOPNOTSUPP; |
2294 | } |
2295 | } |
2296 | if (rc) { |
2297 | dasd_devmap_del_copy_relation(copy, busid: prim_busid); |
2298 | dasd_devmap_del_copy_relation(copy, busid: sec_busid); |
2299 | count = rc; |
2300 | } |
2301 | |
2302 | return count; |
2303 | } |
2304 | static DEVICE_ATTR(copy_pair, 0644, dasd_copy_pair_show, |
2305 | dasd_copy_pair_store); |
2306 | |
2307 | static ssize_t |
2308 | dasd_copy_role_show(struct device *dev, |
2309 | struct device_attribute *attr, char *buf) |
2310 | { |
2311 | struct dasd_copy_relation *copy; |
2312 | struct dasd_device *device; |
2313 | int len, i; |
2314 | |
2315 | device = dasd_device_from_cdev(cdev: to_ccwdev(dev)); |
2316 | if (IS_ERR(ptr: device)) |
2317 | return -ENODEV; |
2318 | |
2319 | if (!device->copy) { |
2320 | len = sysfs_emit(buf, fmt: "none\n" ); |
2321 | goto out; |
2322 | } |
2323 | copy = device->copy; |
2324 | /* only the active device is primary */ |
2325 | if (copy->active->device == device) { |
2326 | len = sysfs_emit(buf, fmt: "primary\n" ); |
2327 | goto out; |
2328 | } |
2329 | for (i = 0; i < DASD_CP_ENTRIES; i++) { |
2330 | if (copy->entry[i].device == device) { |
2331 | len = sysfs_emit(buf, fmt: "secondary\n" ); |
2332 | goto out; |
2333 | } |
2334 | } |
2335 | /* not in the list, no COPY role */ |
2336 | len = sysfs_emit(buf, fmt: "none\n" ); |
2337 | out: |
2338 | dasd_put_device(device); |
2339 | return len; |
2340 | } |
2341 | static DEVICE_ATTR(copy_role, 0444, dasd_copy_role_show, NULL); |
2342 | |
2343 | static ssize_t dasd_device_ping(struct device *dev, |
2344 | struct device_attribute *attr, |
2345 | const char *buf, size_t count) |
2346 | { |
2347 | struct dasd_device *device; |
2348 | size_t rc; |
2349 | |
2350 | device = dasd_device_from_cdev(cdev: to_ccwdev(dev)); |
2351 | if (IS_ERR(ptr: device)) |
2352 | return -ENODEV; |
2353 | |
2354 | /* |
2355 | * do not try during offline processing |
2356 | * early check only |
2357 | * the sleep_on function itself checks for offline |
2358 | * processing again |
2359 | */ |
2360 | if (test_bit(DASD_FLAG_OFFLINE, &device->flags)) { |
2361 | rc = -EBUSY; |
2362 | goto out; |
2363 | } |
2364 | if (!device->discipline || !device->discipline->device_ping) { |
2365 | rc = -EOPNOTSUPP; |
2366 | goto out; |
2367 | } |
2368 | rc = device->discipline->device_ping(device); |
2369 | if (!rc) |
2370 | rc = count; |
2371 | out: |
2372 | dasd_put_device(device); |
2373 | return rc; |
2374 | } |
2375 | static DEVICE_ATTR(ping, 0200, NULL, dasd_device_ping); |
2376 | |
2377 | #define DASD_DEFINE_ATTR(_name, _func) \ |
2378 | static ssize_t dasd_##_name##_show(struct device *dev, \ |
2379 | struct device_attribute *attr, \ |
2380 | char *buf) \ |
2381 | { \ |
2382 | struct ccw_device *cdev = to_ccwdev(dev); \ |
2383 | struct dasd_device *device = dasd_device_from_cdev(cdev); \ |
2384 | int val = 0; \ |
2385 | \ |
2386 | if (IS_ERR(device)) \ |
2387 | return -ENODEV; \ |
2388 | if (device->discipline && _func) \ |
2389 | val = _func(device); \ |
2390 | dasd_put_device(device); \ |
2391 | \ |
2392 | return sysfs_emit(buf, "%d\n", val); \ |
2393 | } \ |
2394 | static DEVICE_ATTR(_name, 0444, dasd_##_name##_show, NULL); \ |
2395 | |
2396 | DASD_DEFINE_ATTR(ese, device->discipline->is_ese); |
2397 | DASD_DEFINE_ATTR(extent_size, device->discipline->ext_size); |
2398 | DASD_DEFINE_ATTR(pool_id, device->discipline->ext_pool_id); |
2399 | DASD_DEFINE_ATTR(space_configured, device->discipline->space_configured); |
2400 | DASD_DEFINE_ATTR(space_allocated, device->discipline->space_allocated); |
2401 | DASD_DEFINE_ATTR(logical_capacity, device->discipline->logical_capacity); |
2402 | DASD_DEFINE_ATTR(warn_threshold, device->discipline->ext_pool_warn_thrshld); |
2403 | DASD_DEFINE_ATTR(cap_at_warnlevel, device->discipline->ext_pool_cap_at_warnlevel); |
2404 | DASD_DEFINE_ATTR(pool_oos, device->discipline->ext_pool_oos); |
2405 | |
2406 | static struct attribute * dasd_attrs[] = { |
2407 | &dev_attr_readonly.attr, |
2408 | &dev_attr_discipline.attr, |
2409 | &dev_attr_status.attr, |
2410 | &dev_attr_alias.attr, |
2411 | &dev_attr_vendor.attr, |
2412 | &dev_attr_uid.attr, |
2413 | &dev_attr_use_diag.attr, |
2414 | &dev_attr_raw_track_access.attr, |
2415 | &dev_attr_eer_enabled.attr, |
2416 | &dev_attr_erplog.attr, |
2417 | &dev_attr_failfast.attr, |
2418 | &dev_attr_expires.attr, |
2419 | &dev_attr_retries.attr, |
2420 | &dev_attr_timeout.attr, |
2421 | &dev_attr_reservation_policy.attr, |
2422 | &dev_attr_last_known_reservation_state.attr, |
2423 | &dev_attr_safe_offline.attr, |
2424 | &dev_attr_host_access_count.attr, |
2425 | &dev_attr_path_masks.attr, |
2426 | &dev_attr_path_threshold.attr, |
2427 | &dev_attr_path_autodisable.attr, |
2428 | &dev_attr_path_interval.attr, |
2429 | &dev_attr_path_reset.attr, |
2430 | &dev_attr_hpf.attr, |
2431 | &dev_attr_ese.attr, |
2432 | &dev_attr_fc_security.attr, |
2433 | &dev_attr_copy_pair.attr, |
2434 | &dev_attr_copy_role.attr, |
2435 | &dev_attr_ping.attr, |
2436 | &dev_attr_aq_mask.attr, |
2437 | &dev_attr_aq_requeue.attr, |
2438 | &dev_attr_aq_timeouts.attr, |
2439 | NULL, |
2440 | }; |
2441 | |
2442 | static const struct attribute_group dasd_attr_group = { |
2443 | .attrs = dasd_attrs, |
2444 | }; |
2445 | |
2446 | static struct attribute *capacity_attrs[] = { |
2447 | &dev_attr_space_configured.attr, |
2448 | &dev_attr_space_allocated.attr, |
2449 | &dev_attr_logical_capacity.attr, |
2450 | NULL, |
2451 | }; |
2452 | |
2453 | static const struct attribute_group capacity_attr_group = { |
2454 | .name = "capacity" , |
2455 | .attrs = capacity_attrs, |
2456 | }; |
2457 | |
2458 | static struct attribute *ext_pool_attrs[] = { |
2459 | &dev_attr_pool_id.attr, |
2460 | &dev_attr_extent_size.attr, |
2461 | &dev_attr_warn_threshold.attr, |
2462 | &dev_attr_cap_at_warnlevel.attr, |
2463 | &dev_attr_pool_oos.attr, |
2464 | NULL, |
2465 | }; |
2466 | |
2467 | static const struct attribute_group ext_pool_attr_group = { |
2468 | .name = "extent_pool" , |
2469 | .attrs = ext_pool_attrs, |
2470 | }; |
2471 | |
2472 | const struct attribute_group *dasd_dev_groups[] = { |
2473 | &dasd_attr_group, |
2474 | &capacity_attr_group, |
2475 | &ext_pool_attr_group, |
2476 | NULL, |
2477 | }; |
2478 | EXPORT_SYMBOL_GPL(dasd_dev_groups); |
2479 | |
2480 | /* |
2481 | * Return value of the specified feature. |
2482 | */ |
2483 | int |
2484 | dasd_get_feature(struct ccw_device *cdev, int feature) |
2485 | { |
2486 | struct dasd_devmap *devmap; |
2487 | |
2488 | devmap = dasd_find_busid(bus_id: dev_name(dev: &cdev->dev)); |
2489 | if (IS_ERR(ptr: devmap)) |
2490 | return PTR_ERR(ptr: devmap); |
2491 | |
2492 | return ((devmap->features & feature) != 0); |
2493 | } |
2494 | |
2495 | /* |
2496 | * Set / reset given feature. |
2497 | * Flag indicates whether to set (!=0) or the reset (=0) the feature. |
2498 | */ |
2499 | int |
2500 | dasd_set_feature(struct ccw_device *cdev, int feature, int flag) |
2501 | { |
2502 | struct dasd_devmap *devmap; |
2503 | |
2504 | devmap = dasd_devmap_from_cdev(cdev); |
2505 | if (IS_ERR(ptr: devmap)) |
2506 | return PTR_ERR(ptr: devmap); |
2507 | |
2508 | spin_lock(lock: &dasd_devmap_lock); |
2509 | if (flag) |
2510 | devmap->features |= feature; |
2511 | else |
2512 | devmap->features &= ~feature; |
2513 | if (devmap->device) |
2514 | devmap->device->features = devmap->features; |
2515 | spin_unlock(lock: &dasd_devmap_lock); |
2516 | return 0; |
2517 | } |
2518 | EXPORT_SYMBOL(dasd_set_feature); |
2519 | |
2520 | static struct attribute *paths_info_attrs[] = { |
2521 | &path_fcs_attribute.attr, |
2522 | NULL, |
2523 | }; |
2524 | ATTRIBUTE_GROUPS(paths_info); |
2525 | |
2526 | static struct kobj_type path_attr_type = { |
2527 | .release = dasd_path_release, |
2528 | .default_groups = paths_info_groups, |
2529 | .sysfs_ops = &kobj_sysfs_ops, |
2530 | }; |
2531 | |
2532 | static void dasd_path_init_kobj(struct dasd_device *device, int chp) |
2533 | { |
2534 | device->path[chp].kobj.kset = device->paths_info; |
2535 | kobject_init(kobj: &device->path[chp].kobj, ktype: &path_attr_type); |
2536 | } |
2537 | |
2538 | void dasd_path_create_kobj(struct dasd_device *device, int chp) |
2539 | { |
2540 | int rc; |
2541 | |
2542 | if (test_bit(DASD_FLAG_OFFLINE, &device->flags)) |
2543 | return; |
2544 | if (!device->paths_info) { |
2545 | dev_warn(&device->cdev->dev, "Unable to create paths objects\n" ); |
2546 | return; |
2547 | } |
2548 | if (device->path[chp].in_sysfs) |
2549 | return; |
2550 | if (!device->path[chp].conf_data) |
2551 | return; |
2552 | |
2553 | dasd_path_init_kobj(device, chp); |
2554 | |
2555 | rc = kobject_add(kobj: &device->path[chp].kobj, NULL, fmt: "%x.%02x" , |
2556 | device->path[chp].cssid, device->path[chp].chpid); |
2557 | if (rc) |
2558 | kobject_put(kobj: &device->path[chp].kobj); |
2559 | device->path[chp].in_sysfs = true; |
2560 | } |
2561 | EXPORT_SYMBOL(dasd_path_create_kobj); |
2562 | |
2563 | void dasd_path_create_kobjects(struct dasd_device *device) |
2564 | { |
2565 | u8 lpm, opm; |
2566 | |
2567 | opm = dasd_path_get_opm(device); |
2568 | for (lpm = 0x80; lpm; lpm >>= 1) { |
2569 | if (!(lpm & opm)) |
2570 | continue; |
2571 | dasd_path_create_kobj(device, pathmask_to_pos(lpm)); |
2572 | } |
2573 | } |
2574 | EXPORT_SYMBOL(dasd_path_create_kobjects); |
2575 | |
2576 | static void dasd_path_remove_kobj(struct dasd_device *device, int chp) |
2577 | { |
2578 | if (device->path[chp].in_sysfs) { |
2579 | kobject_put(kobj: &device->path[chp].kobj); |
2580 | device->path[chp].in_sysfs = false; |
2581 | } |
2582 | } |
2583 | |
2584 | /* |
2585 | * As we keep kobjects for the lifetime of a device, this function must not be |
2586 | * called anywhere but in the context of offlining a device. |
2587 | */ |
2588 | void dasd_path_remove_kobjects(struct dasd_device *device) |
2589 | { |
2590 | int i; |
2591 | |
2592 | for (i = 0; i < 8; i++) |
2593 | dasd_path_remove_kobj(device, chp: i); |
2594 | } |
2595 | EXPORT_SYMBOL(dasd_path_remove_kobjects); |
2596 | |
2597 | int |
2598 | dasd_devmap_init(void) |
2599 | { |
2600 | int i; |
2601 | |
2602 | /* Initialize devmap structures. */ |
2603 | dasd_max_devindex = 0; |
2604 | for (i = 0; i < 256; i++) |
2605 | INIT_LIST_HEAD(list: &dasd_hashlists[i]); |
2606 | return 0; |
2607 | } |
2608 | |
2609 | void |
2610 | dasd_devmap_exit(void) |
2611 | { |
2612 | dasd_forget_ranges(); |
2613 | } |
2614 | |