]> err.no Git - linux-2.6/blobdiff - drivers/s390/cio/cio.c
Merge branch 'master' of master.kernel.org:/pub/scm/linux/kernel/git/torvalds/linux-2.6
[linux-2.6] / drivers / s390 / cio / cio.c
index 46905345159e6705036d7d20030de558a534b60d..60590a12d5299ce43e2626f045fdd488589d40cc 100644 (file)
 #include <asm/reset.h>
 #include <asm/ipl.h>
 #include <asm/chpid.h>
-#include "airq.h"
+#include <asm/airq.h>
 #include "cio.h"
 #include "css.h"
 #include "chsc.h"
 #include "ioasm.h"
+#include "io_sch.h"
 #include "blacklist.h"
 #include "cio_debug.h"
 #include "chp.h"
@@ -56,39 +57,37 @@ __setup ("cio_msg=", cio_setup);
 
 /*
  * Function: cio_debug_init
- * Initializes three debug logs (under /proc/s390dbf) for common I/O:
- * - cio_msg logs the messages which are printk'ed when CONFIG_DEBUG_IO is on
+ * Initializes three debug logs for common I/O:
+ * - cio_msg logs generic cio messages
  * - cio_trace logs the calling of different functions
- * - cio_crw logs the messages which are printk'ed when CONFIG_DEBUG_CRW is on
- * debug levels depend on CONFIG_DEBUG_IO resp. CONFIG_DEBUG_CRW
+ * - cio_crw logs machine check related cio messages
  */
-static int __init
-cio_debug_init (void)
+static int __init cio_debug_init(void)
 {
-       cio_debug_msg_id = debug_register ("cio_msg", 16, 4, 16*sizeof (long));
+       cio_debug_msg_id = debug_register("cio_msg", 16, 1, 16 * sizeof(long));
        if (!cio_debug_msg_id)
                goto out_unregister;
-       debug_register_view (cio_debug_msg_id, &debug_sprintf_view);
-       debug_set_level (cio_debug_msg_id, 2);
-       cio_debug_trace_id = debug_register ("cio_trace", 16, 4, 16);
+       debug_register_view(cio_debug_msg_id, &debug_sprintf_view);
+       debug_set_level(cio_debug_msg_id, 2);
+       cio_debug_trace_id = debug_register("cio_trace", 16, 1, 16);
        if (!cio_debug_trace_id)
                goto out_unregister;
-       debug_register_view (cio_debug_trace_id, &debug_hex_ascii_view);
-       debug_set_level (cio_debug_trace_id, 2);
-       cio_debug_crw_id = debug_register ("cio_crw", 4, 4, 16*sizeof (long));
+       debug_register_view(cio_debug_trace_id, &debug_hex_ascii_view);
+       debug_set_level(cio_debug_trace_id, 2);
+       cio_debug_crw_id = debug_register("cio_crw", 16, 1, 16 * sizeof(long));
        if (!cio_debug_crw_id)
                goto out_unregister;
-       debug_register_view (cio_debug_crw_id, &debug_sprintf_view);
-       debug_set_level (cio_debug_crw_id, 2);
+       debug_register_view(cio_debug_crw_id, &debug_sprintf_view);
+       debug_set_level(cio_debug_crw_id, 4);
        return 0;
 
 out_unregister:
        if (cio_debug_msg_id)
-               debug_unregister (cio_debug_msg_id);
+               debug_unregister(cio_debug_msg_id);
        if (cio_debug_trace_id)
-               debug_unregister (cio_debug_trace_id);
+               debug_unregister(cio_debug_trace_id);
        if (cio_debug_crw_id)
-               debug_unregister (cio_debug_crw_id);
+               debug_unregister(cio_debug_crw_id);
        printk(KERN_WARNING"cio: could not initialize debugging\n");
        return -1;
 }
@@ -147,7 +146,7 @@ cio_tpi(void)
        spin_lock(sch->lock);
        memcpy (&sch->schib.scsw, &irb->scsw, sizeof (struct scsw));
        if (sch->driver && sch->driver->irq)
