blacklist.c 9.8 KB

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