cio.c 25.8 KB
Newer Older
Linus Torvalds's avatar
Linus Torvalds committed
1
2
3
4
/*
 *  drivers/s390/cio/cio.c
 *   S/390 common I/O routines -- low level i/o calls
 *
5
 *    Copyright IBM Corp. 1999,2008
Linus Torvalds's avatar
Linus Torvalds committed
6
 *    Author(s): Ingo Adlung (adlung@de.ibm.com)
7
 *		 Cornelia Huck (cornelia.huck@de.ibm.com)
Linus Torvalds's avatar
Linus Torvalds committed
8
9
10
11
12
13
14
15
16
17
18
19
20
 *		 Arnd Bergmann (arndb@de.ibm.com)
 *		 Martin Schwidefsky (schwidefsky@de.ibm.com)
 */

#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/device.h>
#include <linux/kernel_stat.h>
#include <linux/interrupt.h>
#include <asm/cio.h>
#include <asm/delay.h>
#include <asm/irq.h>
21
#include <asm/irq_regs.h>
22
#include <asm/setup.h>
23
#include <asm/reset.h>
Michael Holzheu's avatar
Michael Holzheu committed
24
#include <asm/ipl.h>
25
#include <asm/chpid.h>
26
#include <asm/airq.h>
27
#include <asm/isc.h>
28
#include <asm/cpu.h>
29
#include <asm/fcx.h>
Linus Torvalds's avatar
Linus Torvalds committed
30
31
32
33
#include "cio.h"
#include "css.h"
#include "chsc.h"
#include "ioasm.h"
34
#include "io_sch.h"
Linus Torvalds's avatar
Linus Torvalds committed
35
36
#include "blacklist.h"
#include "cio_debug.h"
37
#include "chp.h"
38
#include "../s390mach.h"
Linus Torvalds's avatar
Linus Torvalds committed
39
40
41
42
43
44
45

debug_info_t *cio_debug_msg_id;
debug_info_t *cio_debug_trace_id;
debug_info_t *cio_debug_crw_id;

/*
 * Function: cio_debug_init
46
47
 * Initializes three debug logs for common I/O:
 * - cio_msg logs generic cio messages
Linus Torvalds's avatar
Linus Torvalds committed
48
 * - cio_trace logs the calling of different functions
49
 * - cio_crw logs machine check related cio messages
Linus Torvalds's avatar
Linus Torvalds committed
50
 */
51
static int __init cio_debug_init(void)
Linus Torvalds's avatar
Linus Torvalds committed
52
{
53
	cio_debug_msg_id = debug_register("cio_msg", 16, 1, 16 * sizeof(long));
Linus Torvalds's avatar
Linus Torvalds committed
54
55
	if (!cio_debug_msg_id)
		goto out_unregister;
56
57
	debug_register_view(cio_debug_msg_id, &debug_sprintf_view);
	debug_set_level(cio_debug_msg_id, 2);
58
	cio_debug_trace_id = debug_register("cio_trace", 16, 1, 16);
Linus Torvalds's avatar
Linus Torvalds committed
59
60
	if (!cio_debug_trace_id)
		goto out_unregister;
61
62
	debug_register_view(cio_debug_trace_id, &debug_hex_ascii_view);
	debug_set_level(cio_debug_trace_id, 2);
63
	cio_debug_crw_id = debug_register("cio_crw", 16, 1, 16 * sizeof(long));
Linus Torvalds's avatar
Linus Torvalds committed
64
65
	if (!cio_debug_crw_id)
		goto out_unregister;
66
67
	debug_register_view(cio_debug_crw_id, &debug_sprintf_view);
	debug_set_level(cio_debug_crw_id, 4);
Linus Torvalds's avatar
Linus Torvalds committed
68
69
70
71
	return 0;

out_unregister:
	if (cio_debug_msg_id)
72
		debug_unregister(cio_debug_msg_id);
Linus Torvalds's avatar
Linus Torvalds committed
73
	if (cio_debug_trace_id)
74
		debug_unregister(cio_debug_trace_id);
Linus Torvalds's avatar
Linus Torvalds committed
75
	if (cio_debug_crw_id)
76
		debug_unregister(cio_debug_crw_id);
Linus Torvalds's avatar
Linus Torvalds committed
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
	return -1;
}

arch_initcall (cio_debug_init);

int
cio_set_options (struct subchannel *sch, int flags)
{
       sch->options.suspend = (flags & DOIO_ALLOW_SUSPEND) != 0;
       sch->options.prefetch = (flags & DOIO_DENY_PREFETCH) != 0;
       sch->options.inter = (flags & DOIO_SUPPRESS_INTER) != 0;
       return 0;
}

/* FIXME: who wants to use this? */
int
cio_get_options (struct subchannel *sch)
{
       int flags;

       flags = 0;
       if (sch->options.suspend)
		flags |= DOIO_ALLOW_SUSPEND;
       if (sch->options.prefetch)
		flags |= DOIO_DENY_PREFETCH;
       if (sch->options.inter)
		flags |= DOIO_SUPPRESS_INTER;
       return flags;
}

107
static int
Linus Torvalds's avatar
Linus Torvalds committed
108
109
110
111
112
113
114
115
116
cio_start_handle_notoper(struct subchannel *sch, __u8 lpm)
{
	char dbf_text[15];

	if (lpm != 0)
		sch->lpm &= ~lpm;
	else
		sch->lpm = 0;

117
	stsch (sch->schid, &sch->schib);
Linus Torvalds's avatar
Linus Torvalds committed
118

119
	CIO_MSG_EVENT(2, "cio_start: 'not oper' status for "
120
121
		      "subchannel 0.%x.%04x!\n", sch->schid.ssid,
		      sch->schid.sch_no);
122
	sprintf(dbf_text, "no%s", dev_name(&sch->dev));
Linus Torvalds's avatar
Linus Torvalds committed
123
124
125
126
127
128
129
130
131
132
133
134
135
136
	CIO_TRACE_EVENT(0, dbf_text);
	CIO_HEX_EVENT(0, &sch->schib, sizeof (struct schib));

	return (sch->lpm ? -EACCES : -ENODEV);
}