-               sch->driver->irq(&sch->dev);
+               sch->driver->irq(sch);
        spin_unlock(sch->lock);
        irq_exit ();
        _local_bh_enable();
@@ -184,33 +183,35 @@ cio_start_key (struct subchannel *sch,    /* subchannel structure */
 {
        char dbf_txt[15];
        int ccode;
+       struct orb *orb;
 
-       CIO_TRACE_EVENT (4, "stIO");
-       CIO_TRACE_EVENT (4, sch->dev.bus_id);
+       CIO_TRACE_EVENT(4, "stIO");
+       CIO_TRACE_EVENT(4, sch->dev.bus_id);
 
+       orb = &to_io_private(sch)->orb;
        /* sch is always under 2G. */
-       sch->orb.intparm = (__u32)(unsigned long)sch;
-       sch->orb.fmt = 1;
+       orb->intparm = (u32)(addr_t)sch;
+       orb->fmt = 1;
 
-       sch->orb.pfch = sch->options.prefetch == 0;
-       sch->orb.spnd = sch->options.suspend;
-       sch->orb.ssic = sch->options.suspend && sch->options.inter;
-       sch->orb.lpm = (lpm != 0) ? lpm : sch->lpm;
+       orb->pfch = sch->options.prefetch == 0;
+       orb->spnd = sch->options.suspend;
+       orb->ssic = sch->options.suspend && sch->options.inter;
+       orb->lpm = (lpm != 0) ? lpm : sch->lpm;
 #ifdef CONFIG_64BIT
        /*
         * for 64 bit we always support 64 bit IDAWs with 4k page size only
         */
-       sch->orb.c64 = 1;
-       sch->orb.i2k = 0;
+       orb->c64 = 1;
+       orb->i2k = 0;
 #endif
-       sch->orb.key = key >> 4;
+       orb->key = key >> 4;
        /* issue "Start Subchannel" */
-       sch->orb.cpa = (__u32) __pa (cpa);
-       ccode = ssch (sch->schid, &sch->orb);
+       orb->cpa = (__u32) __pa(cpa);
+       ccode = ssch(sch->schid, orb);
 
        /* process condition code */
-       sprintf (dbf_txt, "ccode:%d", ccode);
-       CIO_TRACE_EVENT (4, dbf_txt);
+       sprintf(dbf_txt, "ccode:%d", ccode);
+       CIO_TRACE_EVENT(4, dbf_txt);
 
        switch (ccode) {
        case 0:
@@ -405,8 +406,8 @@ cio_modify (struct subchannel *sch)
 /*
  * Enable subchannel.
  */
-int
-cio_enable_subchannel (struct subchannel *sch, unsigned int isc)
+int cio_enable_subchannel(struct subchannel *sch, unsigned int isc,
+                         u32 intparm)
 {
        char dbf_txt[15];
        int ccode;
@@ -425,7 +426,7 @@ cio_enable_subchannel (struct subchannel *sch, unsigned int isc)
        for (retry = 5, ret = 0; retry > 0; retry--) {
                sch->schib.pmcw.ena = 1;
                sch->schib.pmcw.isc = isc;
-               sch->schib.pmcw.intparm = (__u32)(unsigned long)sch;
+               sch->schib.pmcw.intparm = intparm;
                ret = cio_modify(sch);
                if (ret == -ENODEV)
                        break;
@@ -567,7 +568,7 @@ cio_validate_subchannel (struct subchannel *sch, struct subchannel_id schid)
         */
        if (sch->st != 0) {
                CIO_DEBUG(KERN_INFO, 0,
-                         "cio: Subchannel 0.%x.%04x reports "
+                         "Subchannel 0.%x.%04x reports "
                          "non-I/O subchannel type %04X\n",
                          sch->schid.ssid, sch->schid.sch_no, sch->st);
                /* We stop here for non-io subchannels. */
@@ -576,11 +577,11 @@ cio_validate_subchannel (struct subchannel *sch, struct subchannel_id schid)
        }
 
        /* Initialization for io subchannels. */
-       if (!sch->schib.pmcw.dnv) {
-               /* io subchannel but device number is invalid. */
+       if (!css_sch_is_valid(&sch->schib)) {
                err = -ENODEV;
                goto out;
        }
+
        /* Devno is valid. */
        if (is_blacklisted (sch->schid.ssid, sch->schib.pmcw.dev)) {
                /*
@@ -600,7 +601,7 @@ cio_validate_subchannel (struct subchannel *sch, struct subchannel_id schid)
        sch->lpm = sch->schib.pmcw.pam & sch->opm;
 
        CIO_DEBUG(KERN_INFO, 0,
-                 "cio: Detected device %04x on subchannel 0.%x.%04X"
+                 "Detected device %04x on subchannel 0.%x.%04X"
                  " - PIM = %02X, PAM = %02X, POM = %02X\n",
                  sch->schib.pmcw.dev, sch->schid.ssid,
                  sch->schid.sch_no, sch->schib.pmcw.pim,
@@ -680,7 +681,7 @@ do_IRQ (struct pt_regs *regs)
                                sizeof (irb->scsw));
                        /* Call interrupt handler if there is one. */
                        if (sch->driver && sch->driver->irq)
-                               sch->driver->irq(&sch->dev);
+                               sch->driver->irq(sch);
                }
                if (sch)
                        spin_unlock(sch->lock);
@@ -698,8 +699,14 @@ do_IRQ (struct pt_regs *regs)
 
 #ifdef CONFIG_CCW_CONSOLE
 static struct subchannel console_subchannel;
+static struct io_subchannel_private console_priv;
 static int console_subchannel_in_use;
 
+void *cio_get_console_priv(void)
+{
+       return &console_priv;
+}
+
 /*
  * busy wait for the next interrupt on the console
  */
@@ -738,9 +745,9 @@ cio_test_for_console(struct subchannel_id schid, void *data)
 {
        if (stsch_err(schid, &console_subchannel.schib) != 0)
                return -ENXIO;
-       if (console_subchannel.schib.pmcw.dnv &&
-           console_subchannel.schib.pmcw.dev ==
-           console_devno) {
+       if ((console_subchannel.schib.pmcw.st == SUBCHANNEL_TYPE_IO) &&
+           console_subchannel.schib.pmcw.dnv &&
+           (console_subchannel.schib.pmcw.dev == console_devno)) {
                console_irq = schid.sch_no;
                return 1; /* found */
        }
@@ -758,6 +765,7 @@ cio_get_console_sch_no(void)
                /* VM provided us with the irq number of the console. */
                schid.sch_no = console_irq;
                if (stsch(schid, &console_subchannel.schib) != 0 ||
+                   (console_subchannel.schib.pmcw.st != SUBCHANNEL_TYPE_IO) ||
                    !console_subchannel.schib.pmcw.dnv)
                        return -1;
                console_devno = console_subchannel.schib.pmcw.dev;
@@ -804,7 +812,7 @@ cio_probe_console(void)
        ctl_set_bit(6, 24);
        console_subchannel.schib.pmcw.isc = 7;
        console_subchannel.schib.pmcw.intparm =
-               (__u32)(unsigned long)&console_subchannel;
+               (u32)(addr_t)&console_subchannel;
        ret = cio_modify(&console_subchannel);
        if (ret) {
                console_subchannel_in_use = 0;
@@ -1022,7 +1030,7 @@ static int __reipl_subchannel_match(struct subchannel_id schid, void *data)
 
        if (stsch_reset(schid, &schib))
                return -ENXIO;
-       if (schib.pmcw.dnv &&
+       if ((schib.pmcw.st == SUBCHANNEL_TYPE_IO) && schib.pmcw.dnv &&
            (schib.pmcw.dev == match_id->devid.devno) &&
            (schid.ssid == match_id->devid.ssid)) {
                match_id->schid = schid;
@@ -1068,6 +1076,8 @@ int __init cio_get_iplinfo(struct cio_iplinfo *iplinfo)
                return -ENODEV;
        if (stsch(schid, &schib))
                return -ENODEV;
+       if (schib.pmcw.st != SUBCHANNEL_TYPE_IO)
+               return -ENODEV;
        if (!schib.pmcw.dnv)
                return -ENODEV;
        iplinfo->devno = schib.pmcw.dev;