blacklist.c 9.9 KB

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