int
cio_start_key (struct subchannel *sch,	/* subchannel structure */
	       struct ccw1 * cpa,	/* logical channel prog addr */
	       __u8 lpm,		/* logical path mask */
	       __u8 key)                /* storage key */
{
	char dbf_txt[15];
	int ccode;
137
	union orb *orb;
Linus Torvalds's avatar
Linus Torvalds committed
138

139
	CIO_TRACE_EVENT(4, "stIO");
140
	CIO_TRACE_EVENT(4, dev_name(&sch->dev));
Linus Torvalds's avatar
Linus Torvalds committed
141

142
	orb = &to_io_private(sch)->orb;
143
	memset(orb, 0, sizeof(union orb));
Linus Torvalds's avatar
Linus Torvalds committed
144
	/* sch is always under 2G. */
145
146
	orb->cmd.intparm = (u32)(addr_t)sch;
	orb->cmd.fmt = 1;
Linus Torvalds's avatar
Linus Torvalds committed
147

148
149
150
151
	orb->cmd.pfch = sch->options.prefetch == 0;
	orb->cmd.spnd = sch->options.suspend;
	orb->cmd.ssic = sch->options.suspend && sch->options.inter;
	orb->cmd.lpm = (lpm != 0) ? lpm : sch->lpm;
152
#ifdef CONFIG_64BIT
Linus Torvalds's avatar
Linus Torvalds committed
153
154
155
	/*
	 * for 64 bit we always support 64 bit IDAWs with 4k page size only
	 */
156
157
	orb->cmd.c64 = 1;
	orb->cmd.i2k = 0;
Linus Torvalds's avatar
Linus Torvalds committed
158
#endif
159
	orb->cmd.key = key >> 4;
Linus Torvalds's avatar
Linus Torvalds committed
160
	/* issue "Start Subchannel" */
161
	orb->cmd.cpa = (__u32) __pa(cpa);
162
	ccode = ssch(sch->schid, orb);
Linus Torvalds's avatar
Linus Torvalds committed
163
164

	/* process condition code */
165
166
	sprintf(dbf_txt, "ccode:%d", ccode);
	CIO_TRACE_EVENT(4, dbf_txt);
Linus Torvalds's avatar
Linus Torvalds committed
167
168
169
170
171
172

	switch (ccode) {
	case 0:
		/*
		 * initialize device status information
		 */
173
		sch->schib.scsw.cmd.actl |= SCSW_ACTL_START_PEND;
Linus Torvalds's avatar
Linus Torvalds committed
174
175
176
177
		return 0;
	case 1:		/* status pending */
	case 2:		/* busy */
		return -EBUSY;
178
	case 3:		/* device/path not operational */
Linus Torvalds's avatar
Linus Torvalds committed
179
		return cio_start_handle_notoper(sch, lpm);
180
181
	default:
		return ccode;
Linus Torvalds's avatar
Linus Torvalds committed
182
183
184
185
186
187
	}
}

int
cio_start (struct subchannel *sch, struct ccw1 *cpa, __u8 lpm)
{
188
	return cio_start_key(sch, cpa, lpm, PAGE_DEFAULT_KEY);
Linus Torvalds's avatar
Linus Torvalds committed
189
190
191
192
193
194
195
196
197
198
199
200
}

/*
 * resume suspended I/O operation
 */
int
cio_resume (struct subchannel *sch)
{
	char dbf_txt[15];
	int ccode;

	CIO_TRACE_EVENT (4, "resIO");
201
	CIO_TRACE_EVENT(4, dev_name(&sch->dev));
Linus Torvalds's avatar
Linus Torvalds committed
202

203
	ccode = rsch (sch->schid);
Linus Torvalds's avatar
Linus Torvalds committed
204
205
206
207
208
209

	sprintf (dbf_txt, "ccode:%d", ccode);
	CIO_TRACE_EVENT (4, dbf_txt);

	switch (ccode) {
	case 0:
210
		sch->schib.scsw.cmd.actl |= SCSW_ACTL_RESUME_PEND;
Linus Torvalds's avatar
Linus Torvalds committed
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
		return 0;
	case 1:
		return -EBUSY;
	case 2:
		return -EINVAL;
	default:
		/*
		 * useless to wait for request completion
		 *  as device is no longer operational !
		 */
		return -ENODEV;
	}
}

/*
 * halt I/O operation
 */
int
cio_halt(struct subchannel *sch)
{
	char dbf_txt[15];
	int ccode;

	if (!sch)
		return -ENODEV;

	CIO_TRACE_EVENT (2, "haltIO");
238
	CIO_TRACE_EVENT(2, dev_name(&sch->dev));
Linus Torvalds's avatar
Linus Torvalds committed
239
240
241
242

	/*
	 * Issue "Halt subchannel" and process condition code
	 */
243
	ccode = hsch (sch->schid);
Linus Torvalds's avatar
Linus Torvalds committed
244
245
246
247
248
249

	sprintf (dbf_txt, "ccode:%d", ccode);
	CIO_TRACE_EVENT (2, dbf_txt);

	switch (ccode) {
	case 0:
250
		sch->schib.scsw.cmd.actl |= SCSW_ACTL_HALT_PEND;
Linus Torvalds's avatar
Linus Torvalds committed
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
		return 0;
	case 1:		/* status pending */
	case 2:		/* busy */
		return -EBUSY;
	default:		/* device not operational */
		return -ENODEV;
	}
}

