blacklist.c 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351
  1. /*
  2. * drivers/s390/cio/blacklist.c
  3. * S/390 common I/O routines -- blacklisting of specific devices
  4. * $Revision: 1.34 $
  5. *
  6. * Copyright (C) 1999-2002 IBM Deutschland Entwicklung GmbH,
  7. * IBM Corporation
  8. * Author(s): Ingo Adlung (adlung@de.ibm.com)
  9. * Cornelia Huck (cohuck@de.ibm.com)
  10. * Arnd Bergmann (arndb@de.ibm.com)
  11. */
  12. #include <linux/config.h>
  13. #include <linux/init.h>
  14. #include <linux/vmalloc.h>
  15. #include <linux/slab.h>
  16. #include <linux/proc_fs.h>
  17. #include <linux/ctype.h>
  18. #include <linux/device.h>
  19. #include <asm/cio.h>
  20. #include <asm/uaccess.h>
  21. #include "blacklist.h"
  22. #include "cio.h"
  23. #include "cio_debug.h"
  24. #include "css.h"
  25. /*
  26. * "Blacklisting" of certain devices:
  27. * Device numbers given in the commandline as cio_ignore=... won't be known
  28. * to Linux.
  29. *
  30. * These can be single devices or ranges of devices
  31. */
  32. /* 65536 bits to indicate if a devno is blacklisted or not */
  33. #define __BL_DEV_WORDS (__MAX_SUBCHANNELS + (8*sizeof(long) - 1) / \
  34. (8*sizeof(long)))
  35. static unsigned long bl_dev[__BL_DEV_WORDS];
  36. typedef enum {add, free} range_action;
  37. /*
  38. * Function: blacklist_range
  39. * (Un-)blacklist the devices from-to
  40. */
  41. static inline void
  42. blacklist_range (range_action action, unsigned int from, unsigned int to)
  43. {
  44. if (!to)
  45. to = from;
  46. if (from > to || to > __MAX_SUBCHANNELS) {
  47. printk (KERN_WARNING "Invalid blacklist range "
  48. "0x%04x to 0x%04x, skipping\n", from, to);
  49. return;
  50. }
  51. for (; from <= to; from++) {
  52. if (action == add)
  53. set_bit (from, bl_dev);
  54. else
  55. clear_bit (from, bl_dev);
  56. }
  57. }
  58. /*
  59. * Function: blacklist_busid
  60. * Get devno/busid from given string.
  61. * Shamelessly grabbed from dasd_devmap.c.
  62. */
  63. static inline int
  64. blacklist_busid(char **str, int *id0, int *id1, int *devno)
  65. {
  66. int val, old_style;
  67. char *sav;
  68. sav = *str;
  69. /* check for leading '0x' */
  70. old_style = 0;
  71. if ((*str)[0] == '0' && (*str)[1] == 'x') {
  72. *str += 2;
  73. old_style = 1;
  74. }
  75. if (!isxdigit((*str)[0])) /* We require at least one hex digit */
  76. goto confused;
  77. val = simple_strtoul(*str, str, 16);
  78. if (old_style || (*str)[0] != '.') {
  79. *id0 = *id1 = 0;
  80. if (val < 0 || val > 0xffff)
  81. goto confused;
  82. *devno = val;
  83. if ((*str)[0] != ',' && (*str)[0] != '-' &&
  84. (*str)[0] != '\n' && (*str)[0] != '\0')
  85. goto confused;
  86. return 0;
  87. }
  88. /* New style x.y.z busid */
  89. if (val < 0 || val > 0xff)
  90. goto confused;
  91. *id0 = val;
  92. (*str)++;
  93. if (!isxdigit((*str)[0])) /* We require at least one hex digit */
  94. goto confused;
  95. val = simple_strtoul(*str, str, 16);
  96. if (val < 0 || val > 0xff || (*str)++[0] != '.')
  97. goto confused;
  98. *id1 = val;
  99. if (!isxdigit((*str)[0])) /* We require at least one hex digit */
  100. goto confused;
  101. val = simple_strtoul(*str, str, 16);
  102. if (val < 0 || val > 0xffff)
  103. goto confused;
  104. *devno = val;
  105. if ((*str)[0] != ',' && (*str)[0] != '-' &&
  106. (*str)[0] != '\n' && (*str)[0] != '\0')
  107. goto confused;
  108. return 0;
  109. confused:
  110. strsep(str, ",\n");
  111. printk(KERN_WARNING "Invalid cio_ignore parameter '%s'\n", sav);
  112. return 1;
  113. }
  114. static inline int
  115. blacklist_parse_parameters (char *str, range_action action)
  116. {
  117. unsigned int from, to, from_id0, to_id0, from_id1, to_id1;
  118. while (*str != 0 && *str != '\n') {
  119. range_action ra = action;
  120. while(*str == ',')
  121. str++;
  122. if (*str == '!') {
  123. ra = !action;
  124. ++str;
  125. }
  126. /*
  127. * Since we have to parse the proc commands and the
  128. * kernel arguments we have to check four cases
  129. */
  130. if (strncmp(str,"all,",4) == 0 || strcmp(str,"all") == 0 ||
  131. strncmp(str,"all\n",4) == 0 || strncmp(str,"all ",4) == 0) {
  132. from = 0;
  133. to = __MAX_SUBCHANNELS;
  134. str += 3;
  135. } else {
  136. int rc;
  137. rc = blacklist_busid(&str, &from_id0,
  138. &from_id1, &from);
  139. if (rc)
  140. continue;
  141. to = from;
  142. to_id0 = from_id0;
  143. to_id1 = from_id1;
  144. if (*str == '-') {
  145. str++;
  146. rc = blacklist_busid(&str, &to_id0,
  147. &to_id1, &to);
  148. if (rc)
  149. continue;
  150. }
  151. if (*str == '-') {
  152. printk(KERN_WARNING "invalid cio_ignore "
  153. "parameter '%s'\n",
  154. strsep(&str, ",\n"));
  155. continue;
  156. }
  157. if ((from_id0 != to_id0) || (from_id1 != to_id1)) {
  158. printk(KERN_WARNING "invalid cio_ignore range "
  159. "%x.%x.%04x-%x.%x.%04x\n",
  160. from_id0, from_id1, from,
  161. to_id0, to_id1, to);
  162. continue;
  163. }
  164. }
  165. /* FIXME: ignoring id0 and id1 here. */
  166. pr_debug("blacklist_setup: adding range "
  167. "from 0.0.%04x to 0.0.%04x\n", from, to);
  168. blacklist_range (ra, from, to);
  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 devno)
  199. {
  200. return test_bit (devno, bl_dev);
  201. }
  202. #ifdef CONFIG_PROC_FS
  203. /*
  204. * Function: s390_redo_validation
  205. * Look for no longer blacklisted devices
  206. * FIXME: there must be a better way to do this */
  207. static inline void
  208. s390_redo_validation (void)
  209. {
  210. unsigned int irq;
  211. CIO_TRACE_EVENT (0, "redoval");
  212. for (irq = 0; irq < __MAX_SUBCHANNELS; irq++) {
  213. int ret;
  214. struct subchannel *sch;
  215. sch = get_subchannel_by_schid(irq);
  216. if (sch) {
  217. /* Already known. */
  218. put_device(&sch->dev);
  219. continue;
  220. }
  221. ret = css_probe_device(irq);
  222. if (ret == -ENXIO)
  223. break; /* We're through. */
  224. if (ret == -ENOMEM)
  225. /*
  226. * Stop validation for now. Bad, but no need for a
  227. * panic.
  228. */
  229. break;
  230. }
  231. }
  232. /*
  233. * Function: blacklist_parse_proc_parameters
  234. * parse the stuff which is piped to /proc/cio_ignore
  235. */
  236. static inline void
  237. blacklist_parse_proc_parameters (char *buf)
  238. {
  239. if (strncmp (buf, "free ", 5) == 0) {
  240. blacklist_parse_parameters (buf + 5, free);
  241. } else if (strncmp (buf, "add ", 4) == 0) {
  242. /*
  243. * We don't need to check for known devices since
  244. * css_probe_device will handle this correctly.
  245. */
  246. blacklist_parse_parameters (buf + 4, add);
  247. } else {
  248. printk (KERN_WARNING "cio_ignore: Parse error; \n"
  249. KERN_WARNING "try using 'free all|<devno-range>,"
  250. "<devno-range>,...'\n"
  251. KERN_WARNING "or 'add <devno-range>,"
  252. "<devno-range>,...'\n");
  253. return;
  254. }
  255. s390_redo_validation ();
  256. }
  257. /* FIXME: These should be real bus ids and not home-grown ones! */
  258. static int cio_ignore_read (char *page, char **start, off_t off,
  259. int count, int *eof, void *data)
  260. {
  261. const unsigned int entry_size = 18; /* "0.0.ABCD-0.0.EFGH\n" */
  262. long devno;
  263. int len;
  264. len = 0;
  265. for (devno = off; /* abuse the page variable
  266. * as counter, see fs/proc/generic.c */
  267. devno < __MAX_SUBCHANNELS && len + entry_size < count; devno++) {
  268. if (!test_bit(devno, bl_dev))
  269. continue;
  270. len += sprintf(page + len, "0.0.%04lx", devno);
  271. if (test_bit(devno + 1, bl_dev)) { /* print range */
  272. while (++devno < __MAX_SUBCHANNELS)
  273. if (!test_bit(devno, bl_dev))
  274. break;
  275. len += sprintf(page + len, "-0.0.%04lx", --devno);
  276. }
  277. len += sprintf(page + len, "\n");
  278. }
  279. if (devno < __MAX_SUBCHANNELS)
  280. *eof = 1;
  281. *start = (char *) (devno - off); /* number of checked entries */
  282. return len;
  283. }
  284. static int cio_ignore_write(struct file *file, const char __user *user_buf,
  285. unsigned long user_len, void *data)
  286. {
  287. char *buf;
  288. if (user_len > 65536)
  289. user_len = 65536;
  290. buf = vmalloc (user_len + 1); /* maybe better use the stack? */
  291. if (buf == NULL)
  292. return -ENOMEM;
  293. if (strncpy_from_user (buf, user_buf, user_len) < 0) {
  294. vfree (buf);
  295. return -EFAULT;
  296. }
  297. buf[user_len] = '\0';
  298. blacklist_parse_proc_parameters (buf);
  299. vfree (buf);
  300. return user_len;
  301. }
  302. static int
  303. cio_ignore_proc_init (void)
  304. {
  305. struct proc_dir_entry *entry;
  306. entry = create_proc_entry ("cio_ignore", S_IFREG | S_IRUGO | S_IWUSR,
  307. &proc_root);
  308. if (!entry)
  309. return 0;
  310. entry->read_proc = cio_ignore_read;
  311. entry->write_proc = cio_ignore_write;
  312. return 1;
  313. }
  314. __initcall (cio_ignore_proc_init);
  315. #endif /* CONFIG_PROC_FS */