11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *   S/390 common I/O routines -- low level i/o calls
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
4a53c8fab3f87c995c30ac226a03af95361243144Heiko Carstens *    Copyright IBM Corp. 1999, 2008
51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *    Author(s): Ingo Adlung (adlung@de.ibm.com)
64ce3b30cf32c5c078518f0f3e6623bcb6eee9872Cornelia Huck *		 Cornelia Huck (cornelia.huck@de.ibm.com)
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *		 Arnd Bergmann (arndb@de.ibm.com)
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *		 Martin Schwidefsky (schwidefsky@de.ibm.com)
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11e6d5a428e01b1387852f17b3dd7934239a0be0d4Michael Ernst#define KMSG_COMPONENT "cio"
12e6d5a428e01b1387852f17b3dd7934239a0be0d4Michael Ernst#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
13e6d5a428e01b1387852f17b3dd7934239a0be0d4Michael Ernst
1488dbd2037229bd2ed7543ffd0d8f2d9dec9d31d2Heiko Carstens#include <linux/ftrace.h>
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h>
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h>
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/slab.h>
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/device.h>
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel_stat.h>
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/interrupt.h>
21257ceab7456bd2a2657fd1c689384cabc95e3d30Thomas Gleixner#include <linux/irq.h>
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/cio.h>
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/delay.h>
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/irq.h>
255a489b9846f688db7e69aa7ccb23c53459a9c20eHeiko Carstens#include <asm/irq_regs.h>
26e87bfe51b5ca2db99dd680bbb1e8fe3c94b607dfHeiko Carstens#include <asm/setup.h>
2715e9b586e0bd3692e2a21c5be178810d9d32214eHeiko Carstens#include <asm/reset.h>
2846b05d2617c8efd8ec6b19acd2c95541a0118c13Michael Holzheu#include <asm/ipl.h>
29e5854a5839fa426a7873f038080f63587de5f1f1Peter Oberparleiter#include <asm/chpid.h>
304e8e56c6713398f417317d449f50c08bf2756c66Peter Oberparleiter#include <asm/airq.h>
313a3fc29a6d0626fb4897b7391c4e956efbacd394Cornelia Huck#include <asm/isc.h>
32bfc3f0281e08066fa8111c3972cff6edc1049864Frederic Weisbecker#include <linux/cputime.h>
3383262d6349e60b9d10798d489719d80029c00798Peter Oberparleiter#include <asm/fcx.h>
34f5daba1d4116d964435ddd99f32b6c80448a496bHeiko Carstens#include <asm/nmi.h>
35f5daba1d4116d964435ddd99f32b6c80448a496bHeiko Carstens#include <asm/crw.h>
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "cio.h"
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "css.h"
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "chsc.h"
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "ioasm.h"
40cd6b4f27b9bb2a6a5ec82b96b87c85421257be6cCornelia Huck#include "io_sch.h"
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "blacklist.h"
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "cio_debug.h"
43e6b6e10ac1de116fc6d2288f185393014851cccfPeter Oberparleiter#include "chp.h"
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdebug_info_t *cio_debug_msg_id;
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdebug_info_t *cio_debug_trace_id;
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdebug_info_t *cio_debug_crw_id;
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4963aef00b55d37e9fad837a8b38a2c261f0d32041Martin SchwidefskyDEFINE_PER_CPU_ALIGNED(struct irb, cio_irb);
5063aef00b55d37e9fad837a8b38a2c261f0d32041Martin SchwidefskyEXPORT_PER_CPU_SYMBOL(cio_irb);
5163aef00b55d37e9fad837a8b38a2c261f0d32041Martin Schwidefsky
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Function: cio_debug_init
54bc698bcf8897363732226dc9ecba044771679996Cornelia Huck * Initializes three debug logs for common I/O:
55bc698bcf8897363732226dc9ecba044771679996Cornelia Huck * - cio_msg logs generic cio messages
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * - cio_trace logs the calling of different functions
57bc698bcf8897363732226dc9ecba044771679996Cornelia Huck * - cio_crw logs machine check related cio messages
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
59bc698bcf8897363732226dc9ecba044771679996Cornelia Huckstatic int __init cio_debug_init(void)
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
61f7e1e65d29636d050cdde0770b9544572959a67dSebastian Ott	cio_debug_msg_id = debug_register("cio_msg", 16, 1, 11 * sizeof(long));
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!cio_debug_msg_id)
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out_unregister;
64bc698bcf8897363732226dc9ecba044771679996Cornelia Huck	debug_register_view(cio_debug_msg_id, &debug_sprintf_view);
65bc698bcf8897363732226dc9ecba044771679996Cornelia Huck	debug_set_level(cio_debug_msg_id, 2);
66361f494d4e62ee5f7a971bf34945deeb69392159Peter Tiedemann	cio_debug_trace_id = debug_register("cio_trace", 16, 1, 16);
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!cio_debug_trace_id)
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out_unregister;
69bc698bcf8897363732226dc9ecba044771679996Cornelia Huck	debug_register_view(cio_debug_trace_id, &debug_hex_ascii_view);
70bc698bcf8897363732226dc9ecba044771679996Cornelia Huck	debug_set_level(cio_debug_trace_id, 2);
71f7e1e65d29636d050cdde0770b9544572959a67dSebastian Ott	cio_debug_crw_id = debug_register("cio_crw", 8, 1, 8 * sizeof(long));
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!cio_debug_crw_id)
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out_unregister;
74bc698bcf8897363732226dc9ecba044771679996Cornelia Huck	debug_register_view(cio_debug_crw_id, &debug_sprintf_view);
75bc698bcf8897363732226dc9ecba044771679996Cornelia Huck	debug_set_level(cio_debug_crw_id, 4);
761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout_unregister:
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (cio_debug_msg_id)
80bc698bcf8897363732226dc9ecba044771679996Cornelia Huck		debug_unregister(cio_debug_msg_id);
811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (cio_debug_trace_id)
82bc698bcf8897363732226dc9ecba044771679996Cornelia Huck		debug_unregister(cio_debug_trace_id);
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (cio_debug_crw_id)
84bc698bcf8897363732226dc9ecba044771679996Cornelia Huck		debug_unregister(cio_debug_crw_id);
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return -1;
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsarch_initcall (cio_debug_init);
891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
90c513d07a2df0f7076c1707274e29737f09df3b7fSebastian Ottint cio_set_options(struct subchannel *sch, int flags)
911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
92c513d07a2df0f7076c1707274e29737f09df3b7fSebastian Ott	struct io_subchannel_private *priv = to_io_private(sch);
931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
94c513d07a2df0f7076c1707274e29737f09df3b7fSebastian Ott	priv->options.suspend = (flags & DOIO_ALLOW_SUSPEND) != 0;
95c513d07a2df0f7076c1707274e29737f09df3b7fSebastian Ott	priv->options.prefetch = (flags & DOIO_DENY_PREFETCH) != 0;
96c513d07a2df0f7076c1707274e29737f09df3b7fSebastian Ott	priv->options.inter = (flags & DOIO_SUPPRESS_INTER) != 0;
97c513d07a2df0f7076c1707274e29737f09df3b7fSebastian Ott	return 0;
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1004d284cac76d0bfebc42d76b428c4e44d921200a9Heiko Carstensstatic int
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldscio_start_handle_notoper(struct subchannel *sch, __u8 lpm)
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char dbf_text[15];
1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (lpm != 0)
1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sch->lpm &= ~lpm;
1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sch->lpm = 0;
1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
110139b83dd57248a3c8fcfb256e562311ad61478e9Michael Ernst	CIO_MSG_EVENT(2, "cio_start: 'not oper' status for "
111fb6958a594da49ece869793e6ec163b89fc5f79fCornelia Huck		      "subchannel 0.%x.%04x!\n", sch->schid.ssid,
112fb6958a594da49ece869793e6ec163b89fc5f79fCornelia Huck		      sch->schid.sch_no);
113cdb912a40df8b8507ab60b3d52f9980c0ba1f44dSebastian Ott
114cdb912a40df8b8507ab60b3d52f9980c0ba1f44dSebastian Ott	if (cio_update_schib(sch))
115cdb912a40df8b8507ab60b3d52f9980c0ba1f44dSebastian Ott		return -ENODEV;
116cdb912a40df8b8507ab60b3d52f9980c0ba1f44dSebastian Ott
1172a0217d5c7d22d6dd28f8ae5d20b06d24dc426b8Kay Sievers	sprintf(dbf_text, "no%s", dev_name(&sch->dev));
1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	CIO_TRACE_EVENT(0, dbf_text);
1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	CIO_HEX_EVENT(0, &sch->schib, sizeof (struct schib));
1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return (sch->lpm ? -EACCES : -ENODEV);
1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint
1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldscio_start_key (struct subchannel *sch,	/* subchannel structure */
1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	       struct ccw1 * cpa,	/* logical channel prog addr */
1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	       __u8 lpm,		/* logical path mask */
1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	       __u8 key)                /* storage key */
1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
130c513d07a2df0f7076c1707274e29737f09df3b7fSebastian Ott	struct io_subchannel_private *priv = to_io_private(sch);
131c513d07a2df0f7076c1707274e29737f09df3b7fSebastian Ott	union orb *orb = &priv->orb;
1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ccode;
1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
134efd986db2d720e8f6660ec2c292509ee7d28cc6aSebastian Ott	CIO_TRACE_EVENT(5, "stIO");
135efd986db2d720e8f6660ec2c292509ee7d28cc6aSebastian Ott	CIO_TRACE_EVENT(5, dev_name(&sch->dev));
1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1379adb8c1d4f0ac78b3469e377ce5f8a846cbaedafStefan Weinhuber	memset(orb, 0, sizeof(union orb));
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* sch is always under 2G. */
13983262d6349e60b9d10798d489719d80029c00798Peter Oberparleiter	orb->cmd.intparm = (u32)(addr_t)sch;
14083262d6349e60b9d10798d489719d80029c00798Peter Oberparleiter	orb->cmd.fmt = 1;
1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
142c513d07a2df0f7076c1707274e29737f09df3b7fSebastian Ott	orb->cmd.pfch = priv->options.prefetch == 0;
143c513d07a2df0f7076c1707274e29737f09df3b7fSebastian Ott	orb->cmd.spnd = priv->options.suspend;
144c513d07a2df0f7076c1707274e29737f09df3b7fSebastian Ott	orb->cmd.ssic = priv->options.suspend && priv->options.inter;
14583262d6349e60b9d10798d489719d80029c00798Peter Oberparleiter	orb->cmd.lpm = (lpm != 0) ? lpm : sch->lpm;
146347a8dc3b815f0c0fa62a1df075184ffe4cbdcf1Martin Schwidefsky#ifdef CONFIG_64BIT
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * for 64 bit we always support 64 bit IDAWs with 4k page size only
1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
15083262d6349e60b9d10798d489719d80029c00798Peter Oberparleiter	orb->cmd.c64 = 1;
15183262d6349e60b9d10798d489719d80029c00798Peter Oberparleiter	orb->cmd.i2k = 0;
1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
15383262d6349e60b9d10798d489719d80029c00798Peter Oberparleiter	orb->cmd.key = key >> 4;
1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* issue "Start Subchannel" */
15583262d6349e60b9d10798d489719d80029c00798Peter Oberparleiter	orb->cmd.cpa = (__u32) __pa(cpa);
156cd6b4f27b9bb2a6a5ec82b96b87c85421257be6cCornelia Huck	ccode = ssch(sch->schid, orb);
1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* process condition code */
159efd986db2d720e8f6660ec2c292509ee7d28cc6aSebastian Ott	CIO_HEX_EVENT(5, &ccode, sizeof(ccode));
1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (ccode) {
1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 0:
1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * initialize device status information
1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
16623d805b647db6c2063a13089497615efa9deacddPeter Oberparleiter		sch->schib.scsw.cmd.actl |= SCSW_ACTL_START_PEND;
1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0;
1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 1:		/* status pending */
1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 2:		/* busy */
1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EBUSY;
171c91ebe496120e05301465fff31094bfecf798e9fCornelia Huck	case 3:		/* device/path not operational */
1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return cio_start_handle_notoper(sch, lpm);
173c91ebe496120e05301465fff31094bfecf798e9fCornelia Huck	default:
174c91ebe496120e05301465fff31094bfecf798e9fCornelia Huck		return ccode;
1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint
1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldscio_start (struct subchannel *sch, struct ccw1 *cpa, __u8 lpm)
1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1810b642ede47969d4180b0922d982777fe64379228Peter Oberparleiter	return cio_start_key(sch, cpa, lpm, PAGE_DEFAULT_KEY);
1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * resume suspended I/O operation
1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint
1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldscio_resume (struct subchannel *sch)
1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ccode;
1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
192efd986db2d720e8f6660ec2c292509ee7d28cc6aSebastian Ott	CIO_TRACE_EVENT(4, "resIO");
1932a0217d5c7d22d6dd28f8ae5d20b06d24dc426b8Kay Sievers	CIO_TRACE_EVENT(4, dev_name(&sch->dev));
1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
195a8237fc4108060402d904bea5e1062e22e731969Cornelia Huck	ccode = rsch (sch->schid);
1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
197efd986db2d720e8f6660ec2c292509ee7d28cc6aSebastian Ott	CIO_HEX_EVENT(4, &ccode, sizeof(ccode));
1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (ccode) {
2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 0:
20123d805b647db6c2063a13089497615efa9deacddPeter Oberparleiter		sch->schib.scsw.cmd.actl |= SCSW_ACTL_RESUME_PEND;
2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0;
2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 1:
2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EBUSY;
2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 2:
2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * useless to wait for request completion
2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 *  as device is no longer operational !
2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENODEV;
2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * halt I/O operation
2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint
2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldscio_halt(struct subchannel *sch)
2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ccode;
2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!sch)
2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENODEV;
2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
227efd986db2d720e8f6660ec2c292509ee7d28cc6aSebastian Ott	CIO_TRACE_EVENT(2, "haltIO");
2282a0217d5c7d22d6dd28f8ae5d20b06d24dc426b8Kay Sievers	CIO_TRACE_EVENT(2, dev_name(&sch->dev));
2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Issue "Halt subchannel" and process condition code
2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
233a8237fc4108060402d904bea5e1062e22e731969Cornelia Huck	ccode = hsch (sch->schid);
2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
235efd986db2d720e8f6660ec2c292509ee7d28cc6aSebastian Ott	CIO_HEX_EVENT(2, &ccode, sizeof(ccode));
2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (ccode) {
2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 0:
23923d805b647db6c2063a13089497615efa9deacddPeter Oberparleiter		sch->schib.scsw.cmd.actl |= SCSW_ACTL_HALT_PEND;
2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0;
2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 1:		/* status pending */
2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 2:		/* busy */
2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EBUSY;
2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:		/* device not operational */
2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENODEV;
2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Clear I/O operation
2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint
2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldscio_clear(struct subchannel *sch)
2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ccode;
2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!sch)
2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENODEV;
2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
260efd986db2d720e8f6660ec2c292509ee7d28cc6aSebastian Ott	CIO_TRACE_EVENT(2, "clearIO");
2612a0217d5c7d22d6dd28f8ae5d20b06d24dc426b8Kay Sievers	CIO_TRACE_EVENT(2, dev_name(&sch->dev));
2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Issue "Clear subchannel" and process condition code
2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
266a8237fc4108060402d904bea5e1062e22e731969Cornelia Huck	ccode = csch (sch->schid);
2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
268efd986db2d720e8f6660ec2c292509ee7d28cc6aSebastian Ott	CIO_HEX_EVENT(2, &ccode, sizeof(ccode));
2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (ccode) {
2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 0:
27223d805b647db6c2063a13089497615efa9deacddPeter Oberparleiter		sch->schib.scsw.cmd.actl |= SCSW_ACTL_CLEAR_PEND;
2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0;
2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:		/* device not operational */
2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENODEV;
2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Function: cio_cancel
2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Issues a "Cancel Subchannel" on the specified subchannel
2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Note: We don't need any fancy intparms and flags here
2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	 since xsch is executed synchronously.
2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Only for common I/O internal use as for now.
2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint
2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldscio_cancel (struct subchannel *sch)
2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ccode;
2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!sch)
2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENODEV;
2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
294efd986db2d720e8f6660ec2c292509ee7d28cc6aSebastian Ott	CIO_TRACE_EVENT(2, "cancelIO");
2952a0217d5c7d22d6dd28f8ae5d20b06d24dc426b8Kay Sievers	CIO_TRACE_EVENT(2, dev_name(&sch->dev));
2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
297a8237fc4108060402d904bea5e1062e22e731969Cornelia Huck	ccode = xsch (sch->schid);
2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
299efd986db2d720e8f6660ec2c292509ee7d28cc6aSebastian Ott	CIO_HEX_EVENT(2, &ccode, sizeof(ccode));
3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (ccode) {
3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 0:		/* success */
3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Update information in scsw. */
304cdb912a40df8b8507ab60b3d52f9980c0ba1f44dSebastian Ott		if (cio_update_schib(sch))
305cdb912a40df8b8507ab60b3d52f9980c0ba1f44dSebastian Ott			return -ENODEV;
3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0;
3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 1:		/* status pending */
3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EBUSY;
3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 2:		/* not applicable */
3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:	/* not oper */
3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENODEV;
3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
31613952ec12dfeea793ff83c2a96139ed57eb0b897Sebastian Ott
31713952ec12dfeea793ff83c2a96139ed57eb0b897Sebastian Ottstatic void cio_apply_config(struct subchannel *sch, struct schib *schib)
31813952ec12dfeea793ff83c2a96139ed57eb0b897Sebastian Ott{
31913952ec12dfeea793ff83c2a96139ed57eb0b897Sebastian Ott	schib->pmcw.intparm = sch->config.intparm;
32013952ec12dfeea793ff83c2a96139ed57eb0b897Sebastian Ott	schib->pmcw.mbi = sch->config.mbi;
32113952ec12dfeea793ff83c2a96139ed57eb0b897Sebastian Ott	schib->pmcw.isc = sch->config.isc;
32213952ec12dfeea793ff83c2a96139ed57eb0b897Sebastian Ott	schib->pmcw.ena = sch->config.ena;
32313952ec12dfeea793ff83c2a96139ed57eb0b897Sebastian Ott	schib->pmcw.mme = sch->config.mme;
32413952ec12dfeea793ff83c2a96139ed57eb0b897Sebastian Ott	schib->pmcw.mp = sch->config.mp;
32513952ec12dfeea793ff83c2a96139ed57eb0b897Sebastian Ott	schib->pmcw.csense = sch->config.csense;
32613952ec12dfeea793ff83c2a96139ed57eb0b897Sebastian Ott	schib->pmcw.mbfc = sch->config.mbfc;
32713952ec12dfeea793ff83c2a96139ed57eb0b897Sebastian Ott	if (sch->config.mbfc)
32813952ec12dfeea793ff83c2a96139ed57eb0b897Sebastian Ott		schib->mba = sch->config.mba;
32913952ec12dfeea793ff83c2a96139ed57eb0b897Sebastian Ott}
33013952ec12dfeea793ff83c2a96139ed57eb0b897Sebastian Ott
33113952ec12dfeea793ff83c2a96139ed57eb0b897Sebastian Ottstatic int cio_check_config(struct subchannel *sch, struct schib *schib)
33213952ec12dfeea793ff83c2a96139ed57eb0b897Sebastian Ott{
33313952ec12dfeea793ff83c2a96139ed57eb0b897Sebastian Ott	return (schib->pmcw.intparm == sch->config.intparm) &&
33413952ec12dfeea793ff83c2a96139ed57eb0b897Sebastian Ott		(schib->pmcw.mbi == sch->config.mbi) &&
33513952ec12dfeea793ff83c2a96139ed57eb0b897Sebastian Ott		(schib->pmcw.isc == sch->config.isc) &&
33613952ec12dfeea793ff83c2a96139ed57eb0b897Sebastian Ott		(schib->pmcw.ena == sch->config.ena) &&
33713952ec12dfeea793ff83c2a96139ed57eb0b897Sebastian Ott		(schib->pmcw.mme == sch->config.mme) &&
33813952ec12dfeea793ff83c2a96139ed57eb0b897Sebastian Ott		(schib->pmcw.mp == sch->config.mp) &&
33913952ec12dfeea793ff83c2a96139ed57eb0b897Sebastian Ott		(schib->pmcw.csense == sch->config.csense) &&
34013952ec12dfeea793ff83c2a96139ed57eb0b897Sebastian Ott		(schib->pmcw.mbfc == sch->config.mbfc) &&
34113952ec12dfeea793ff83c2a96139ed57eb0b897Sebastian Ott		(!sch->config.mbfc || (schib->mba == sch->config.mba));
34213952ec12dfeea793ff83c2a96139ed57eb0b897Sebastian Ott}
34313952ec12dfeea793ff83c2a96139ed57eb0b897Sebastian Ott
3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
34513952ec12dfeea793ff83c2a96139ed57eb0b897Sebastian Ott * cio_commit_config - apply configuration to the subchannel
3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
34713952ec12dfeea793ff83c2a96139ed57eb0b897Sebastian Ottint cio_commit_config(struct subchannel *sch)
3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
34913952ec12dfeea793ff83c2a96139ed57eb0b897Sebastian Ott	int ccode, retry, ret = 0;
3501bc8927cc5b57c4d9198e4c4ac6b426b7c7d72c7Sebastian Ott	struct schib schib;
3511bc8927cc5b57c4d9198e4c4ac6b426b7c7d72c7Sebastian Ott	struct irb irb;
35213952ec12dfeea793ff83c2a96139ed57eb0b897Sebastian Ott
3538821d24cd261aede9b0436cd3252b17a60ccc33aSebastian Ott	if (stsch_err(sch->schid, &schib) || !css_sch_is_valid(&schib))
35413952ec12dfeea793ff83c2a96139ed57eb0b897Sebastian Ott		return -ENODEV;
3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (retry = 0; retry < 5; retry++) {
35713952ec12dfeea793ff83c2a96139ed57eb0b897Sebastian Ott		/* copy desired changes to local schib */
35813952ec12dfeea793ff83c2a96139ed57eb0b897Sebastian Ott		cio_apply_config(sch, &schib);
35913952ec12dfeea793ff83c2a96139ed57eb0b897Sebastian Ott		ccode = msch_err(sch->schid, &schib);
36013952ec12dfeea793ff83c2a96139ed57eb0b897Sebastian Ott		if (ccode < 0) /* -EIO if msch gets a program check. */
3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return ccode;
3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (ccode) {
36373ac36ea14fd18ea3dc057e41b16ff31a3c0bd5aColy Li		case 0: /* successful */
3648821d24cd261aede9b0436cd3252b17a60ccc33aSebastian Ott			if (stsch_err(sch->schid, &schib) ||
36513952ec12dfeea793ff83c2a96139ed57eb0b897Sebastian Ott			    !css_sch_is_valid(&schib))
36613952ec12dfeea793ff83c2a96139ed57eb0b897Sebastian Ott				return -ENODEV;
36713952ec12dfeea793ff83c2a96139ed57eb0b897Sebastian Ott			if (cio_check_config(sch, &schib)) {
36813952ec12dfeea793ff83c2a96139ed57eb0b897Sebastian Ott				/* commit changes from local schib */
36913952ec12dfeea793ff83c2a96139ed57eb0b897Sebastian Ott				memcpy(&sch->schib, &schib, sizeof(schib));
37013952ec12dfeea793ff83c2a96139ed57eb0b897Sebastian Ott				return 0;
37113952ec12dfeea793ff83c2a96139ed57eb0b897Sebastian Ott			}
37213952ec12dfeea793ff83c2a96139ed57eb0b897Sebastian Ott			ret = -EAGAIN;
37313952ec12dfeea793ff83c2a96139ed57eb0b897Sebastian Ott			break;
37413952ec12dfeea793ff83c2a96139ed57eb0b897Sebastian Ott		case 1: /* status pending */
3751bc8927cc5b57c4d9198e4c4ac6b426b7c7d72c7Sebastian Ott			ret = -EBUSY;
3761bc8927cc5b57c4d9198e4c4ac6b426b7c7d72c7Sebastian Ott			if (tsch(sch->schid, &irb))
3771bc8927cc5b57c4d9198e4c4ac6b426b7c7d72c7Sebastian Ott				return ret;
3781bc8927cc5b57c4d9198e4c4ac6b426b7c7d72c7Sebastian Ott			break;
37913952ec12dfeea793ff83c2a96139ed57eb0b897Sebastian Ott		case 2: /* busy */
38013952ec12dfeea793ff83c2a96139ed57eb0b897Sebastian Ott			udelay(100); /* allow for recovery */
3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ret = -EBUSY;
3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
38313952ec12dfeea793ff83c2a96139ed57eb0b897Sebastian Ott		case 3: /* not operational */
3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -ENODEV;
3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return ret;
3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
39044a1c19e3b47a7ac596808177ccd250b95f5e688Cornelia Huck/**
391cdb912a40df8b8507ab60b3d52f9980c0ba1f44dSebastian Ott * cio_update_schib - Perform stsch and update schib if subchannel is valid.
392cdb912a40df8b8507ab60b3d52f9980c0ba1f44dSebastian Ott * @sch: subchannel on which to perform stsch
393cdb912a40df8b8507ab60b3d52f9980c0ba1f44dSebastian Ott * Return zero on success, -ENODEV otherwise.
394cdb912a40df8b8507ab60b3d52f9980c0ba1f44dSebastian Ott */
395cdb912a40df8b8507ab60b3d52f9980c0ba1f44dSebastian Ottint cio_update_schib(struct subchannel *sch)
396cdb912a40df8b8507ab60b3d52f9980c0ba1f44dSebastian Ott{
397cdb912a40df8b8507ab60b3d52f9980c0ba1f44dSebastian Ott	struct schib schib;
398cdb912a40df8b8507ab60b3d52f9980c0ba1f44dSebastian Ott
3998821d24cd261aede9b0436cd3252b17a60ccc33aSebastian Ott	if (stsch_err(sch->schid, &schib) || !css_sch_is_valid(&schib))
400cdb912a40df8b8507ab60b3d52f9980c0ba1f44dSebastian Ott		return -ENODEV;
401cdb912a40df8b8507ab60b3d52f9980c0ba1f44dSebastian Ott
402cdb912a40df8b8507ab60b3d52f9980c0ba1f44dSebastian Ott	memcpy(&sch->schib, &schib, sizeof(schib));
403cdb912a40df8b8507ab60b3d52f9980c0ba1f44dSebastian Ott	return 0;
404cdb912a40df8b8507ab60b3d52f9980c0ba1f44dSebastian Ott}
405cdb912a40df8b8507ab60b3d52f9980c0ba1f44dSebastian OttEXPORT_SYMBOL_GPL(cio_update_schib);
406cdb912a40df8b8507ab60b3d52f9980c0ba1f44dSebastian Ott
407cdb912a40df8b8507ab60b3d52f9980c0ba1f44dSebastian Ott/**
40844a1c19e3b47a7ac596808177ccd250b95f5e688Cornelia Huck * cio_enable_subchannel - enable a subchannel.
40944a1c19e3b47a7ac596808177ccd250b95f5e688Cornelia Huck * @sch: subchannel to be enabled
41044a1c19e3b47a7ac596808177ccd250b95f5e688Cornelia Huck * @intparm: interruption parameter to set
4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
412edf2209692769d3e461c0351553098bc017c2cafCornelia Huckint cio_enable_subchannel(struct subchannel *sch, u32 intparm)
4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ret;
4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
416efd986db2d720e8f6660ec2c292509ee7d28cc6aSebastian Ott	CIO_TRACE_EVENT(2, "ensch");
4172a0217d5c7d22d6dd28f8ae5d20b06d24dc426b8Kay Sievers	CIO_TRACE_EVENT(2, dev_name(&sch->dev));
4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
419d7b5a4c94f49131811112526f7d404a50f0b5ca7Cornelia Huck	if (sch_is_pseudo_sch(sch))
420d7b5a4c94f49131811112526f7d404a50f0b5ca7Cornelia Huck		return -EINVAL;
421cdb912a40df8b8507ab60b3d52f9980c0ba1f44dSebastian Ott	if (cio_update_schib(sch))
4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENODEV;
4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
42413952ec12dfeea793ff83c2a96139ed57eb0b897Sebastian Ott	sch->config.ena = 1;
42513952ec12dfeea793ff83c2a96139ed57eb0b897Sebastian Ott	sch->config.isc = sch->isc;
42613952ec12dfeea793ff83c2a96139ed57eb0b897Sebastian Ott	sch->config.intparm = intparm;
42713952ec12dfeea793ff83c2a96139ed57eb0b897Sebastian Ott
4281bc8927cc5b57c4d9198e4c4ac6b426b7c7d72c7Sebastian Ott	ret = cio_commit_config(sch);
4291bc8927cc5b57c4d9198e4c4ac6b426b7c7d72c7Sebastian Ott	if (ret == -EIO) {
4301bc8927cc5b57c4d9198e4c4ac6b426b7c7d72c7Sebastian Ott		/*
4311bc8927cc5b57c4d9198e4c4ac6b426b7c7d72c7Sebastian Ott		 * Got a program check in msch. Try without
4321bc8927cc5b57c4d9198e4c4ac6b426b7c7d72c7Sebastian Ott		 * the concurrent sense bit the next time.
4331bc8927cc5b57c4d9198e4c4ac6b426b7c7d72c7Sebastian Ott		 */
4341bc8927cc5b57c4d9198e4c4ac6b426b7c7d72c7Sebastian Ott		sch->config.csense = 0;
43513952ec12dfeea793ff83c2a96139ed57eb0b897Sebastian Ott		ret = cio_commit_config(sch);
4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
437efd986db2d720e8f6660ec2c292509ee7d28cc6aSebastian Ott	CIO_HEX_EVENT(2, &ret, sizeof(ret));
4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return ret;
4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
44044a1c19e3b47a7ac596808177ccd250b95f5e688Cornelia HuckEXPORT_SYMBOL_GPL(cio_enable_subchannel);
4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
44244a1c19e3b47a7ac596808177ccd250b95f5e688Cornelia Huck/**
44344a1c19e3b47a7ac596808177ccd250b95f5e688Cornelia Huck * cio_disable_subchannel - disable a subchannel.
44444a1c19e3b47a7ac596808177ccd250b95f5e688Cornelia Huck * @sch: subchannel to disable
4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
44644a1c19e3b47a7ac596808177ccd250b95f5e688Cornelia Huckint cio_disable_subchannel(struct subchannel *sch)
4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ret;
4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
450efd986db2d720e8f6660ec2c292509ee7d28cc6aSebastian Ott	CIO_TRACE_EVENT(2, "dissch");
4512a0217d5c7d22d6dd28f8ae5d20b06d24dc426b8Kay Sievers	CIO_TRACE_EVENT(2, dev_name(&sch->dev));
4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
453d7b5a4c94f49131811112526f7d404a50f0b5ca7Cornelia Huck	if (sch_is_pseudo_sch(sch))
454d7b5a4c94f49131811112526f7d404a50f0b5ca7Cornelia Huck		return 0;
455cdb912a40df8b8507ab60b3d52f9980c0ba1f44dSebastian Ott	if (cio_update_schib(sch))
4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENODEV;
4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
45813952ec12dfeea793ff83c2a96139ed57eb0b897Sebastian Ott	sch->config.ena = 0;
4591bc8927cc5b57c4d9198e4c4ac6b426b7c7d72c7Sebastian Ott	ret = cio_commit_config(sch);
46013952ec12dfeea793ff83c2a96139ed57eb0b897Sebastian Ott
461efd986db2d720e8f6660ec2c292509ee7d28cc6aSebastian Ott	CIO_HEX_EVENT(2, &ret, sizeof(ret));
4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return ret;
4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
46444a1c19e3b47a7ac596808177ccd250b95f5e688Cornelia HuckEXPORT_SYMBOL_GPL(cio_disable_subchannel);
4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
466b3a686f47a3615fcfec0a01c4103c50bb9621369Cornelia Huckstatic int cio_check_devno_blacklisted(struct subchannel *sch)
4670ae7a7b250bdf7ee87c8346164ef3c47fb79dfbdCornelia Huck{
4680ae7a7b250bdf7ee87c8346164ef3c47fb79dfbdCornelia Huck	if (is_blacklisted(sch->schid.ssid, sch->schib.pmcw.dev)) {
4690ae7a7b250bdf7ee87c8346164ef3c47fb79dfbdCornelia Huck		/*
4700ae7a7b250bdf7ee87c8346164ef3c47fb79dfbdCornelia Huck		 * This device must not be known to Linux. So we simply
4710ae7a7b250bdf7ee87c8346164ef3c47fb79dfbdCornelia Huck		 * say that there is no device and return ENODEV.
4720ae7a7b250bdf7ee87c8346164ef3c47fb79dfbdCornelia Huck		 */
4730ae7a7b250bdf7ee87c8346164ef3c47fb79dfbdCornelia Huck		CIO_MSG_EVENT(6, "Blacklisted device detected "
4740ae7a7b250bdf7ee87c8346164ef3c47fb79dfbdCornelia Huck			      "at devno %04X, subchannel set %x\n",
4750ae7a7b250bdf7ee87c8346164ef3c47fb79dfbdCornelia Huck			      sch->schib.pmcw.dev, sch->schid.ssid);
4760ae7a7b250bdf7ee87c8346164ef3c47fb79dfbdCornelia Huck		return -ENODEV;
4770ae7a7b250bdf7ee87c8346164ef3c47fb79dfbdCornelia Huck	}
4780ae7a7b250bdf7ee87c8346164ef3c47fb79dfbdCornelia Huck	return 0;
4790ae7a7b250bdf7ee87c8346164ef3c47fb79dfbdCornelia Huck}
4800ae7a7b250bdf7ee87c8346164ef3c47fb79dfbdCornelia Huck
481b3a686f47a3615fcfec0a01c4103c50bb9621369Cornelia Huckstatic int cio_validate_io_subchannel(struct subchannel *sch)
482b3a686f47a3615fcfec0a01c4103c50bb9621369Cornelia Huck{
483b3a686f47a3615fcfec0a01c4103c50bb9621369Cornelia Huck	/* Initialization for io subchannels. */
484b3a686f47a3615fcfec0a01c4103c50bb9621369Cornelia Huck	if (!css_sch_is_valid(&sch->schib))
485b3a686f47a3615fcfec0a01c4103c50bb9621369Cornelia Huck		return -ENODEV;
486b3a686f47a3615fcfec0a01c4103c50bb9621369Cornelia Huck
487b3a686f47a3615fcfec0a01c4103c50bb9621369Cornelia Huck	/* Devno is valid. */
488b3a686f47a3615fcfec0a01c4103c50bb9621369Cornelia Huck	return cio_check_devno_blacklisted(sch);
489b3a686f47a3615fcfec0a01c4103c50bb9621369Cornelia Huck}
490b3a686f47a3615fcfec0a01c4103c50bb9621369Cornelia Huck
491b3a686f47a3615fcfec0a01c4103c50bb9621369Cornelia Huckstatic int cio_validate_msg_subchannel(struct subchannel *sch)
492b3a686f47a3615fcfec0a01c4103c50bb9621369Cornelia Huck{
493b3a686f47a3615fcfec0a01c4103c50bb9621369Cornelia Huck	/* Initialization for message subchannels. */
494b3a686f47a3615fcfec0a01c4103c50bb9621369Cornelia Huck	if (!css_sch_is_valid(&sch->schib))
495b3a686f47a3615fcfec0a01c4103c50bb9621369Cornelia Huck		return -ENODEV;
496b3a686f47a3615fcfec0a01c4103c50bb9621369Cornelia Huck
497b3a686f47a3615fcfec0a01c4103c50bb9621369Cornelia Huck	/* Devno is valid. */
498b3a686f47a3615fcfec0a01c4103c50bb9621369Cornelia Huck	return cio_check_devno_blacklisted(sch);
499b3a686f47a3615fcfec0a01c4103c50bb9621369Cornelia Huck}
500b3a686f47a3615fcfec0a01c4103c50bb9621369Cornelia Huck
5010ae7a7b250bdf7ee87c8346164ef3c47fb79dfbdCornelia Huck/**
5020ae7a7b250bdf7ee87c8346164ef3c47fb79dfbdCornelia Huck * cio_validate_subchannel - basic validation of subchannel
5030ae7a7b250bdf7ee87c8346164ef3c47fb79dfbdCornelia Huck * @sch: subchannel structure to be filled out
5040ae7a7b250bdf7ee87c8346164ef3c47fb79dfbdCornelia Huck * @schid: subchannel id
5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Find out subchannel type and initialize struct subchannel.
5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Return codes:
5080ae7a7b250bdf7ee87c8346164ef3c47fb79dfbdCornelia Huck *   0 on success
5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *   -ENXIO for non-defined subchannels
5100ae7a7b250bdf7ee87c8346164ef3c47fb79dfbdCornelia Huck *   -ENODEV for invalid subchannels or blacklisted devices
5110ae7a7b250bdf7ee87c8346164ef3c47fb79dfbdCornelia Huck *   -EIO for subchannels in an invalid subchannel set
5121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
5130ae7a7b250bdf7ee87c8346164ef3c47fb79dfbdCornelia Huckint cio_validate_subchannel(struct subchannel *sch, struct subchannel_id schid)
5141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char dbf_txt[15];
5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ccode;
5172ec2298412e1ab4674b3780005058d4f0b8bd858Cornelia Huck	int err;
5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5190ae7a7b250bdf7ee87c8346164ef3c47fb79dfbdCornelia Huck	sprintf(dbf_txt, "valsch%x", schid.sch_no);
5200ae7a7b250bdf7ee87c8346164ef3c47fb79dfbdCornelia Huck	CIO_TRACE_EVENT(4, dbf_txt);
5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * The first subchannel that is not-operational (ccode==3)
524e5dcf0025d7af58f525590ac86ac27cb44714e8dSebastian Ott	 * indicates that there aren't any more devices available.
525fb6958a594da49ece869793e6ec163b89fc5f79fCornelia Huck	 * If stsch gets an exception, it means the current subchannel set
526e5dcf0025d7af58f525590ac86ac27cb44714e8dSebastian Ott	 * is not valid.
5271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
528e5dcf0025d7af58f525590ac86ac27cb44714e8dSebastian Ott	ccode = stsch_err(schid, &sch->schib);
5292ec2298412e1ab4674b3780005058d4f0b8bd858Cornelia Huck	if (ccode) {
5302ec2298412e1ab4674b3780005058d4f0b8bd858Cornelia Huck		err = (ccode == 3) ? -ENXIO : ccode;
5312ec2298412e1ab4674b3780005058d4f0b8bd858Cornelia Huck		goto out;
5322ec2298412e1ab4674b3780005058d4f0b8bd858Cornelia Huck	}
5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sch->st = sch->schib.pmcw.st;
534e5dcf0025d7af58f525590ac86ac27cb44714e8dSebastian Ott	sch->schid = schid;
535c820de39bd083222f5be2563181c87493e436f7cCornelia Huck
5360ae7a7b250bdf7ee87c8346164ef3c47fb79dfbdCornelia Huck	switch (sch->st) {
5370ae7a7b250bdf7ee87c8346164ef3c47fb79dfbdCornelia Huck	case SUBCHANNEL_TYPE_IO:
5380ae7a7b250bdf7ee87c8346164ef3c47fb79dfbdCornelia Huck		err = cio_validate_io_subchannel(sch);
5390ae7a7b250bdf7ee87c8346164ef3c47fb79dfbdCornelia Huck		break;
540b3a686f47a3615fcfec0a01c4103c50bb9621369Cornelia Huck	case SUBCHANNEL_TYPE_MSG:
541b3a686f47a3615fcfec0a01c4103c50bb9621369Cornelia Huck		err = cio_validate_msg_subchannel(sch);
542b3a686f47a3615fcfec0a01c4103c50bb9621369Cornelia Huck		break;
5430ae7a7b250bdf7ee87c8346164ef3c47fb79dfbdCornelia Huck	default:
5440ae7a7b250bdf7ee87c8346164ef3c47fb79dfbdCornelia Huck		err = 0;
5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5460ae7a7b250bdf7ee87c8346164ef3c47fb79dfbdCornelia Huck	if (err)
547808e48882316dd4a325cd1cc382516945edad77dMichael Ernst		goto out;
548808e48882316dd4a325cd1cc382516945edad77dMichael Ernst
5490ae7a7b250bdf7ee87c8346164ef3c47fb79dfbdCornelia Huck	CIO_MSG_EVENT(4, "Subchannel 0.%x.%04x reports subchannel type %04X\n",
5500ae7a7b250bdf7ee87c8346164ef3c47fb79dfbdCornelia Huck		      sch->schid.ssid, sch->schid.sch_no, sch->st);
5512ec2298412e1ab4674b3780005058d4f0b8bd858Cornelia Huckout:
5522ec2298412e1ab4674b3780005058d4f0b8bd858Cornelia Huck	return err;
5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
5561f44a225777e40fd9a945b09f958052c47494e1eMartin Schwidefsky * do_cio_interrupt() handles all normal I/O device IRQ's
5571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
5581f44a225777e40fd9a945b09f958052c47494e1eMartin Schwidefskystatic irqreturn_t do_cio_interrupt(int irq, void *dummy)
5591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5601f44a225777e40fd9a945b09f958052c47494e1eMartin Schwidefsky	struct tpi_info *tpi_info;
5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct subchannel *sch;
5621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct irb *irb;
5631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
564fe0f49768d807a8fe6336b097feb8c4441951710Martin Schwidefsky	set_cpu_flag(CIF_NOHZ_DELAY);
5651f44a225777e40fd9a945b09f958052c47494e1eMartin Schwidefsky	tpi_info = (struct tpi_info *) &get_irq_regs()->int_code;
5660bf7fcf155160fd483af7ffdc50efd4be96f1c96Christoph Lameter	irb = this_cpu_ptr(&cio_irb);
56748f6b00c6e3190b786c44731b25ac124c81c2247Martin Schwidefsky	sch = (struct subchannel *)(unsigned long) tpi_info->intparm;
56848f6b00c6e3190b786c44731b25ac124c81c2247Martin Schwidefsky	if (!sch) {
56948f6b00c6e3190b786c44731b25ac124c81c2247Martin Schwidefsky		/* Clear pending interrupt condition. */
57048f6b00c6e3190b786c44731b25ac124c81c2247Martin Schwidefsky		inc_irq_stat(IRQIO_CIO);
57148f6b00c6e3190b786c44731b25ac124c81c2247Martin Schwidefsky		tsch(tpi_info->schid, irb);
5721f44a225777e40fd9a945b09f958052c47494e1eMartin Schwidefsky		return IRQ_HANDLED;
57348f6b00c6e3190b786c44731b25ac124c81c2247Martin Schwidefsky	}
57448f6b00c6e3190b786c44731b25ac124c81c2247Martin Schwidefsky	spin_lock(sch->lock);
57548f6b00c6e3190b786c44731b25ac124c81c2247Martin Schwidefsky	/* Store interrupt response block to lowcore. */
57648f6b00c6e3190b786c44731b25ac124c81c2247Martin Schwidefsky	if (tsch(tpi_info->schid, irb) == 0) {
57748f6b00c6e3190b786c44731b25ac124c81c2247Martin Schwidefsky		/* Keep subchannel information word up to date. */
57848f6b00c6e3190b786c44731b25ac124c81c2247Martin Schwidefsky		memcpy (&sch->schib.scsw, &irb->scsw, sizeof (irb->scsw));
57948f6b00c6e3190b786c44731b25ac124c81c2247Martin Schwidefsky		/* Call interrupt handler if there is one. */
58048f6b00c6e3190b786c44731b25ac124c81c2247Martin Schwidefsky		if (sch->driver && sch->driver->irq)
58148f6b00c6e3190b786c44731b25ac124c81c2247Martin Schwidefsky			sch->driver->irq(sch);
58248f6b00c6e3190b786c44731b25ac124c81c2247Martin Schwidefsky		else
583420f42ecf48a926ba775ec7d7294425f004b6adeHeiko Carstens			inc_irq_stat(IRQIO_CIO);
58448f6b00c6e3190b786c44731b25ac124c81c2247Martin Schwidefsky	} else
58548f6b00c6e3190b786c44731b25ac124c81c2247Martin Schwidefsky		inc_irq_stat(IRQIO_CIO);
58648f6b00c6e3190b786c44731b25ac124c81c2247Martin Schwidefsky	spin_unlock(sch->lock);
5871f44a225777e40fd9a945b09f958052c47494e1eMartin Schwidefsky
5881f44a225777e40fd9a945b09f958052c47494e1eMartin Schwidefsky	return IRQ_HANDLED;
5891f44a225777e40fd9a945b09f958052c47494e1eMartin Schwidefsky}
5901f44a225777e40fd9a945b09f958052c47494e1eMartin Schwidefsky
5911f44a225777e40fd9a945b09f958052c47494e1eMartin Schwidefskystatic struct irqaction io_interrupt = {
5921f44a225777e40fd9a945b09f958052c47494e1eMartin Schwidefsky	.name	 = "IO",
5931f44a225777e40fd9a945b09f958052c47494e1eMartin Schwidefsky	.handler = do_cio_interrupt,
5941f44a225777e40fd9a945b09f958052c47494e1eMartin Schwidefsky};
5951f44a225777e40fd9a945b09f958052c47494e1eMartin Schwidefsky
5961f44a225777e40fd9a945b09f958052c47494e1eMartin Schwidefskyvoid __init init_cio_interrupts(void)
5971f44a225777e40fd9a945b09f958052c47494e1eMartin Schwidefsky{
5981f44a225777e40fd9a945b09f958052c47494e1eMartin Schwidefsky	irq_set_chip_and_handler(IO_INTERRUPT,
5991f44a225777e40fd9a945b09f958052c47494e1eMartin Schwidefsky				 &dummy_irq_chip, handle_percpu_irq);
6001f44a225777e40fd9a945b09f958052c47494e1eMartin Schwidefsky	setup_irq(IO_INTERRUPT, &io_interrupt);
6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_CCW_CONSOLE
604863fc8492734822b95671780db803cd9a4b7d923Sebastian Ottstatic struct subchannel *console_sch;
605dbe33fc9ad0cd965afe71cd6fca9539afd704e38Sebastian Ottstatic struct lock_class_key console_sch_key;
6061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
607191fd44c11e10daf9d2cabd16935952e9c735949Heiko Carstens/*
608b603d258a43b4e7339660bdd3b5c25eacd603e54Martin Schwidefsky * Use cio_tsch to update the subchannel status and call the interrupt handler
609188561a462d3b82451d6ba09e2e32c9ba2c9938cSebastian Ott * if status had been pending. Called with the subchannel's lock held.
610191fd44c11e10daf9d2cabd16935952e9c735949Heiko Carstens */
611188561a462d3b82451d6ba09e2e32c9ba2c9938cSebastian Ottvoid cio_tsch(struct subchannel *sch)
612191fd44c11e10daf9d2cabd16935952e9c735949Heiko Carstens{
613191fd44c11e10daf9d2cabd16935952e9c735949Heiko Carstens	struct irb *irb;
614191fd44c11e10daf9d2cabd16935952e9c735949Heiko Carstens	int irq_context;
615191fd44c11e10daf9d2cabd16935952e9c735949Heiko Carstens
6160bf7fcf155160fd483af7ffdc50efd4be96f1c96Christoph Lameter	irb = this_cpu_ptr(&cio_irb);
617191fd44c11e10daf9d2cabd16935952e9c735949Heiko Carstens	/* Store interrupt response block to lowcore. */
618b603d258a43b4e7339660bdd3b5c25eacd603e54Martin Schwidefsky	if (tsch(sch->schid, irb) != 0)
619191fd44c11e10daf9d2cabd16935952e9c735949Heiko Carstens		/* Not status pending or not operational. */
620b603d258a43b4e7339660bdd3b5c25eacd603e54Martin Schwidefsky		return;
621b603d258a43b4e7339660bdd3b5c25eacd603e54Martin Schwidefsky	memcpy(&sch->schib.scsw, &irb->scsw, sizeof(union scsw));
622b603d258a43b4e7339660bdd3b5c25eacd603e54Martin Schwidefsky	/* Call interrupt handler with updated status. */
623191fd44c11e10daf9d2cabd16935952e9c735949Heiko Carstens	irq_context = in_interrupt();
624b603d258a43b4e7339660bdd3b5c25eacd603e54Martin Schwidefsky	if (!irq_context) {
625191fd44c11e10daf9d2cabd16935952e9c735949Heiko Carstens		local_bh_disable();
626b603d258a43b4e7339660bdd3b5c25eacd603e54Martin Schwidefsky		irq_enter();
627b603d258a43b4e7339660bdd3b5c25eacd603e54Martin Schwidefsky	}
628bc5dfcff65f24f15567f766d8bd081d594ef8cc2Thomas Gleixner	kstat_incr_irq_this_cpu(IO_INTERRUPT);
629191fd44c11e10daf9d2cabd16935952e9c735949Heiko Carstens	if (sch->driver && sch->driver->irq)
630191fd44c11e10daf9d2cabd16935952e9c735949Heiko Carstens		sch->driver->irq(sch);
631de400d6b78d15a73023485f050bc6b1709dc7a79Peter Oberparleiter	else
632420f42ecf48a926ba775ec7d7294425f004b6adeHeiko Carstens		inc_irq_stat(IRQIO_CIO);
633b603d258a43b4e7339660bdd3b5c25eacd603e54Martin Schwidefsky	if (!irq_context) {
634b603d258a43b4e7339660bdd3b5c25eacd603e54Martin Schwidefsky		irq_exit();
635191fd44c11e10daf9d2cabd16935952e9c735949Heiko Carstens		_local_bh_enable();
636b603d258a43b4e7339660bdd3b5c25eacd603e54Martin Schwidefsky	}
637191fd44c11e10daf9d2cabd16935952e9c735949Heiko Carstens}
638191fd44c11e10daf9d2cabd16935952e9c735949Heiko Carstens
639863fc8492734822b95671780db803cd9a4b7d923Sebastian Ottstatic int cio_test_for_console(struct subchannel_id schid, void *data)
640cd6b4f27b9bb2a6a5ec82b96b87c85421257be6cCornelia Huck{
641863fc8492734822b95671780db803cd9a4b7d923Sebastian Ott	struct schib schib;
642cd6b4f27b9bb2a6a5ec82b96b87c85421257be6cCornelia Huck
643863fc8492734822b95671780db803cd9a4b7d923Sebastian Ott	if (stsch_err(schid, &schib) != 0)
644f97a56fb768e5fe9cd07c56ca47870136bb5530cCornelia Huck		return -ENXIO;
645863fc8492734822b95671780db803cd9a4b7d923Sebastian Ott	if ((schib.pmcw.st == SUBCHANNEL_TYPE_IO) && schib.pmcw.dnv &&
646863fc8492734822b95671780db803cd9a4b7d923Sebastian Ott	    (schib.pmcw.dev == console_devno)) {
647f97a56fb768e5fe9cd07c56ca47870136bb5530cCornelia Huck		console_irq = schid.sch_no;
648f97a56fb768e5fe9cd07c56ca47870136bb5530cCornelia Huck		return 1; /* found */
649f97a56fb768e5fe9cd07c56ca47870136bb5530cCornelia Huck	}
650f97a56fb768e5fe9cd07c56ca47870136bb5530cCornelia Huck	return 0;
651f97a56fb768e5fe9cd07c56ca47870136bb5530cCornelia Huck}
652f97a56fb768e5fe9cd07c56ca47870136bb5530cCornelia Huck
653863fc8492734822b95671780db803cd9a4b7d923Sebastian Ottstatic int cio_get_console_sch_no(void)
6541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
655a8237fc4108060402d904bea5e1062e22e731969Cornelia Huck	struct subchannel_id schid;
656863fc8492734822b95671780db803cd9a4b7d923Sebastian Ott	struct schib schib;
657863fc8492734822b95671780db803cd9a4b7d923Sebastian Ott
658a8237fc4108060402d904bea5e1062e22e731969Cornelia Huck	init_subchannel_id(&schid);
6591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (console_irq != -1) {
6601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* VM provided us with the irq number of the console. */
661a8237fc4108060402d904bea5e1062e22e731969Cornelia Huck		schid.sch_no = console_irq;
662863fc8492734822b95671780db803cd9a4b7d923Sebastian Ott		if (stsch_err(schid, &schib) != 0 ||
663863fc8492734822b95671780db803cd9a4b7d923Sebastian Ott		    (schib.pmcw.st != SUBCHANNEL_TYPE_IO) || !schib.pmcw.dnv)
6641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -1;
665863fc8492734822b95671780db803cd9a4b7d923Sebastian Ott		console_devno = schib.pmcw.dev;
6661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else if (console_devno != -1) {
6671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* At least the console device number is known. */
668f97a56fb768e5fe9cd07c56ca47870136bb5530cCornelia Huck		for_each_subchannel(cio_test_for_console, NULL);
6691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return console_irq;
6711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
673863fc8492734822b95671780db803cd9a4b7d923Sebastian Ottstruct subchannel *cio_probe_console(void)
6741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
675a8237fc4108060402d904bea5e1062e22e731969Cornelia Huck	struct subchannel_id schid;
676863fc8492734822b95671780db803cd9a4b7d923Sebastian Ott	struct subchannel *sch;
677863fc8492734822b95671780db803cd9a4b7d923Sebastian Ott	int sch_no, ret;
6781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
679f97a56fb768e5fe9cd07c56ca47870136bb5530cCornelia Huck	sch_no = cio_get_console_sch_no();
680f97a56fb768e5fe9cd07c56ca47870136bb5530cCornelia Huck	if (sch_no == -1) {
681e6d5a428e01b1387852f17b3dd7934239a0be0d4Michael Ernst		pr_warning("No CCW console was found\n");
6821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return ERR_PTR(-ENODEV);
6831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
684a8237fc4108060402d904bea5e1062e22e731969Cornelia Huck	init_subchannel_id(&schid);
685f97a56fb768e5fe9cd07c56ca47870136bb5530cCornelia Huck	schid.sch_no = sch_no;
686863fc8492734822b95671780db803cd9a4b7d923Sebastian Ott	sch = css_alloc_subchannel(schid);
687863fc8492734822b95671780db803cd9a4b7d923Sebastian Ott	if (IS_ERR(sch))
688863fc8492734822b95671780db803cd9a4b7d923Sebastian Ott		return sch;
6891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
690dbe33fc9ad0cd965afe71cd6fca9539afd704e38Sebastian Ott	lockdep_set_class(sch->lock, &console_sch_key);
6916ef556ccc8fd256259745c4f0d0ab65aaf703824Cornelia Huck	isc_register(CONSOLE_ISC);
692863fc8492734822b95671780db803cd9a4b7d923Sebastian Ott	sch->config.isc = CONSOLE_ISC;
693863fc8492734822b95671780db803cd9a4b7d923Sebastian Ott	sch->config.intparm = (u32)(addr_t)sch;
694863fc8492734822b95671780db803cd9a4b7d923Sebastian Ott	ret = cio_commit_config(sch);
6951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ret) {
6966ef556ccc8fd256259745c4f0d0ab65aaf703824Cornelia Huck		isc_unregister(CONSOLE_ISC);
697863fc8492734822b95671780db803cd9a4b7d923Sebastian Ott		put_device(&sch->dev);
6981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return ERR_PTR(ret);
6991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
700863fc8492734822b95671780db803cd9a4b7d923Sebastian Ott	console_sch = sch;
701863fc8492734822b95671780db803cd9a4b7d923Sebastian Ott	return sch;
7021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
704863fc8492734822b95671780db803cd9a4b7d923Sebastian Ottint cio_is_console(struct subchannel_id schid)
7051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
706863fc8492734822b95671780db803cd9a4b7d923Sebastian Ott	if (!console_sch)
7071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0;
708863fc8492734822b95671780db803cd9a4b7d923Sebastian Ott	return schid_equal(&schid, &console_sch->schid);
7091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
71114556b33f2a5d6a3bc75cd33b709452a31555b25Sebastian Ottvoid cio_register_early_subchannels(void)
7121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
71314556b33f2a5d6a3bc75cd33b709452a31555b25Sebastian Ott	int ret;
71414556b33f2a5d6a3bc75cd33b709452a31555b25Sebastian Ott
71514556b33f2a5d6a3bc75cd33b709452a31555b25Sebastian Ott	if (!console_sch)
71614556b33f2a5d6a3bc75cd33b709452a31555b25Sebastian Ott		return;
71714556b33f2a5d6a3bc75cd33b709452a31555b25Sebastian Ott
71814556b33f2a5d6a3bc75cd33b709452a31555b25Sebastian Ott	ret = css_register_subchannel(console_sch);
71914556b33f2a5d6a3bc75cd33b709452a31555b25Sebastian Ott	if (ret)
72014556b33f2a5d6a3bc75cd33b709452a31555b25Sebastian Ott		put_device(&console_sch->dev);
7211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
722863fc8492734822b95671780db803cd9a4b7d923Sebastian Ott#endif /* CONFIG_CCW_CONSOLE */
7231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7244d284cac76d0bfebc42d76b428c4e44d921200a9Heiko Carstensstatic int
725a8237fc4108060402d904bea5e1062e22e731969Cornelia Huck__disable_subchannel_easy(struct subchannel_id schid, struct schib *schib)
7261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int retry, cc;
7281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cc = 0;
7301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (retry=0;retry<3;retry++) {
7311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		schib->pmcw.ena = 0;
7328821d24cd261aede9b0436cd3252b17a60ccc33aSebastian Ott		cc = msch_err(schid, schib);
7331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (cc)
7341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return (cc==3?-ENODEV:-EBUSY);
7358821d24cd261aede9b0436cd3252b17a60ccc33aSebastian Ott		if (stsch_err(schid, schib) || !css_sch_is_valid(schib))
736cdb912a40df8b8507ab60b3d52f9980c0ba1f44dSebastian Ott			return -ENODEV;
7371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!schib->pmcw.ena)
7381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return 0;
7391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return -EBUSY; /* uhm... */
7411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7434d284cac76d0bfebc42d76b428c4e44d921200a9Heiko Carstensstatic int
7440ae7a7b250bdf7ee87c8346164ef3c47fb79dfbdCornelia Huck__clear_io_subchannel_easy(struct subchannel_id schid)
7451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int retry;
7471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (csch(schid))
7491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENODEV;
7501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (retry=0;retry<20;retry++) {
7511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct tpi_info ti;
7521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (tpi(&ti)) {
7540bf7fcf155160fd483af7ffdc50efd4be96f1c96Christoph Lameter			tsch(ti.schid, this_cpu_ptr(&cio_irb));
755a8237fc4108060402d904bea5e1062e22e731969Cornelia Huck			if (schid_equal(&ti.schid, &schid))
7564c24da79e29537f0e240a331220a1c46cb9bc085Cornelia Huck				return 0;
7571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
7585a0d0e65379256b4da2c9092e197a2c761f51c01Heiko Carstens		udelay_simple(100);
7591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return -EBUSY;
7611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7639d92a7e1b0d095c8be96ce5e592c6c5541684631Cornelia Huckstatic void __clear_chsc_subchannel_easy(void)
7649d92a7e1b0d095c8be96ce5e592c6c5541684631Cornelia Huck{
7659d92a7e1b0d095c8be96ce5e592c6c5541684631Cornelia Huck	/* It seems we can only wait for a bit here :/ */
7665a0d0e65379256b4da2c9092e197a2c761f51c01Heiko Carstens	udelay_simple(100);
7679d92a7e1b0d095c8be96ce5e592c6c5541684631Cornelia Huck}
7689d92a7e1b0d095c8be96ce5e592c6c5541684631Cornelia Huck
769a45e14148fb34175cba042df8979e7982758635fMichael Holzheustatic int pgm_check_occured;
770a45e14148fb34175cba042df8979e7982758635fMichael Holzheu
771a45e14148fb34175cba042df8979e7982758635fMichael Holzheustatic void cio_reset_pgm_check_handler(void)
772a45e14148fb34175cba042df8979e7982758635fMichael Holzheu{
773a45e14148fb34175cba042df8979e7982758635fMichael Holzheu	pgm_check_occured = 1;
774a45e14148fb34175cba042df8979e7982758635fMichael Holzheu}
775a45e14148fb34175cba042df8979e7982758635fMichael Holzheu
776f9c9fe3ecfc0c5ff17728d0c5ee95a4e269ec190Peter Oberparleiterstatic int stsch_reset(struct subchannel_id schid, struct schib *addr)
777a45e14148fb34175cba042df8979e7982758635fMichael Holzheu{
778a45e14148fb34175cba042df8979e7982758635fMichael Holzheu	int rc;
779a45e14148fb34175cba042df8979e7982758635fMichael Holzheu
780a45e14148fb34175cba042df8979e7982758635fMichael Holzheu	pgm_check_occured = 0;
781ab14de6c37fae22911ba99f4171613e6d758050bHeiko Carstens	s390_base_pgm_handler_fn = cio_reset_pgm_check_handler;
7828821d24cd261aede9b0436cd3252b17a60ccc33aSebastian Ott	rc = stsch_err(schid, addr);
783ab14de6c37fae22911ba99f4171613e6d758050bHeiko Carstens	s390_base_pgm_handler_fn = NULL;
784aa77015c4e94cb1d30680646c163d7ae1f93f941Michael Holzheu
785ab14de6c37fae22911ba99f4171613e6d758050bHeiko Carstens	/* The program check handler could have changed pgm_check_occured. */
7866faf4444f2445b068a4f75a86ae81b104c0eed2cHeiko Carstens	barrier();
787aa77015c4e94cb1d30680646c163d7ae1f93f941Michael Holzheu
788a45e14148fb34175cba042df8979e7982758635fMichael Holzheu	if (pgm_check_occured)
789a45e14148fb34175cba042df8979e7982758635fMichael Holzheu		return -EIO;
790a45e14148fb34175cba042df8979e7982758635fMichael Holzheu	else
791a45e14148fb34175cba042df8979e7982758635fMichael Holzheu		return rc;
792a45e14148fb34175cba042df8979e7982758635fMichael Holzheu}
793a45e14148fb34175cba042df8979e7982758635fMichael Holzheu
79415e9b586e0bd3692e2a21c5be178810d9d32214eHeiko Carstensstatic int __shutdown_subchannel_easy(struct subchannel_id schid, void *data)
795f97a56fb768e5fe9cd07c56ca47870136bb5530cCornelia Huck{
796f97a56fb768e5fe9cd07c56ca47870136bb5530cCornelia Huck	struct schib schib;
797f97a56fb768e5fe9cd07c56ca47870136bb5530cCornelia Huck
798a45e14148fb34175cba042df8979e7982758635fMichael Holzheu	if (stsch_reset(schid, &schib))
799f97a56fb768e5fe9cd07c56ca47870136bb5530cCornelia Huck		return -ENXIO;
800f97a56fb768e5fe9cd07c56ca47870136bb5530cCornelia Huck	if (!schib.pmcw.ena)
801f97a56fb768e5fe9cd07c56ca47870136bb5530cCornelia Huck		return 0;
802f97a56fb768e5fe9cd07c56ca47870136bb5530cCornelia Huck	switch(__disable_subchannel_easy(schid, &schib)) {
803f97a56fb768e5fe9cd07c56ca47870136bb5530cCornelia Huck	case 0:
804f97a56fb768e5fe9cd07c56ca47870136bb5530cCornelia Huck	case -ENODEV:
805f97a56fb768e5fe9cd07c56ca47870136bb5530cCornelia Huck		break;
806f97a56fb768e5fe9cd07c56ca47870136bb5530cCornelia Huck	default: /* -EBUSY */
8070ae7a7b250bdf7ee87c8346164ef3c47fb79dfbdCornelia Huck		switch (schib.pmcw.st) {
8080ae7a7b250bdf7ee87c8346164ef3c47fb79dfbdCornelia Huck		case SUBCHANNEL_TYPE_IO:
8090ae7a7b250bdf7ee87c8346164ef3c47fb79dfbdCornelia Huck			if (__clear_io_subchannel_easy(schid))
8100ae7a7b250bdf7ee87c8346164ef3c47fb79dfbdCornelia Huck				goto out; /* give up... */
8110ae7a7b250bdf7ee87c8346164ef3c47fb79dfbdCornelia Huck			break;
8129d92a7e1b0d095c8be96ce5e592c6c5541684631Cornelia Huck		case SUBCHANNEL_TYPE_CHSC:
8139d92a7e1b0d095c8be96ce5e592c6c5541684631Cornelia Huck			__clear_chsc_subchannel_easy();
8149d92a7e1b0d095c8be96ce5e592c6c5541684631Cornelia Huck			break;
8150ae7a7b250bdf7ee87c8346164ef3c47fb79dfbdCornelia Huck		default:
8160ae7a7b250bdf7ee87c8346164ef3c47fb79dfbdCornelia Huck			/* No default clear strategy */
8170ae7a7b250bdf7ee87c8346164ef3c47fb79dfbdCornelia Huck			break;
8180ae7a7b250bdf7ee87c8346164ef3c47fb79dfbdCornelia Huck		}
8198821d24cd261aede9b0436cd3252b17a60ccc33aSebastian Ott		stsch_err(schid, &schib);
820f97a56fb768e5fe9cd07c56ca47870136bb5530cCornelia Huck		__disable_subchannel_easy(schid, &schib);
821f97a56fb768e5fe9cd07c56ca47870136bb5530cCornelia Huck	}
8220ae7a7b250bdf7ee87c8346164ef3c47fb79dfbdCornelia Huckout:
823f97a56fb768e5fe9cd07c56ca47870136bb5530cCornelia Huck	return 0;
824f97a56fb768e5fe9cd07c56ca47870136bb5530cCornelia Huck}
8251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
82615e9b586e0bd3692e2a21c5be178810d9d32214eHeiko Carstensstatic atomic_t chpid_reset_count;
82715e9b586e0bd3692e2a21c5be178810d9d32214eHeiko Carstens
82815e9b586e0bd3692e2a21c5be178810d9d32214eHeiko Carstensstatic void s390_reset_chpids_mcck_handler(void)
82915e9b586e0bd3692e2a21c5be178810d9d32214eHeiko Carstens{
83015e9b586e0bd3692e2a21c5be178810d9d32214eHeiko Carstens	struct crw crw;
83115e9b586e0bd3692e2a21c5be178810d9d32214eHeiko Carstens	struct mci *mci;
83215e9b586e0bd3692e2a21c5be178810d9d32214eHeiko Carstens
83315e9b586e0bd3692e2a21c5be178810d9d32214eHeiko Carstens	/* Check for pending channel report word. */
83415e9b586e0bd3692e2a21c5be178810d9d32214eHeiko Carstens	mci = (struct mci *)&S390_lowcore.mcck_interruption_code;
83515e9b586e0bd3692e2a21c5be178810d9d32214eHeiko Carstens	if (!mci->cp)
83615e9b586e0bd3692e2a21c5be178810d9d32214eHeiko Carstens		return;
83715e9b586e0bd3692e2a21c5be178810d9d32214eHeiko Carstens	/* Process channel report words. */
83815e9b586e0bd3692e2a21c5be178810d9d32214eHeiko Carstens	while (stcrw(&crw) == 0) {
83915e9b586e0bd3692e2a21c5be178810d9d32214eHeiko Carstens		/* Check for responses to RCHP. */
84015e9b586e0bd3692e2a21c5be178810d9d32214eHeiko Carstens		if (crw.slct && crw.rsc == CRW_RSC_CPATH)
84115e9b586e0bd3692e2a21c5be178810d9d32214eHeiko Carstens			atomic_dec(&chpid_reset_count);
84215e9b586e0bd3692e2a21c5be178810d9d32214eHeiko Carstens	}
84315e9b586e0bd3692e2a21c5be178810d9d32214eHeiko Carstens}
84415e9b586e0bd3692e2a21c5be178810d9d32214eHeiko Carstens
84515e9b586e0bd3692e2a21c5be178810d9d32214eHeiko Carstens#define RCHP_TIMEOUT (30 * USEC_PER_SEC)
84615e9b586e0bd3692e2a21c5be178810d9d32214eHeiko Carstensstatic void css_reset(void)
84715e9b586e0bd3692e2a21c5be178810d9d32214eHeiko Carstens{
84815e9b586e0bd3692e2a21c5be178810d9d32214eHeiko Carstens	int i, ret;
84915e9b586e0bd3692e2a21c5be178810d9d32214eHeiko Carstens	unsigned long long timeout;
850f86635fad14c4a6810cf0e08488fc9129a3b3b32Peter Oberparleiter	struct chp_id chpid;
85115e9b586e0bd3692e2a21c5be178810d9d32214eHeiko Carstens
85215e9b586e0bd3692e2a21c5be178810d9d32214eHeiko Carstens	/* Reset subchannels. */
85315e9b586e0bd3692e2a21c5be178810d9d32214eHeiko Carstens	for_each_subchannel(__shutdown_subchannel_easy,  NULL);
85415e9b586e0bd3692e2a21c5be178810d9d32214eHeiko Carstens	/* Reset channel paths. */
855ab14de6c37fae22911ba99f4171613e6d758050bHeiko Carstens	s390_base_mcck_handler_fn = s390_reset_chpids_mcck_handler;
85615e9b586e0bd3692e2a21c5be178810d9d32214eHeiko Carstens	/* Enable channel report machine checks. */
85715e9b586e0bd3692e2a21c5be178810d9d32214eHeiko Carstens	__ctl_set_bit(14, 28);
85815e9b586e0bd3692e2a21c5be178810d9d32214eHeiko Carstens	/* Temporarily reenable machine checks. */
85915e9b586e0bd3692e2a21c5be178810d9d32214eHeiko Carstens	local_mcck_enable();
860f86635fad14c4a6810cf0e08488fc9129a3b3b32Peter Oberparleiter	chp_id_init(&chpid);
86115e9b586e0bd3692e2a21c5be178810d9d32214eHeiko Carstens	for (i = 0; i <= __MAX_CHPID; i++) {
862f86635fad14c4a6810cf0e08488fc9129a3b3b32Peter Oberparleiter		chpid.id = i;
863f86635fad14c4a6810cf0e08488fc9129a3b3b32Peter Oberparleiter		ret = rchp(chpid);
86415e9b586e0bd3692e2a21c5be178810d9d32214eHeiko Carstens		if ((ret == 0) || (ret == 2))
86515e9b586e0bd3692e2a21c5be178810d9d32214eHeiko Carstens			/*
86615e9b586e0bd3692e2a21c5be178810d9d32214eHeiko Carstens			 * rchp either succeeded, or another rchp is already
86715e9b586e0bd3692e2a21c5be178810d9d32214eHeiko Carstens			 * in progress. In either case, we'll get a crw.
86815e9b586e0bd3692e2a21c5be178810d9d32214eHeiko Carstens			 */
86915e9b586e0bd3692e2a21c5be178810d9d32214eHeiko Carstens			atomic_inc(&chpid_reset_count);
87015e9b586e0bd3692e2a21c5be178810d9d32214eHeiko Carstens	}
87115e9b586e0bd3692e2a21c5be178810d9d32214eHeiko Carstens	/* Wait for machine check for all channel paths. */
8728c071b0f19dfa230335d22ce56a8fab5bd20cedcMartin Schwidefsky	timeout = get_tod_clock_fast() + (RCHP_TIMEOUT << 12);
87315e9b586e0bd3692e2a21c5be178810d9d32214eHeiko Carstens	while (atomic_read(&chpid_reset_count) != 0) {
8748c071b0f19dfa230335d22ce56a8fab5bd20cedcMartin Schwidefsky		if (get_tod_clock_fast() > timeout)
87515e9b586e0bd3692e2a21c5be178810d9d32214eHeiko Carstens			break;
87615e9b586e0bd3692e2a21c5be178810d9d32214eHeiko Carstens		cpu_relax();
87715e9b586e0bd3692e2a21c5be178810d9d32214eHeiko Carstens	}
87815e9b586e0bd3692e2a21c5be178810d9d32214eHeiko Carstens	/* Disable machine checks again. */
87915e9b586e0bd3692e2a21c5be178810d9d32214eHeiko Carstens	local_mcck_disable();
88015e9b586e0bd3692e2a21c5be178810d9d32214eHeiko Carstens	/* Disable channel report machine checks. */
88115e9b586e0bd3692e2a21c5be178810d9d32214eHeiko Carstens	__ctl_clear_bit(14, 28);
882ab14de6c37fae22911ba99f4171613e6d758050bHeiko Carstens	s390_base_mcck_handler_fn = NULL;
88315e9b586e0bd3692e2a21c5be178810d9d32214eHeiko Carstens}
88415e9b586e0bd3692e2a21c5be178810d9d32214eHeiko Carstens
88515e9b586e0bd3692e2a21c5be178810d9d32214eHeiko Carstensstatic struct reset_call css_reset_call = {
88615e9b586e0bd3692e2a21c5be178810d9d32214eHeiko Carstens	.fn = css_reset,
88715e9b586e0bd3692e2a21c5be178810d9d32214eHeiko Carstens};
88815e9b586e0bd3692e2a21c5be178810d9d32214eHeiko Carstens
88915e9b586e0bd3692e2a21c5be178810d9d32214eHeiko Carstensstatic int __init init_css_reset_call(void)
89015e9b586e0bd3692e2a21c5be178810d9d32214eHeiko Carstens{
89115e9b586e0bd3692e2a21c5be178810d9d32214eHeiko Carstens	atomic_set(&chpid_reset_count, 0);
89215e9b586e0bd3692e2a21c5be178810d9d32214eHeiko Carstens	register_reset_call(&css_reset_call);
89315e9b586e0bd3692e2a21c5be178810d9d32214eHeiko Carstens	return 0;
89415e9b586e0bd3692e2a21c5be178810d9d32214eHeiko Carstens}
89515e9b586e0bd3692e2a21c5be178810d9d32214eHeiko Carstens
89615e9b586e0bd3692e2a21c5be178810d9d32214eHeiko Carstensarch_initcall(init_css_reset_call);
89715e9b586e0bd3692e2a21c5be178810d9d32214eHeiko Carstens
89815e9b586e0bd3692e2a21c5be178810d9d32214eHeiko Carstensstruct sch_match_id {
89915e9b586e0bd3692e2a21c5be178810d9d32214eHeiko Carstens	struct subchannel_id schid;
90015e9b586e0bd3692e2a21c5be178810d9d32214eHeiko Carstens	struct ccw_dev_id devid;
90115e9b586e0bd3692e2a21c5be178810d9d32214eHeiko Carstens	int rc;
90215e9b586e0bd3692e2a21c5be178810d9d32214eHeiko Carstens};
90315e9b586e0bd3692e2a21c5be178810d9d32214eHeiko Carstens
90415e9b586e0bd3692e2a21c5be178810d9d32214eHeiko Carstensstatic int __reipl_subchannel_match(struct subchannel_id schid, void *data)
90515e9b586e0bd3692e2a21c5be178810d9d32214eHeiko Carstens{
90615e9b586e0bd3692e2a21c5be178810d9d32214eHeiko Carstens	struct schib schib;
90715e9b586e0bd3692e2a21c5be178810d9d32214eHeiko Carstens	struct sch_match_id *match_id = data;
90815e9b586e0bd3692e2a21c5be178810d9d32214eHeiko Carstens
909a45e14148fb34175cba042df8979e7982758635fMichael Holzheu	if (stsch_reset(schid, &schib))
91015e9b586e0bd3692e2a21c5be178810d9d32214eHeiko Carstens		return -ENXIO;
911b279a4f56d5476a0b9b0a97397f7a7bbe00b9b2fCornelia Huck	if ((schib.pmcw.st == SUBCHANNEL_TYPE_IO) && schib.pmcw.dnv &&
91215e9b586e0bd3692e2a21c5be178810d9d32214eHeiko Carstens	    (schib.pmcw.dev == match_id->devid.devno) &&
91315e9b586e0bd3692e2a21c5be178810d9d32214eHeiko Carstens	    (schid.ssid == match_id->devid.ssid)) {
91415e9b586e0bd3692e2a21c5be178810d9d32214eHeiko Carstens		match_id->schid = schid;
91515e9b586e0bd3692e2a21c5be178810d9d32214eHeiko Carstens		match_id->rc = 0;
91615e9b586e0bd3692e2a21c5be178810d9d32214eHeiko Carstens		return 1;
91715e9b586e0bd3692e2a21c5be178810d9d32214eHeiko Carstens	}
91815e9b586e0bd3692e2a21c5be178810d9d32214eHeiko Carstens	return 0;
91915e9b586e0bd3692e2a21c5be178810d9d32214eHeiko Carstens}
92015e9b586e0bd3692e2a21c5be178810d9d32214eHeiko Carstens
92115e9b586e0bd3692e2a21c5be178810d9d32214eHeiko Carstensstatic int reipl_find_schid(struct ccw_dev_id *devid,
92215e9b586e0bd3692e2a21c5be178810d9d32214eHeiko Carstens			    struct subchannel_id *schid)
9231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
924ff6b8ea68f4b7353f88b97024f28127e2148aa00Michael Holzheu	struct sch_match_id match_id;
925ff6b8ea68f4b7353f88b97024f28127e2148aa00Michael Holzheu
926ff6b8ea68f4b7353f88b97024f28127e2148aa00Michael Holzheu	match_id.devid = *devid;
927ff6b8ea68f4b7353f88b97024f28127e2148aa00Michael Holzheu	match_id.rc = -ENODEV;
92815e9b586e0bd3692e2a21c5be178810d9d32214eHeiko Carstens	for_each_subchannel(__reipl_subchannel_match, &match_id);
929ff6b8ea68f4b7353f88b97024f28127e2148aa00Michael Holzheu	if (match_id.rc == 0)
930ff6b8ea68f4b7353f88b97024f28127e2148aa00Michael Holzheu		*schid = match_id.schid;
931ff6b8ea68f4b7353f88b97024f28127e2148aa00Michael Holzheu	return match_id.rc;
9321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
9331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
934ff6b8ea68f4b7353f88b97024f28127e2148aa00Michael Holzheuextern void do_reipl_asm(__u32 schid);
935ff6b8ea68f4b7353f88b97024f28127e2148aa00Michael Holzheu
9361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Make sure all subchannels are quiet before we re-ipl an lpar. */
937ff6b8ea68f4b7353f88b97024f28127e2148aa00Michael Holzheuvoid reipl_ccw_dev(struct ccw_dev_id *devid)
9381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
93941459d36cf0d57813017dae6080a879cc038e5feHeiko Carstens	struct subchannel_id uninitialized_var(schid);
940ff6b8ea68f4b7353f88b97024f28127e2148aa00Michael Holzheu
94160a0c68df2632feaa4a986af084650d1165d89c5Michael Holzheu	s390_reset_system(NULL, NULL);
94215e9b586e0bd3692e2a21c5be178810d9d32214eHeiko Carstens	if (reipl_find_schid(devid, &schid) != 0)
943ff6b8ea68f4b7353f88b97024f28127e2148aa00Michael Holzheu		panic("IPL Device not found\n");
944ff6b8ea68f4b7353f88b97024f28127e2148aa00Michael Holzheu	do_reipl_asm(*((__u32*)&schid));
9451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
946e87bfe51b5ca2db99dd680bbb1e8fe3c94b607dfHeiko Carstens
9476fc321fd7dd91f0592f37503219196835314fbb7Heiko Carstensint __init cio_get_iplinfo(struct cio_iplinfo *iplinfo)
948e87bfe51b5ca2db99dd680bbb1e8fe3c94b607dfHeiko Carstens{
949e87bfe51b5ca2db99dd680bbb1e8fe3c94b607dfHeiko Carstens	struct subchannel_id schid;
9506fc321fd7dd91f0592f37503219196835314fbb7Heiko Carstens	struct schib schib;
951e87bfe51b5ca2db99dd680bbb1e8fe3c94b607dfHeiko Carstens
952cbb870c8221147ae337612e04b2bb0211f31a74bHeiko Carstens	schid = *(struct subchannel_id *)&S390_lowcore.subchannel_id;
953e87bfe51b5ca2db99dd680bbb1e8fe3c94b607dfHeiko Carstens	if (!schid.one)
9546fc321fd7dd91f0592f37503219196835314fbb7Heiko Carstens		return -ENODEV;
9558821d24cd261aede9b0436cd3252b17a60ccc33aSebastian Ott	if (stsch_err(schid, &schib))
9566fc321fd7dd91f0592f37503219196835314fbb7Heiko Carstens		return -ENODEV;
957b279a4f56d5476a0b9b0a97397f7a7bbe00b9b2fCornelia Huck	if (schib.pmcw.st != SUBCHANNEL_TYPE_IO)
958b279a4f56d5476a0b9b0a97397f7a7bbe00b9b2fCornelia Huck		return -ENODEV;
9596fc321fd7dd91f0592f37503219196835314fbb7Heiko Carstens	if (!schib.pmcw.dnv)
9606fc321fd7dd91f0592f37503219196835314fbb7Heiko Carstens		return -ENODEV;
9616fc321fd7dd91f0592f37503219196835314fbb7Heiko Carstens	iplinfo->devno = schib.pmcw.dev;
9626fc321fd7dd91f0592f37503219196835314fbb7Heiko Carstens	iplinfo->is_qdio = schib.pmcw.qf;
9636fc321fd7dd91f0592f37503219196835314fbb7Heiko Carstens	return 0;
964e87bfe51b5ca2db99dd680bbb1e8fe3c94b607dfHeiko Carstens}
96583262d6349e60b9d10798d489719d80029c00798Peter Oberparleiter
96683262d6349e60b9d10798d489719d80029c00798Peter Oberparleiter/**
96783262d6349e60b9d10798d489719d80029c00798Peter Oberparleiter * cio_tm_start_key - perform start function
96883262d6349e60b9d10798d489719d80029c00798Peter Oberparleiter * @sch: subchannel on which to perform the start function
96983262d6349e60b9d10798d489719d80029c00798Peter Oberparleiter * @tcw: transport-command word to be started
97083262d6349e60b9d10798d489719d80029c00798Peter Oberparleiter * @lpm: mask of paths to use
97183262d6349e60b9d10798d489719d80029c00798Peter Oberparleiter * @key: storage key to use for storage access
97283262d6349e60b9d10798d489719d80029c00798Peter Oberparleiter *
97383262d6349e60b9d10798d489719d80029c00798Peter Oberparleiter * Start the tcw on the given subchannel. Return zero on success, non-zero
97483262d6349e60b9d10798d489719d80029c00798Peter Oberparleiter * otherwise.
97583262d6349e60b9d10798d489719d80029c00798Peter Oberparleiter */
97683262d6349e60b9d10798d489719d80029c00798Peter Oberparleiterint cio_tm_start_key(struct subchannel *sch, struct tcw *tcw, u8 lpm, u8 key)
97783262d6349e60b9d10798d489719d80029c00798Peter Oberparleiter{
97883262d6349e60b9d10798d489719d80029c00798Peter Oberparleiter	int cc;
97983262d6349e60b9d10798d489719d80029c00798Peter Oberparleiter	union orb *orb = &to_io_private(sch)->orb;
98083262d6349e60b9d10798d489719d80029c00798Peter Oberparleiter
98183262d6349e60b9d10798d489719d80029c00798Peter Oberparleiter	memset(orb, 0, sizeof(union orb));
98283262d6349e60b9d10798d489719d80029c00798Peter Oberparleiter	orb->tm.intparm = (u32) (addr_t) sch;
98383262d6349e60b9d10798d489719d80029c00798Peter Oberparleiter	orb->tm.key = key >> 4;
98483262d6349e60b9d10798d489719d80029c00798Peter Oberparleiter	orb->tm.b = 1;
98583262d6349e60b9d10798d489719d80029c00798Peter Oberparleiter	orb->tm.lpm = lpm ? lpm : sch->lpm;
98683262d6349e60b9d10798d489719d80029c00798Peter Oberparleiter	orb->tm.tcw = (u32) (addr_t) tcw;
98783262d6349e60b9d10798d489719d80029c00798Peter Oberparleiter	cc = ssch(sch->schid, orb);
98883262d6349e60b9d10798d489719d80029c00798Peter Oberparleiter	switch (cc) {
98983262d6349e60b9d10798d489719d80029c00798Peter Oberparleiter	case 0:
99083262d6349e60b9d10798d489719d80029c00798Peter Oberparleiter		return 0;
99183262d6349e60b9d10798d489719d80029c00798Peter Oberparleiter	case 1:
99283262d6349e60b9d10798d489719d80029c00798Peter Oberparleiter	case 2:
99383262d6349e60b9d10798d489719d80029c00798Peter Oberparleiter		return -EBUSY;
99483262d6349e60b9d10798d489719d80029c00798Peter Oberparleiter	default:
99583262d6349e60b9d10798d489719d80029c00798Peter Oberparleiter		return cio_start_handle_notoper(sch, lpm);
99683262d6349e60b9d10798d489719d80029c00798Peter Oberparleiter	}
99783262d6349e60b9d10798d489719d80029c00798Peter Oberparleiter}
99883262d6349e60b9d10798d489719d80029c00798Peter Oberparleiter
99983262d6349e60b9d10798d489719d80029c00798Peter Oberparleiter/**
100083262d6349e60b9d10798d489719d80029c00798Peter Oberparleiter * cio_tm_intrg - perform interrogate function
100183262d6349e60b9d10798d489719d80029c00798Peter Oberparleiter * @sch - subchannel on which to perform the interrogate function
100283262d6349e60b9d10798d489719d80029c00798Peter Oberparleiter *
100383262d6349e60b9d10798d489719d80029c00798Peter Oberparleiter * If the specified subchannel is running in transport-mode, perform the
100483262d6349e60b9d10798d489719d80029c00798Peter Oberparleiter * interrogate function. Return zero on success, non-zero otherwie.
100583262d6349e60b9d10798d489719d80029c00798Peter Oberparleiter */
100683262d6349e60b9d10798d489719d80029c00798Peter Oberparleiterint cio_tm_intrg(struct subchannel *sch)
100783262d6349e60b9d10798d489719d80029c00798Peter Oberparleiter{
100883262d6349e60b9d10798d489719d80029c00798Peter Oberparleiter	int cc;
100983262d6349e60b9d10798d489719d80029c00798Peter Oberparleiter
101083262d6349e60b9d10798d489719d80029c00798Peter Oberparleiter	if (!to_io_private(sch)->orb.tm.b)
101183262d6349e60b9d10798d489719d80029c00798Peter Oberparleiter		return -EINVAL;
101283262d6349e60b9d10798d489719d80029c00798Peter Oberparleiter	cc = xsch(sch->schid);
101383262d6349e60b9d10798d489719d80029c00798Peter Oberparleiter	switch (cc) {
101483262d6349e60b9d10798d489719d80029c00798Peter Oberparleiter	case 0:
101583262d6349e60b9d10798d489719d80029c00798Peter Oberparleiter	case 2:
101683262d6349e60b9d10798d489719d80029c00798Peter Oberparleiter		return 0;
101783262d6349e60b9d10798d489719d80029c00798Peter Oberparleiter	case 1:
101883262d6349e60b9d10798d489719d80029c00798Peter Oberparleiter		return -EBUSY;
101983262d6349e60b9d10798d489719d80029c00798Peter Oberparleiter	default:
102083262d6349e60b9d10798d489719d80029c00798Peter Oberparleiter		return -ENODEV;
102183262d6349e60b9d10798d489719d80029c00798Peter Oberparleiter	}
102283262d6349e60b9d10798d489719d80029c00798Peter Oberparleiter}
1023