/*
 * Clear I/O operation
 */
int
cio_clear(struct subchannel *sch)
{
	char dbf_txt[15];
	int ccode;

	if (!sch)
		return -ENODEV;

	CIO_TRACE_EVENT (2, "clearIO");
273
	CIO_TRACE_EVENT(2, dev_name(&sch->dev));
Linus Torvalds's avatar
Linus Torvalds committed
274
275
276
277

	/*
	 * Issue "Clear subchannel" and process condition code
	 */
278
	ccode = csch (sch->schid);
Linus Torvalds's avatar
Linus Torvalds committed
279
280
281
282
283
284

	sprintf (dbf_txt, "ccode:%d", ccode);
	CIO_TRACE_EVENT (2, dbf_txt);

	switch (ccode) {
	case 0:
285
		sch->schib.scsw.cmd.actl |= SCSW_ACTL_CLEAR_PEND;
Linus Torvalds's avatar
Linus Torvalds committed
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
		return 0;
	default:		/* device not operational */
		return -ENODEV;
	}
}

/*
 * Function: cio_cancel
 * Issues a "Cancel Subchannel" on the specified subchannel
 * Note: We don't need any fancy intparms and flags here
 *	 since xsch is executed synchronously.
 * Only for common I/O internal use as for now.
 */
int
cio_cancel (struct subchannel *sch)
{
	char dbf_txt[15];
	int ccode;

	if (!sch)
		return -ENODEV;

	CIO_TRACE_EVENT (2, "cancelIO");
309
	CIO_TRACE_EVENT(2, dev_name(&sch->dev));
Linus Torvalds's avatar
Linus Torvalds committed
310

311
	ccode = xsch (sch->schid);
Linus Torvalds's avatar
Linus Torvalds committed
312
313
314
315
316
317
318

	sprintf (dbf_txt, "ccode:%d", ccode);
	CIO_TRACE_EVENT (2, dbf_txt);

	switch (ccode) {
	case 0:		/* success */
		/* Update information in scsw. */
319
		stsch (sch->schid, &sch->schib);
Linus Torvalds's avatar
Linus Torvalds committed
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
		return 0;
	case 1:		/* status pending */
		return -EBUSY;
	case 2:		/* not applicable */
		return -EINVAL;
	default:	/* not oper */
		return -ENODEV;
	}
}

/*
 * Function: cio_modify
 * Issues a "Modify Subchannel" on the specified subchannel
 */
int
cio_modify (struct subchannel *sch)
{
	int ccode, retry, ret;

	ret = 0;
	for (retry = 0; retry < 5; retry++) {
341
		ccode = msch_err (sch->schid, &sch->schib);
Linus Torvalds's avatar
Linus Torvalds committed
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
		if (ccode < 0)	/* -EIO if msch gets a program check. */
			return ccode;
		switch (ccode) {
		case 0: /* successfull */
			return 0;
		case 1:	/* status pending */
			return -EBUSY;
		case 2:	/* busy */
			udelay (100);	/* allow for recovery */
			ret = -EBUSY;
			break;
		case 3:	/* not operational */
			return -ENODEV;
		}
	}
	return ret;
}

360
361
362
363
/**
 * cio_enable_subchannel - enable a subchannel.
 * @sch: subchannel to be enabled
 * @intparm: interruption parameter to set
Linus Torvalds's avatar
Linus Torvalds committed
364
 */
365
int cio_enable_subchannel(struct subchannel *sch, u32 intparm)
Linus Torvalds's avatar
Linus Torvalds committed
366
367
368
369
370
371
372
{
	char dbf_txt[15];
	int ccode;
	int retry;
	int ret;

	CIO_TRACE_EVENT (2, "ensch");
373
	CIO_TRACE_EVENT(2, dev_name(&sch->dev));
Linus Torvalds's avatar
Linus Torvalds committed
374

375
376
	if (sch_is_pseudo_sch(sch))
		return -EINVAL;
377
	ccode = stsch (sch->schid, &sch->schib);
Linus Torvalds's avatar
Linus Torvalds committed
378
379
380
381
382
	if (ccode)
		return -ENODEV;

	for (retry = 5, ret = 0; retry > 0; retry--) {
		sch->schib.pmcw.ena = 1;
383
		sch->schib.pmcw.isc = sch->isc;
384
		sch->schib.pmcw.intparm = intparm;
Linus Torvalds's avatar
Linus Torvalds committed
385
386
387
388
389
390
391
392
393
394
		ret = cio_modify(sch);
		if (ret == -ENODEV)
			break;
		if (ret == -EIO)
			/*
			 * Got a program check in cio_modify. Try without
			 * the concurrent sense bit the next time.
			 */
			sch->schib.pmcw.csense = 0;
		if (ret == 0) {
395
			stsch (sch->schid, &sch->schib);
Linus Torvalds's avatar
Linus Torvalds committed
396
397
398
399
400
			if (sch->schib.pmcw.ena)
				break;
		}
		if (ret == -EBUSY) {
			struct irb irb;
401
			if (tsch(sch->schid, &irb) != 0)
Linus Torvalds's avatar
Linus Torvalds committed
402
403
404
405
406
407
408
				break;
		}
	}
	sprintf (dbf_txt, "ret:%d", ret);
	CIO_TRACE_EVENT (2, dbf_txt);
	return ret;
}
409
EXPORT_SYMBOL_GPL(cio_enable_subchannel);
Linus Torvalds's avatar
Linus Torvalds committed
410

411
412
413
/**
 * cio_disable_subchannel - disable a subchannel.
 * @sch: subchannel to disable
Linus Torvalds's avatar
Linus Torvalds committed
414
 */
