blob: 5137dafd1e8d18e03470d836496407d2564d2be3 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * drivers/s390/cio/css.c
3 * driver for channel subsystem
4 * $Revision: 1.85 $
5 *
6 * Copyright (C) 2002 IBM Deutschland Entwicklung GmbH,
7 * IBM Corporation
8 * Author(s): Arnd Bergmann (arndb@de.ibm.com)
9 * Cornelia Huck (cohuck@de.ibm.com)
10 */
11#include <linux/module.h>
12#include <linux/init.h>
13#include <linux/device.h>
14#include <linux/slab.h>
15#include <linux/errno.h>
16#include <linux/list.h>
17
18#include "css.h"
19#include "cio.h"
20#include "cio_debug.h"
21#include "ioasm.h"
22#include "chsc.h"
23
24unsigned int highest_subchannel;
25int need_rescan = 0;
26int css_init_done = 0;
27
28struct pgid global_pgid;
29int css_characteristics_avail = 0;
30
31struct device css_bus_device = {
32 .bus_id = "css0",
33};
34
35static struct subchannel *
Cornelia Hucka8237fc2006-01-06 00:19:21 -080036css_alloc_subchannel(struct subchannel_id schid)
Linus Torvalds1da177e2005-04-16 15:20:36 -070037{
38 struct subchannel *sch;
39 int ret;
40
41 sch = kmalloc (sizeof (*sch), GFP_KERNEL | GFP_DMA);
42 if (sch == NULL)
43 return ERR_PTR(-ENOMEM);
Cornelia Hucka8237fc2006-01-06 00:19:21 -080044 ret = cio_validate_subchannel (sch, schid);
Linus Torvalds1da177e2005-04-16 15:20:36 -070045 if (ret < 0) {
46 kfree(sch);
47 return ERR_PTR(ret);
48 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070049
50 if (sch->st != SUBCHANNEL_TYPE_IO) {
51 /* For now we ignore all non-io subchannels. */
52 kfree(sch);
53 return ERR_PTR(-EINVAL);
54 }
55
56 /*
57 * Set intparm to subchannel address.
58 * This is fine even on 64bit since the subchannel is always located
59 * under 2G.
60 */
61 sch->schib.pmcw.intparm = (__u32)(unsigned long)sch;
62 ret = cio_modify(sch);
63 if (ret) {
64 kfree(sch);
65 return ERR_PTR(ret);
66 }
67 return sch;
68}
69
70static void
71css_free_subchannel(struct subchannel *sch)
72{
73 if (sch) {
74 /* Reset intparm to zeroes. */
75 sch->schib.pmcw.intparm = 0;
76 cio_modify(sch);
77 kfree(sch);
78 }
79
80}
81
82static void
83css_subchannel_release(struct device *dev)
84{
85 struct subchannel *sch;
86
87 sch = to_subchannel(dev);
Cornelia Hucka8237fc2006-01-06 00:19:21 -080088 if (!cio_is_console(sch->schid))
Linus Torvalds1da177e2005-04-16 15:20:36 -070089 kfree(sch);
90}
91
92extern int css_get_ssd_info(struct subchannel *sch);
93
94static int
95css_register_subchannel(struct subchannel *sch)
96{
97 int ret;
98
99 /* Initialize the subchannel structure */
100 sch->dev.parent = &css_bus_device;
101 sch->dev.bus = &css_bus_type;
102 sch->dev.release = &css_subchannel_release;
103
104 /* make it known to the system */
105 ret = device_register(&sch->dev);
106 if (ret)
107 printk (KERN_WARNING "%s: could not register %s\n",
108 __func__, sch->dev.bus_id);
109 else
110 css_get_ssd_info(sch);
111 return ret;
112}
113
114int
Cornelia Hucka8237fc2006-01-06 00:19:21 -0800115css_probe_device(struct subchannel_id schid)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700116{
117 int ret;
118 struct subchannel *sch;
119
Cornelia Hucka8237fc2006-01-06 00:19:21 -0800120 sch = css_alloc_subchannel(schid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700121 if (IS_ERR(sch))
122 return PTR_ERR(sch);
123 ret = css_register_subchannel(sch);
124 if (ret)
125 css_free_subchannel(sch);
126 return ret;
127}
128
Cornelia Huckb0744bd2005-06-25 14:55:27 -0700129static int
130check_subchannel(struct device * dev, void * data)
131{
132 struct subchannel *sch;
Cornelia Hucka8237fc2006-01-06 00:19:21 -0800133 struct subchannel_id *schid = data;
Cornelia Huckb0744bd2005-06-25 14:55:27 -0700134
135 sch = to_subchannel(dev);
Cornelia Hucka8237fc2006-01-06 00:19:21 -0800136 return schid_equal(&sch->schid, schid);
Cornelia Huckb0744bd2005-06-25 14:55:27 -0700137}
138
Linus Torvalds1da177e2005-04-16 15:20:36 -0700139struct subchannel *
Cornelia Hucka8237fc2006-01-06 00:19:21 -0800140get_subchannel_by_schid(struct subchannel_id schid)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700141{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700142 struct device *dev;
143
Cornelia Huckb0744bd2005-06-25 14:55:27 -0700144 dev = bus_find_device(&css_bus_type, NULL,
Cornelia Hucka8237fc2006-01-06 00:19:21 -0800145 (void *)&schid, check_subchannel);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700146
Cornelia Huckb0744bd2005-06-25 14:55:27 -0700147 return dev ? to_subchannel(dev) : NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700148}
149
Cornelia Huckb0744bd2005-06-25 14:55:27 -0700150
Linus Torvalds1da177e2005-04-16 15:20:36 -0700151static inline int
Cornelia Hucka8237fc2006-01-06 00:19:21 -0800152css_get_subchannel_status(struct subchannel *sch, struct subchannel_id schid)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700153{
154 struct schib schib;
155 int cc;
156
157 cc = stsch(schid, &schib);
158 if (cc)
159 return CIO_GONE;
160 if (!schib.pmcw.dnv)
161 return CIO_GONE;
162 if (sch && sch->schib.pmcw.dnv &&
163 (schib.pmcw.dev != sch->schib.pmcw.dev))
164 return CIO_REVALIDATE;
165 if (sch && !sch->lpm)
166 return CIO_NO_PATH;
167 return CIO_OPER;
168}
169
170static int
Cornelia Hucka8237fc2006-01-06 00:19:21 -0800171css_evaluate_subchannel(struct subchannel_id schid, int slow)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700172{
173 int event, ret, disc;
174 struct subchannel *sch;
175 unsigned long flags;
176
Cornelia Hucka8237fc2006-01-06 00:19:21 -0800177 sch = get_subchannel_by_schid(schid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700178 disc = sch ? device_is_disconnected(sch) : 0;
179 if (disc && slow) {
180 if (sch)
181 put_device(&sch->dev);
182 return 0; /* Already processed. */
183 }
184 /*
185 * We've got a machine check, so running I/O won't get an interrupt.
186 * Kill any pending timers.
187 */
188 if (sch)
189 device_kill_pending_timer(sch);
190 if (!disc && !slow) {
191 if (sch)
192 put_device(&sch->dev);
193 return -EAGAIN; /* Will be done on the slow path. */
194 }
Cornelia Hucka8237fc2006-01-06 00:19:21 -0800195 event = css_get_subchannel_status(sch, schid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700196 CIO_MSG_EVENT(4, "Evaluating schid %04x, event %d, %s, %s path.\n",
Cornelia Hucka8237fc2006-01-06 00:19:21 -0800197 schid.sch_no, event,
198 sch?(disc?"disconnected":"normal"):"unknown",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700199 slow?"slow":"fast");
200 switch (event) {
201 case CIO_NO_PATH:
202 case CIO_GONE:
203 if (!sch) {
204 /* Never used this subchannel. Ignore. */
205 ret = 0;
206 break;
207 }
208 if (disc && (event == CIO_NO_PATH)) {
209 /*
210 * Uargh, hack again. Because we don't get a machine
211 * check on configure on, our path bookkeeping can
212 * be out of date here (it's fine while we only do
213 * logical varying or get chsc machine checks). We
214 * need to force reprobing or we might miss devices
215 * coming operational again. It won't do harm in real
216 * no path situations.
217 */
218 spin_lock_irqsave(&sch->lock, flags);
219 device_trigger_reprobe(sch);
220 spin_unlock_irqrestore(&sch->lock, flags);
221 ret = 0;
222 break;
223 }
224 if (sch->driver && sch->driver->notify &&
225 sch->driver->notify(&sch->dev, event)) {
226 cio_disable_subchannel(sch);
227 device_set_disconnected(sch);
228 ret = 0;
229 break;
230 }
231 /*
232 * Unregister subchannel.
233 * The device will be killed automatically.
234 */
235 cio_disable_subchannel(sch);
236 device_unregister(&sch->dev);
237 /* Reset intparm to zeroes. */
238 sch->schib.pmcw.intparm = 0;
239 cio_modify(sch);
240 put_device(&sch->dev);
241 ret = 0;
242 break;
243 case CIO_REVALIDATE:
244 /*
245 * Revalidation machine check. Sick.
246 * We don't notify the driver since we have to throw the device
247 * away in any case.
248 */
249 if (!disc) {
250 device_unregister(&sch->dev);
251 /* Reset intparm to zeroes. */
252 sch->schib.pmcw.intparm = 0;
253 cio_modify(sch);
254 put_device(&sch->dev);
Cornelia Hucka8237fc2006-01-06 00:19:21 -0800255 ret = css_probe_device(schid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700256 } else {
257 /*
258 * We can't immediately deregister the disconnected
259 * device since it might block.
260 */
261 spin_lock_irqsave(&sch->lock, flags);
262 device_trigger_reprobe(sch);
263 spin_unlock_irqrestore(&sch->lock, flags);
264 ret = 0;
265 }
266 break;
267 case CIO_OPER:
268 if (disc) {
269 spin_lock_irqsave(&sch->lock, flags);
270 /* Get device operational again. */
271 device_trigger_reprobe(sch);
272 spin_unlock_irqrestore(&sch->lock, flags);
273 }
Cornelia Hucka8237fc2006-01-06 00:19:21 -0800274 ret = sch ? 0 : css_probe_device(schid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700275 break;
276 default:
277 BUG();
278 ret = 0;
279 }
280 return ret;
281}
282
283static void
284css_rescan_devices(void)
285{
Cornelia Hucka8237fc2006-01-06 00:19:21 -0800286 int ret;
287 struct subchannel_id schid;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700288
Cornelia Hucka8237fc2006-01-06 00:19:21 -0800289 init_subchannel_id(&schid);
290 do {
291 ret = css_evaluate_subchannel(schid, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700292 /* No more memory. It doesn't make sense to continue. No
293 * panic because this can happen in midflight and just
294 * because we can't use a new device is no reason to crash
295 * the system. */
296 if (ret == -ENOMEM)
297 break;
298 /* -ENXIO indicates that there are no more subchannels. */
299 if (ret == -ENXIO)
300 break;
Cornelia Hucka8237fc2006-01-06 00:19:21 -0800301 } while (schid.sch_no++ < __MAX_SUBCHANNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700302}
303
304struct slow_subchannel {
305 struct list_head slow_list;
Cornelia Hucka8237fc2006-01-06 00:19:21 -0800306 struct subchannel_id schid;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700307};
308
309static LIST_HEAD(slow_subchannels_head);
310static DEFINE_SPINLOCK(slow_subchannel_lock);
311
312static void
313css_trigger_slow_path(void)
314{
315 CIO_TRACE_EVENT(4, "slowpath");
316
317 if (need_rescan) {
318 need_rescan = 0;
319 css_rescan_devices();
320 return;
321 }
322
323 spin_lock_irq(&slow_subchannel_lock);
324 while (!list_empty(&slow_subchannels_head)) {
325 struct slow_subchannel *slow_sch =
326 list_entry(slow_subchannels_head.next,
327 struct slow_subchannel, slow_list);
328
329 list_del_init(slow_subchannels_head.next);
330 spin_unlock_irq(&slow_subchannel_lock);
331 css_evaluate_subchannel(slow_sch->schid, 1);
332 spin_lock_irq(&slow_subchannel_lock);
333 kfree(slow_sch);
334 }
335 spin_unlock_irq(&slow_subchannel_lock);
336}
337
338typedef void (*workfunc)(void *);
339DECLARE_WORK(slow_path_work, (workfunc)css_trigger_slow_path, NULL);
340struct workqueue_struct *slow_path_wq;
341
342/*
343 * Rescan for new devices. FIXME: This is slow.
344 * This function is called when we have lost CRWs due to overflows and we have
345 * to do subchannel housekeeping.
346 */
347void
348css_reiterate_subchannels(void)
349{
350 css_clear_subchannel_slow_list();
351 need_rescan = 1;
352}
353
354/*
355 * Called from the machine check handler for subchannel report words.
356 */
357int
358css_process_crw(int irq)
359{
360 int ret;
Cornelia Hucka8237fc2006-01-06 00:19:21 -0800361 struct subchannel_id mchk_schid;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700362
363 CIO_CRW_EVENT(2, "source is subchannel %04X\n", irq);
364
365 if (need_rescan)
366 /* We need to iterate all subchannels anyway. */
367 return -EAGAIN;
Cornelia Hucka8237fc2006-01-06 00:19:21 -0800368
369 init_subchannel_id(&mchk_schid);
370 mchk_schid.sch_no = irq;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700371 /*
372 * Since we are always presented with IPI in the CRW, we have to
373 * use stsch() to find out if the subchannel in question has come
374 * or gone.
375 */
Cornelia Hucka8237fc2006-01-06 00:19:21 -0800376 ret = css_evaluate_subchannel(mchk_schid, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377 if (ret == -EAGAIN) {
Cornelia Hucka8237fc2006-01-06 00:19:21 -0800378 if (css_enqueue_subchannel_slow(mchk_schid)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379 css_clear_subchannel_slow_list();
380 need_rescan = 1;
381 }
382 }
383 return ret;
384}
385
386static void __init
387css_generate_pgid(void)
388{
389 /* Let's build our path group ID here. */
390 if (css_characteristics_avail && css_general_characteristics.mcss)
391 global_pgid.cpu_addr = 0x8000;
392 else {
393#ifdef CONFIG_SMP
394 global_pgid.cpu_addr = hard_smp_processor_id();
395#else
396 global_pgid.cpu_addr = 0;
397#endif
398 }
399 global_pgid.cpu_id = ((cpuid_t *) __LC_CPUID)->ident;
400 global_pgid.cpu_model = ((cpuid_t *) __LC_CPUID)->machine;
401 global_pgid.tod_high = (__u32) (get_clock() >> 32);
402}
403
404/*
405 * Now that the driver core is running, we can setup our channel subsystem.
406 * The struct subchannel's are created during probing (except for the
407 * static console subchannel).
408 */
409static int __init
410init_channel_subsystem (void)
411{
Cornelia Hucka8237fc2006-01-06 00:19:21 -0800412 int ret;
413 struct subchannel_id schid;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700414
415 if (chsc_determine_css_characteristics() == 0)
416 css_characteristics_avail = 1;
417
418 css_generate_pgid();
419
420 if ((ret = bus_register(&css_bus_type)))
421 goto out;
422 if ((ret = device_register (&css_bus_device)))
423 goto out_bus;
424
425 css_init_done = 1;
426
427 ctl_set_bit(6, 28);
428
Cornelia Hucka8237fc2006-01-06 00:19:21 -0800429 init_subchannel_id(&schid);
430 do {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700431 struct subchannel *sch;
432
Cornelia Hucka8237fc2006-01-06 00:19:21 -0800433 if (cio_is_console(schid))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700434 sch = cio_get_console_subchannel();
435 else {
Cornelia Hucka8237fc2006-01-06 00:19:21 -0800436 sch = css_alloc_subchannel(schid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700437 if (IS_ERR(sch))
438 ret = PTR_ERR(sch);
439 else
440 ret = 0;
441 if (ret == -ENOMEM)
442 panic("Out of memory in "
443 "init_channel_subsystem\n");
444 /* -ENXIO: no more subchannels. */
445 if (ret == -ENXIO)
446 break;
447 if (ret)
448 continue;
449 }
450 /*
451 * We register ALL valid subchannels in ioinfo, even those
452 * that have been present before init_channel_subsystem.
453 * These subchannels can't have been registered yet (kmalloc
454 * not working) so we do it now. This is true e.g. for the
455 * console subchannel.
456 */
457 css_register_subchannel(sch);
Cornelia Hucka8237fc2006-01-06 00:19:21 -0800458 } while (schid.sch_no++ < __MAX_SUBCHANNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700459 return 0;
460
461out_bus:
462 bus_unregister(&css_bus_type);
463out:
464 return ret;
465}
466
467/*
468 * find a driver for a subchannel. They identify by the subchannel
469 * type with the exception that the console subchannel driver has its own
470 * subchannel type although the device is an i/o subchannel
471 */
472static int
473css_bus_match (struct device *dev, struct device_driver *drv)
474{
475 struct subchannel *sch = container_of (dev, struct subchannel, dev);
476 struct css_driver *driver = container_of (drv, struct css_driver, drv);
477
478 if (sch->st == driver->subchannel_type)
479 return 1;
480
481 return 0;
482}
483
484struct bus_type css_bus_type = {
485 .name = "css",
486 .match = &css_bus_match,
487};
488
489subsys_initcall(init_channel_subsystem);
490
Linus Torvalds1da177e2005-04-16 15:20:36 -0700491int
Cornelia Hucka8237fc2006-01-06 00:19:21 -0800492css_enqueue_subchannel_slow(struct subchannel_id schid)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700493{
494 struct slow_subchannel *new_slow_sch;
495 unsigned long flags;
496
497 new_slow_sch = kmalloc(sizeof(struct slow_subchannel), GFP_ATOMIC);
498 if (!new_slow_sch)
499 return -ENOMEM;
500 memset(new_slow_sch, 0, sizeof(struct slow_subchannel));
501 new_slow_sch->schid = schid;
502 spin_lock_irqsave(&slow_subchannel_lock, flags);
503 list_add_tail(&new_slow_sch->slow_list, &slow_subchannels_head);
504 spin_unlock_irqrestore(&slow_subchannel_lock, flags);
505 return 0;
506}
507
508void
509css_clear_subchannel_slow_list(void)
510{
511 unsigned long flags;
512
513 spin_lock_irqsave(&slow_subchannel_lock, flags);
514 while (!list_empty(&slow_subchannels_head)) {
515 struct slow_subchannel *slow_sch =
516 list_entry(slow_subchannels_head.next,
517 struct slow_subchannel, slow_list);
518
519 list_del_init(slow_subchannels_head.next);
520 kfree(slow_sch);
521 }
522 spin_unlock_irqrestore(&slow_subchannel_lock, flags);
523}
524
525
526
527int
528css_slow_subchannels_exist(void)
529{
530 return (!list_empty(&slow_subchannels_head));
531}
532
533MODULE_LICENSE("GPL");
534EXPORT_SYMBOL(css_bus_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700535EXPORT_SYMBOL_GPL(css_characteristics_avail);