dcssblk.c 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996
  1. /*
  2. * dcssblk.c -- the S/390 block driver for dcss memory
  3. *
  4. * Authors: Carsten Otte, Stefan Weinhuber, Gerald Schaefer
  5. */
  6. #define KMSG_COMPONENT "dcssblk"
  7. #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
  8. #include <linux/module.h>
  9. #include <linux/moduleparam.h>
  10. #include <linux/ctype.h>
  11. #include <linux/errno.h>
  12. #include <linux/init.h>
  13. #include <linux/slab.h>
  14. #include <linux/blkdev.h>
  15. #include <asm/extmem.h>
  16. #include <asm/io.h>
  17. #include <linux/completion.h>
  18. #include <linux/interrupt.h>
  19. #define DCSSBLK_NAME "dcssblk"
  20. #define DCSSBLK_MINORS_PER_DISK 1
  21. #define DCSSBLK_PARM_LEN 400
  22. #define DCSS_BUS_ID_SIZE 20
  23. static int dcssblk_open(struct block_device *bdev, fmode_t mode);
  24. static int dcssblk_release(struct gendisk *disk, fmode_t mode);
  25. static int dcssblk_make_request(struct request_queue *q, struct bio *bio);
  26. static int dcssblk_direct_access(struct block_device *bdev, sector_t secnum,
  27. void **kaddr, unsigned long *pfn);
  28. static char dcssblk_segments[DCSSBLK_PARM_LEN] = "\0";
  29. static int dcssblk_major;
  30. static struct block_device_operations dcssblk_devops = {
  31. .owner = THIS_MODULE,
  32. .open = dcssblk_open,
  33. .release = dcssblk_release,
  34. .direct_access = dcssblk_direct_access,
  35. };
  36. struct dcssblk_dev_info {
  37. struct list_head lh;
  38. struct device dev;
  39. char segment_name[DCSS_BUS_ID_SIZE];
  40. atomic_t use_count;
  41. struct gendisk *gd;
  42. unsigned long start;
  43. unsigned long end;
  44. int segment_type;
  45. unsigned char save_pending;
  46. unsigned char is_shared;
  47. struct request_queue *dcssblk_queue;
  48. int num_of_segments;
  49. struct list_head seg_list;
  50. };
  51. struct segment_info {
  52. struct list_head lh;
  53. char segment_name[DCSS_BUS_ID_SIZE];
  54. unsigned long start;
  55. unsigned long end;
  56. int segment_type;
  57. };
  58. static ssize_t dcssblk_add_store(struct device * dev, struct device_attribute *attr, const char * buf,
  59. size_t count);
  60. static ssize_t dcssblk_remove_store(struct device * dev, struct device_attribute *attr, const char * buf,
  61. size_t count);
  62. static ssize_t dcssblk_save_store(struct device * dev, struct device_attribute *attr, const char * buf,
  63. size_t count);
  64. static ssize_t dcssblk_save_show(struct device *dev, struct device_attribute *attr, char *buf);
  65. static ssize_t dcssblk_shared_store(struct device * dev, struct device_attribute *attr, const char * buf,
  66. size_t count);
  67. static ssize_t dcssblk_shared_show(struct device *dev, struct device_attribute *attr, char *buf);
  68. static ssize_t dcssblk_seglist_show(struct device *dev,
  69. struct device_attribute *attr,
  70. char *buf);
  71. static DEVICE_ATTR(add, S_IWUSR, NULL, dcssblk_add_store);
  72. static DEVICE_ATTR(remove, S_IWUSR, NULL, dcssblk_remove_store);
  73. static DEVICE_ATTR(save, S_IWUSR | S_IRUSR, dcssblk_save_show,
  74. dcssblk_save_store);
  75. static DEVICE_ATTR(shared, S_IWUSR | S_IRUSR, dcssblk_shared_show,
  76. dcssblk_shared_store);
  77. static DEVICE_ATTR(seglist, S_IRUSR, dcssblk_seglist_show, NULL);
  78. static struct device *dcssblk_root_dev;
  79. static LIST_HEAD(dcssblk_devices);
  80. static struct rw_semaphore dcssblk_devices_sem;
  81. /*
  82. * release function for segment device.
  83. */
  84. static void
  85. dcssblk_release_segment(struct device *dev)
  86. {
  87. struct dcssblk_dev_info *dev_info;
  88. struct segment_info *entry, *temp;
  89. dev_info = container_of(dev, struct dcssblk_dev_info, dev);
  90. list_for_each_entry_safe(entry, temp, &dev_info->seg_list, lh) {
  91. list_del(&entry->lh);
  92. kfree(entry);
  93. }
  94. kfree(dev_info);
  95. module_put(THIS_MODULE);
  96. }
  97. /*
  98. * get a minor number. needs to be called with
  99. * down_write(&dcssblk_devices_sem) and the
  100. * device needs to be enqueued before the semaphore is
  101. * freed.
  102. */
  103. static int
  104. dcssblk_assign_free_minor(struct dcssblk_dev_info *dev_info)
  105. {
  106. int minor, found;
  107. struct dcssblk_dev_info *entry;
  108. if (dev_info == NULL)
  109. return -EINVAL;
  110. for (minor = 0; minor < (1<<MINORBITS); minor++) {
  111. found = 0;
  112. // test if minor available
  113. list_for_each_entry(entry, &dcssblk_devices, lh)
  114. if (minor == MINOR(disk_devt(entry->gd)))
  115. found++;
  116. if (!found) break; // got unused minor
  117. }
  118. if (found)
  119. return -EBUSY;
  120. dev_info->gd->first_minor = minor;
  121. return 0;
  122. }
  123. /*
  124. * get the struct dcssblk_dev_info from dcssblk_devices
  125. * for the given name.
  126. * down_read(&dcssblk_devices_sem) must be held.
  127. */
  128. static struct dcssblk_dev_info *
  129. dcssblk_get_device_by_name(char *name)
  130. {
  131. struct dcssblk_dev_info *entry;
  132. list_for_each_entry(entry, &dcssblk_devices, lh) {
  133. if (!strcmp(name, entry->segment_name)) {
  134. return entry;
  135. }
  136. }
  137. return NULL;
  138. }
  139. /*
  140. * get the struct segment_info from seg_list
  141. * for the given name.
  142. * down_read(&dcssblk_devices_sem) must be held.
  143. */
  144. static struct segment_info *
  145. dcssblk_get_segment_by_name(char *name)
  146. {
  147. struct dcssblk_dev_info *dev_info;
  148. struct segment_info *entry;
  149. list_for_each_entry(dev_info, &dcssblk_devices, lh) {
  150. list_for_each_entry(entry, &dev_info->seg_list, lh) {
  151. if (!strcmp(name, entry->segment_name))
  152. return entry;
  153. }
  154. }
  155. return NULL;
  156. }
  157. /*
  158. * get the highest address of the multi-segment block.
  159. */
  160. static unsigned long
  161. dcssblk_find_highest_addr(struct dcssblk_dev_info *dev_info)
  162. {
  163. unsigned long highest_addr;
  164. struct segment_info *entry;
  165. highest_addr = 0;
  166. list_for_each_entry(entry, &dev_info->seg_list, lh) {
  167. if (highest_addr < entry->end)
  168. highest_addr = entry->end;
  169. }
  170. return highest_addr;
  171. }
  172. /*
  173. * get the lowest address of the multi-segment block.
  174. */
  175. static unsigned long
  176. dcssblk_find_lowest_addr(struct dcssblk_dev_info *dev_info)
  177. {
  178. int set_first;
  179. unsigned long lowest_addr;
  180. struct segment_info *entry;
  181. set_first = 0;
  182. lowest_addr = 0;
  183. list_for_each_entry(entry, &dev_info->seg_list, lh) {
  184. if (set_first == 0) {
  185. lowest_addr = entry->start;
  186. set_first = 1;
  187. } else {
  188. if (lowest_addr > entry->start)
  189. lowest_addr = entry->start;
  190. }
  191. }
  192. return lowest_addr;
  193. }
  194. /*
  195. * Check continuity of segments.
  196. */
  197. static int
  198. dcssblk_is_continuous(struct dcssblk_dev_info *dev_info)
  199. {
  200. int i, j, rc;
  201. struct segment_info *sort_list, *entry, temp;
  202. if (dev_info->num_of_segments <= 1)
  203. return 0;
  204. sort_list = kzalloc(
  205. sizeof(struct segment_info) * dev_info->num_of_segments,
  206. GFP_KERNEL);
  207. if (sort_list == NULL)
  208. return -ENOMEM;
  209. i = 0;
  210. list_for_each_entry(entry, &dev_info->seg_list, lh) {
  211. memcpy(&sort_list[i], entry, sizeof(struct segment_info));
  212. i++;
  213. }
  214. /* sort segments */
  215. for (i = 0; i < dev_info->num_of_segments; i++)
  216. for (j = 0; j < dev_info->num_of_segments; j++)
  217. if (sort_list[j].start > sort_list[i].start) {
  218. memcpy(&temp, &sort_list[i],
  219. sizeof(struct segment_info));
  220. memcpy(&sort_list[i], &sort_list[j],
  221. sizeof(struct segment_info));
  222. memcpy(&sort_list[j], &temp,
  223. sizeof(struct segment_info));
  224. }
  225. /* check continuity */
  226. for (i = 0; i < dev_info->num_of_segments - 1; i++) {
  227. if ((sort_list[i].end + 1) != sort_list[i+1].start) {
  228. pr_err("Adjacent DCSSs %s and %s are not "
  229. "contiguous\n", sort_list[i].segment_name,
  230. sort_list[i+1].segment_name);
  231. rc = -EINVAL;
  232. goto out;
  233. }
  234. /* EN and EW are allowed in a block device */
  235. if (sort_list[i].segment_type != sort_list[i+1].segment_type) {
  236. if (!(sort_list[i].segment_type & SEGMENT_EXCLUSIVE) ||
  237. (sort_list[i].segment_type == SEG_TYPE_ER) ||
  238. !(sort_list[i+1].segment_type &
  239. SEGMENT_EXCLUSIVE) ||
  240. (sort_list[i+1].segment_type == SEG_TYPE_ER)) {
  241. pr_err("DCSS %s and DCSS %s have "
  242. "incompatible types\n",
  243. sort_list[i].segment_name,
  244. sort_list[i+1].segment_name);
  245. rc = -EINVAL;
  246. goto out;
  247. }
  248. }
  249. }
  250. rc = 0;
  251. out:
  252. kfree(sort_list);
  253. return rc;
  254. }
  255. /*
  256. * Load a segment
  257. */
  258. static int
  259. dcssblk_load_segment(char *name, struct segment_info **seg_info)
  260. {
  261. int rc;
  262. /* already loaded? */
  263. down_read(&dcssblk_devices_sem);
  264. *seg_info = dcssblk_get_segment_by_name(name);
  265. up_read(&dcssblk_devices_sem);
  266. if (*seg_info != NULL)
  267. return -EEXIST;
  268. /* get a struct segment_info */
  269. *seg_info = kzalloc(sizeof(struct segment_info), GFP_KERNEL);
  270. if (*seg_info == NULL)
  271. return -ENOMEM;
  272. strcpy((*seg_info)->segment_name, name);
  273. /* load the segment */
  274. rc = segment_load(name, SEGMENT_SHARED,
  275. &(*seg_info)->start, &(*seg_info)->end);
  276. if (rc < 0) {
  277. segment_warning(rc, (*seg_info)->segment_name);
  278. kfree(*seg_info);
  279. } else {
  280. INIT_LIST_HEAD(&(*seg_info)->lh);
  281. (*seg_info)->segment_type = rc;
  282. }
  283. return rc;
  284. }
  285. static void dcssblk_unregister_callback(struct device *dev)
  286. {
  287. device_unregister(dev);
  288. put_device(dev);
  289. }
  290. /*
  291. * device attribute for switching shared/nonshared (exclusive)
  292. * operation (show + store)
  293. */
  294. static ssize_t
  295. dcssblk_shared_show(struct device *dev, struct device_attribute *attr, char *buf)
  296. {
  297. struct dcssblk_dev_info *dev_info;
  298. dev_info = container_of(dev, struct dcssblk_dev_info, dev);
  299. return sprintf(buf, dev_info->is_shared ? "1\n" : "0\n");
  300. }
  301. static ssize_t
  302. dcssblk_shared_store(struct device *dev, struct device_attribute *attr, const char *inbuf, size_t count)
  303. {
  304. struct dcssblk_dev_info *dev_info;
  305. struct segment_info *entry, *temp;
  306. int rc;
  307. if ((count > 1) && (inbuf[1] != '\n') && (inbuf[1] != '\0'))
  308. return -EINVAL;
  309. down_write(&dcssblk_devices_sem);
  310. dev_info = container_of(dev, struct dcssblk_dev_info, dev);
  311. if (atomic_read(&dev_info->use_count)) {
  312. rc = -EBUSY;
  313. goto out;
  314. }
  315. if (inbuf[0] == '1') {
  316. /* reload segments in shared mode */
  317. list_for_each_entry(entry, &dev_info->seg_list, lh) {
  318. rc = segment_modify_shared(entry->segment_name,
  319. SEGMENT_SHARED);
  320. if (rc < 0) {
  321. BUG_ON(rc == -EINVAL);
  322. if (rc != -EAGAIN)
  323. goto removeseg;
  324. }
  325. }
  326. dev_info->is_shared = 1;
  327. switch (dev_info->segment_type) {
  328. case SEG_TYPE_SR:
  329. case SEG_TYPE_ER:
  330. case SEG_TYPE_SC:
  331. set_disk_ro(dev_info->gd, 1);
  332. }
  333. } else if (inbuf[0] == '0') {
  334. /* reload segments in exclusive mode */
  335. if (dev_info->segment_type == SEG_TYPE_SC) {
  336. pr_err("DCSS %s is of type SC and cannot be "
  337. "loaded as exclusive-writable\n",
  338. dev_info->segment_name);
  339. rc = -EINVAL;
  340. goto out;
  341. }
  342. list_for_each_entry(entry, &dev_info->seg_list, lh) {
  343. rc = segment_modify_shared(entry->segment_name,
  344. SEGMENT_EXCLUSIVE);
  345. if (rc < 0) {
  346. BUG_ON(rc == -EINVAL);
  347. if (rc != -EAGAIN)
  348. goto removeseg;
  349. }
  350. }
  351. dev_info->is_shared = 0;
  352. set_disk_ro(dev_info->gd, 0);
  353. } else {
  354. rc = -EINVAL;
  355. goto out;
  356. }
  357. rc = count;
  358. goto out;
  359. removeseg:
  360. pr_err("DCSS device %s is removed after a failed access mode "
  361. "change\n", dev_info->segment_name);
  362. temp = entry;
  363. list_for_each_entry(entry, &dev_info->seg_list, lh) {
  364. if (entry != temp)
  365. segment_unload(entry->segment_name);
  366. }
  367. list_del(&dev_info->lh);
  368. del_gendisk(dev_info->gd);
  369. blk_cleanup_queue(dev_info->dcssblk_queue);
  370. dev_info->gd->queue = NULL;
  371. put_disk(dev_info->gd);
  372. rc = device_schedule_callback(dev, dcssblk_unregister_callback);
  373. out:
  374. up_write(&dcssblk_devices_sem);
  375. return rc;
  376. }
  377. /*
  378. * device attribute for save operation on current copy
  379. * of the segment. If the segment is busy, saving will
  380. * become pending until it gets released, which can be
  381. * undone by storing a non-true value to this entry.
  382. * (show + store)
  383. */
  384. static ssize_t
  385. dcssblk_save_show(struct device *dev, struct device_attribute *attr, char *buf)
  386. {
  387. struct dcssblk_dev_info *dev_info;
  388. dev_info = container_of(dev, struct dcssblk_dev_info, dev);
  389. return sprintf(buf, dev_info->save_pending ? "1\n" : "0\n");
  390. }
  391. static ssize_t
  392. dcssblk_save_store(struct device *dev, struct device_attribute *attr, const char *inbuf, size_t count)
  393. {
  394. struct dcssblk_dev_info *dev_info;
  395. struct segment_info *entry;
  396. if ((count > 1) && (inbuf[1] != '\n') && (inbuf[1] != '\0'))
  397. return -EINVAL;
  398. dev_info = container_of(dev, struct dcssblk_dev_info, dev);
  399. down_write(&dcssblk_devices_sem);
  400. if (inbuf[0] == '1') {
  401. if (atomic_read(&dev_info->use_count) == 0) {
  402. // device is idle => we save immediately
  403. pr_info("All DCSSs that map to device %s are "
  404. "saved\n", dev_info->segment_name);
  405. list_for_each_entry(entry, &dev_info->seg_list, lh) {
  406. segment_save(entry->segment_name);
  407. }
  408. } else {
  409. // device is busy => we save it when it becomes
  410. // idle in dcssblk_release
  411. pr_info("Device %s is in use, its DCSSs will be "
  412. "saved when it becomes idle\n",
  413. dev_info->segment_name);
  414. dev_info->save_pending = 1;
  415. }
  416. } else if (inbuf[0] == '0') {
  417. if (dev_info->save_pending) {
  418. // device is busy & the user wants to undo his save
  419. // request
  420. dev_info->save_pending = 0;
  421. pr_info("A pending save request for device %s "
  422. "has been canceled\n",
  423. dev_info->segment_name);
  424. }
  425. } else {
  426. up_write(&dcssblk_devices_sem);
  427. return -EINVAL;
  428. }
  429. up_write(&dcssblk_devices_sem);
  430. return count;
  431. }
  432. /*
  433. * device attribute for showing all segments in a device
  434. */
  435. static ssize_t
  436. dcssblk_seglist_show(struct device *dev, struct device_attribute *attr,
  437. char *buf)
  438. {
  439. int i;
  440. struct dcssblk_dev_info *dev_info;
  441. struct segment_info *entry;
  442. down_read(&dcssblk_devices_sem);
  443. dev_info = container_of(dev, struct dcssblk_dev_info, dev);
  444. i = 0;
  445. buf[0] = '\0';
  446. list_for_each_entry(entry, &dev_info->seg_list, lh) {
  447. strcpy(&buf[i], entry->segment_name);
  448. i += strlen(entry->segment_name);
  449. buf[i] = '\n';
  450. i++;
  451. }
  452. up_read(&dcssblk_devices_sem);
  453. return i;
  454. }
  455. /*
  456. * device attribute for adding devices
  457. */
  458. static ssize_t
  459. dcssblk_add_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
  460. {
  461. int rc, i, j, num_of_segments;
  462. struct dcssblk_dev_info *dev_info;
  463. struct segment_info *seg_info, *temp;
  464. char *local_buf;
  465. unsigned long seg_byte_size;
  466. dev_info = NULL;
  467. seg_info = NULL;
  468. if (dev != dcssblk_root_dev) {
  469. rc = -EINVAL;
  470. goto out_nobuf;
  471. }
  472. if ((count < 1) || (buf[0] == '\0') || (buf[0] == '\n')) {
  473. rc = -ENAMETOOLONG;
  474. goto out_nobuf;
  475. }
  476. local_buf = kmalloc(count + 1, GFP_KERNEL);
  477. if (local_buf == NULL) {
  478. rc = -ENOMEM;
  479. goto out_nobuf;
  480. }
  481. /*
  482. * parse input
  483. */
  484. num_of_segments = 0;
  485. for (i = 0; ((buf[i] != '\0') && (buf[i] != '\n') && i < count); i++) {
  486. for (j = i; (buf[j] != ':') &&
  487. (buf[j] != '\0') &&
  488. (buf[j] != '\n') &&
  489. j < count; j++) {
  490. local_buf[j-i] = toupper(buf[j]);
  491. }
  492. local_buf[j-i] = '\0';
  493. if (((j - i) == 0) || ((j - i) > 8)) {
  494. rc = -ENAMETOOLONG;
  495. goto seg_list_del;
  496. }
  497. rc = dcssblk_load_segment(local_buf, &seg_info);
  498. if (rc < 0)
  499. goto seg_list_del;
  500. /*
  501. * get a struct dcssblk_dev_info
  502. */
  503. if (num_of_segments == 0) {
  504. dev_info = kzalloc(sizeof(struct dcssblk_dev_info),
  505. GFP_KERNEL);
  506. if (dev_info == NULL) {
  507. rc = -ENOMEM;
  508. goto out;
  509. }
  510. strcpy(dev_info->segment_name, local_buf);
  511. dev_info->segment_type = seg_info->segment_type;
  512. INIT_LIST_HEAD(&dev_info->seg_list);
  513. }
  514. list_add_tail(&seg_info->lh, &dev_info->seg_list);
  515. num_of_segments++;
  516. i = j;
  517. if ((buf[j] == '\0') || (buf[j] == '\n'))
  518. break;
  519. }
  520. /* no trailing colon at the end of the input */
  521. if ((i > 0) && (buf[i-1] == ':')) {
  522. rc = -ENAMETOOLONG;
  523. goto seg_list_del;
  524. }
  525. strlcpy(local_buf, buf, i + 1);
  526. dev_info->num_of_segments = num_of_segments;
  527. rc = dcssblk_is_continuous(dev_info);
  528. if (rc < 0)
  529. goto seg_list_del;
  530. dev_info->start = dcssblk_find_lowest_addr(dev_info);
  531. dev_info->end = dcssblk_find_highest_addr(dev_info);
  532. dev_set_name(&dev_info->dev, dev_info->segment_name);
  533. dev_info->dev.release = dcssblk_release_segment;
  534. INIT_LIST_HEAD(&dev_info->lh);
  535. dev_info->gd = alloc_disk(DCSSBLK_MINORS_PER_DISK);
  536. if (dev_info->gd == NULL) {
  537. rc = -ENOMEM;
  538. goto seg_list_del;
  539. }
  540. dev_info->gd->major = dcssblk_major;
  541. dev_info->gd->fops = &dcssblk_devops;
  542. dev_info->dcssblk_queue = blk_alloc_queue(GFP_KERNEL);
  543. dev_info->gd->queue = dev_info->dcssblk_queue;
  544. dev_info->gd->private_data = dev_info;
  545. dev_info->gd->driverfs_dev = &dev_info->dev;
  546. blk_queue_make_request(dev_info->dcssblk_queue, dcssblk_make_request);
  547. blk_queue_hardsect_size(dev_info->dcssblk_queue, 4096);
  548. seg_byte_size = (dev_info->end - dev_info->start + 1);
  549. set_capacity(dev_info->gd, seg_byte_size >> 9); // size in sectors
  550. pr_info("Loaded %s with total size %lu bytes and capacity %lu "
  551. "sectors\n", local_buf, seg_byte_size, seg_byte_size >> 9);
  552. dev_info->save_pending = 0;
  553. dev_info->is_shared = 1;
  554. dev_info->dev.parent = dcssblk_root_dev;
  555. /*
  556. *get minor, add to list
  557. */
  558. down_write(&dcssblk_devices_sem);
  559. if (dcssblk_get_segment_by_name(local_buf)) {
  560. rc = -EEXIST;
  561. goto release_gd;
  562. }
  563. rc = dcssblk_assign_free_minor(dev_info);
  564. if (rc)
  565. goto release_gd;
  566. sprintf(dev_info->gd->disk_name, "dcssblk%d",
  567. MINOR(disk_devt(dev_info->gd)));
  568. list_add_tail(&dev_info->lh, &dcssblk_devices);
  569. if (!try_module_get(THIS_MODULE)) {
  570. rc = -ENODEV;
  571. goto dev_list_del;
  572. }
  573. /*
  574. * register the device
  575. */
  576. rc = device_register(&dev_info->dev);
  577. if (rc) {
  578. module_put(THIS_MODULE);
  579. goto dev_list_del;
  580. }
  581. get_device(&dev_info->dev);
  582. rc = device_create_file(&dev_info->dev, &dev_attr_shared);
  583. if (rc)
  584. goto unregister_dev;
  585. rc = device_create_file(&dev_info->dev, &dev_attr_save);
  586. if (rc)
  587. goto unregister_dev;
  588. rc = device_create_file(&dev_info->dev, &dev_attr_seglist);
  589. if (rc)
  590. goto unregister_dev;
  591. add_disk(dev_info->gd);
  592. switch (dev_info->segment_type) {
  593. case SEG_TYPE_SR:
  594. case SEG_TYPE_ER:
  595. case SEG_TYPE_SC:
  596. set_disk_ro(dev_info->gd,1);
  597. break;
  598. default:
  599. set_disk_ro(dev_info->gd,0);
  600. break;
  601. }
  602. up_write(&dcssblk_devices_sem);
  603. rc = count;
  604. goto out;
  605. unregister_dev:
  606. list_del(&dev_info->lh);
  607. blk_cleanup_queue(dev_info->dcssblk_queue);
  608. dev_info->gd->queue = NULL;
  609. put_disk(dev_info->gd);
  610. device_unregister(&dev_info->dev);
  611. list_for_each_entry(seg_info, &dev_info->seg_list, lh) {
  612. segment_unload(seg_info->segment_name);
  613. }
  614. put_device(&dev_info->dev);
  615. up_write(&dcssblk_devices_sem);
  616. goto out;
  617. dev_list_del:
  618. list_del(&dev_info->lh);
  619. release_gd:
  620. blk_cleanup_queue(dev_info->dcssblk_queue);
  621. dev_info->gd->queue = NULL;
  622. put_disk(dev_info->gd);
  623. up_write(&dcssblk_devices_sem);
  624. seg_list_del:
  625. if (dev_info == NULL)
  626. goto out;
  627. list_for_each_entry_safe(seg_info, temp, &dev_info->seg_list, lh) {
  628. list_del(&seg_info->lh);
  629. segment_unload(seg_info->segment_name);
  630. kfree(seg_info);
  631. }
  632. kfree(dev_info);
  633. out:
  634. kfree(local_buf);
  635. out_nobuf:
  636. return rc;
  637. }
  638. /*
  639. * device attribute for removing devices
  640. */
  641. static ssize_t
  642. dcssblk_remove_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
  643. {
  644. struct dcssblk_dev_info *dev_info;
  645. struct segment_info *entry;
  646. int rc, i;
  647. char *local_buf;
  648. if (dev != dcssblk_root_dev) {
  649. return -EINVAL;
  650. }
  651. local_buf = kmalloc(count + 1, GFP_KERNEL);
  652. if (local_buf == NULL) {
  653. return -ENOMEM;
  654. }
  655. /*
  656. * parse input
  657. */
  658. for (i = 0; ((*(buf+i)!='\0') && (*(buf+i)!='\n') && i < count); i++) {
  659. local_buf[i] = toupper(buf[i]);
  660. }
  661. local_buf[i] = '\0';
  662. if ((i == 0) || (i > 8)) {
  663. rc = -ENAMETOOLONG;
  664. goto out_buf;
  665. }
  666. down_write(&dcssblk_devices_sem);
  667. dev_info = dcssblk_get_device_by_name(local_buf);
  668. if (dev_info == NULL) {
  669. up_write(&dcssblk_devices_sem);
  670. pr_warning("Device %s cannot be removed because it is not a "
  671. "known device\n", local_buf);
  672. rc = -ENODEV;
  673. goto out_buf;
  674. }
  675. if (atomic_read(&dev_info->use_count) != 0) {
  676. up_write(&dcssblk_devices_sem);
  677. pr_warning("Device %s cannot be removed while it is in "
  678. "use\n", local_buf);
  679. rc = -EBUSY;
  680. goto out_buf;
  681. }
  682. list_del(&dev_info->lh);
  683. del_gendisk(dev_info->gd);
  684. blk_cleanup_queue(dev_info->dcssblk_queue);
  685. dev_info->gd->queue = NULL;
  686. put_disk(dev_info->gd);
  687. device_unregister(&dev_info->dev);
  688. /* unload all related segments */
  689. list_for_each_entry(entry, &dev_info->seg_list, lh)
  690. segment_unload(entry->segment_name);
  691. put_device(&dev_info->dev);
  692. up_write(&dcssblk_devices_sem);
  693. rc = count;
  694. out_buf:
  695. kfree(local_buf);
  696. return rc;
  697. }
  698. static int
  699. dcssblk_open(struct block_device *bdev, fmode_t mode)
  700. {
  701. struct dcssblk_dev_info *dev_info;
  702. int rc;
  703. dev_info = bdev->bd_disk->private_data;
  704. if (NULL == dev_info) {
  705. rc = -ENODEV;
  706. goto out;
  707. }
  708. atomic_inc(&dev_info->use_count);
  709. bdev->bd_block_size = 4096;
  710. rc = 0;
  711. out:
  712. return rc;
  713. }
  714. static int
  715. dcssblk_release(struct gendisk *disk, fmode_t mode)
  716. {
  717. struct dcssblk_dev_info *dev_info = disk->private_data;
  718. struct segment_info *entry;
  719. int rc;
  720. if (!dev_info) {
  721. rc = -ENODEV;
  722. goto out;
  723. }
  724. down_write(&dcssblk_devices_sem);
  725. if (atomic_dec_and_test(&dev_info->use_count)
  726. && (dev_info->save_pending)) {
  727. pr_info("Device %s has become idle and is being saved "
  728. "now\n", dev_info->segment_name);
  729. list_for_each_entry(entry, &dev_info->seg_list, lh) {
  730. segment_save(entry->segment_name);
  731. }
  732. dev_info->save_pending = 0;
  733. }
  734. up_write(&dcssblk_devices_sem);
  735. rc = 0;
  736. out:
  737. return rc;
  738. }
  739. static int
  740. dcssblk_make_request(struct request_queue *q, struct bio *bio)
  741. {
  742. struct dcssblk_dev_info *dev_info;
  743. struct bio_vec *bvec;
  744. unsigned long index;
  745. unsigned long page_addr;
  746. unsigned long source_addr;
  747. unsigned long bytes_done;
  748. int i;
  749. bytes_done = 0;
  750. dev_info = bio->bi_bdev->bd_disk->private_data;
  751. if (dev_info == NULL)
  752. goto fail;
  753. if ((bio->bi_sector & 7) != 0 || (bio->bi_size & 4095) != 0)
  754. /* Request is not page-aligned. */
  755. goto fail;
  756. if (((bio->bi_size >> 9) + bio->bi_sector)
  757. > get_capacity(bio->bi_bdev->bd_disk)) {
  758. /* Request beyond end of DCSS segment. */
  759. goto fail;
  760. }
  761. /* verify data transfer direction */
  762. if (dev_info->is_shared) {
  763. switch (dev_info->segment_type) {
  764. case SEG_TYPE_SR:
  765. case SEG_TYPE_ER:
  766. case SEG_TYPE_SC:
  767. /* cannot write to these segments */
  768. if (bio_data_dir(bio) == WRITE) {
  769. pr_warning("Writing to %s failed because it "
  770. "is a read-only device\n",
  771. dev_name(&dev_info->dev));
  772. goto fail;
  773. }
  774. }
  775. }
  776. index = (bio->bi_sector >> 3);
  777. bio_for_each_segment(bvec, bio, i) {
  778. page_addr = (unsigned long)
  779. page_address(bvec->bv_page) + bvec->bv_offset;
  780. source_addr = dev_info->start + (index<<12) + bytes_done;
  781. if (unlikely((page_addr & 4095) != 0) || (bvec->bv_len & 4095) != 0)
  782. // More paranoia.
  783. goto fail;
  784. if (bio_data_dir(bio) == READ) {
  785. memcpy((void*)page_addr, (void*)source_addr,
  786. bvec->bv_len);
  787. } else {
  788. memcpy((void*)source_addr, (void*)page_addr,
  789. bvec->bv_len);
  790. }
  791. bytes_done += bvec->bv_len;
  792. }
  793. bio_endio(bio, 0);
  794. return 0;
  795. fail:
  796. bio_io_error(bio);
  797. return 0;
  798. }
  799. static int
  800. dcssblk_direct_access (struct block_device *bdev, sector_t secnum,
  801. void **kaddr, unsigned long *pfn)
  802. {
  803. struct dcssblk_dev_info *dev_info;
  804. unsigned long pgoff;
  805. dev_info = bdev->bd_disk->private_data;
  806. if (!dev_info)
  807. return -ENODEV;
  808. if (secnum % (PAGE_SIZE/512))
  809. return -EINVAL;
  810. pgoff = secnum / (PAGE_SIZE / 512);
  811. if ((pgoff+1)*PAGE_SIZE-1 > dev_info->end - dev_info->start)
  812. return -ERANGE;
  813. *kaddr = (void *) (dev_info->start+pgoff*PAGE_SIZE);
  814. *pfn = virt_to_phys(*kaddr) >> PAGE_SHIFT;
  815. return 0;
  816. }
  817. static void
  818. dcssblk_check_params(void)
  819. {
  820. int rc, i, j, k;
  821. char buf[DCSSBLK_PARM_LEN + 1];
  822. struct dcssblk_dev_info *dev_info;
  823. for (i = 0; (i < DCSSBLK_PARM_LEN) && (dcssblk_segments[i] != '\0');
  824. i++) {
  825. for (j = i; (dcssblk_segments[j] != ',') &&
  826. (dcssblk_segments[j] != '\0') &&
  827. (dcssblk_segments[j] != '(') &&
  828. (j < DCSSBLK_PARM_LEN); j++)
  829. {
  830. buf[j-i] = dcssblk_segments[j];
  831. }
  832. buf[j-i] = '\0';
  833. rc = dcssblk_add_store(dcssblk_root_dev, NULL, buf, j-i);
  834. if ((rc >= 0) && (dcssblk_segments[j] == '(')) {
  835. for (k = 0; (buf[k] != ':') && (buf[k] != '\0'); k++)
  836. buf[k] = toupper(buf[k]);
  837. buf[k] = '\0';
  838. if (!strncmp(&dcssblk_segments[j], "(local)", 7)) {
  839. down_read(&dcssblk_devices_sem);
  840. dev_info = dcssblk_get_device_by_name(buf);
  841. up_read(&dcssblk_devices_sem);
  842. if (dev_info)
  843. dcssblk_shared_store(&dev_info->dev,
  844. NULL, "0\n", 2);
  845. }
  846. }
  847. while ((dcssblk_segments[j] != ',') &&
  848. (dcssblk_segments[j] != '\0'))
  849. {
  850. j++;
  851. }
  852. if (dcssblk_segments[j] == '\0')
  853. break;
  854. i = j;
  855. }
  856. }
  857. /*
  858. * The init/exit functions.
  859. */
  860. static void __exit
  861. dcssblk_exit(void)
  862. {
  863. root_device_unregister(dcssblk_root_dev);
  864. unregister_blkdev(dcssblk_major, DCSSBLK_NAME);
  865. }
  866. static int __init
  867. dcssblk_init(void)
  868. {
  869. int rc;
  870. dcssblk_root_dev = root_device_register("dcssblk");
  871. if (IS_ERR(dcssblk_root_dev))
  872. return PTR_ERR(dcssblk_root_dev);
  873. rc = device_create_file(dcssblk_root_dev, &dev_attr_add);
  874. if (rc) {
  875. root_device_unregister(dcssblk_root_dev);
  876. return rc;
  877. }
  878. rc = device_create_file(dcssblk_root_dev, &dev_attr_remove);
  879. if (rc) {
  880. root_device_unregister(dcssblk_root_dev);
  881. return rc;
  882. }
  883. rc = register_blkdev(0, DCSSBLK_NAME);
  884. if (rc < 0) {
  885. root_device_unregister(dcssblk_root_dev);
  886. return rc;
  887. }
  888. dcssblk_major = rc;
  889. init_rwsem(&dcssblk_devices_sem);
  890. dcssblk_check_params();
  891. return 0;
  892. }
  893. module_init(dcssblk_init);
  894. module_exit(dcssblk_exit);
  895. module_param_string(segments, dcssblk_segments, DCSSBLK_PARM_LEN, 0444);
  896. MODULE_PARM_DESC(segments, "Name of DCSS segment(s) to be loaded, "
  897. "comma-separated list, names in each set separated "
  898. "by commas are separated by colons, each set contains "
  899. "names of contiguous segments and each name max. 8 chars.\n"
  900. "Adding \"(local)\" to the end of each set equals echoing 0 "
  901. "to /sys/devices/dcssblk/<device name>/shared after loading "
  902. "the contiguous segments - \n"
  903. "e.g. segments=\"mydcss1,mydcss2:mydcss3,mydcss4(local)\"");
  904. MODULE_LICENSE("GPL");