415
int cio_disable_subchannel(struct subchannel *sch)
Linus Torvalds's avatar
Linus Torvalds committed
416
417
418
419
420
421
422
{
	char dbf_txt[15];
	int ccode;
	int retry;
	int ret;

	CIO_TRACE_EVENT (2, "dissch");
423
	CIO_TRACE_EVENT(2, dev_name(&sch->dev));
Linus Torvalds's avatar
Linus Torvalds committed
424

425
426
	if (sch_is_pseudo_sch(sch))
		return 0;
427
	ccode = stsch (sch->schid, &sch->schib);
Linus Torvalds's avatar
Linus Torvalds committed
428
429
430
	if (ccode == 3)		/* Not operational. */
		return -ENODEV;

431
	if (scsw_actl(&sch->schib.scsw) != 0)
Linus Torvalds's avatar
Linus Torvalds committed
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
		/*
		 * the disable function must not be called while there are
		 *  requests pending for completion !
		 */
		return -EBUSY;

	for (retry = 5, ret = 0; retry > 0; retry--) {
		sch->schib.pmcw.ena = 0;
		ret = cio_modify(sch);
		if (ret == -ENODEV)
			break;
		if (ret == -EBUSY)
			/*
			 * The subchannel is busy or status pending.
			 * We'll disable when the next interrupt was delivered
			 * via the state machine.
			 */
			break;
		if (ret == 0) {
451
			stsch (sch->schid, &sch->schib);
Linus Torvalds's avatar
Linus Torvalds committed
452
453
454
455
456
457
458
459
			if (!sch->schib.pmcw.ena)
				break;
		}
	}
	sprintf (dbf_txt, "ret:%d", ret);
	CIO_TRACE_EVENT (2, dbf_txt);
	return ret;
}
460
EXPORT_SYMBOL_GPL(cio_disable_subchannel);
Linus Torvalds's avatar
Linus Torvalds committed
461

462
int cio_create_sch_lock(struct subchannel *sch)
463
464
465
466
467
468
469
470
{
	sch->lock = kmalloc(sizeof(spinlock_t), GFP_KERNEL);
	if (!sch->lock)
		return -ENOMEM;
	spin_lock_init(sch->lock);
	return 0;
}

471
static int cio_check_devno_blacklisted(struct subchannel *sch)
472
473
474
475
476
477
478
479
480
481
482
483
484
485
{
	if (is_blacklisted(sch->schid.ssid, sch->schib.pmcw.dev)) {
		/*
		 * This device must not be known to Linux. So we simply
		 * say that there is no device and return ENODEV.
		 */
		CIO_MSG_EVENT(6, "Blacklisted device detected "
			      "at devno %04X, subchannel set %x\n",
			      sch->schib.pmcw.dev, sch->schid.ssid);
		return -ENODEV;
	}
	return 0;
}

486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
static int cio_validate_io_subchannel(struct subchannel *sch)
{
	/* Initialization for io subchannels. */
	if (!css_sch_is_valid(&sch->schib))
		return -ENODEV;

	/* Devno is valid. */
	return cio_check_devno_blacklisted(sch);
}

static int cio_validate_msg_subchannel(struct subchannel *sch)
{
	/* Initialization for message subchannels. */
	if (!css_sch_is_valid(&sch->schib))
		return -ENODEV;

	/* Devno is valid. */
	return cio_check_devno_blacklisted(sch);
}

506
507
508
509
/**
 * cio_validate_subchannel - basic validation of subchannel
 * @sch: subchannel structure to be filled out
 * @schid: subchannel id
Linus Torvalds's avatar
Linus Torvalds committed
510
511
512
 *
 * Find out subchannel type and initialize struct subchannel.
 * Return codes:
513
 *   0 on success
Linus Torvalds's avatar
Linus Torvalds committed
514
 *   -ENXIO for non-defined subchannels
515
516
 *   -ENODEV for invalid subchannels or blacklisted devices
 *   -EIO for subchannels in an invalid subchannel set
Linus Torvalds's avatar
Linus Torvalds committed
517
 */
518
int cio_validate_subchannel(struct subchannel *sch, struct subchannel_id schid)
Linus Torvalds's avatar
Linus Torvalds committed
519
520
521
{
	char dbf_txt[15];
	int ccode;
522
	int err;
Linus Torvalds's avatar
Linus Torvalds committed
523

524
525
	sprintf(dbf_txt, "valsch%x", schid.sch_no);
	CIO_TRACE_EVENT(4, dbf_txt);
Linus Torvalds's avatar
Linus Torvalds committed
526
527
528
529

	/* Nuke all fields. */
	memset(sch, 0, sizeof(struct subchannel));

530
531
532
533
534
535
536
537
	sch->schid = schid;
	if (cio_is_console(schid)) {
		sch->lock = cio_get_console_lock();
	} else {
		err = cio_create_sch_lock(sch);
		if (err)
			goto out;
	}
538
	mutex_init(&sch->reg_mutex);
Linus Torvalds's avatar
Linus Torvalds committed
539
	/* Set a name for the subchannel */
540
541
542
543
	if (cio_is_console(schid))
		sch->dev.init_name = cio_get_console_sch_name(schid);
	else
		dev_set_name(&sch->dev, "0.%x.%04x", schid.ssid, schid.sch_no);
Linus Torvalds's avatar
Linus Torvalds committed
544
545
546
547

	/*
	 * The first subchannel that is not-operational (ccode==3)
	 *  indicates that there aren't any more devices available.
548
549
	 * If stsch gets an exception, it means the current subchannel set
	 *  is not valid.
Linus Torvalds's avatar
Linus Torvalds committed
550
	 */
551
	ccode = stsch_err (schid, &sch->schib);
552
553
554
555
	if (ccode) {
		err = (ccode == 3) ? -ENXIO : ccode;
		goto out;
	}
Linus Torvalds's avatar
Linus Torvalds committed
556
557
	/* Copy subchannel type from path management control word. */
	sch->st = sch->schib.pmcw.st;
Cornelia Huck's avatar
Cornelia Huck committed
558

559
560
561
562
	switch (sch->st) {
	case SUBCHANNEL_TYPE_IO:
		err = cio_validate_io_subchannel(sch);
		break;
563
564
565
	case SUBCHANNEL_TYPE_MSG:
		err = cio_validate_msg_subchannel(sch);
		break;
566
567
	default:
		err = 0;
Linus Torvalds's avatar
Linus Torvalds committed
568
	}
569
	if (err)
570
571
		goto out;

572
573
	CIO_MSG_EVENT(4, "Subchannel 0.%x.%04x reports subchannel type %04X\n",
		      sch->schid.ssid, sch->schid.sch_no, sch->st);
Linus Torvalds's avatar
Linus Torvalds committed
574
	return 0;
575
576
577
578
579
out:
	if (!cio_is_console(schid))
		kfree(sch->lock);
	sch->lock = NULL;
	return err;
Linus Torvalds's avatar
Linus Torvalds committed
580
581
582
583
584
585
586
587
588
589
590
591
592
593
}

