blacklist.c 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392
  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 inline 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 "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 inline 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 "Invalid cio_ignore parameter '%s'\n", sav);
  113. return 1;
  114. }
  115. static inline int
  116. blacklist_parse_parameters (char *str, range_action action)
  117. {
  118. unsigned 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 "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 "invalid cio_ignore range "
  162. "%x.%x.%04x-%x.%x.%04x\n",
  163. from_id0, from_ssid, from,
  164. to_id0, to_ssid, to);
  165. continue;
  166. }
  167. pr_debug("blacklist_setup: adding range "
  168. "from %x.%x.%04x to %x.%x.%04x\n",
  169. from_id0, from_ssid, from, to_id0, to_ssid, to);
  170. blacklist_range (ra, from, to, to_ssid);
  171. }
  172. }
  173. return 1;
  174. }
  175. /* Parsing the commandline for blacklist parameters, e.g. to blacklist
  176. * bus ids 0.0.1234, 0.0.1235 and 0.0.1236, you could use any of:
  177. * - cio_ignore=1234-1236
  178. * - cio_ignore=0x1234-0x1235,1236
  179. * - cio_ignore=0x1234,1235-1236
  180. * - cio_ignore=1236 cio_ignore=1234-0x1236
  181. * - cio_ignore=1234 cio_ignore=1236 cio_ignore=0x1235
  182. * - cio_ignore=0.0.1234-0.0.1236
  183. * - cio_ignore=0.0.1234,0x1235,1236
  184. * - ...
  185. */
  186. static int __init
  187. blacklist_setup (char *str)
  188. {
  189. CIO_MSG_EVENT(6, "Reading blacklist parameters\n");
  190. return blacklist_parse_parameters (str, add);
  191. }
  192. __setup ("cio_ignore=", blacklist_setup);
  193. /* Checking if devices are blacklisted */
  194. /*
  195. * Function: is_blacklisted
  196. * Returns 1 if the given devicenumber can be found in the blacklist,
  197. * otherwise 0.
  198. * Used by validate_subchannel()
  199. */
  200. int
  201. is_blacklisted (int ssid, int devno)
  202. {
  203. return test_bit (devno, bl_dev[ssid]);
  204. }
  205. #ifdef CONFIG_PROC_FS
  206. /*
  207. * Function: blacklist_parse_proc_parameters
  208. * parse the stuff which is piped to /proc/cio_ignore
  209. */
  210. static inline void
  211. blacklist_parse_proc_parameters (char *buf)
  212. {
  213. if (strncmp (buf, "free ", 5) == 0) {
  214. blacklist_parse_parameters (buf + 5, free);
  215. } else if (strncmp (buf, "add ", 4) == 0) {
  216. /*
  217. * We don't need to check for known devices since
  218. * css_probe_device will handle this correctly.
  219. */
  220. blacklist_parse_parameters (buf + 4, add);
  221. } else {
  222. printk (KERN_WARNING "cio_ignore: Parse error; \n"
  223. KERN_WARNING "try using 'free all|<devno-range>,"
  224. "<devno-range>,...'\n"
  225. KERN_WARNING "or 'add <devno-range>,"
  226. "<devno-range>,...'\n");
  227. return;
  228. }
  229. css_schedule_reprobe();
  230. }
  231. /* Iterator struct for all devices. */
  232. struct ccwdev_iter {
  233. int devno;
  234. int ssid;
  235. int in_range;
  236. };
  237. static void *
  238. cio_ignore_proc_seq_start(struct seq_file *s, loff_t *offset)
  239. {
  240. struct ccwdev_iter *iter;
  241. if (*offset >= (__MAX_SUBCHANNEL + 1) * (__MAX_SSID + 1))
  242. return NULL;
  243. iter = kzalloc(sizeof(struct ccwdev_iter), GFP_KERNEL);
  244. if (!iter)
  245. return ERR_PTR(-ENOMEM);
  246. iter->ssid = *offset / (__MAX_SUBCHANNEL + 1);
  247. iter->devno = *offset % (__MAX_SUBCHANNEL + 1);
  248. return iter;
  249. }
  250. static void
  251. cio_ignore_proc_seq_stop(struct seq_file *s, void *it)
  252. {
  253. if (!IS_ERR(it))
  254. kfree(it);
  255. }
  256. static void *
  257. cio_ignore_proc_seq_next(struct seq_file *s, void *it, loff_t *offset)
  258. {
  259. struct ccwdev_iter *iter;
  260. if (*offset >= (__MAX_SUBCHANNEL + 1) * (__MAX_SSID + 1))
  261. return NULL;
  262. iter = it;
  263. if (iter->devno == __MAX_SUBCHANNEL) {
  264. iter->devno = 0;
  265. iter->ssid++;
  266. if (iter->ssid > __MAX_SSID)
  267. return NULL;
  268. } else
  269. iter->devno++;
  270. (*offset)++;
  271. return iter;
  272. }
  273. static int
  274. cio_ignore_proc_seq_show(struct seq_file *s, void *it)
  275. {
  276. struct ccwdev_iter *iter;
  277. iter = it;
  278. if (!is_blacklisted(iter->ssid, iter->devno))
  279. /* Not blacklisted, nothing to output. */
  280. return 0;
  281. if (!iter->in_range) {
  282. /* First device in range. */
  283. if ((iter->devno == __MAX_SUBCHANNEL) ||
  284. !is_blacklisted(iter->ssid, iter->devno + 1))
  285. /* Singular device. */
  286. return seq_printf(s, "0.%x.%04x\n",
  287. iter->ssid, iter->devno);
  288. iter->in_range = 1;
  289. return seq_printf(s, "0.%x.%04x-", iter->ssid, iter->devno);
  290. }
  291. if ((iter->devno == __MAX_SUBCHANNEL) ||
  292. !is_blacklisted(iter->ssid, iter->devno + 1)) {
  293. /* Last device in range. */
  294. iter->in_range = 0;
  295. return seq_printf(s, "0.%x.%04x\n", iter->ssid, iter->devno);
  296. }
  297. return 0;
  298. }
  299. static ssize_t
  300. cio_ignore_write(struct file *file, const char __user *user_buf,
  301. size_t user_len, loff_t *offset)
  302. {
  303. char *buf;
  304. if (*offset)
  305. return -EINVAL;
  306. if (user_len > 65536)
  307. user_len = 65536;
  308. buf = vmalloc (user_len + 1); /* maybe better use the stack? */
  309. if (buf == NULL)
  310. return -ENOMEM;
  311. if (strncpy_from_user (buf, user_buf, user_len) < 0) {
  312. vfree (buf);
  313. return -EFAULT;
  314. }
  315. buf[user_len] = '\0';
  316. blacklist_parse_proc_parameters (buf);
  317. vfree (buf);
  318. return user_len;
  319. }
  320. static struct seq_operations cio_ignore_proc_seq_ops = {
  321. .start = cio_ignore_proc_seq_start,
  322. .stop = cio_ignore_proc_seq_stop,
  323. .next = cio_ignore_proc_seq_next,
  324. .show = cio_ignore_proc_seq_show,
  325. };
  326. static int
  327. cio_ignore_proc_open(struct inode *inode, struct file *file)
  328. {
  329. return seq_open(file, &cio_ignore_proc_seq_ops);
  330. }
  331. static struct file_operations cio_ignore_proc_fops = {
  332. .open = cio_ignore_proc_open,
  333. .read = seq_read,
  334. .llseek = seq_lseek,
  335. .release = seq_release,
  336. .write = cio_ignore_write,
  337. };
  338. static int
  339. cio_ignore_proc_init (void)
  340. {
  341. struct proc_dir_entry *entry;
  342. entry = create_proc_entry ("cio_ignore", S_IFREG | S_IRUGO | S_IWUSR,
  343. &proc_root);
  344. if (!entry)
  345. return -ENOENT;
  346. entry->proc_fops = &cio_ignore_proc_fops;
  347. return 0;
  348. }
  349. __initcall (cio_ignore_proc_init);
  350. #endif /* CONFIG_PROC_FS */