1724117b7SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds * S/390 common I/O routines -- low level i/o calls
41da177e4SLinus Torvalds *
50ae7a7b2SCornelia Huck * Copyright IBM Corp. 1999, 2008
61da177e4SLinus Torvalds * Author(s): Ingo Adlung (adlung@de.ibm.com)
74ce3b30cSCornelia Huck * Cornelia Huck (cornelia.huck@de.ibm.com)
81da177e4SLinus Torvalds * Arnd Bergmann (arndb@de.ibm.com)
91da177e4SLinus Torvalds * Martin Schwidefsky (schwidefsky@de.ibm.com)
101da177e4SLinus Torvalds */
111da177e4SLinus Torvalds
12e6d5a428SMichael Ernst #define KMSG_COMPONENT "cio"
13e6d5a428SMichael Ernst #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
14e6d5a428SMichael Ernst
1588dbd203SHeiko Carstens #include <linux/ftrace.h>
161da177e4SLinus Torvalds #include <linux/module.h>
171da177e4SLinus Torvalds #include <linux/init.h>
181da177e4SLinus Torvalds #include <linux/slab.h>
191da177e4SLinus Torvalds #include <linux/device.h>
201da177e4SLinus Torvalds #include <linux/kernel_stat.h>
211da177e4SLinus Torvalds #include <linux/interrupt.h>
22257ceab7SThomas Gleixner #include <linux/irq.h>
231da177e4SLinus Torvalds #include <asm/cio.h>
241da177e4SLinus Torvalds #include <asm/delay.h>
251da177e4SLinus Torvalds #include <asm/irq.h>
265a489b98SHeiko Carstens #include <asm/irq_regs.h>
27e87bfe51SHeiko Carstens #include <asm/setup.h>
2846b05d26SMichael Holzheu #include <asm/ipl.h>
29e5854a58SPeter Oberparleiter #include <asm/chpid.h>
304e8e56c6SPeter Oberparleiter #include <asm/airq.h>
313a3fc29aSCornelia Huck #include <asm/isc.h>
3232ef5517SIngo Molnar #include <linux/sched/cputime.h>
3383262d63SPeter Oberparleiter #include <asm/fcx.h>
34f5daba1dSHeiko Carstens #include <asm/nmi.h>
35f5daba1dSHeiko Carstens #include <asm/crw.h>
361da177e4SLinus Torvalds #include "cio.h"
371da177e4SLinus Torvalds #include "css.h"
381da177e4SLinus Torvalds #include "chsc.h"
391da177e4SLinus Torvalds #include "ioasm.h"
40cd6b4f27SCornelia Huck #include "io_sch.h"
411da177e4SLinus Torvalds #include "blacklist.h"
421da177e4SLinus Torvalds #include "cio_debug.h"
43e6b6e10aSPeter Oberparleiter #include "chp.h"
4442248979SPeter Oberparleiter #include "trace.h"
451da177e4SLinus Torvalds
461da177e4SLinus Torvalds debug_info_t *cio_debug_msg_id;
471da177e4SLinus Torvalds debug_info_t *cio_debug_trace_id;
481da177e4SLinus Torvalds debug_info_t *cio_debug_crw_id;
491da177e4SLinus Torvalds
5063aef00bSMartin Schwidefsky DEFINE_PER_CPU_ALIGNED(struct irb, cio_irb);
5163aef00bSMartin Schwidefsky EXPORT_PER_CPU_SYMBOL(cio_irb);
5263aef00bSMartin Schwidefsky
531da177e4SLinus Torvalds /*
541da177e4SLinus Torvalds * Function: cio_debug_init
55bc698bcfSCornelia Huck * Initializes three debug logs for common I/O:
56bc698bcfSCornelia Huck * - cio_msg logs generic cio messages
571da177e4SLinus Torvalds * - cio_trace logs the calling of different functions
58bc698bcfSCornelia Huck * - cio_crw logs machine check related cio messages
591da177e4SLinus Torvalds */
cio_debug_init(void)60bc698bcfSCornelia Huck static int __init cio_debug_init(void)
611da177e4SLinus Torvalds {
62f7e1e65dSSebastian Ott cio_debug_msg_id = debug_register("cio_msg", 16, 1, 11 * sizeof(long));
631da177e4SLinus Torvalds if (!cio_debug_msg_id)
641da177e4SLinus Torvalds goto out_unregister;
651da177e4SLinus Torvalds debug_register_view(cio_debug_msg_id, &debug_sprintf_view);
661da177e4SLinus Torvalds debug_set_level(cio_debug_msg_id, 2);
67361f494dSPeter Tiedemann cio_debug_trace_id = debug_register("cio_trace", 16, 1, 16);
681da177e4SLinus Torvalds if (!cio_debug_trace_id)
691da177e4SLinus Torvalds goto out_unregister;
701da177e4SLinus Torvalds debug_register_view(cio_debug_trace_id, &debug_hex_ascii_view);
711da177e4SLinus Torvalds debug_set_level(cio_debug_trace_id, 2);
72f7e1e65dSSebastian Ott cio_debug_crw_id = debug_register("cio_crw", 8, 1, 8 * sizeof(long));
731da177e4SLinus Torvalds if (!cio_debug_crw_id)
741da177e4SLinus Torvalds goto out_unregister;
751da177e4SLinus Torvalds debug_register_view(cio_debug_crw_id, &debug_sprintf_view);
76bc698bcfSCornelia Huck debug_set_level(cio_debug_crw_id, 4);
771da177e4SLinus Torvalds return 0;
781da177e4SLinus Torvalds
791da177e4SLinus Torvalds out_unregister:
801da177e4SLinus Torvalds debug_unregister(cio_debug_msg_id);
811da177e4SLinus Torvalds debug_unregister(cio_debug_trace_id);
821da177e4SLinus Torvalds debug_unregister(cio_debug_crw_id);
831da177e4SLinus Torvalds return -1;
841da177e4SLinus Torvalds }
851da177e4SLinus Torvalds
861da177e4SLinus Torvalds arch_initcall (cio_debug_init);
871da177e4SLinus Torvalds
cio_set_options(struct subchannel * sch,int flags)88c513d07aSSebastian Ott int cio_set_options(struct subchannel *sch, int flags)
891da177e4SLinus Torvalds {
90c513d07aSSebastian Ott struct io_subchannel_private *priv = to_io_private(sch);
91c513d07aSSebastian Ott
92c513d07aSSebastian Ott priv->options.suspend = (flags & DOIO_ALLOW_SUSPEND) != 0;
93c513d07aSSebastian Ott priv->options.prefetch = (flags & DOIO_DENY_PREFETCH) != 0;
94c513d07aSSebastian Ott priv->options.inter = (flags & DOIO_SUPPRESS_INTER) != 0;
951da177e4SLinus Torvalds return 0;
961da177e4SLinus Torvalds }
971da177e4SLinus Torvalds
984d284cacSHeiko Carstens static int
cio_start_handle_notoper(struct subchannel * sch,__u8 lpm)991da177e4SLinus Torvalds cio_start_handle_notoper(struct subchannel *sch, __u8 lpm)
1001da177e4SLinus Torvalds {
1011da177e4SLinus Torvalds char dbf_text[15];
1021da177e4SLinus Torvalds
1031da177e4SLinus Torvalds if (lpm != 0)
1041da177e4SLinus Torvalds sch->lpm &= ~lpm;
1051da177e4SLinus Torvalds else
1061da177e4SLinus Torvalds sch->lpm = 0;
1071da177e4SLinus Torvalds
108139b83ddSMichael Ernst CIO_MSG_EVENT(2, "cio_start: 'not oper' status for "
109fb6958a5SCornelia Huck "subchannel 0.%x.%04x!\n", sch->schid.ssid,
110fb6958a5SCornelia Huck sch->schid.sch_no);
111cdb912a4SSebastian Ott
112cdb912a4SSebastian Ott if (cio_update_schib(sch))
113cdb912a4SSebastian Ott return -ENODEV;
114cdb912a4SSebastian Ott
1152a0217d5SKay Sievers sprintf(dbf_text, "no%s", dev_name(&sch->dev));
1161da177e4SLinus Torvalds CIO_TRACE_EVENT(0, dbf_text);
1171da177e4SLinus Torvalds CIO_HEX_EVENT(0, &sch->schib, sizeof (struct schib));
1181da177e4SLinus Torvalds
1191da177e4SLinus Torvalds return (sch->lpm ? -EACCES : -ENODEV);
1201da177e4SLinus Torvalds }
1211da177e4SLinus Torvalds
1221da177e4SLinus Torvalds int
cio_start_key(struct subchannel * sch,struct ccw1 * cpa,__u8 lpm,__u8 key)1231da177e4SLinus Torvalds cio_start_key (struct subchannel *sch, /* subchannel structure */
1241da177e4SLinus Torvalds struct ccw1 * cpa, /* logical channel prog addr */
1251da177e4SLinus Torvalds __u8 lpm, /* logical path mask */
1261da177e4SLinus Torvalds __u8 key) /* storage key */
1271da177e4SLinus Torvalds {
128c513d07aSSebastian Ott struct io_subchannel_private *priv = to_io_private(sch);
129c513d07aSSebastian Ott union orb *orb = &priv->orb;
1301da177e4SLinus Torvalds int ccode;
1311da177e4SLinus Torvalds
132efd986dbSSebastian Ott CIO_TRACE_EVENT(5, "stIO");
133efd986dbSSebastian Ott CIO_TRACE_EVENT(5, dev_name(&sch->dev));
1341da177e4SLinus Torvalds
1359adb8c1dSStefan Weinhuber memset(orb, 0, sizeof(union orb));
1361da177e4SLinus Torvalds /* sch is always under 2G. */
1375c2e5a0cSAlexander Gordeev orb->cmd.intparm = (u32)virt_to_phys(sch);
13883262d63SPeter Oberparleiter orb->cmd.fmt = 1;
1391da177e4SLinus Torvalds
140c513d07aSSebastian Ott orb->cmd.pfch = priv->options.prefetch == 0;
141c513d07aSSebastian Ott orb->cmd.spnd = priv->options.suspend;
142c513d07aSSebastian Ott orb->cmd.ssic = priv->options.suspend && priv->options.inter;
14383262d63SPeter Oberparleiter orb->cmd.lpm = (lpm != 0) ? lpm : sch->lpm;
1441da177e4SLinus Torvalds /*
1451da177e4SLinus Torvalds * for 64 bit we always support 64 bit IDAWs with 4k page size only
1461da177e4SLinus Torvalds */
14783262d63SPeter Oberparleiter orb->cmd.c64 = 1;
14883262d63SPeter Oberparleiter orb->cmd.i2k = 0;
14983262d63SPeter Oberparleiter orb->cmd.key = key >> 4;
1501da177e4SLinus Torvalds /* issue "Start Subchannel" */
1515c2e5a0cSAlexander Gordeev orb->cmd.cpa = (u32)virt_to_phys(cpa);
152cd6b4f27SCornelia Huck ccode = ssch(sch->schid, orb);
1531da177e4SLinus Torvalds
1541da177e4SLinus Torvalds /* process condition code */
155efd986dbSSebastian Ott CIO_HEX_EVENT(5, &ccode, sizeof(ccode));
1561da177e4SLinus Torvalds
1571da177e4SLinus Torvalds switch (ccode) {
1581da177e4SLinus Torvalds case 0:
1591da177e4SLinus Torvalds /*
1601da177e4SLinus Torvalds * initialize device status information
1611da177e4SLinus Torvalds */
16223d805b6SPeter Oberparleiter sch->schib.scsw.cmd.actl |= SCSW_ACTL_START_PEND;
1631da177e4SLinus Torvalds return 0;
1641da177e4SLinus Torvalds case 1: /* status pending */
1651da177e4SLinus Torvalds case 2: /* busy */
1661da177e4SLinus Torvalds return -EBUSY;
167c91ebe49SCornelia Huck case 3: /* device/path not operational */
1681da177e4SLinus Torvalds return cio_start_handle_notoper(sch, lpm);
169c91ebe49SCornelia Huck default:
170c91ebe49SCornelia Huck return ccode;
1711da177e4SLinus Torvalds }
1721da177e4SLinus Torvalds }
173a22217e2SDong Jia Shi EXPORT_SYMBOL_GPL(cio_start_key);
1741da177e4SLinus Torvalds
1751da177e4SLinus Torvalds int
cio_start(struct subchannel * sch,struct ccw1 * cpa,__u8 lpm)1761da177e4SLinus Torvalds cio_start (struct subchannel *sch, struct ccw1 *cpa, __u8 lpm)
1771da177e4SLinus Torvalds {
1780b642edeSPeter Oberparleiter return cio_start_key(sch, cpa, lpm, PAGE_DEFAULT_KEY);
1791da177e4SLinus Torvalds }
180a22217e2SDong Jia Shi EXPORT_SYMBOL_GPL(cio_start);
1811da177e4SLinus Torvalds
1821da177e4SLinus Torvalds /*
1831da177e4SLinus Torvalds * resume suspended I/O operation
1841da177e4SLinus Torvalds */
1851da177e4SLinus Torvalds int
cio_resume(struct subchannel * sch)1861da177e4SLinus Torvalds cio_resume (struct subchannel *sch)
1871da177e4SLinus Torvalds {
1881da177e4SLinus Torvalds int ccode;
1891da177e4SLinus Torvalds
1901da177e4SLinus Torvalds CIO_TRACE_EVENT(4, "resIO");
1912a0217d5SKay Sievers CIO_TRACE_EVENT(4, dev_name(&sch->dev));
1921da177e4SLinus Torvalds
193a8237fc4SCornelia Huck ccode = rsch (sch->schid);
1941da177e4SLinus Torvalds
195efd986dbSSebastian Ott CIO_HEX_EVENT(4, &ccode, sizeof(ccode));
1961da177e4SLinus Torvalds
1971da177e4SLinus Torvalds switch (ccode) {
1981da177e4SLinus Torvalds case 0:
19923d805b6SPeter Oberparleiter sch->schib.scsw.cmd.actl |= SCSW_ACTL_RESUME_PEND;
2001da177e4SLinus Torvalds return 0;
2011da177e4SLinus Torvalds case 1:
2021da177e4SLinus Torvalds return -EBUSY;
2031da177e4SLinus Torvalds case 2:
2041da177e4SLinus Torvalds return -EINVAL;
2051da177e4SLinus Torvalds default:
2061da177e4SLinus Torvalds /*
2071da177e4SLinus Torvalds * useless to wait for request completion
2081da177e4SLinus Torvalds * as device is no longer operational !
2091da177e4SLinus Torvalds */
2101da177e4SLinus Torvalds return -ENODEV;
2111da177e4SLinus Torvalds }
2121da177e4SLinus Torvalds }
213a22217e2SDong Jia Shi EXPORT_SYMBOL_GPL(cio_resume);
2141da177e4SLinus Torvalds
2151da177e4SLinus Torvalds /*
2161da177e4SLinus Torvalds * halt I/O operation
2171da177e4SLinus Torvalds */
2181da177e4SLinus Torvalds int
cio_halt(struct subchannel * sch)2191da177e4SLinus Torvalds cio_halt(struct subchannel *sch)
2201da177e4SLinus Torvalds {
2211da177e4SLinus Torvalds int ccode;
2221da177e4SLinus Torvalds
2231da177e4SLinus Torvalds if (!sch)
2241da177e4SLinus Torvalds return -ENODEV;
2251da177e4SLinus Torvalds
2261da177e4SLinus Torvalds CIO_TRACE_EVENT(2, "haltIO");
2272a0217d5SKay Sievers CIO_TRACE_EVENT(2, dev_name(&sch->dev));
2281da177e4SLinus Torvalds
2291da177e4SLinus Torvalds /*
2301da177e4SLinus Torvalds * Issue "Halt subchannel" and process condition code
2311da177e4SLinus Torvalds */
232a8237fc4SCornelia Huck ccode = hsch (sch->schid);
2331da177e4SLinus Torvalds
234efd986dbSSebastian Ott CIO_HEX_EVENT(2, &ccode, sizeof(ccode));
2351da177e4SLinus Torvalds
2361da177e4SLinus Torvalds switch (ccode) {
2371da177e4SLinus Torvalds case 0:
23823d805b6SPeter Oberparleiter sch->schib.scsw.cmd.actl |= SCSW_ACTL_HALT_PEND;
2391da177e4SLinus Torvalds return 0;
2401da177e4SLinus Torvalds case 1: /* status pending */
2411da177e4SLinus Torvalds case 2: /* busy */
2421da177e4SLinus Torvalds return -EBUSY;
2431da177e4SLinus Torvalds default: /* device not operational */
2441da177e4SLinus Torvalds return -ENODEV;
2451da177e4SLinus Torvalds }
2461da177e4SLinus Torvalds }
247a22217e2SDong Jia Shi EXPORT_SYMBOL_GPL(cio_halt);
2481da177e4SLinus Torvalds
2491da177e4SLinus Torvalds /*
2501da177e4SLinus Torvalds * Clear I/O operation
2511da177e4SLinus Torvalds */
2521da177e4SLinus Torvalds int
cio_clear(struct subchannel * sch)2531da177e4SLinus Torvalds cio_clear(struct subchannel *sch)
2541da177e4SLinus Torvalds {
2551da177e4SLinus Torvalds int ccode;
2561da177e4SLinus Torvalds
2571da177e4SLinus Torvalds if (!sch)
2581da177e4SLinus Torvalds return -ENODEV;
2591da177e4SLinus Torvalds
2601da177e4SLinus Torvalds CIO_TRACE_EVENT(2, "clearIO");
2612a0217d5SKay Sievers CIO_TRACE_EVENT(2, dev_name(&sch->dev));
2621da177e4SLinus Torvalds
2631da177e4SLinus Torvalds /*
2641da177e4SLinus Torvalds * Issue "Clear subchannel" and process condition code
2651da177e4SLinus Torvalds */
266a8237fc4SCornelia Huck ccode = csch (sch->schid);
2671da177e4SLinus Torvalds
268efd986dbSSebastian Ott CIO_HEX_EVENT(2, &ccode, sizeof(ccode));
2691da177e4SLinus Torvalds
2701da177e4SLinus Torvalds switch (ccode) {
2711da177e4SLinus Torvalds case 0:
27223d805b6SPeter Oberparleiter sch->schib.scsw.cmd.actl |= SCSW_ACTL_CLEAR_PEND;
2731da177e4SLinus Torvalds return 0;
2741da177e4SLinus Torvalds default: /* device not operational */
2751da177e4SLinus Torvalds return -ENODEV;
2761da177e4SLinus Torvalds }
2771da177e4SLinus Torvalds }
278a22217e2SDong Jia Shi EXPORT_SYMBOL_GPL(cio_clear);
2791da177e4SLinus Torvalds
2801da177e4SLinus Torvalds /*
2811da177e4SLinus Torvalds * Function: cio_cancel
2821da177e4SLinus Torvalds * Issues a "Cancel Subchannel" on the specified subchannel
2831da177e4SLinus Torvalds * Note: We don't need any fancy intparms and flags here
2841da177e4SLinus Torvalds * since xsch is executed synchronously.
2851da177e4SLinus Torvalds * Only for common I/O internal use as for now.
2861da177e4SLinus Torvalds */
2871da177e4SLinus Torvalds int
cio_cancel(struct subchannel * sch)2881da177e4SLinus Torvalds cio_cancel (struct subchannel *sch)
2891da177e4SLinus Torvalds {
2901da177e4SLinus Torvalds int ccode;
2911da177e4SLinus Torvalds
2921da177e4SLinus Torvalds if (!sch)
2931da177e4SLinus Torvalds return -ENODEV;
2941da177e4SLinus Torvalds
2951da177e4SLinus Torvalds CIO_TRACE_EVENT(2, "cancelIO");
2962a0217d5SKay Sievers CIO_TRACE_EVENT(2, dev_name(&sch->dev));
2971da177e4SLinus Torvalds
298a8237fc4SCornelia Huck ccode = xsch (sch->schid);
2991da177e4SLinus Torvalds
300efd986dbSSebastian Ott CIO_HEX_EVENT(2, &ccode, sizeof(ccode));
3011da177e4SLinus Torvalds
3021da177e4SLinus Torvalds switch (ccode) {
3031da177e4SLinus Torvalds case 0: /* success */
3041da177e4SLinus Torvalds /* Update information in scsw. */
305cdb912a4SSebastian Ott if (cio_update_schib(sch))
306cdb912a4SSebastian Ott return -ENODEV;
3071da177e4SLinus Torvalds return 0;
3081da177e4SLinus Torvalds case 1: /* status pending */
3091da177e4SLinus Torvalds return -EBUSY;
3101da177e4SLinus Torvalds case 2: /* not applicable */
3111da177e4SLinus Torvalds return -EINVAL;
3121da177e4SLinus Torvalds default: /* not oper */
3131da177e4SLinus Torvalds return -ENODEV;
3141da177e4SLinus Torvalds }
3151da177e4SLinus Torvalds }
316a22217e2SDong Jia Shi EXPORT_SYMBOL_GPL(cio_cancel);
3171da177e4SLinus Torvalds
3185434da4dSDong Jia Shi /**
3195434da4dSDong Jia Shi * cio_cancel_halt_clear - Cancel running I/O by performing cancel, halt
3205434da4dSDong Jia Shi * and clear ordinally if subchannel is valid.
3215434da4dSDong Jia Shi * @sch: subchannel on which to perform the cancel_halt_clear operation
3225434da4dSDong Jia Shi * @iretry: the number of the times remained to retry the next operation
3235434da4dSDong Jia Shi *
3245434da4dSDong Jia Shi * This should be called repeatedly since halt/clear are asynchronous
3255434da4dSDong Jia Shi * operations. We do one try with cio_cancel, three tries with cio_halt,
3265434da4dSDong Jia Shi * 255 tries with cio_clear. The caller should initialize @iretry with
3275434da4dSDong Jia Shi * the value 255 for its first call to this, and keep using the same
3285434da4dSDong Jia Shi * @iretry in the subsequent calls until it gets a non -EBUSY return.
3295434da4dSDong Jia Shi *
3305434da4dSDong Jia Shi * Returns 0 if device now idle, -ENODEV for device not operational,
3315434da4dSDong Jia Shi * -EBUSY if an interrupt is expected (either from halt/clear or from a
3325434da4dSDong Jia Shi * status pending), and -EIO if out of retries.
3335434da4dSDong Jia Shi */
cio_cancel_halt_clear(struct subchannel * sch,int * iretry)3345434da4dSDong Jia Shi int cio_cancel_halt_clear(struct subchannel *sch, int *iretry)
3355434da4dSDong Jia Shi {
3365434da4dSDong Jia Shi int ret;
3375434da4dSDong Jia Shi
3385434da4dSDong Jia Shi if (cio_update_schib(sch))
3395434da4dSDong Jia Shi return -ENODEV;
3405434da4dSDong Jia Shi if (!sch->schib.pmcw.ena)
3415434da4dSDong Jia Shi /* Not operational -> done. */
3425434da4dSDong Jia Shi return 0;
3435434da4dSDong Jia Shi /* Stage 1: cancel io. */
3445434da4dSDong Jia Shi if (!(scsw_actl(&sch->schib.scsw) & SCSW_ACTL_HALT_PEND) &&
3455434da4dSDong Jia Shi !(scsw_actl(&sch->schib.scsw) & SCSW_ACTL_CLEAR_PEND)) {
3465434da4dSDong Jia Shi if (!scsw_is_tm(&sch->schib.scsw)) {
3475434da4dSDong Jia Shi ret = cio_cancel(sch);
3485434da4dSDong Jia Shi if (ret != -EINVAL)
3495434da4dSDong Jia Shi return ret;
3505434da4dSDong Jia Shi }
3515434da4dSDong Jia Shi /*
3525434da4dSDong Jia Shi * Cancel io unsuccessful or not applicable (transport mode).
3535434da4dSDong Jia Shi * Continue with asynchronous instructions.
3545434da4dSDong Jia Shi */
3555434da4dSDong Jia Shi *iretry = 3; /* 3 halt retries. */
3565434da4dSDong Jia Shi }
3575434da4dSDong Jia Shi /* Stage 2: halt io. */
3585434da4dSDong Jia Shi if (!(scsw_actl(&sch->schib.scsw) & SCSW_ACTL_CLEAR_PEND)) {
3595434da4dSDong Jia Shi if (*iretry) {
3605434da4dSDong Jia Shi *iretry -= 1;
3615434da4dSDong Jia Shi ret = cio_halt(sch);
3625434da4dSDong Jia Shi if (ret != -EBUSY)
3635434da4dSDong Jia Shi return (ret == 0) ? -EBUSY : ret;
3645434da4dSDong Jia Shi }
3655434da4dSDong Jia Shi /* Halt io unsuccessful. */
3665434da4dSDong Jia Shi *iretry = 255; /* 255 clear retries. */
3675434da4dSDong Jia Shi }
3685434da4dSDong Jia Shi /* Stage 3: clear io. */
3695434da4dSDong Jia Shi if (*iretry) {
3705434da4dSDong Jia Shi *iretry -= 1;
3715434da4dSDong Jia Shi ret = cio_clear(sch);
3725434da4dSDong Jia Shi return (ret == 0) ? -EBUSY : ret;
3735434da4dSDong Jia Shi }
3745434da4dSDong Jia Shi /* Function was unsuccessful */
3755434da4dSDong Jia Shi return -EIO;
3765434da4dSDong Jia Shi }
377a22217e2SDong Jia Shi EXPORT_SYMBOL_GPL(cio_cancel_halt_clear);
3781da177e4SLinus Torvalds
cio_apply_config(struct subchannel * sch,struct schib * schib)37913952ec1SSebastian Ott static void cio_apply_config(struct subchannel *sch, struct schib *schib)
38013952ec1SSebastian Ott {
38113952ec1SSebastian Ott schib->pmcw.intparm = sch->config.intparm;
38213952ec1SSebastian Ott schib->pmcw.mbi = sch->config.mbi;
38313952ec1SSebastian Ott schib->pmcw.isc = sch->config.isc;
38413952ec1SSebastian Ott schib->pmcw.ena = sch->config.ena;
38513952ec1SSebastian Ott schib->pmcw.mme = sch->config.mme;
38613952ec1SSebastian Ott schib->pmcw.mp = sch->config.mp;
38713952ec1SSebastian Ott schib->pmcw.csense = sch->config.csense;
38813952ec1SSebastian Ott schib->pmcw.mbfc = sch->config.mbfc;
38913952ec1SSebastian Ott if (sch->config.mbfc)
39013952ec1SSebastian Ott schib->mba = sch->config.mba;
39113952ec1SSebastian Ott }
39213952ec1SSebastian Ott
cio_check_config(struct subchannel * sch,struct schib * schib)39313952ec1SSebastian Ott static int cio_check_config(struct subchannel *sch, struct schib *schib)
39413952ec1SSebastian Ott {
39513952ec1SSebastian Ott return (schib->pmcw.intparm == sch->config.intparm) &&
39613952ec1SSebastian Ott (schib->pmcw.mbi == sch->config.mbi) &&
39713952ec1SSebastian Ott (schib->pmcw.isc == sch->config.isc) &&
39813952ec1SSebastian Ott (schib->pmcw.ena == sch->config.ena) &&
39913952ec1SSebastian Ott (schib->pmcw.mme == sch->config.mme) &&
40013952ec1SSebastian Ott (schib->pmcw.mp == sch->config.mp) &&
40113952ec1SSebastian Ott (schib->pmcw.csense == sch->config.csense) &&
40213952ec1SSebastian Ott (schib->pmcw.mbfc == sch->config.mbfc) &&
40313952ec1SSebastian Ott (!sch->config.mbfc || (schib->mba == sch->config.mba));
40413952ec1SSebastian Ott }
40513952ec1SSebastian Ott
40613952ec1SSebastian Ott /*
40713952ec1SSebastian Ott * cio_commit_config - apply configuration to the subchannel
40813952ec1SSebastian Ott */
cio_commit_config(struct subchannel * sch)40913952ec1SSebastian Ott int cio_commit_config(struct subchannel *sch)
41013952ec1SSebastian Ott {
41113952ec1SSebastian Ott int ccode, retry, ret = 0;
4121bc8927cSSebastian Ott struct schib schib;
4131bc8927cSSebastian Ott struct irb irb;
41413952ec1SSebastian Ott
41562e65da9SPeter Oberparleiter if (stsch(sch->schid, &schib) || !css_sch_is_valid(&schib))
41613952ec1SSebastian Ott return -ENODEV;
41713952ec1SSebastian Ott
4181da177e4SLinus Torvalds for (retry = 0; retry < 5; retry++) {
41913952ec1SSebastian Ott /* copy desired changes to local schib */
42013952ec1SSebastian Ott cio_apply_config(sch, &schib);
42162e65da9SPeter Oberparleiter ccode = msch(sch->schid, &schib);
4221da177e4SLinus Torvalds if (ccode < 0) /* -EIO if msch gets a program check. */
4231da177e4SLinus Torvalds return ccode;
4241da177e4SLinus Torvalds switch (ccode) {
42573ac36eaSColy Li case 0: /* successful */
42662e65da9SPeter Oberparleiter if (stsch(sch->schid, &schib) ||
42713952ec1SSebastian Ott !css_sch_is_valid(&schib))
42813952ec1SSebastian Ott return -ENODEV;
42913952ec1SSebastian Ott if (cio_check_config(sch, &schib)) {
43013952ec1SSebastian Ott /* commit changes from local schib */
43113952ec1SSebastian Ott memcpy(&sch->schib, &schib, sizeof(schib));
4321da177e4SLinus Torvalds return 0;
43313952ec1SSebastian Ott }
43413952ec1SSebastian Ott ret = -EAGAIN;
43513952ec1SSebastian Ott break;
4361da177e4SLinus Torvalds case 1: /* status pending */
4371bc8927cSSebastian Ott ret = -EBUSY;
4381bc8927cSSebastian Ott if (tsch(sch->schid, &irb))
4391bc8927cSSebastian Ott return ret;
4401bc8927cSSebastian Ott break;
4411da177e4SLinus Torvalds case 2: /* busy */
4421da177e4SLinus Torvalds udelay(100); /* allow for recovery */
4431da177e4SLinus Torvalds ret = -EBUSY;
4441da177e4SLinus Torvalds break;
4451da177e4SLinus Torvalds case 3: /* not operational */
4461da177e4SLinus Torvalds return -ENODEV;
4471da177e4SLinus Torvalds }
4481da177e4SLinus Torvalds }
4491da177e4SLinus Torvalds return ret;
4501da177e4SLinus Torvalds }
451a22217e2SDong Jia Shi EXPORT_SYMBOL_GPL(cio_commit_config);
4521da177e4SLinus Torvalds
45344a1c19eSCornelia Huck /**
454cdb912a4SSebastian Ott * cio_update_schib - Perform stsch and update schib if subchannel is valid.
455cdb912a4SSebastian Ott * @sch: subchannel on which to perform stsch
456cdb912a4SSebastian Ott * Return zero on success, -ENODEV otherwise.
457cdb912a4SSebastian Ott */
cio_update_schib(struct subchannel * sch)458cdb912a4SSebastian Ott int cio_update_schib(struct subchannel *sch)
459cdb912a4SSebastian Ott {
460cdb912a4SSebastian Ott struct schib schib;
461cdb912a4SSebastian Ott
462*a1dc0428SVineeth Vijayan if (stsch(sch->schid, &schib))
463cdb912a4SSebastian Ott return -ENODEV;
464cdb912a4SSebastian Ott
465cdb912a4SSebastian Ott memcpy(&sch->schib, &schib, sizeof(schib));
466*a1dc0428SVineeth Vijayan
467*a1dc0428SVineeth Vijayan if (!css_sch_is_valid(&schib))
468*a1dc0428SVineeth Vijayan return -EACCES;
469*a1dc0428SVineeth Vijayan
470cdb912a4SSebastian Ott return 0;
471cdb912a4SSebastian Ott }
472cdb912a4SSebastian Ott EXPORT_SYMBOL_GPL(cio_update_schib);
473cdb912a4SSebastian Ott
474cdb912a4SSebastian Ott /**
47544a1c19eSCornelia Huck * cio_enable_subchannel - enable a subchannel.
47644a1c19eSCornelia Huck * @sch: subchannel to be enabled
47744a1c19eSCornelia Huck * @intparm: interruption parameter to set
4781da177e4SLinus Torvalds */
cio_enable_subchannel(struct subchannel * sch,u32 intparm)479edf22096SCornelia Huck int cio_enable_subchannel(struct subchannel *sch, u32 intparm)
4801da177e4SLinus Torvalds {
4811da177e4SLinus Torvalds int ret;
4821da177e4SLinus Torvalds
4831da177e4SLinus Torvalds CIO_TRACE_EVENT(2, "ensch");
4842a0217d5SKay Sievers CIO_TRACE_EVENT(2, dev_name(&sch->dev));
4851da177e4SLinus Torvalds
486d7b5a4c9SCornelia Huck if (sch_is_pseudo_sch(sch))
487d7b5a4c9SCornelia Huck return -EINVAL;
488cdb912a4SSebastian Ott if (cio_update_schib(sch))
4891da177e4SLinus Torvalds return -ENODEV;
4901da177e4SLinus Torvalds
49113952ec1SSebastian Ott sch->config.ena = 1;
49213952ec1SSebastian Ott sch->config.isc = sch->isc;
49313952ec1SSebastian Ott sch->config.intparm = intparm;
49413952ec1SSebastian Ott
49513952ec1SSebastian Ott ret = cio_commit_config(sch);
49613952ec1SSebastian Ott if (ret == -EIO) {
4971da177e4SLinus Torvalds /*
49813952ec1SSebastian Ott * Got a program check in msch. Try without
4991da177e4SLinus Torvalds * the concurrent sense bit the next time.
5001da177e4SLinus Torvalds */
50113952ec1SSebastian Ott sch->config.csense = 0;
5021bc8927cSSebastian Ott ret = cio_commit_config(sch);
5031da177e4SLinus Torvalds }
504efd986dbSSebastian Ott CIO_HEX_EVENT(2, &ret, sizeof(ret));
5051da177e4SLinus Torvalds return ret;
5061da177e4SLinus Torvalds }
50744a1c19eSCornelia Huck EXPORT_SYMBOL_GPL(cio_enable_subchannel);
5081da177e4SLinus Torvalds
50944a1c19eSCornelia Huck /**
51044a1c19eSCornelia Huck * cio_disable_subchannel - disable a subchannel.
51144a1c19eSCornelia Huck * @sch: subchannel to disable
5121da177e4SLinus Torvalds */
cio_disable_subchannel(struct subchannel * sch)51344a1c19eSCornelia Huck int cio_disable_subchannel(struct subchannel *sch)
5141da177e4SLinus Torvalds {
5151da177e4SLinus Torvalds int ret;
5161da177e4SLinus Torvalds
5171da177e4SLinus Torvalds CIO_TRACE_EVENT(2, "dissch");
5182a0217d5SKay Sievers CIO_TRACE_EVENT(2, dev_name(&sch->dev));
5191da177e4SLinus Torvalds
520d7b5a4c9SCornelia Huck if (sch_is_pseudo_sch(sch))
521d7b5a4c9SCornelia Huck return 0;
522cdb912a4SSebastian Ott if (cio_update_schib(sch))
5231da177e4SLinus Torvalds return -ENODEV;
5241da177e4SLinus Torvalds
52513952ec1SSebastian Ott sch->config.ena = 0;
526ed04b892SCornelia Huck ret = cio_commit_config(sch);
5271bc8927cSSebastian Ott
528efd986dbSSebastian Ott CIO_HEX_EVENT(2, &ret, sizeof(ret));
5291da177e4SLinus Torvalds return ret;
5301da177e4SLinus Torvalds }
53144a1c19eSCornelia Huck EXPORT_SYMBOL_GPL(cio_disable_subchannel);
5321da177e4SLinus Torvalds
5331da177e4SLinus Torvalds /*
5341f44a225SMartin Schwidefsky * do_cio_interrupt() handles all normal I/O device IRQ's
5351da177e4SLinus Torvalds */
do_cio_interrupt(int irq,void * dummy)5361f44a225SMartin Schwidefsky static irqreturn_t do_cio_interrupt(int irq, void *dummy)
5371da177e4SLinus Torvalds {
5381f44a225SMartin Schwidefsky struct tpi_info *tpi_info;
5391da177e4SLinus Torvalds struct subchannel *sch;
5401da177e4SLinus Torvalds struct irb *irb;
5411da177e4SLinus Torvalds
542fe0f4976SMartin Schwidefsky set_cpu_flag(CIF_NOHZ_DELAY);
54334bbeed0SSven Schnelle tpi_info = &get_irq_regs()->tpi_info;
54442248979SPeter Oberparleiter trace_s390_cio_interrupt(tpi_info);
5450bf7fcf1SChristoph Lameter irb = this_cpu_ptr(&cio_irb);
5465c2e5a0cSAlexander Gordeev if (!tpi_info->intparm) {
547a806170eSHeiko Carstens /* Clear pending interrupt condition. */
548420f42ecSHeiko Carstens inc_irq_stat(IRQIO_CIO);
549a806170eSHeiko Carstens tsch(tpi_info->schid, irb);
5501f44a225SMartin Schwidefsky return IRQ_HANDLED;
551a806170eSHeiko Carstens }
5525c2e5a0cSAlexander Gordeev sch = phys_to_virt(tpi_info->intparm);
5532ec22984SCornelia Huck spin_lock(sch->lock);
5541da177e4SLinus Torvalds /* Store interrupt response block to lowcore. */
555a806170eSHeiko Carstens if (tsch(tpi_info->schid, irb) == 0) {
5561da177e4SLinus Torvalds /* Keep subchannel information word up to date. */
55748f6b00cSMartin Schwidefsky memcpy (&sch->schib.scsw, &irb->scsw, sizeof (irb->scsw));
5581da177e4SLinus Torvalds /* Call interrupt handler if there is one. */
5591da177e4SLinus Torvalds if (sch->driver && sch->driver->irq)
560602b20f2SCornelia Huck sch->driver->irq(sch);
561de400d6bSPeter Oberparleiter else
562420f42ecSHeiko Carstens inc_irq_stat(IRQIO_CIO);
563de400d6bSPeter Oberparleiter } else
564420f42ecSHeiko Carstens inc_irq_stat(IRQIO_CIO);
5652ec22984SCornelia Huck spin_unlock(sch->lock);
5661f44a225SMartin Schwidefsky
5671f44a225SMartin Schwidefsky return IRQ_HANDLED;
5681f44a225SMartin Schwidefsky }
5691f44a225SMartin Schwidefsky
init_cio_interrupts(void)5701f44a225SMartin Schwidefsky void __init init_cio_interrupts(void)
5711f44a225SMartin Schwidefsky {
5721f44a225SMartin Schwidefsky irq_set_chip_and_handler(IO_INTERRUPT,
5731f44a225SMartin Schwidefsky &dummy_irq_chip, handle_percpu_irq);
5748719b6d2Safzal mohammed if (request_irq(IO_INTERRUPT, do_cio_interrupt, 0, "I/O", NULL))
5758719b6d2Safzal mohammed panic("Failed to register I/O interrupt\n");
5761da177e4SLinus Torvalds }
5771da177e4SLinus Torvalds
5781da177e4SLinus Torvalds #ifdef CONFIG_CCW_CONSOLE
579863fc849SSebastian Ott static struct subchannel *console_sch;
580dbe33fc9SSebastian Ott static struct lock_class_key console_sch_key;
5811da177e4SLinus Torvalds
582191fd44cSHeiko Carstens /*
583b603d258SMartin Schwidefsky * Use cio_tsch to update the subchannel status and call the interrupt handler
584188561a4SSebastian Ott * if status had been pending. Called with the subchannel's lock held.
585191fd44cSHeiko Carstens */
cio_tsch(struct subchannel * sch)586188561a4SSebastian Ott void cio_tsch(struct subchannel *sch)
587191fd44cSHeiko Carstens {
588191fd44cSHeiko Carstens struct irb *irb;
589191fd44cSHeiko Carstens int irq_context;
590191fd44cSHeiko Carstens
5910bf7fcf1SChristoph Lameter irb = this_cpu_ptr(&cio_irb);
592191fd44cSHeiko Carstens /* Store interrupt response block to lowcore. */
593b603d258SMartin Schwidefsky if (tsch(sch->schid, irb) != 0)
594191fd44cSHeiko Carstens /* Not status pending or not operational. */
595b603d258SMartin Schwidefsky return;
596b603d258SMartin Schwidefsky memcpy(&sch->schib.scsw, &irb->scsw, sizeof(union scsw));
597b603d258SMartin Schwidefsky /* Call interrupt handler with updated status. */
598191fd44cSHeiko Carstens irq_context = in_interrupt();
599b603d258SMartin Schwidefsky if (!irq_context) {
600191fd44cSHeiko Carstens local_bh_disable();
601191fd44cSHeiko Carstens irq_enter();
602b603d258SMartin Schwidefsky }
603bc5dfcffSThomas Gleixner kstat_incr_irq_this_cpu(IO_INTERRUPT);
604191fd44cSHeiko Carstens if (sch->driver && sch->driver->irq)
605191fd44cSHeiko Carstens sch->driver->irq(sch);
606de400d6bSPeter Oberparleiter else
607420f42ecSHeiko Carstens inc_irq_stat(IRQIO_CIO);
608b603d258SMartin Schwidefsky if (!irq_context) {
609191fd44cSHeiko Carstens irq_exit();
610191fd44cSHeiko Carstens _local_bh_enable();
611b603d258SMartin Schwidefsky }
612191fd44cSHeiko Carstens }
613191fd44cSHeiko Carstens
cio_test_for_console(struct subchannel_id schid,void * data)614863fc849SSebastian Ott static int cio_test_for_console(struct subchannel_id schid, void *data)
615cd6b4f27SCornelia Huck {
616863fc849SSebastian Ott struct schib schib;
617cd6b4f27SCornelia Huck
61862e65da9SPeter Oberparleiter if (stsch(schid, &schib) != 0)
619f97a56fbSCornelia Huck return -ENXIO;
620863fc849SSebastian Ott if ((schib.pmcw.st == SUBCHANNEL_TYPE_IO) && schib.pmcw.dnv &&
621863fc849SSebastian Ott (schib.pmcw.dev == console_devno)) {
622f97a56fbSCornelia Huck console_irq = schid.sch_no;
623f97a56fbSCornelia Huck return 1; /* found */
624f97a56fbSCornelia Huck }
625f97a56fbSCornelia Huck return 0;
626f97a56fbSCornelia Huck }
627f97a56fbSCornelia Huck
cio_get_console_sch_no(void)628863fc849SSebastian Ott static int cio_get_console_sch_no(void)
6291da177e4SLinus Torvalds {
630a8237fc4SCornelia Huck struct subchannel_id schid;
631863fc849SSebastian Ott struct schib schib;
6321da177e4SLinus Torvalds
633a8237fc4SCornelia Huck init_subchannel_id(&schid);
6341da177e4SLinus Torvalds if (console_irq != -1) {
6351da177e4SLinus Torvalds /* VM provided us with the irq number of the console. */
636a8237fc4SCornelia Huck schid.sch_no = console_irq;
63762e65da9SPeter Oberparleiter if (stsch(schid, &schib) != 0 ||
638863fc849SSebastian Ott (schib.pmcw.st != SUBCHANNEL_TYPE_IO) || !schib.pmcw.dnv)
6391da177e4SLinus Torvalds return -1;
640863fc849SSebastian Ott console_devno = schib.pmcw.dev;
6411da177e4SLinus Torvalds } else if (console_devno != -1) {
6421da177e4SLinus Torvalds /* At least the console device number is known. */
643f97a56fbSCornelia Huck for_each_subchannel(cio_test_for_console, NULL);
6441da177e4SLinus Torvalds }
6451da177e4SLinus Torvalds return console_irq;
6461da177e4SLinus Torvalds }
6471da177e4SLinus Torvalds
cio_probe_console(void)648863fc849SSebastian Ott struct subchannel *cio_probe_console(void)
6491da177e4SLinus Torvalds {
650a8237fc4SCornelia Huck struct subchannel_id schid;
651863fc849SSebastian Ott struct subchannel *sch;
652d4f5d79eSSebastian Ott struct schib schib;
653863fc849SSebastian Ott int sch_no, ret;
6541da177e4SLinus Torvalds
655f97a56fbSCornelia Huck sch_no = cio_get_console_sch_no();
656f97a56fbSCornelia Huck if (sch_no == -1) {
657baebc70aSJoe Perches pr_warn("No CCW console was found\n");
6581da177e4SLinus Torvalds return ERR_PTR(-ENODEV);
6591da177e4SLinus Torvalds }
660a8237fc4SCornelia Huck init_subchannel_id(&schid);
661f97a56fbSCornelia Huck schid.sch_no = sch_no;
662d4f5d79eSSebastian Ott ret = stsch(schid, &schib);
663d4f5d79eSSebastian Ott if (ret)
664d4f5d79eSSebastian Ott return ERR_PTR(-ENODEV);
665d4f5d79eSSebastian Ott
666d4f5d79eSSebastian Ott sch = css_alloc_subchannel(schid, &schib);
667863fc849SSebastian Ott if (IS_ERR(sch))
668863fc849SSebastian Ott return sch;
6691da177e4SLinus Torvalds
670dbe33fc9SSebastian Ott lockdep_set_class(sch->lock, &console_sch_key);
6716ef556ccSCornelia Huck isc_register(CONSOLE_ISC);
672863fc849SSebastian Ott sch->config.isc = CONSOLE_ISC;
6735c2e5a0cSAlexander Gordeev sch->config.intparm = (u32)virt_to_phys(sch);
674863fc849SSebastian Ott ret = cio_commit_config(sch);
6751da177e4SLinus Torvalds if (ret) {
6766ef556ccSCornelia Huck isc_unregister(CONSOLE_ISC);
677863fc849SSebastian Ott put_device(&sch->dev);
6781da177e4SLinus Torvalds return ERR_PTR(ret);
6791da177e4SLinus Torvalds }
680863fc849SSebastian Ott console_sch = sch;
681863fc849SSebastian Ott return sch;
6821da177e4SLinus Torvalds }
6831da177e4SLinus Torvalds
cio_is_console(struct subchannel_id schid)684863fc849SSebastian Ott int cio_is_console(struct subchannel_id schid)
6851da177e4SLinus Torvalds {
686863fc849SSebastian Ott if (!console_sch)
6871da177e4SLinus Torvalds return 0;
688863fc849SSebastian Ott return schid_equal(&schid, &console_sch->schid);
6891da177e4SLinus Torvalds }
6901da177e4SLinus Torvalds
cio_register_early_subchannels(void)69114556b33SSebastian Ott void cio_register_early_subchannels(void)
6921da177e4SLinus Torvalds {
69314556b33SSebastian Ott int ret;
69414556b33SSebastian Ott
69514556b33SSebastian Ott if (!console_sch)
69614556b33SSebastian Ott return;
69714556b33SSebastian Ott
69814556b33SSebastian Ott ret = css_register_subchannel(console_sch);
69914556b33SSebastian Ott if (ret)
70014556b33SSebastian Ott put_device(&console_sch->dev);
7011da177e4SLinus Torvalds }
702863fc849SSebastian Ott #endif /* CONFIG_CCW_CONSOLE */
7031da177e4SLinus Torvalds
70483262d63SPeter Oberparleiter /**
70583262d63SPeter Oberparleiter * cio_tm_start_key - perform start function
70683262d63SPeter Oberparleiter * @sch: subchannel on which to perform the start function
70783262d63SPeter Oberparleiter * @tcw: transport-command word to be started
70883262d63SPeter Oberparleiter * @lpm: mask of paths to use
70983262d63SPeter Oberparleiter * @key: storage key to use for storage access
71083262d63SPeter Oberparleiter *
71183262d63SPeter Oberparleiter * Start the tcw on the given subchannel. Return zero on success, non-zero
71283262d63SPeter Oberparleiter * otherwise.
71383262d63SPeter Oberparleiter */
cio_tm_start_key(struct subchannel * sch,struct tcw * tcw,u8 lpm,u8 key)71483262d63SPeter Oberparleiter int cio_tm_start_key(struct subchannel *sch, struct tcw *tcw, u8 lpm, u8 key)
71583262d63SPeter Oberparleiter {
71683262d63SPeter Oberparleiter int cc;
71783262d63SPeter Oberparleiter union orb *orb = &to_io_private(sch)->orb;
71883262d63SPeter Oberparleiter
71983262d63SPeter Oberparleiter memset(orb, 0, sizeof(union orb));
7205c2e5a0cSAlexander Gordeev orb->tm.intparm = (u32)virt_to_phys(sch);
72183262d63SPeter Oberparleiter orb->tm.key = key >> 4;
72283262d63SPeter Oberparleiter orb->tm.b = 1;
72383262d63SPeter Oberparleiter orb->tm.lpm = lpm ? lpm : sch->lpm;
7245c2e5a0cSAlexander Gordeev orb->tm.tcw = (u32)virt_to_phys(tcw);
72583262d63SPeter Oberparleiter cc = ssch(sch->schid, orb);
72683262d63SPeter Oberparleiter switch (cc) {
72783262d63SPeter Oberparleiter case 0:
72883262d63SPeter Oberparleiter return 0;
72983262d63SPeter Oberparleiter case 1:
73083262d63SPeter Oberparleiter case 2:
73183262d63SPeter Oberparleiter return -EBUSY;
73283262d63SPeter Oberparleiter default:
73383262d63SPeter Oberparleiter return cio_start_handle_notoper(sch, lpm);
73483262d63SPeter Oberparleiter }
73583262d63SPeter Oberparleiter }
736a22217e2SDong Jia Shi EXPORT_SYMBOL_GPL(cio_tm_start_key);
73783262d63SPeter Oberparleiter
73883262d63SPeter Oberparleiter /**
73983262d63SPeter Oberparleiter * cio_tm_intrg - perform interrogate function
740364e3f90SSebastian Ott * @sch: subchannel on which to perform the interrogate function
74183262d63SPeter Oberparleiter *
74283262d63SPeter Oberparleiter * If the specified subchannel is running in transport-mode, perform the
74383262d63SPeter Oberparleiter * interrogate function. Return zero on success, non-zero otherwie.
74483262d63SPeter Oberparleiter */
cio_tm_intrg(struct subchannel * sch)74583262d63SPeter Oberparleiter int cio_tm_intrg(struct subchannel *sch)
74683262d63SPeter Oberparleiter {
74783262d63SPeter Oberparleiter int cc;
74883262d63SPeter Oberparleiter
74983262d63SPeter Oberparleiter if (!to_io_private(sch)->orb.tm.b)
75083262d63SPeter Oberparleiter return -EINVAL;
75183262d63SPeter Oberparleiter cc = xsch(sch->schid);
75283262d63SPeter Oberparleiter switch (cc) {
75383262d63SPeter Oberparleiter case 0:
75483262d63SPeter Oberparleiter case 2:
75583262d63SPeter Oberparleiter return 0;
75683262d63SPeter Oberparleiter case 1:
75783262d63SPeter Oberparleiter return -EBUSY;
75883262d63SPeter Oberparleiter default:
75983262d63SPeter Oberparleiter return -ENODEV;
76083262d63SPeter Oberparleiter }
76183262d63SPeter Oberparleiter }
762a22217e2SDong Jia Shi EXPORT_SYMBOL_GPL(cio_tm_intrg);
763