/*
 * do_IRQ() handles all normal I/O device IRQ's (the special
 *	    SMP cross-CPU interrupts have their own specific
 *	    handlers).
 *
 */
void
do_IRQ (struct pt_regs *regs)
{
	struct tpi_info *tpi_info;
	struct subchannel *sch;
	struct irb *irb;
594
	struct pt_regs *old_regs;
Linus Torvalds's avatar
Linus Torvalds committed
595

596
	old_regs = set_irq_regs(regs);
597
	irq_enter();
598
	s390_idle_check();
599
600
601
	if (S390_lowcore.int_clock >= S390_lowcore.clock_comparator)
		/* Serve timer interrupts first. */
		clock_comparator_work();
Linus Torvalds's avatar
Linus Torvalds committed
602
603
604
605
606
607
608
609
610
611
612
613
	/*
	 * Get interrupt information from lowcore
	 */
	tpi_info = (struct tpi_info *) __LC_SUBCHANNEL_ID;
	irb = (struct irb *) __LC_IRB;
	do {
		kstat_cpu(smp_processor_id()).irqs[IO_INTERRUPT]++;
		/*
		 * Non I/O-subchannel thin interrupts are processed differently
		 */
		if (tpi_info->adapter_IO == 1 &&
		    tpi_info->int_type == IO_INTERRUPT_TYPE) {
614
			do_adapter_IO(tpi_info->isc);
Linus Torvalds's avatar
Linus Torvalds committed
615
616
617
			continue;
		}
		sch = (struct subchannel *)(unsigned long)tpi_info->intparm;
618
619
620
621
622
623
		if (!sch) {
			/* Clear pending interrupt condition. */
			tsch(tpi_info->schid, irb);
			continue;
		}
		spin_lock(sch->lock);
Linus Torvalds's avatar
Linus Torvalds committed
624
		/* Store interrupt response block to lowcore. */
625
		if (tsch(tpi_info->schid, irb) == 0) {
Linus Torvalds's avatar
Linus Torvalds committed
626
627
628
629
630
			/* Keep subchannel information word up to date. */
			memcpy (&sch->schib.scsw, &irb->scsw,
				sizeof (irb->scsw));
			/* Call interrupt handler if there is one. */
			if (sch->driver && sch->driver->irq)
631
				sch->driver->irq(sch);
Linus Torvalds's avatar
Linus Torvalds committed
632
		}
633
		spin_unlock(sch->lock);
Linus Torvalds's avatar
Linus Torvalds committed
634
635
636
637
638
639
640
641
		/*
		 * Are more interrupts pending?
		 * If so, the tpi instruction will update the lowcore
		 * to hold the info for the next interrupt.
		 * We don't do this for VM because a tpi drops the cpu
		 * out of the sie which costs more cycles than it saves.
		 */
	} while (!MACHINE_IS_VM && tpi (NULL) != 0);
642
	irq_exit();
643
	set_irq_regs(old_regs);
Linus Torvalds's avatar
Linus Torvalds committed
644
645
646
647
}

#ifdef CONFIG_CCW_CONSOLE
static struct subchannel console_subchannel;
648
static char console_sch_name[10] = "0.x.xxxx";
649
static struct io_subchannel_private console_priv;
Linus Torvalds's avatar
Linus Torvalds committed
650
651
static int console_subchannel_in_use;

652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
/*
 * Use tpi to get a pending interrupt, call the interrupt handler and
 * return a pointer to the subchannel structure.
 */
static int cio_tpi(void)
{
	struct tpi_info *tpi_info;
	struct subchannel *sch;
	struct irb *irb;
	int irq_context;

	tpi_info = (struct tpi_info *) __LC_SUBCHANNEL_ID;
	if (tpi(NULL) != 1)
		return 0;
	irb = (struct irb *) __LC_IRB;
	/* Store interrupt response block to lowcore. */
	if (tsch(tpi_info->schid, irb) != 0)
		/* Not status pending or not operational. */
		return 1;
	sch = (struct subchannel *)(unsigned long)tpi_info->intparm;
	if (!sch)
		return 1;
	irq_context = in_interrupt();
	if (!irq_context)
		local_bh_disable();
	irq_enter();
	spin_lock(sch->lock);
	memcpy(&sch->schib.scsw, &irb->scsw, sizeof(union scsw));
	if (sch->driver && sch->driver->irq)
		sch->driver->irq(sch);
	spin_unlock(sch->lock);
	irq_exit();
	if (!irq_context)
		_local_bh_enable();
	return 1;
}

689
690
691
692
693
void *cio_get_console_priv(void)
{
	return &console_priv;
}

