dasd_devmap.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799
  1. /*
  2. * File...........: linux/drivers/s390/block/dasd_devmap.c
  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. * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 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. #include <linux/config.h>
  16. #include <linux/ctype.h>
  17. #include <linux/init.h>
  18. #include <asm/debug.h>
  19. #include <asm/uaccess.h>
  20. /* This is ugly... */
  21. #define PRINTK_HEADER "dasd_devmap:"
  22. #include "dasd_int.h"
  23. kmem_cache_t *dasd_page_cache;
  24. EXPORT_SYMBOL(dasd_page_cache);
  25. /*
  26. * dasd_devmap_t is used to store the features and the relation
  27. * between device number and device index. To find a dasd_devmap_t
  28. * that corresponds to a device number of a device index each
  29. * dasd_devmap_t is added to two linked lists, one to search by
  30. * the device number and one to search by the device index. As
  31. * soon as big minor numbers are available the device index list
  32. * can be removed since the device number will then be identical
  33. * to the device index.
  34. */
  35. struct dasd_devmap {
  36. struct list_head list;
  37. char bus_id[BUS_ID_SIZE];
  38. unsigned int devindex;
  39. unsigned short features;
  40. struct dasd_device *device;
  41. };
  42. /*
  43. * Parameter parsing functions for dasd= parameter. The syntax is:
  44. * <devno> : (0x)?[0-9a-fA-F]+
  45. * <busid> : [0-0a-f]\.[0-9a-f]\.(0x)?[0-9a-fA-F]+
  46. * <feature> : ro
  47. * <feature_list> : \(<feature>(:<feature>)*\)
  48. * <devno-range> : <devno>(-<devno>)?<feature_list>?
  49. * <busid-range> : <busid>(-<busid>)?<feature_list>?
  50. * <devices> : <devno-range>|<busid-range>
  51. * <dasd_module> : dasd_diag_mod|dasd_eckd_mod|dasd_fba_mod
  52. *
  53. * <dasd> : autodetect|probeonly|<devices>(,<devices>)*
  54. */
  55. int dasd_probeonly = 0; /* is true, when probeonly mode is active */
  56. int dasd_autodetect = 0; /* is true, when autodetection is active */
  57. /*
  58. * char *dasd[] is intended to hold the ranges supplied by the dasd= statement
  59. * it is named 'dasd' to directly be filled by insmod with the comma separated
  60. * strings when running as a module.
  61. */
  62. static char *dasd[256];
  63. /*
  64. * Single spinlock to protect devmap structures and lists.
  65. */
  66. static DEFINE_SPINLOCK(dasd_devmap_lock);
  67. /*
  68. * Hash lists for devmap structures.
  69. */
  70. static struct list_head dasd_hashlists[256];
  71. int dasd_max_devindex;
  72. static struct dasd_devmap *dasd_add_busid(char *, int);
  73. static inline int
  74. dasd_hash_busid(char *bus_id)
  75. {
  76. int hash, i;
  77. hash = 0;
  78. for (i = 0; (i < BUS_ID_SIZE) && *bus_id; i++, bus_id++)
  79. hash += *bus_id;
  80. return hash & 0xff;
  81. }
  82. #ifndef MODULE
  83. /*
  84. * The parameter parsing functions for builtin-drivers are called
  85. * before kmalloc works. Store the pointers to the parameters strings
  86. * into dasd[] for later processing.
  87. */
  88. static int __init
  89. dasd_call_setup(char *str)
  90. {
  91. static int count = 0;
  92. if (count < 256)
  93. dasd[count++] = str;
  94. return 1;
  95. }
  96. __setup ("dasd=", dasd_call_setup);
  97. #endif /* #ifndef MODULE */
  98. /*
  99. * Read a device busid/devno from a string.
  100. */
  101. static inline int
  102. dasd_busid(char **str, int *id0, int *id1, int *devno)
  103. {
  104. int val, old_style;
  105. /* check for leading '0x' */
  106. old_style = 0;
  107. if ((*str)[0] == '0' && (*str)[1] == 'x') {
  108. *str += 2;
  109. old_style = 1;
  110. }
  111. if (!isxdigit((*str)[0])) /* We require at least one hex digit */
  112. return -EINVAL;
  113. val = simple_strtoul(*str, str, 16);
  114. if (old_style || (*str)[0] != '.') {
  115. *id0 = *id1 = 0;
  116. if (val < 0 || val > 0xffff)
  117. return -EINVAL;
  118. *devno = val;
  119. return 0;
  120. }
  121. /* New style x.y.z busid */
  122. if (val < 0 || val > 0xff)
  123. return -EINVAL;
  124. *id0 = val;
  125. (*str)++;
  126. if (!isxdigit((*str)[0])) /* We require at least one hex digit */
  127. return -EINVAL;
  128. val = simple_strtoul(*str, str, 16);
  129. if (val < 0 || val > 0xff || (*str)++[0] != '.')
  130. return -EINVAL;
  131. *id1 = val;
  132. if (!isxdigit((*str)[0])) /* We require at least one hex digit */
  133. return -EINVAL;
  134. val = simple_strtoul(*str, str, 16);
  135. if (val < 0 || val > 0xffff)
  136. return -EINVAL;
  137. *devno = val;
  138. return 0;
  139. }
  140. /*
  141. * Read colon separated list of dasd features. Currently there is
  142. * only one: "ro" for read-only devices. The default feature set
  143. * is empty (value 0).
  144. */
  145. static inline int
  146. dasd_feature_list(char *str, char **endp)
  147. {
  148. int features, len, rc;
  149. rc = 0;
  150. if (*str != '(') {
  151. *endp = str;
  152. return DASD_FEATURE_DEFAULT;
  153. }
  154. str++;
  155. features = 0;
  156. while (1) {
  157. for (len = 0;
  158. str[len] && str[len] != ':' && str[len] != ')'; len++);
  159. if (len == 2 && !strncmp(str, "ro", 2))
  160. features |= DASD_FEATURE_READONLY;
  161. else if (len == 4 && !strncmp(str, "diag", 4))
  162. features |= DASD_FEATURE_USEDIAG;
  163. else {
  164. MESSAGE(KERN_WARNING,
  165. "unsupported feature: %*s, "
  166. "ignoring setting", len, str);
  167. rc = -EINVAL;
  168. }
  169. str += len;
  170. if (*str != ':')
  171. break;
  172. str++;
  173. }
  174. if (*str != ')') {
  175. MESSAGE(KERN_WARNING, "%s",
  176. "missing ')' in dasd parameter string\n");
  177. rc = -EINVAL;
  178. } else
  179. str++;
  180. *endp = str;
  181. if (rc != 0)
  182. return rc;
  183. return features;
  184. }
  185. /*
  186. * Try to match the first element on the comma separated parse string
  187. * with one of the known keywords. If a keyword is found, take the approprate
  188. * action and return a pointer to the residual string. If the first element
  189. * could not be matched to any keyword then return an error code.
  190. */
  191. static char *
  192. dasd_parse_keyword( char *parsestring ) {
  193. char *nextcomma, *residual_str;
  194. int length;
  195. nextcomma = strchr(parsestring,',');
  196. if (nextcomma) {
  197. length = nextcomma - parsestring;
  198. residual_str = nextcomma + 1;
  199. } else {
  200. length = strlen(parsestring);
  201. residual_str = parsestring + length;
  202. }
  203. if (strncmp ("autodetect", parsestring, length) == 0) {
  204. dasd_autodetect = 1;
  205. MESSAGE (KERN_INFO, "%s",
  206. "turning to autodetection mode");
  207. return residual_str;
  208. }
  209. if (strncmp ("probeonly", parsestring, length) == 0) {
  210. dasd_probeonly = 1;
  211. MESSAGE(KERN_INFO, "%s",
  212. "turning to probeonly mode");
  213. return residual_str;
  214. }
  215. if (strncmp ("fixedbuffers", parsestring, length) == 0) {
  216. if (dasd_page_cache)
  217. return residual_str;
  218. dasd_page_cache =
  219. kmem_cache_create("dasd_page_cache", PAGE_SIZE, 0,
  220. SLAB_CACHE_DMA, NULL, NULL );
  221. if (!dasd_page_cache)
  222. MESSAGE(KERN_WARNING, "%s", "Failed to create slab, "
  223. "fixed buffer mode disabled.");
  224. else
  225. MESSAGE (KERN_INFO, "%s",
  226. "turning on fixed buffer mode");
  227. return residual_str;
  228. }
  229. return ERR_PTR(-EINVAL);
  230. }
  231. /*
  232. * Try to interprete the first element on the comma separated parse string
  233. * as a device number or a range of devices. If the interpretation is
  234. * successfull, create the matching dasd_devmap entries and return a pointer
  235. * to the residual string.
  236. * If interpretation fails or in case of an error, return an error code.
  237. */
  238. static char *
  239. dasd_parse_range( char *parsestring ) {
  240. struct dasd_devmap *devmap;
  241. int from, from_id0, from_id1;
  242. int to, to_id0, to_id1;
  243. int features, rc;
  244. char bus_id[BUS_ID_SIZE+1], *str;
  245. str = parsestring;
  246. rc = dasd_busid(&str, &from_id0, &from_id1, &from);
  247. if (rc == 0) {
  248. to = from;
  249. to_id0 = from_id0;
  250. to_id1 = from_id1;
  251. if (*str == '-') {
  252. str++;
  253. rc = dasd_busid(&str, &to_id0, &to_id1, &to);
  254. }
  255. }
  256. if (rc == 0 &&
  257. (from_id0 != to_id0 || from_id1 != to_id1 || from > to))
  258. rc = -EINVAL;
  259. if (rc) {
  260. MESSAGE(KERN_ERR, "Invalid device range %s", parsestring);
  261. return ERR_PTR(rc);
  262. }
  263. features = dasd_feature_list(str, &str);
  264. if (features < 0)
  265. return ERR_PTR(-EINVAL);
  266. while (from <= to) {
  267. sprintf(bus_id, "%01x.%01x.%04x",
  268. from_id0, from_id1, from++);
  269. devmap = dasd_add_busid(bus_id, features);
  270. if (IS_ERR(devmap))
  271. return (char *)devmap;
  272. }
  273. if (*str == ',')
  274. return str + 1;
  275. if (*str == '\0')
  276. return str;
  277. MESSAGE(KERN_WARNING,
  278. "junk at end of dasd parameter string: %s\n", str);
  279. return ERR_PTR(-EINVAL);
  280. }
  281. static inline char *
  282. dasd_parse_next_element( char *parsestring ) {
  283. char * residual_str;
  284. residual_str = dasd_parse_keyword(parsestring);
  285. if (!IS_ERR(residual_str))
  286. return residual_str;
  287. residual_str = dasd_parse_range(parsestring);
  288. return residual_str;
  289. }
  290. /*
  291. * Parse parameters stored in dasd[]
  292. * The 'dasd=...' parameter allows to specify a comma separated list of
  293. * keywords and device ranges. When the dasd driver is build into the kernel,
  294. * the complete list will be stored as one element of the dasd[] array.
  295. * When the dasd driver is build as a module, then the list is broken into
  296. * it's elements and each dasd[] entry contains one element.
  297. */
  298. int
  299. dasd_parse(void)
  300. {
  301. int rc, i;
  302. char *parsestring;
  303. rc = 0;
  304. for (i = 0; i < 256; i++) {
  305. if (dasd[i] == NULL)
  306. break;
  307. parsestring = dasd[i];
  308. /* loop over the comma separated list in the parsestring */
  309. while (*parsestring) {
  310. parsestring = dasd_parse_next_element(parsestring);
  311. if(IS_ERR(parsestring)) {
  312. rc = PTR_ERR(parsestring);
  313. break;
  314. }
  315. }
  316. if (rc) {
  317. DBF_EVENT(DBF_ALERT, "%s", "invalid range found");
  318. break;
  319. }
  320. }
  321. return rc;
  322. }
  323. /*
  324. * Add a devmap for the device specified by busid. It is possible that
  325. * the devmap already exists (dasd= parameter). The order of the devices
  326. * added through this function will define the kdevs for the individual
  327. * devices.
  328. */
  329. static struct dasd_devmap *
  330. dasd_add_busid(char *bus_id, int features)
  331. {
  332. struct dasd_devmap *devmap, *new, *tmp;
  333. int hash;
  334. new = (struct dasd_devmap *)
  335. kmalloc(sizeof(struct dasd_devmap), GFP_KERNEL);
  336. if (!new)
  337. return ERR_PTR(-ENOMEM);
  338. spin_lock(&dasd_devmap_lock);
  339. devmap = 0;
  340. hash = dasd_hash_busid(bus_id);
  341. list_for_each_entry(tmp, &dasd_hashlists[hash], list)
  342. if (strncmp(tmp->bus_id, bus_id, BUS_ID_SIZE) == 0) {
  343. devmap = tmp;
  344. break;
  345. }
  346. if (!devmap) {
  347. /* This bus_id is new. */
  348. new->devindex = dasd_max_devindex++;
  349. strncpy(new->bus_id, bus_id, BUS_ID_SIZE);
  350. new->features = features;
  351. new->device = 0;
  352. list_add(&new->list, &dasd_hashlists[hash]);
  353. devmap = new;
  354. new = 0;
  355. }
  356. spin_unlock(&dasd_devmap_lock);
  357. kfree(new);
  358. return devmap;
  359. }
  360. /*
  361. * Find devmap for device with given bus_id.
  362. */
  363. static struct dasd_devmap *
  364. dasd_find_busid(char *bus_id)
  365. {
  366. struct dasd_devmap *devmap, *tmp;
  367. int hash;
  368. spin_lock(&dasd_devmap_lock);
  369. devmap = ERR_PTR(-ENODEV);
  370. hash = dasd_hash_busid(bus_id);
  371. list_for_each_entry(tmp, &dasd_hashlists[hash], list) {
  372. if (strncmp(tmp->bus_id, bus_id, BUS_ID_SIZE) == 0) {
  373. devmap = tmp;
  374. break;
  375. }
  376. }
  377. spin_unlock(&dasd_devmap_lock);
  378. return devmap;
  379. }
  380. /*
  381. * Check if busid has been added to the list of dasd ranges.
  382. */
  383. int
  384. dasd_busid_known(char *bus_id)
  385. {
  386. return IS_ERR(dasd_find_busid(bus_id)) ? -ENOENT : 0;
  387. }
  388. /*
  389. * Forget all about the device numbers added so far.
  390. * This may only be called at module unload or system shutdown.
  391. */
  392. static void
  393. dasd_forget_ranges(void)
  394. {
  395. struct dasd_devmap *devmap, *n;
  396. int i;
  397. spin_lock(&dasd_devmap_lock);
  398. for (i = 0; i < 256; i++) {
  399. list_for_each_entry_safe(devmap, n, &dasd_hashlists[i], list) {
  400. if (devmap->device != NULL)
  401. BUG();
  402. list_del(&devmap->list);
  403. kfree(devmap);
  404. }
  405. }
  406. spin_unlock(&dasd_devmap_lock);
  407. }
  408. /*
  409. * Find the device struct by its device index.
  410. */
  411. struct dasd_device *
  412. dasd_device_from_devindex(int devindex)
  413. {
  414. struct dasd_devmap *devmap, *tmp;
  415. struct dasd_device *device;
  416. int i;
  417. spin_lock(&dasd_devmap_lock);
  418. devmap = 0;
  419. for (i = 0; (i < 256) && !devmap; i++)
  420. list_for_each_entry(tmp, &dasd_hashlists[i], list)
  421. if (tmp->devindex == devindex) {
  422. /* Found the devmap for the device. */
  423. devmap = tmp;
  424. break;
  425. }
  426. if (devmap && devmap->device) {
  427. device = devmap->device;
  428. dasd_get_device(device);
  429. } else
  430. device = ERR_PTR(-ENODEV);
  431. spin_unlock(&dasd_devmap_lock);
  432. return device;
  433. }
  434. /*
  435. * Return devmap for cdev. If no devmap exists yet, create one and
  436. * connect it to the cdev.
  437. */
  438. static struct dasd_devmap *
  439. dasd_devmap_from_cdev(struct ccw_device *cdev)
  440. {
  441. struct dasd_devmap *devmap;
  442. devmap = dasd_find_busid(cdev->dev.bus_id);
  443. if (IS_ERR(devmap))
  444. devmap = dasd_add_busid(cdev->dev.bus_id,
  445. DASD_FEATURE_DEFAULT);
  446. return devmap;
  447. }
  448. /*
  449. * Create a dasd device structure for cdev.
  450. */
  451. struct dasd_device *
  452. dasd_create_device(struct ccw_device *cdev)
  453. {
  454. struct dasd_devmap *devmap;
  455. struct dasd_device *device;
  456. int rc;
  457. devmap = dasd_devmap_from_cdev(cdev);
  458. if (IS_ERR(devmap))
  459. return (void *) devmap;
  460. cdev->dev.driver_data = devmap;
  461. device = dasd_alloc_device();
  462. if (IS_ERR(device))
  463. return device;
  464. atomic_set(&device->ref_count, 2);
  465. spin_lock(&dasd_devmap_lock);
  466. if (!devmap->device) {
  467. devmap->device = device;
  468. device->devindex = devmap->devindex;
  469. device->features = devmap->features;
  470. get_device(&cdev->dev);
  471. device->cdev = cdev;
  472. rc = 0;
  473. } else
  474. /* Someone else was faster. */
  475. rc = -EBUSY;
  476. spin_unlock(&dasd_devmap_lock);
  477. if (rc) {
  478. dasd_free_device(device);
  479. return ERR_PTR(rc);
  480. }
  481. return device;
  482. }
  483. /*
  484. * Wait queue for dasd_delete_device waits.
  485. */
  486. static DECLARE_WAIT_QUEUE_HEAD(dasd_delete_wq);
  487. /*
  488. * Remove a dasd device structure. The passed referenced
  489. * is destroyed.
  490. */
  491. void
  492. dasd_delete_device(struct dasd_device *device)
  493. {
  494. struct ccw_device *cdev;
  495. struct dasd_devmap *devmap;
  496. /* First remove device pointer from devmap. */
  497. devmap = dasd_find_busid(device->cdev->dev.bus_id);
  498. if (IS_ERR(devmap))
  499. BUG();
  500. spin_lock(&dasd_devmap_lock);
  501. if (devmap->device != device) {
  502. spin_unlock(&dasd_devmap_lock);
  503. dasd_put_device(device);
  504. return;
  505. }
  506. devmap->device = NULL;
  507. spin_unlock(&dasd_devmap_lock);
  508. /* Drop ref_count by 2, one for the devmap reference and
  509. * one for the passed reference. */
  510. atomic_sub(2, &device->ref_count);
  511. /* Wait for reference counter to drop to zero. */
  512. wait_event(dasd_delete_wq, atomic_read(&device->ref_count) == 0);
  513. /* Disconnect dasd_device structure from ccw_device structure. */
  514. cdev = device->cdev;
  515. device->cdev = NULL;
  516. /* Disconnect dasd_devmap structure from ccw_device structure. */
  517. cdev->dev.driver_data = NULL;
  518. /* Put ccw_device structure. */
  519. put_device(&cdev->dev);
  520. /* Now the device structure can be freed. */
  521. dasd_free_device(device);
  522. }
  523. /*
  524. * Reference counter dropped to zero. Wake up waiter
  525. * in dasd_delete_device.
  526. */
  527. void
  528. dasd_put_device_wake(struct dasd_device *device)
  529. {
  530. wake_up(&dasd_delete_wq);
  531. }
  532. /*
  533. * Return dasd_device structure associated with cdev.
  534. */
  535. struct dasd_device *
  536. dasd_device_from_cdev(struct ccw_device *cdev)
  537. {
  538. struct dasd_devmap *devmap;
  539. struct dasd_device *device;
  540. device = ERR_PTR(-ENODEV);
  541. spin_lock(&dasd_devmap_lock);
  542. devmap = cdev->dev.driver_data;
  543. if (devmap && devmap->device) {
  544. device = devmap->device;
  545. dasd_get_device(device);
  546. }
  547. spin_unlock(&dasd_devmap_lock);
  548. return device;
  549. }
  550. /*
  551. * SECTION: files in sysfs
  552. */
  553. /*
  554. * readonly controls the readonly status of a dasd
  555. */
  556. static ssize_t
  557. dasd_ro_show(struct device *dev, struct device_attribute *attr, char *buf)
  558. {
  559. struct dasd_devmap *devmap;
  560. int ro_flag;
  561. devmap = dasd_find_busid(dev->bus_id);
  562. if (!IS_ERR(devmap))
  563. ro_flag = (devmap->features & DASD_FEATURE_READONLY) != 0;
  564. else
  565. ro_flag = (DASD_FEATURE_DEFAULT & DASD_FEATURE_READONLY) != 0;
  566. return snprintf(buf, PAGE_SIZE, ro_flag ? "1\n" : "0\n");
  567. }
  568. static ssize_t
  569. dasd_ro_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
  570. {
  571. struct dasd_devmap *devmap;
  572. int ro_flag;
  573. devmap = dasd_devmap_from_cdev(to_ccwdev(dev));
  574. if (IS_ERR(devmap))
  575. return PTR_ERR(devmap);
  576. ro_flag = buf[0] == '1';
  577. spin_lock(&dasd_devmap_lock);
  578. if (ro_flag)
  579. devmap->features |= DASD_FEATURE_READONLY;
  580. else
  581. devmap->features &= ~DASD_FEATURE_READONLY;
  582. if (devmap->device)
  583. devmap->device->features = devmap->features;
  584. if (devmap->device && devmap->device->gdp)
  585. set_disk_ro(devmap->device->gdp, ro_flag);
  586. spin_unlock(&dasd_devmap_lock);
  587. return count;
  588. }
  589. static DEVICE_ATTR(readonly, 0644, dasd_ro_show, dasd_ro_store);
  590. /*
  591. * use_diag controls whether the driver should use diag rather than ssch
  592. * to talk to the device
  593. */
  594. static ssize_t
  595. dasd_use_diag_show(struct device *dev, struct device_attribute *attr, char *buf)
  596. {
  597. struct dasd_devmap *devmap;
  598. int use_diag;
  599. devmap = dasd_find_busid(dev->bus_id);
  600. if (!IS_ERR(devmap))
  601. use_diag = (devmap->features & DASD_FEATURE_USEDIAG) != 0;
  602. else
  603. use_diag = (DASD_FEATURE_DEFAULT & DASD_FEATURE_USEDIAG) != 0;
  604. return sprintf(buf, use_diag ? "1\n" : "0\n");
  605. }
  606. static ssize_t
  607. dasd_use_diag_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
  608. {
  609. struct dasd_devmap *devmap;
  610. ssize_t rc;
  611. int use_diag;
  612. devmap = dasd_devmap_from_cdev(to_ccwdev(dev));
  613. if (IS_ERR(devmap))
  614. return PTR_ERR(devmap);
  615. use_diag = buf[0] == '1';
  616. spin_lock(&dasd_devmap_lock);
  617. /* Changing diag discipline flag is only allowed in offline state. */
  618. rc = count;
  619. if (!devmap->device) {
  620. if (use_diag)
  621. devmap->features |= DASD_FEATURE_USEDIAG;
  622. else
  623. devmap->features &= ~DASD_FEATURE_USEDIAG;
  624. } else
  625. rc = -EPERM;
  626. spin_unlock(&dasd_devmap_lock);
  627. return rc;
  628. }
  629. static
  630. DEVICE_ATTR(use_diag, 0644, dasd_use_diag_show, dasd_use_diag_store);
  631. static ssize_t
  632. dasd_discipline_show(struct device *dev, struct device_attribute *attr, char *buf)
  633. {
  634. struct dasd_devmap *devmap;
  635. char *dname;
  636. spin_lock(&dasd_devmap_lock);
  637. dname = "none";
  638. devmap = dev->driver_data;
  639. if (devmap && devmap->device && devmap->device->discipline)
  640. dname = devmap->device->discipline->name;
  641. spin_unlock(&dasd_devmap_lock);
  642. return snprintf(buf, PAGE_SIZE, "%s\n", dname);
  643. }
  644. static DEVICE_ATTR(discipline, 0444, dasd_discipline_show, NULL);
  645. static struct attribute * dasd_attrs[] = {
  646. &dev_attr_readonly.attr,
  647. &dev_attr_discipline.attr,
  648. &dev_attr_use_diag.attr,
  649. NULL,
  650. };
  651. static struct attribute_group dasd_attr_group = {
  652. .attrs = dasd_attrs,
  653. };
  654. /*
  655. * Return value of the specified feature.
  656. */
  657. int
  658. dasd_get_feature(struct ccw_device *cdev, int feature)
  659. {
  660. struct dasd_devmap *devmap;
  661. devmap = dasd_find_busid(cdev->dev.bus_id);
  662. if (IS_ERR(devmap))
  663. return (int) PTR_ERR(devmap);
  664. return ((devmap->features & feature) != 0);
  665. }
  666. /*
  667. * Set / reset given feature.
  668. * Flag indicates wether to set (!=0) or the reset (=0) the feature.
  669. */
  670. int
  671. dasd_set_feature(struct ccw_device *cdev, int feature, int flag)
  672. {
  673. struct dasd_devmap *devmap;
  674. devmap = dasd_find_busid(cdev->dev.bus_id);
  675. if (IS_ERR(devmap))
  676. return (int) PTR_ERR(devmap);
  677. spin_lock(&dasd_devmap_lock);
  678. if (flag)
  679. devmap->features |= feature;
  680. else
  681. devmap->features &= ~feature;
  682. if (devmap->device)
  683. devmap->device->features = devmap->features;
  684. spin_unlock(&dasd_devmap_lock);
  685. return 0;
  686. }
  687. int
  688. dasd_add_sysfs_files(struct ccw_device *cdev)
  689. {
  690. return sysfs_create_group(&cdev->dev.kobj, &dasd_attr_group);
  691. }
  692. void
  693. dasd_remove_sysfs_files(struct ccw_device *cdev)
  694. {
  695. sysfs_remove_group(&cdev->dev.kobj, &dasd_attr_group);
  696. }
  697. int
  698. dasd_devmap_init(void)
  699. {
  700. int i;
  701. /* Initialize devmap structures. */
  702. dasd_max_devindex = 0;
  703. for (i = 0; i < 256; i++)
  704. INIT_LIST_HEAD(&dasd_hashlists[i]);
  705. return 0;
  706. }
  707. void
  708. dasd_devmap_exit(void)
  709. {
  710. dasd_forget_ranges();
  711. }