dasd_devmap.c 24 KB

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