Linus Torvalds's avatar
Linus Torvalds committed
694
695
696
/*
 * busy wait for the next interrupt on the console
 */
697
698
699
void wait_cons_dev(void)
	__releases(console_subchannel.lock)
	__acquires(console_subchannel.lock)
Linus Torvalds's avatar
Linus Torvalds committed
700
701
702
703
704
705
706
707
708
709
710
{
	unsigned long cr6      __attribute__ ((aligned (8)));
	unsigned long save_cr6 __attribute__ ((aligned (8)));

	/* 
	 * before entering the spinlock we may already have
	 * processed the interrupt on a different CPU...
	 */
	if (!console_subchannel_in_use)
		return;

711
	/* disable all but the console isc */
Linus Torvalds's avatar
Linus Torvalds committed
712
	__ctl_store (save_cr6, 6, 6);
713
	cr6 = 1UL << (31 - CONSOLE_ISC);
Linus Torvalds's avatar
Linus Torvalds committed
714
715
716
	__ctl_load (cr6, 6, 6);

	do {
717
		spin_unlock(console_subchannel.lock);
Linus Torvalds's avatar
Linus Torvalds committed
718
719
		if (!cio_tpi())
			cpu_relax();
720
		spin_lock(console_subchannel.lock);
721
	} while (console_subchannel.schib.scsw.cmd.actl != 0);
Linus Torvalds's avatar
Linus Torvalds committed
722
723
724
725
726
727
728
	/*
	 * restore previous isc value
	 */
	__ctl_load (save_cr6, 6, 6);
}

static int
729
730
cio_test_for_console(struct subchannel_id schid, void *data)
{
731
	if (stsch_err(schid, &console_subchannel.schib) != 0)
732
		return -ENXIO;
733
734
735
	if ((console_subchannel.schib.pmcw.st == SUBCHANNEL_TYPE_IO) &&
	    console_subchannel.schib.pmcw.dnv &&
	    (console_subchannel.schib.pmcw.dev == console_devno)) {
736
737
738
739
740
741
742
743
744
		console_irq = schid.sch_no;
		return 1; /* found */
	}
	return 0;
}


static int
cio_get_console_sch_no(void)
Linus Torvalds's avatar
Linus Torvalds committed
745
{
746
	struct subchannel_id schid;
Linus Torvalds's avatar
Linus Torvalds committed
747
	
748
	init_subchannel_id(&schid);
Linus Torvalds's avatar
Linus Torvalds committed
749
750
	if (console_irq != -1) {
		/* VM provided us with the irq number of the console. */
751
752
		schid.sch_no = console_irq;
		if (stsch(schid, &console_subchannel.schib) != 0 ||
753
		    (console_subchannel.schib.pmcw.st != SUBCHANNEL_TYPE_IO) ||
Linus Torvalds's avatar
Linus Torvalds committed
754
755
756
757
758
		    !console_subchannel.schib.pmcw.dnv)
			return -1;
		console_devno = console_subchannel.schib.pmcw.dev;
	} else if (console_devno != -1) {
		/* At least the console device number is known. */
759
		for_each_subchannel(cio_test_for_console, NULL);
Linus Torvalds's avatar
Linus Torvalds committed
760
761
762
763
764
765
766
767
768
769
770
771
772
773
		if (console_irq == -1)
			return -1;
	} else {
		/* unlike in 2.4, we cannot autoprobe here, since
		 * the channel subsystem is not fully initialized.
		 * With some luck, the HWC console can take over */
		return -1;
	}
	return console_irq;
}

struct subchannel *
cio_probe_console(void)
{
774
	int sch_no, ret;
775
	struct subchannel_id schid;
Linus Torvalds's avatar
Linus Torvalds committed
776
777
778

	if (xchg(&console_subchannel_in_use, 1) != 0)
		return ERR_PTR(-EBUSY);
779
780
	sch_no = cio_get_console_sch_no();
	if (sch_no == -1) {
Linus Torvalds's avatar
Linus Torvalds committed
781
		console_subchannel_in_use = 0;
782
		printk(KERN_WARNING "cio: No ccw console found!\n");
Linus Torvalds's avatar
Linus Torvalds committed
783
784
785
		return ERR_PTR(-ENODEV);
	}
	memset(&console_subchannel, 0, sizeof(struct subchannel));
786
	init_subchannel_id(&schid);
787
	schid.sch_no = sch_no;
788
	ret = cio_validate_subchannel(&console_subchannel, schid);
Linus Torvalds's avatar
Linus Torvalds committed
789
790
791
792
793
794
	if (ret) {
		console_subchannel_in_use = 0;
		return ERR_PTR(-ENODEV);
	}

	/*
795
	 * enable console I/O-interrupt subclass
Linus Torvalds's avatar
Linus Torvalds committed
796
	 */
797
	isc_register(CONSOLE_ISC);
798
	console_subchannel.schib.pmcw.isc = CONSOLE_ISC;
Linus Torvalds's avatar
Linus Torvalds committed
799
	console_subchannel.schib.pmcw.intparm =
800
		(u32)(addr_t)&console_subchannel;
Linus Torvalds's avatar
Linus Torvalds committed
801
802
	ret = cio_modify(&console_subchannel);
	if (ret) {
803
		isc_unregister(CONSOLE_ISC);
Linus Torvalds's avatar
Linus Torvalds committed
804
805
806
807
808
809
810
811
812
813
814
		console_subchannel_in_use = 0;
		return ERR_PTR(ret);
	}
	return &console_subchannel;
}

void
cio_release_console(void)
{
	console_subchannel.schib.pmcw.intparm = 0;
	cio_modify(&console_subchannel);
815
	isc_unregister(CONSOLE_ISC);
Linus Torvalds's avatar
Linus Torvalds committed
816
817
818
819
820
	console_subchannel_in_use = 0;
}

