blacklist.c 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389
  1. /*
  2. * drivers/s390/cio/blacklist.c
  3. * S/390 common I/O routines -- blacklisting of specific devices
  4. *
  5. * Copyright (C) 1999-2002 IBM Deutschland Entwicklung GmbH,
  6. * IBM Corporation
  7. * Author(s): Ingo Adlung (adlung@de.ibm.com)
  8. * Cornelia Huck (cornelia.huck@de.ibm.com)
  9. * Arnd Bergmann (arndb@de.ibm.com)
  10. */
  11. #include <linux/init.h>
  12. #include <linux/vmalloc.h>
  13. #include <linux/slab.h>
  14. #include <linux/proc_fs.h>
  15. #include <linux/seq_file.h>
  16. #include <linux/ctype.h>
  17. #include <linux/device.h>
  18. #include <asm/cio.h>
  19. #include <asm/uaccess.h>
  20. #include "blacklist.h"
  21. #include "cio.h"
  22. #include "cio_debug.h"
  23. #include "css.h"
  24. /*
  25. * "Blacklisting" of certain devices:
  26. * Device numbers given in the commandline as cio_ignore=... won't be known
  27. * to Linux.
  28. *
  29. * These can be single devices or ranges of devices
  30. */
  31. /* 65536 bits for each set to indicate if a devno is blacklisted or not */
  32. #define __BL_DEV_WORDS ((__MAX_SUBCHANNEL + (8*sizeof(long) - 1)) / \
  33. (8*sizeof(long)))
  34. static unsigned long bl_dev[__MAX_SSID + 1][__BL_DEV_WORDS];
  35. typedef enum {add, free} range_action;
  36. /*
  37. * Function: blacklist_range
  38. * (Un-)blacklist the devices from-to
  39. */
  40. static void
  41. blacklist_range (range_action action, unsigned int from, unsigned int to,
  42. unsigned int ssid)
  43. {
  44. if (!to)
  45. to = from;
  46. if (from > to || to > __MAX_SUBCHANNEL || ssid > __MAX_SSID) {
  47. printk (KERN_WARNING "cio: Invalid blacklist range "
  48. "0.%x.%04x to 0.%x.%04x, skipping\n",
  49. ssid, from, ssid, to);
  50. return;
  51. }
  52. for (; from <= to; from++) {
  53. if (action == add)
  54. set_bit (from, bl_dev[ssid]);
  55. else
  56. clear_bit (from, bl_dev[ssid]);
  57. }
  58. }
  59. /*
  60. * Function: blacklist_busid
  61. * Get devno/busid from given string.
  62. * Shamelessly grabbed from dasd_devmap.c.
  63. */
  64. static int
  65. blacklist_busid(char **str, int *id0, int *ssid, int *devno)
  66. {
  67. int val, old_style;
  68. char *sav;
  69. sav = *str;
  70. /* check for leading '0x' */
  71. old_style = 0;
  72. if ((*str)[0] == '0' && (*str)[1] == 'x') {
  73. *str += 2;
  74. old_style = 1;
  75. }
  76. if (!isxdigit((*str)[0])) /* We require at least one hex digit */
  77. goto confused;
  78. val = simple_strtoul(*str, str, 16);
  79. if (old_style || (*str)[0] != '.') {
  80. *id0 = *ssid = 0;
  81. if (val < 0 || val > 0xffff)
  82. goto confused;
  83. *devno = val;
  84. if ((*str)[0] != ',' && (*str)[0] != '-' &&
  85. (*str)[0] != '\n' && (*str)[0] != '\0')
  86. goto confused;
  87. return 0;
  88. }
  89. /* New style x.y.z busid */
  90. if (val < 0 || val > 0xff)
  91. goto confused;
  92. *id0 = val;
  93. (*str)++;
  94. if (!isxdigit((*str)[0])) /* We require at least one hex digit */
  95. goto confused;
  96. val = simple_strtoul(*str, str, 16);
  97. if (val < 0 || val > 0xff || (*str)++[0] != '.')
  98. goto confused;
  99. *ssid = val;
  100. if (!isxdigit((*str)[0])) /* We require at least one hex digit */
  101. goto confused;
  102. val = simple_strtoul(*str, str, 16);
  103. if (val < 0 || val > 0xffff)
  104. goto confused;
  105. *devno = val;
  106. if ((*str)[0] != ',' && (*str)[0] != '-' &&
  107. (*str)[0] != '\n' && (*str)[0] != '\0')
  108. goto confused;
  109. return 0;
  110. confused:
  111. strsep(str, ",\n");
  112. printk(KERN_WARNING "cio: Invalid cio_ignore parameter '%s'\n", sav);
  113. return 1;
  114. }
  115. static int
  116. blacklist_parse_parameters (char *str, range_action action)
  117. {
  118. int from, to, from_id0, to_id0, from_ssid, to_ssid;
  119. while (*str != 0 && *str != '\n') {
  120. range_action ra = action;
  121. while(*str == ',')
  122. str++;
  123. if (*str == '!') {
  124. ra = !action;
  125. ++str;
  126. }
  127. /*
  128. * Since we have to parse the proc commands and the
  129. * kernel arguments we have to check four cases
  130. */
  131. if (strncmp(str,"all,",4) == 0 || strcmp(str,"all") == 0 ||
  132. strncmp(str,"all\n",4) == 0 || strncmp(str,"all ",4) == 0) {
  133. int j;
  134. str += 3;
  135. for (j=0; j <= __MAX_SSID; j++)
  136. blacklist_range(ra, 0, __MAX_SUBCHANNEL, j);
  137. } else {
  138. int rc;
  139. rc = blacklist_busid(&str, &from_id0,
  140. &from_ssid, &from);
  141. if (rc)
  142. continue;
  143. to = from;
  144. to_id0 = from_id0;
  145. to_ssid = from_ssid;
  146. if (*str == '-') {
  147. str++;
  148. rc = blacklist_busid(&str, &to_id0,
  149. &to_ssid, &to);
  150. if (rc)
  151. continue;
  152. }
  153. if (*str == '-') {
  154. printk(KERN_WARNING "cio: invalid cio_ignore "
  155. "parameter '%s'\n",
  156. strsep(&str, ",\n"));
  157. continue;
  158. }
  159. if ((from_id0 != to_id0) ||
  160. (from_ssid != to_ssid)) {
  161. printk(KERN_WARNING "cio: invalid cio_ignore "
  162. "range %x.%x.%04x-%x.%x.%04x\n",
  163. from_id0, from_ssid, from,
  164. to_id0, to_ssid, to);
  165. continue;
  166. }
  167. blacklist_range (ra, from, to, to_ssid);
  168. }
  169. }
  170. return 1;
  171. }
  172. /* Parsing the commandline for blacklist parameters, e.g. to blacklist
  173. * bus ids 0.0.1234, 0.0.1235 and 0.0.1236, you could use any of:
  174. * - cio_ignore=1234-1236
  175. * - cio_ignore=0x1234-0x1235,1236
  176. * - cio_ignore=0x1234,1235-1236
  177. * - cio_ignore=1236 cio_ignore=1234-0x1236
  178. * - cio_ignore=1234 cio_ignore=1236 cio_ignore=0x1235
  179. * - cio_ignore=0.0.1234-0.0.1236
  180. * - cio_ignore=0.0.1234,0x1235,1236
  181. * - ...
  182. */
  183. static int __init
  184. blacklist_setup (char *str)
  185. {
  186. CIO_MSG_EVENT(6, "Reading blacklist parameters\n");
  187. return blacklist_parse_parameters (str, add);
  188. }
  189. __setup ("cio_ignore=", blacklist_setup);
  190. /* Checking if devices are blacklisted */
  191. /*
  192. * Function: is_blacklisted
  193. * Returns 1 if the given devicenumber can be found in the blacklist,
  194. * otherwise 0.
  195. * Used by validate_subchannel()
  196. */
  197. int
  198. is_blacklisted (int ssid, int devno)
  199. {
  200. return test_bit (devno, bl_dev[ssid]);
  201. }
  202. #ifdef CONFIG_PROC_FS
  203. /*
  204. * Function: blacklist_parse_proc_parameters
  205. * parse the stuff which is piped to /proc/cio_ignore
  206. */
  207. static void
  208. blacklist_parse_proc_parameters (char *buf)
  209. {
  210. if (strncmp (buf, "free ", 5) == 0) {
  211. blacklist_parse_parameters (buf + 5, free);
  212. } else if (strncmp (buf, "add ", 4) == 0) {
  213. /*
  214. * We don't need to check for known devices since
  215. * css_probe_device will handle this correctly.
  216. */
  217. blacklist_parse_parameters (buf + 4, add);
  218. } else {
  219. printk (KERN_WARNING "cio: cio_ignore: Parse error; \n"
  220. KERN_WARNING "try using 'free all|<devno-range>,"
  221. "<devno-range>,...'\n"
  222. KERN_WARNING "or 'add <devno-range>,"
  223. "<devno-range>,...'\n");
  224. return;
  225. }
  226. css_schedule_reprobe();
  227. }
  228. /* Iterator struct for all devices. */
  229. struct ccwdev_iter {
  230. int devno;
  231. int ssid;
  232. int in_range;
  233. };
  234. static void *
  235. cio_ignore_proc_seq_start(struct seq_file *s, loff_t *offset)
  236. {
  237. struct ccwdev_iter *iter;
  238. if (*offset >= (__MAX_SUBCHANNEL + 1) * (__MAX_SSID + 1))
  239. return NULL;
  240. iter = kzalloc(sizeof(struct ccwdev_iter), GFP_KERNEL);
  241. if (!iter)
  242. return ERR_PTR(-ENOMEM);
  243. iter->ssid = *offset / (__MAX_SUBCHANNEL + 1);
  244. iter->devno = *offset % (__MAX_SUBCHANNEL + 1);
  245. return iter;
  246. }
  247. static void
  248. cio_ignore_proc_seq_stop(struct seq_file *s, void *it)
  249. {
  250. if (!IS_ERR(it))
  251. kfree(it);
  252. }
  253. static void *
  254. cio_ignore_proc_seq_next(struct seq_file *s, void *it, loff_t *offset)
  255. {
  256. struct ccwdev_iter *iter;
  257. if (*offset >= (__MAX_SUBCHANNEL + 1) * (__MAX_SSID + 1))
  258. return NULL;
  259. iter = it;
  260. if (iter->devno == __MAX_SUBCHANNEL) {
  261. iter->devno = 0;
  262. iter->ssid++;
  263. if (iter->ssid > __MAX_SSID)
  264. return NULL;
  265. } else
  266. iter->devno++;
  267. (*offset)++;
  268. return iter;
  269. }
  270. static int
  271. cio_ignore_proc_seq_show(struct seq_file *s, void *it)
  272. {
  273. struct ccwdev_iter *iter;
  274. iter = it;
  275. if (!is_blacklisted(iter->ssid, iter->devno))
  276. /* Not blacklisted, nothing to output. */
  277. return 0;
  278. if (!iter->in_range) {
  279. /* First device in range. */
  280. if ((iter->devno == __MAX_SUBCHANNEL) ||
  281. !is_blacklisted(iter->ssid, iter->devno + 1))
  282. /* Singular device. */
  283. return seq_printf(s, "0.%x.%04x\n",
  284. iter->ssid, iter->devno);
  285. iter->in_range = 1;
  286. return seq_printf(s, "0.%x.%04x-", iter->ssid, iter->devno);
  287. }
  288. if ((iter->devno == __MAX_SUBCHANNEL) ||
  289. !is_blacklisted(iter->ssid, iter->devno + 1)) {
  290. /* Last device in range. */
  291. iter->in_range = 0;
  292. return seq_printf(s, "0.%x.%04x\n", iter->ssid, iter->devno);
  293. }
  294. return 0;
  295. }
  296. static ssize_t
  297. cio_ignore_write(struct file *file, const char __user *user_buf,
  298. size_t user_len, loff_t *offset)
  299. {
  300. char *buf;
  301. if (*offset)
  302. return -EINVAL;
  303. if (user_len > 65536)
  304. user_len = 65536;
  305. buf = vmalloc (user_len + 1); /* maybe better use the stack? */
  306. if (buf == NULL)
  307. return -ENOMEM;
  308. if (strncpy_from_user (buf, user_buf, user_len) < 0) {
  309. vfree (buf);
  310. return -EFAULT;
  311. }
  312. buf[user_len] = '\0';
  313. blacklist_parse_proc_parameters (buf);
  314. vfree (buf);
  315. return user_len;
  316. }
  317. static struct seq_operations cio_ignore_proc_seq_ops = {
  318. .start = cio_ignore_proc_seq_start,
  319. .stop = cio_ignore_proc_seq_stop,
  320. .next = cio_ignore_proc_seq_next,
  321. .show = cio_ignore_proc_seq_show,
  322. };
  323. static int
  324. cio_ignore_proc_open(struct inode *inode, struct file *file)
  325. {
  326. return seq_open(file, &cio_ignore_proc_seq_ops);
  327. }
  328. static const struct file_operations cio_ignore_proc_fops = {
  329. .open = cio_ignore_proc_open,
  330. .read = seq_read,
  331. .llseek = seq_lseek,
  332. .release = seq_release,
  333. .write = cio_ignore_write,
  334. };
  335. static int
  336. cio_ignore_proc_init (void)
  337. {
  338. struct proc_dir_entry *entry;
  339. entry = create_proc_entry ("cio_ignore", S_IFREG | S_IRUGO | S_IWUSR,
  340. &proc_root);
  341. if (!entry)
  342. return -ENOENT;
  343. entry->proc_fops = &cio_ignore_proc_fops;
  344. return 0;
  345. }
  346. __initcall (cio_ignore_proc_init);
  347. #endif /* CONFIG_PROC_FS */