ibmasmfs.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638
  1. /*
  2. * IBM ASM Service Processor Device Driver
  3. *
  4. * This program is free software; you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation; either version 2 of the License, or
  7. * (at your option) any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program; if not, write to the Free Software
  16. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  17. *
  18. * Copyright (C) IBM Corporation, 2004
  19. *
  20. * Author: Max Asböck <amax@us.ibm.com>
  21. *
  22. */
  23. /*
  24. * Parts of this code are based on an article by Jonathan Corbet
  25. * that appeared in Linux Weekly News.
  26. */
  27. /*
  28. * The IBMASM file virtual filesystem. It creates the following hierarchy
  29. * dymamically when mounted from user space:
  30. *
  31. * /ibmasm
  32. * |-- 0
  33. * | |-- command
  34. * | |-- event
  35. * | |-- reverse_heartbeat
  36. * | `-- remote_video
  37. * | |-- depth
  38. * | |-- height
  39. * | `-- width
  40. * .
  41. * .
  42. * .
  43. * `-- n
  44. * |-- command
  45. * |-- event
  46. * |-- reverse_heartbeat
  47. * `-- remote_video
  48. * |-- depth
  49. * |-- height
  50. * `-- width
  51. *
  52. * For each service processor the following files are created:
  53. *
  54. * command: execute dot commands
  55. * write: execute a dot command on the service processor
  56. * read: return the result of a previously executed dot command
  57. *
  58. * events: listen for service processor events
  59. * read: sleep (interruptible) until an event occurs
  60. * write: wakeup sleeping event listener
  61. *
  62. * reverse_heartbeat: send a heartbeat to the service processor
  63. * read: sleep (interruptible) until the reverse heartbeat fails
  64. * write: wakeup sleeping heartbeat listener
  65. *
  66. * remote_video/width
  67. * remote_video/height
  68. * remote_video/width: control remote display settings
  69. * write: set value
  70. * read: read value
  71. */
  72. #include <linux/fs.h>
  73. #include <linux/pagemap.h>
  74. #include <asm/uaccess.h>
  75. #include <asm/io.h>
  76. #include "ibmasm.h"
  77. #include "remote.h"
  78. #include "dot_command.h"
  79. #define IBMASMFS_MAGIC 0x66726f67
  80. static LIST_HEAD(service_processors);
  81. static struct inode *ibmasmfs_make_inode(struct super_block *sb, int mode);
  82. static void ibmasmfs_create_files (struct super_block *sb, struct dentry *root);
  83. static int ibmasmfs_fill_super (struct super_block *sb, void *data, int silent);
  84. static struct super_block *ibmasmfs_get_super(struct file_system_type *fst,
  85. int flags, const char *name, void *data)
  86. {
  87. return get_sb_single(fst, flags, data, ibmasmfs_fill_super);
  88. }
  89. static struct super_operations ibmasmfs_s_ops = {
  90. .statfs = simple_statfs,
  91. .drop_inode = generic_delete_inode,
  92. };
  93. static struct file_operations *ibmasmfs_dir_ops = &simple_dir_operations;
  94. static struct file_system_type ibmasmfs_type = {
  95. .owner = THIS_MODULE,
  96. .name = "ibmasmfs",
  97. .get_sb = ibmasmfs_get_super,
  98. .kill_sb = kill_litter_super,
  99. };
  100. static int ibmasmfs_fill_super (struct super_block *sb, void *data, int silent)
  101. {
  102. struct inode *root;
  103. struct dentry *root_dentry;
  104. sb->s_blocksize = PAGE_CACHE_SIZE;
  105. sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
  106. sb->s_magic = IBMASMFS_MAGIC;
  107. sb->s_op = &ibmasmfs_s_ops;
  108. sb->s_time_gran = 1;
  109. root = ibmasmfs_make_inode (sb, S_IFDIR | 0500);
  110. if (!root)
  111. return -ENOMEM;
  112. root->i_op = &simple_dir_inode_operations;
  113. root->i_fop = ibmasmfs_dir_ops;
  114. root_dentry = d_alloc_root(root);
  115. if (!root_dentry) {
  116. iput(root);
  117. return -ENOMEM;
  118. }
  119. sb->s_root = root_dentry;
  120. ibmasmfs_create_files(sb, root_dentry);
  121. return 0;
  122. }
  123. static struct inode *ibmasmfs_make_inode(struct super_block *sb, int mode)
  124. {
  125. struct inode *ret = new_inode(sb);
  126. if (ret) {
  127. ret->i_mode = mode;
  128. ret->i_uid = ret->i_gid = 0;
  129. ret->i_blksize = PAGE_CACHE_SIZE;
  130. ret->i_blocks = 0;
  131. ret->i_atime = ret->i_mtime = ret->i_ctime = CURRENT_TIME;
  132. }
  133. return ret;
  134. }
  135. static struct dentry *ibmasmfs_create_file (struct super_block *sb,
  136. struct dentry *parent,
  137. const char *name,
  138. struct file_operations *fops,
  139. void *data,
  140. int mode)
  141. {
  142. struct dentry *dentry;
  143. struct inode *inode;
  144. dentry = d_alloc_name(parent, name);
  145. if (!dentry)
  146. return NULL;
  147. inode = ibmasmfs_make_inode(sb, S_IFREG | mode);
  148. if (!inode) {
  149. dput(dentry);
  150. return NULL;
  151. }
  152. inode->i_fop = fops;
  153. inode->u.generic_ip = data;
  154. d_add(dentry, inode);
  155. return dentry;
  156. }
  157. static struct dentry *ibmasmfs_create_dir (struct super_block *sb,
  158. struct dentry *parent,
  159. const char *name)
  160. {
  161. struct dentry *dentry;
  162. struct inode *inode;
  163. dentry = d_alloc_name(parent, name);
  164. if (!dentry)
  165. return NULL;
  166. inode = ibmasmfs_make_inode(sb, S_IFDIR | 0500);
  167. if (!inode) {
  168. dput(dentry);
  169. return NULL;
  170. }
  171. inode->i_op = &simple_dir_inode_operations;
  172. inode->i_fop = ibmasmfs_dir_ops;
  173. d_add(dentry, inode);
  174. return dentry;
  175. }
  176. int ibmasmfs_register(void)
  177. {
  178. return register_filesystem(&ibmasmfs_type);
  179. }
  180. void ibmasmfs_unregister(void)
  181. {
  182. unregister_filesystem(&ibmasmfs_type);
  183. }
  184. void ibmasmfs_add_sp(struct service_processor *sp)
  185. {
  186. list_add(&sp->node, &service_processors);
  187. }
  188. /* struct to save state between command file operations */
  189. struct ibmasmfs_command_data {
  190. struct service_processor *sp;
  191. struct command *command;
  192. };
  193. /* struct to save state between event file operations */
  194. struct ibmasmfs_event_data {
  195. struct service_processor *sp;
  196. struct event_reader reader;
  197. int active;
  198. };
  199. /* struct to save state between reverse heartbeat file operations */
  200. struct ibmasmfs_heartbeat_data {
  201. struct service_processor *sp;
  202. struct reverse_heartbeat heartbeat;
  203. int active;
  204. };
  205. static int command_file_open(struct inode *inode, struct file *file)
  206. {
  207. struct ibmasmfs_command_data *command_data;
  208. if (!inode->u.generic_ip)
  209. return -ENODEV;
  210. command_data = kmalloc(sizeof(struct ibmasmfs_command_data), GFP_KERNEL);
  211. if (!command_data)
  212. return -ENOMEM;
  213. command_data->command = NULL;
  214. command_data->sp = inode->u.generic_ip;
  215. file->private_data = command_data;
  216. return 0;
  217. }
  218. static int command_file_close(struct inode *inode, struct file *file)
  219. {
  220. struct ibmasmfs_command_data *command_data = file->private_data;
  221. if (command_data->command)
  222. command_put(command_data->command);
  223. kfree(command_data);
  224. return 0;
  225. }
  226. static ssize_t command_file_read(struct file *file, char __user *buf, size_t count, loff_t *offset)
  227. {
  228. struct ibmasmfs_command_data *command_data = file->private_data;
  229. struct command *cmd;
  230. int len;
  231. unsigned long flags;
  232. if (*offset < 0)
  233. return -EINVAL;
  234. if (count == 0 || count > IBMASM_CMD_MAX_BUFFER_SIZE)
  235. return 0;
  236. if (*offset != 0)
  237. return 0;
  238. spin_lock_irqsave(&command_data->sp->lock, flags);
  239. cmd = command_data->command;
  240. if (cmd == NULL) {
  241. spin_unlock_irqrestore(&command_data->sp->lock, flags);
  242. return 0;
  243. }
  244. command_data->command = NULL;
  245. spin_unlock_irqrestore(&command_data->sp->lock, flags);
  246. if (cmd->status != IBMASM_CMD_COMPLETE) {
  247. command_put(cmd);
  248. return -EIO;
  249. }
  250. len = min(count, cmd->buffer_size);
  251. if (copy_to_user(buf, cmd->buffer, len)) {
  252. command_put(cmd);
  253. return -EFAULT;
  254. }
  255. command_put(cmd);
  256. return len;
  257. }
  258. static ssize_t command_file_write(struct file *file, const char __user *ubuff, size_t count, loff_t *offset)
  259. {
  260. struct ibmasmfs_command_data *command_data = file->private_data;
  261. struct command *cmd;
  262. unsigned long flags;
  263. if (*offset < 0)
  264. return -EINVAL;
  265. if (count == 0 || count > IBMASM_CMD_MAX_BUFFER_SIZE)
  266. return 0;
  267. if (*offset != 0)
  268. return 0;
  269. /* commands are executed sequentially, only one command at a time */
  270. if (command_data->command)
  271. return -EAGAIN;
  272. cmd = ibmasm_new_command(command_data->sp, count);
  273. if (!cmd)
  274. return -ENOMEM;
  275. if (copy_from_user(cmd->buffer, ubuff, count)) {
  276. command_put(cmd);
  277. return -EFAULT;
  278. }
  279. spin_lock_irqsave(&command_data->sp->lock, flags);
  280. if (command_data->command) {
  281. spin_unlock_irqrestore(&command_data->sp->lock, flags);
  282. command_put(cmd);
  283. return -EAGAIN;
  284. }
  285. command_data->command = cmd;
  286. spin_unlock_irqrestore(&command_data->sp->lock, flags);
  287. ibmasm_exec_command(command_data->sp, cmd);
  288. ibmasm_wait_for_response(cmd, get_dot_command_timeout(cmd->buffer));
  289. return count;
  290. }
  291. static int event_file_open(struct inode *inode, struct file *file)
  292. {
  293. struct ibmasmfs_event_data *event_data;
  294. struct service_processor *sp;
  295. if (!inode->u.generic_ip)
  296. return -ENODEV;
  297. sp = inode->u.generic_ip;
  298. event_data = kmalloc(sizeof(struct ibmasmfs_event_data), GFP_KERNEL);
  299. if (!event_data)
  300. return -ENOMEM;
  301. ibmasm_event_reader_register(sp, &event_data->reader);
  302. event_data->sp = sp;
  303. event_data->active = 0;
  304. file->private_data = event_data;
  305. return 0;
  306. }
  307. static int event_file_close(struct inode *inode, struct file *file)
  308. {
  309. struct ibmasmfs_event_data *event_data = file->private_data;
  310. ibmasm_event_reader_unregister(event_data->sp, &event_data->reader);
  311. kfree(event_data);
  312. return 0;
  313. }
  314. static ssize_t event_file_read(struct file *file, char __user *buf, size_t count, loff_t *offset)
  315. {
  316. struct ibmasmfs_event_data *event_data = file->private_data;
  317. struct event_reader *reader = &event_data->reader;
  318. struct service_processor *sp = event_data->sp;
  319. int ret;
  320. unsigned long flags;
  321. if (*offset < 0)
  322. return -EINVAL;
  323. if (count == 0 || count > IBMASM_EVENT_MAX_SIZE)
  324. return 0;
  325. if (*offset != 0)
  326. return 0;
  327. spin_lock_irqsave(&sp->lock, flags);
  328. if (event_data->active) {
  329. spin_unlock_irqrestore(&sp->lock, flags);
  330. return -EBUSY;
  331. }
  332. event_data->active = 1;
  333. spin_unlock_irqrestore(&sp->lock, flags);
  334. ret = ibmasm_get_next_event(sp, reader);
  335. if (ret <= 0)
  336. goto out;
  337. if (count < reader->data_size) {
  338. ret = -EINVAL;
  339. goto out;
  340. }
  341. if (copy_to_user(buf, reader->data, reader->data_size)) {
  342. ret = -EFAULT;
  343. goto out;
  344. }
  345. ret = reader->data_size;
  346. out:
  347. event_data->active = 0;
  348. return ret;
  349. }
  350. static ssize_t event_file_write(struct file *file, const char __user *buf, size_t count, loff_t *offset)
  351. {
  352. struct ibmasmfs_event_data *event_data = file->private_data;
  353. if (*offset < 0)
  354. return -EINVAL;
  355. if (count != 1)
  356. return 0;
  357. if (*offset != 0)
  358. return 0;
  359. ibmasm_cancel_next_event(&event_data->reader);
  360. return 0;
  361. }
  362. static int r_heartbeat_file_open(struct inode *inode, struct file *file)
  363. {
  364. struct ibmasmfs_heartbeat_data *rhbeat;
  365. if (!inode->u.generic_ip)
  366. return -ENODEV;
  367. rhbeat = kmalloc(sizeof(struct ibmasmfs_heartbeat_data), GFP_KERNEL);
  368. if (!rhbeat)
  369. return -ENOMEM;
  370. rhbeat->sp = (struct service_processor *)inode->u.generic_ip;
  371. rhbeat->active = 0;
  372. ibmasm_init_reverse_heartbeat(rhbeat->sp, &rhbeat->heartbeat);
  373. file->private_data = rhbeat;
  374. return 0;
  375. }
  376. static int r_heartbeat_file_close(struct inode *inode, struct file *file)
  377. {
  378. struct ibmasmfs_heartbeat_data *rhbeat = file->private_data;
  379. kfree(rhbeat);
  380. return 0;
  381. }
  382. static ssize_t r_heartbeat_file_read(struct file *file, char __user *buf, size_t count, loff_t *offset)
  383. {
  384. struct ibmasmfs_heartbeat_data *rhbeat = file->private_data;
  385. unsigned long flags;
  386. int result;
  387. if (*offset < 0)
  388. return -EINVAL;
  389. if (count == 0 || count > 1024)
  390. return 0;
  391. if (*offset != 0)
  392. return 0;
  393. /* allow only one reverse heartbeat per process */
  394. spin_lock_irqsave(&rhbeat->sp->lock, flags);
  395. if (rhbeat->active) {
  396. spin_unlock_irqrestore(&rhbeat->sp->lock, flags);
  397. return -EBUSY;
  398. }
  399. rhbeat->active = 1;
  400. spin_unlock_irqrestore(&rhbeat->sp->lock, flags);
  401. result = ibmasm_start_reverse_heartbeat(rhbeat->sp, &rhbeat->heartbeat);
  402. rhbeat->active = 0;
  403. return result;
  404. }
  405. static ssize_t r_heartbeat_file_write(struct file *file, const char __user *buf, size_t count, loff_t *offset)
  406. {
  407. struct ibmasmfs_heartbeat_data *rhbeat = file->private_data;
  408. if (*offset < 0)
  409. return -EINVAL;
  410. if (count != 1)
  411. return 0;
  412. if (*offset != 0)
  413. return 0;
  414. if (rhbeat->active)
  415. ibmasm_stop_reverse_heartbeat(&rhbeat->heartbeat);
  416. return 1;
  417. }
  418. static int remote_settings_file_open(struct inode *inode, struct file *file)
  419. {
  420. file->private_data = inode->u.generic_ip;
  421. return 0;
  422. }
  423. static int remote_settings_file_close(struct inode *inode, struct file *file)
  424. {
  425. return 0;
  426. }
  427. static ssize_t remote_settings_file_read(struct file *file, char __user *buf, size_t count, loff_t *offset)
  428. {
  429. void __iomem *address = (void __iomem *)file->private_data;
  430. unsigned char *page;
  431. int retval;
  432. int len = 0;
  433. unsigned int value;
  434. if (*offset < 0)
  435. return -EINVAL;
  436. if (count == 0 || count > 1024)
  437. return 0;
  438. if (*offset != 0)
  439. return 0;
  440. page = (unsigned char *)__get_free_page(GFP_KERNEL);
  441. if (!page)
  442. return -ENOMEM;
  443. value = readl(address);
  444. len = sprintf(page, "%d\n", value);
  445. if (copy_to_user(buf, page, len)) {
  446. retval = -EFAULT;
  447. goto exit;
  448. }
  449. *offset += len;
  450. retval = len;
  451. exit:
  452. free_page((unsigned long)page);
  453. return retval;
  454. }
  455. static ssize_t remote_settings_file_write(struct file *file, const char __user *ubuff, size_t count, loff_t *offset)
  456. {
  457. void __iomem *address = (void __iomem *)file->private_data;
  458. char *buff;
  459. unsigned int value;
  460. if (*offset < 0)
  461. return -EINVAL;
  462. if (count == 0 || count > 1024)
  463. return 0;
  464. if (*offset != 0)
  465. return 0;
  466. buff = kmalloc (count + 1, GFP_KERNEL);
  467. if (!buff)
  468. return -ENOMEM;
  469. memset(buff, 0x0, count + 1);
  470. if (copy_from_user(buff, ubuff, count)) {
  471. kfree(buff);
  472. return -EFAULT;
  473. }
  474. value = simple_strtoul(buff, NULL, 10);
  475. writel(value, address);
  476. kfree(buff);
  477. return count;
  478. }
  479. static struct file_operations command_fops = {
  480. .open = command_file_open,
  481. .release = command_file_close,
  482. .read = command_file_read,
  483. .write = command_file_write,
  484. };
  485. static struct file_operations event_fops = {
  486. .open = event_file_open,
  487. .release = event_file_close,
  488. .read = event_file_read,
  489. .write = event_file_write,
  490. };
  491. static struct file_operations r_heartbeat_fops = {
  492. .open = r_heartbeat_file_open,
  493. .release = r_heartbeat_file_close,
  494. .read = r_heartbeat_file_read,
  495. .write = r_heartbeat_file_write,
  496. };
  497. static struct file_operations remote_settings_fops = {
  498. .open = remote_settings_file_open,
  499. .release = remote_settings_file_close,
  500. .read = remote_settings_file_read,
  501. .write = remote_settings_file_write,
  502. };
  503. static void ibmasmfs_create_files (struct super_block *sb, struct dentry *root)
  504. {
  505. struct list_head *entry;
  506. struct service_processor *sp;
  507. list_for_each(entry, &service_processors) {
  508. struct dentry *dir;
  509. struct dentry *remote_dir;
  510. sp = list_entry(entry, struct service_processor, node);
  511. dir = ibmasmfs_create_dir(sb, root, sp->dirname);
  512. if (!dir)
  513. continue;
  514. ibmasmfs_create_file(sb, dir, "command", &command_fops, sp, S_IRUSR|S_IWUSR);
  515. ibmasmfs_create_file(sb, dir, "event", &event_fops, sp, S_IRUSR|S_IWUSR);
  516. ibmasmfs_create_file(sb, dir, "reverse_heartbeat", &r_heartbeat_fops, sp, S_IRUSR|S_IWUSR);
  517. remote_dir = ibmasmfs_create_dir(sb, dir, "remote_video");
  518. if (!remote_dir)
  519. continue;
  520. ibmasmfs_create_file(sb, remote_dir, "width", &remote_settings_fops, (void *)display_width(sp), S_IRUSR|S_IWUSR);
  521. ibmasmfs_create_file(sb, remote_dir, "height", &remote_settings_fops, (void *)display_height(sp), S_IRUSR|S_IWUSR);
  522. ibmasmfs_create_file(sb, remote_dir, "depth", &remote_settings_fops, (void *)display_depth(sp), S_IRUSR|S_IWUSR);
  523. }
  524. }