/* Bah... hack to catch console special sausages. */
int
821
cio_is_console(struct subchannel_id schid)
Linus Torvalds's avatar
Linus Torvalds committed
822
823
824
{
	if (!console_subchannel_in_use)
		return 0;
825
	return schid_equal(&schid, &console_subchannel.schid);
Linus Torvalds's avatar
Linus Torvalds committed
826
827
828
829
830
831
}

struct subchannel *
cio_get_console_subchannel(void)
{
	if (!console_subchannel_in_use)
Heiko Carstens's avatar
Heiko Carstens committed
832
		return NULL;
Linus Torvalds's avatar
Linus Torvalds committed
833
834
835
	return &console_subchannel;
}

836
837
838
839
840
841
const char *cio_get_console_sch_name(struct subchannel_id schid)
{
	snprintf(console_sch_name, 10, "0.%x.%04x", schid.ssid, schid.sch_no);
	return (const char *)console_sch_name;
}

Linus Torvalds's avatar
Linus Torvalds committed
842
#endif
843
static int
844
__disable_subchannel_easy(struct subchannel_id schid, struct schib *schib)
Linus Torvalds's avatar
Linus Torvalds committed
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
{
	int retry, cc;

	cc = 0;
	for (retry=0;retry<3;retry++) {
		schib->pmcw.ena = 0;
		cc = msch(schid, schib);
		if (cc)
			return (cc==3?-ENODEV:-EBUSY);
		stsch(schid, schib);
		if (!schib->pmcw.ena)
			return 0;
	}
	return -EBUSY; /* uhm... */
}

861
static int
862
__clear_io_subchannel_easy(struct subchannel_id schid)
Linus Torvalds's avatar
Linus Torvalds committed
863
864
865
866
867
868
869
870
871
{
	int retry;

	if (csch(schid))
		return -ENODEV;
	for (retry=0;retry<20;retry++) {
		struct tpi_info ti;

		if (tpi(&ti)) {
872
873
			tsch(ti.schid, (struct irb *)__LC_IRB);
			if (schid_equal(&ti.schid, &schid))
874
				return 0;
Linus Torvalds's avatar
Linus Torvalds committed
875
		}
876
		udelay_simple(100);
Linus Torvalds's avatar
Linus Torvalds committed
877
878
879
880
	}
	return -EBUSY;
}

881
882
883
static void __clear_chsc_subchannel_easy(void)
{
	/* It seems we can only wait for a bit here :/ */
884
	udelay_simple(100);
885
886
}

887
888
889
890
891
892
893
static int pgm_check_occured;

static void cio_reset_pgm_check_handler(void)
{
	pgm_check_occured = 1;
}

894
static int stsch_reset(struct subchannel_id schid, struct schib *addr)
895
896
897
898
{
	int rc;

	pgm_check_occured = 0;
899
	s390_base_pgm_handler_fn = cio_reset_pgm_check_handler;
900
	rc = stsch(schid, addr);
901
	s390_base_pgm_handler_fn = NULL;
Michael Holzheu's avatar
Michael Holzheu committed
902

903
	/* The program check handler could have changed pgm_check_occured. */
904
	barrier();
Michael Holzheu's avatar
Michael Holzheu committed
905

906
907
908
909
910
911
	if (pgm_check_occured)
		return -EIO;
	else
		return rc;
}

912
static int __shutdown_subchannel_easy(struct subchannel_id schid, void *data)
913
914
915
{
	struct schib schib;

916
	if (stsch_reset(schid, &schib))
917
918
919
920
921
922
923
924
		return -ENXIO;
	if (!schib.pmcw.ena)
		return 0;
	switch(__disable_subchannel_easy(schid, &schib)) {
	case 0:
	case -ENODEV:
		break;
	default: /* -EBUSY */
925
926
927
928
929
		switch (schib.pmcw.st) {
		case SUBCHANNEL_TYPE_IO:
			if (__clear_io_subchannel_easy(schid))
				goto out; /* give up... */
			break;
930
931
932
		case SUBCHANNEL_TYPE_CHSC:
			__clear_chsc_subchannel_easy();
			break;
933
934
935
936
		default:
			/* No default clear strategy */
			break;
		}
937
938
939
		stsch(schid, &schib);
		__disable_subchannel_easy(schid, &schib);
	}
940
out:
941
942
	return 0;
}
Linus Torvalds's avatar
Linus Torvalds committed
943

944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
static atomic_t chpid_reset_count;

static void s390_reset_chpids_mcck_handler(void)
{
	struct crw crw;
	struct mci *mci;

	/* Check for pending channel report word. */
	mci = (struct mci *)&S390_lowcore.mcck_interruption_code;
	if (!mci->cp)
		return;
	/* Process channel report words. */
	while (stcrw(&crw) == 0) {
		/* Check for responses to RCHP. */
		if (crw.slct && crw.rsc == CRW_RSC_CPATH)
			atomic_dec(&chpid_reset_count);
	}
}

#define RCHP_TIMEOUT (30 * USEC_PER_SEC)
static void css_reset(void)
{
	int i, ret;
	unsigned long long timeout;
968
	struct chp_id chpid;
969
970
971
972

	/* Reset subchannels. */
	for_each_subchannel(__shutdown_subchannel_easy,  NULL);
	/* Reset channel paths. */
973
	s390_base_mcck_handler_fn = s390_reset_chpids_mcck_handler;
974
975
976
977
	/* Enable channel report machine checks. */
	__ctl_set_bit(14, 28);
	/* Temporarily reenable machine checks. */
	local_mcck_enable();
978
	chp_id_init(&chpid);
979
	for (i = 0; i <= __MAX_CHPID; i++) {
980
981
		chpid.id = i;
		ret = rchp(chpid);
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
		if ((ret == 0) || (ret == 2))
			/*
			 * rchp either succeeded, or another rchp is already
			 * in progress. In either case, we'll get a crw.
			 */
			atomic_inc(&chpid_reset_count);
	}
	/* Wait for machine check for all channel paths. */
	timeout = get_clock() + (RCHP_TIMEOUT << 12);
	while (atomic_read(&chpid_reset_count) != 0) {
		if (get_clock() > timeout)
			break;
		cpu_relax();
	}
	/* Disable machine checks again. */
	local_mcck_disable();
	/* Disable channel report machine checks. */
	__ctl_clear_bit(14, 28);
1000
	s390_base_mcck_handler_fn = NULL;
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
}

static struct reset_call css_reset_call = {
	.fn = css_reset,
};

static int __init init_css_reset_call(void)
{
	atomic_set(&chpid_reset_count, 0);
	register_reset_call(&css_reset_call);
	return 0;
}

arch_initcall(init_css_reset_call);

struct sch_match_id {
	struct subchannel_id schid;
	struct ccw_dev_id devid;
	int rc;
};

static int __reipl_subchannel_match(struct subchannel_id schid, void *data)
{
	struct schib schib;
	struct sch_match_id *match_id = data;

1027
	if (stsch_reset(schid, &schib))
1028
		return -ENXIO;
1029
	if ((schib.pmcw.st == SUBCHANNEL_TYPE_IO) && schib.pmcw.dnv &&
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
	    (schib.pmcw.dev == match_id->devid.devno) &&
	    (schid.ssid == match_id->devid.ssid)) {
		match_id->schid = schid;
		match_id->rc = 0;
		return 1;
	}
	return 0;
}

static int reipl_find_schid(struct ccw_dev_id *devid,
			    struct subchannel_id *schid)
Linus Torvalds's avatar
Linus Torvalds committed
1041
{
Michael Holzheu's avatar
Michael Holzheu committed
1042
1043
1044
1045
	struct sch_match_id match_id;

	match_id.devid = *devid;
	match_id.rc = -ENODEV;
1046
	for_each_subchannel(__reipl_subchannel_match, &match_id);
Michael Holzheu's avatar
Michael Holzheu committed
1047
1048
1049
	if (match_id.rc == 0)
		*schid = match_id.schid;
	return match_id.rc;
Linus Torvalds's avatar
Linus Torvalds committed
1050
1051
}

Michael Holzheu's avatar
Michael Holzheu committed
1052
1053
extern void do_reipl_asm(__u32 schid);

Linus Torvalds's avatar
Linus Torvalds committed
1054
/* Make sure all subchannels are quiet before we re-ipl an lpar. */
Michael Holzheu's avatar
Michael Holzheu committed
1055
void reipl_ccw_dev(struct ccw_dev_id *devid)
Linus Torvalds's avatar
Linus Torvalds committed
1056
{
Michael Holzheu's avatar
Michael Holzheu committed
1057
1058
	struct subchannel_id schid;

1059
1060
	s390_reset_system();
	if (reipl_find_schid(devid, &schid) != 0)
Michael Holzheu's avatar
Michael Holzheu committed
1061
1062
		panic("IPL Device not found\n");
	do_reipl_asm(*((__u32*)&schid));
Linus Torvalds's avatar
Linus Torvalds committed
1063
}
1064

1065
int __init cio_get_iplinfo(struct cio_iplinfo *iplinfo)
1066
1067
{
	struct subchannel_id schid;
1068
	struct schib schib;
1069
1070
1071

	schid = *(struct subchannel_id *)__LC_SUBCHANNEL_ID;
	if (!schid.one)
1072
1073
1074
		return -ENODEV;
	if (stsch(schid, &schib))
		return -ENODEV;
1075
1076
	if (schib.pmcw.st != SUBCHANNEL_TYPE_IO)
		return -ENODEV;
1077
1078
1079
1080
1081
	if (!schib.pmcw.dnv)
		return -ENODEV;
	iplinfo->devno = schib.pmcw.dev;
	iplinfo->is_qdio = schib.pmcw.qf;
	return 0;
1082
}
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140

/**
 * cio_tm_start_key - perform start function
 * @sch: subchannel on which to perform the start function
 * @tcw: transport-command word to be started
 * @lpm: mask of paths to use
 * @key: storage key to use for storage access
 *
 * Start the tcw on the given subchannel. Return zero on success, non-zero
 * otherwise.
 */
int cio_tm_start_key(struct subchannel *sch, struct tcw *tcw, u8 lpm, u8 key)
{
	int cc;
	union orb *orb = &to_io_private(sch)->orb;

	memset(orb, 0, sizeof(union orb));
	orb->tm.intparm = (u32) (addr_t) sch;
	orb->tm.key = key >> 4;
	orb->tm.b = 1;
	orb->tm.lpm = lpm ? lpm : sch->lpm;
	orb->tm.tcw = (u32) (addr_t) tcw;
	cc = ssch(sch->schid, orb);
	switch (cc) {
	case 0:
		return 0;
	case 1:
	case 2:
		return -EBUSY;
	default:
		return cio_start_handle_notoper(sch, lpm);
	}
}

/**
 * cio_tm_intrg - perform interrogate function
 * @sch - subchannel on which to perform the interrogate function
 *
 * If the specified subchannel is running in transport-mode, perform the
 * interrogate function. Return zero on success, non-zero otherwie.
 */
int cio_tm_intrg(struct subchannel *sch)
{
	int cc;

	if (!to_io_private(sch)->orb.tm.b)
		return -EINVAL;
	cc = xsch(sch->schid);
	switch (cc) {
	case 0:
	case 2:
		return 0;
	case 1:
		return -EBUSY;
	default:
		return -ENODEV;
	}
}