*/
 
 /* 65536 bits to indicate if a devno is blacklisted or not */
-#define __BL_DEV_WORDS ((__MAX_SUBCHANNELS + (8*sizeof(long) - 1)) / \
+#define __BL_DEV_WORDS ((__MAX_SUBCHANNEL + (8*sizeof(long) - 1)) / \
                         (8*sizeof(long)))
 static unsigned long bl_dev[__BL_DEV_WORDS];
 typedef enum {add, free} range_action;
        if (!to)
                to = from;
 
-       if (from > to || to > __MAX_SUBCHANNELS) {
+       if (from > to || to > __MAX_SUBCHANNEL) {
                printk (KERN_WARNING "Invalid blacklist range "
                        "0x%04x to 0x%04x, skipping\n", from, to);
                return;
                if (strncmp(str,"all,",4) == 0 || strcmp(str,"all") == 0 ||
                    strncmp(str,"all\n",4) == 0 || strncmp(str,"all ",4) == 0) {
                        from = 0;
-                       to = __MAX_SUBCHANNELS;
+                       to = __MAX_SUBCHANNEL;
                        str += 3;
                } else {
                        int rc;
 static inline void
 s390_redo_validation (void)
 {
-       unsigned int irq;
+       struct subchannel_id schid;
 
        CIO_TRACE_EVENT (0, "redoval");
-       for (irq = 0; irq < __MAX_SUBCHANNELS; irq++) {
+       init_subchannel_id(&schid);
+       do {
                int ret;
                struct subchannel *sch;
 
-               sch = get_subchannel_by_schid(irq);
+               sch = get_subchannel_by_schid(schid);
                if (sch) {
                        /* Already known. */
                        put_device(&sch->dev);
                        continue;
                }
-               ret = css_probe_device(irq);
+               ret = css_probe_device(schid);
                if (ret == -ENXIO)
                        break; /* We're through. */
                if (ret == -ENOMEM)
                         * panic.
                         */
                        break;
-       }
+       } while (schid.sch_no++ < __MAX_SUBCHANNEL);
 }
 
 /*
        len = 0;
        for (devno = off; /* abuse the page variable
                           * as counter, see fs/proc/generic.c */
-            devno < __MAX_SUBCHANNELS && len + entry_size < count; devno++) {
+            devno < __MAX_SUBCHANNEL && len + entry_size < count; devno++) {
                if (!test_bit(devno, bl_dev))
                        continue;
                len += sprintf(page + len, "0.0.%04lx", devno);
                if (test_bit(devno + 1, bl_dev)) { /* print range */
-                       while (++devno < __MAX_SUBCHANNELS)
+                       while (++devno < __MAX_SUBCHANNEL)
                                if (!test_bit(devno, bl_dev))
                                        break;
                        len += sprintf(page + len, "-0.0.%04lx", --devno);
                len += sprintf(page + len, "\n");
        }
 
-       if (devno < __MAX_SUBCHANNELS)
+       if (devno < __MAX_SUBCHANNEL)
                *eof = 1;
        *start = (char *) (devno - off); /* number of checked entries */
        return len;
 
                .code   = 0x0004,
        };
 
-       ssd_area->f_sch = sch->irq;
-       ssd_area->l_sch = sch->irq;
+       ssd_area->f_sch = sch->schid.sch_no;
+       ssd_area->l_sch = sch->schid.sch_no;
 
        ccode = chsc(ssd_area);
        if (ccode > 0) {
         */
        if (ssd_area->st > 3) { /* uhm, that looks strange... */
                CIO_CRW_EVENT(0, "Strange subchannel type %d"
-                             " for sch %04x\n", ssd_area->st, sch->irq);
+                             " for sch %04x\n", ssd_area->st,
+                             sch->schid.sch_no);
                /*
                 * There may have been a new subchannel type defined in the
                 * time since this code was written; since we don't know which
        } else {
                const char *type[4] = {"I/O", "chsc", "message", "ADM"};
                CIO_CRW_EVENT(6, "ssd: sch %04x is %s subchannel\n",
-                             sch->irq, type[ssd_area->st]);
+                             sch->schid.sch_no, type[ssd_area->st]);
 
                sch->ssd_info.valid = 1;
                sch->ssd_info.type = ssd_area->st;
        mask = 0x80 >> j;
        spin_lock(&sch->lock);
 
-       stsch(sch->irq, &schib);
+       stsch(sch->schid, &schib);
        if (!schib.pmcw.dnv)
                goto out_unreg;
        memcpy(&sch->schib, &schib, sizeof(struct schib));
 out_unreg:
        spin_unlock(&sch->lock);
        sch->lpm = 0;
-       if (css_enqueue_subchannel_slow(sch->irq)) {
+       if (css_enqueue_subchannel_slow(sch->schid)) {
                css_clear_subchannel_slow_list();
                need_rescan = 1;
        }
         * new path information and eventually check for logically
         * offline chpids.
         */
-       ccode = stsch(sch->irq, &sch->schib);
+       ccode = stsch(sch->schid, &sch->schib);
        if (ccode > 0)
                return 0;
 
 s390_process_res_acc (u8 chpid, __u16 fla, u32 fla_mask)
 {
        struct subchannel *sch;
-       int irq, rc;
+       int rc;
+       struct subchannel_id schid;
        char dbf_txt[15];
 
        sprintf(dbf_txt, "accpr%x", chpid);
                return 0; /* no need to do the rest */
 
        rc = 0;
-       for (irq = 0; irq < __MAX_SUBCHANNELS; irq++) {
+       init_subchannel_id(&schid);
+       do {
                int chp_mask, old_lpm;
 
-               sch = get_subchannel_by_schid(irq);
+               sch = get_subchannel_by_schid(schid);
                if (!sch) {
                        struct schib schib;
                        int ret;
                         * that beast may be on we'll have to do a stsch
                         * on all devices, grr...
                         */
-                       if (stsch(irq, &schib)) {
+                       if (stsch(schid, &schib)) {
                                /* We're through */
                                if (need_rescan)
                                        rc = -EAGAIN;
                                continue;
                        }
                        /* Put it on the slow path. */
-                       ret = css_enqueue_subchannel_slow(irq);
+                       ret = css_enqueue_subchannel_slow(schid);
                        if (ret) {
                                css_clear_subchannel_slow_list();
                                need_rescan = 1;
                put_device(&sch->dev);
                if (fla_mask == 0xffff)
                        break;
-       }
+       } while (schid.sch_no++ < __MAX_SUBCHANNEL);
        return rc;
 }
 
 chp_add(int chpid)
 {
        struct subchannel *sch;
-       int irq, ret, rc;
+       int ret, rc;
+       struct subchannel_id schid;
        char dbf_txt[15];
 
        if (!get_chp_status(chpid))
        CIO_TRACE_EVENT(2, dbf_txt);
 
        rc = 0;
-       for (irq = 0; irq < __MAX_SUBCHANNELS; irq++) {
+       init_subchannel_id(&schid);
+       do {
                int i;
 
-               sch = get_subchannel_by_schid(irq);
+               sch = get_subchannel_by_schid(schid);
                if (!sch) {
                        struct schib schib;
 
-                       if (stsch(irq, &schib)) {
+                       if (stsch(schid, &schib)) {
                                /* We're through */
                                if (need_rescan)
                                        rc = -EAGAIN;
                                continue;
                        }
                        /* Put it on the slow path. */
-                       ret = css_enqueue_subchannel_slow(irq);
+                       ret = css_enqueue_subchannel_slow(schid);
                        if (ret) {
                                css_clear_subchannel_slow_list();
                                need_rescan = 1;
                spin_lock(&sch->lock);
                for (i=0; i<8; i++)
                        if (sch->schib.pmcw.chpid[i] == chpid) {
-                               if (stsch(sch->irq, &sch->schib) != 0) {
+                               if (stsch(sch->schid, &sch->schib) != 0) {
                                        /* Endgame. */
                                        spin_unlock(&sch->lock);
                                        return rc;
 
                spin_unlock(&sch->lock);
                put_device(&sch->dev);
-       }
+       } while (schid.sch_no++ < __MAX_SUBCHANNEL);
        return rc;
 }
 
        if (!device_is_online(sch))
                /* cio could be doing I/O. */
                return 0;
-       cc = stsch(sch->irq, &sch->schib);
+       cc = stsch(sch->schid, &sch->schib);
        if (cc)
                return 0;
        if (sch->schib.scsw.actl && sch->schib.pmcw.lpum == (0x80 >> index)) {
                         * just varied off path. Then kill it.
                         */
                        if (!__check_for_io_and_kill(sch, chp) && !sch->lpm) {
-                               if (css_enqueue_subchannel_slow(sch->irq)) {
+                               if (css_enqueue_subchannel_slow(sch->schid)) {
                                        css_clear_subchannel_slow_list();
                                        need_rescan = 1;
                                }
 s390_vary_chpid( __u8 chpid, int on)
 {
        char dbf_text[15];
-       int status, irq, ret;
+       int status, ret;
+       struct subchannel_id schid;
        struct subchannel *sch;
 
        sprintf(dbf_text, on?"varyon%x":"varyoff%x", chpid);
        if (!on)
                goto out;
        /* Scan for new devices on varied on path. */
-       for (irq = 0; irq < __MAX_SUBCHANNELS; irq++) {
+       init_subchannel_id(&schid);
+       do {
                struct schib schib;
 
                if (need_rescan)
                        break;
-               sch = get_subchannel_by_schid(irq);
+               sch = get_subchannel_by_schid(schid);
                if (sch) {
                        put_device(&sch->dev);
                        continue;
                }
-               if (stsch(irq, &schib))
+               if (stsch(schid, &schib))
                        /* We're through */
                        break;
                /* Put it on the slow path. */
-               ret = css_enqueue_subchannel_slow(irq);
+               ret = css_enqueue_subchannel_slow(schid);
                if (ret) {
                        css_clear_subchannel_slow_list();
                        need_rescan = 1;
                }
-       }
+       } while (schid.sch_no++ < __MAX_SUBCHANNEL);
 out:
        if (need_rescan || css_slow_subchannels_exist())
                queue_work(slow_path_wq, &slow_path_work);
 
                return 0;
        irb = (struct irb *) __LC_IRB;
        /* Store interrupt response block to lowcore. */
-       if (tsch (tpi_info->irq, irb) != 0)
+       if (tsch (tpi_info->schid, irb) != 0)
                /* Not status pending or not operational. */
                return 1;
        sch = (struct subchannel *)(unsigned long)tpi_info->intparm;
        else
                sch->lpm = 0;
 
-       stsch (sch->irq, &sch->schib);
+       stsch (sch->schid, &sch->schib);
 
        CIO_MSG_EVENT(0, "cio_start: 'not oper' status for "
-                     "subchannel %04x!\n", sch->irq);
+                     "subchannel %04x!\n", sch->schid.sch_no);
        sprintf(dbf_text, "no%s", sch->dev.bus_id);
        CIO_TRACE_EVENT(0, dbf_text);
        CIO_HEX_EVENT(0, &sch->schib, sizeof (struct schib));
        sch->orb.key = key >> 4;
        /* issue "Start Subchannel" */
        sch->orb.cpa = (__u32) __pa (cpa);
-       ccode = ssch (sch->irq, &sch->orb);
+       ccode = ssch (sch->schid, &sch->orb);
 
        /* process condition code */
        sprintf (dbf_txt, "ccode:%d", ccode);
        CIO_TRACE_EVENT (4, "resIO");
        CIO_TRACE_EVENT (4, sch->dev.bus_id);
 
-       ccode = rsch (sch->irq);
+       ccode = rsch (sch->schid);
 
        sprintf (dbf_txt, "ccode:%d", ccode);
        CIO_TRACE_EVENT (4, dbf_txt);
        /*
         * Issue "Halt subchannel" and process condition code
         */
-       ccode = hsch (sch->irq);
+       ccode = hsch (sch->schid);
 
        sprintf (dbf_txt, "ccode:%d", ccode);
        CIO_TRACE_EVENT (2, dbf_txt);
        /*
         * Issue "Clear subchannel" and process condition code
         */
-       ccode = csch (sch->irq);
+       ccode = csch (sch->schid);
 
        sprintf (dbf_txt, "ccode:%d", ccode);
        CIO_TRACE_EVENT (2, dbf_txt);
        CIO_TRACE_EVENT (2, "cancelIO");
        CIO_TRACE_EVENT (2, sch->dev.bus_id);
 
-       ccode = xsch (sch->irq);
+       ccode = xsch (sch->schid);
 
        sprintf (dbf_txt, "ccode:%d", ccode);
        CIO_TRACE_EVENT (2, dbf_txt);
        switch (ccode) {
        case 0:         /* success */
                /* Update information in scsw. */
-               stsch (sch->irq, &sch->schib);
+               stsch (sch->schid, &sch->schib);
                return 0;
        case 1:         /* status pending */
                return -EBUSY;
 
        ret = 0;
        for (retry = 0; retry < 5; retry++) {
-               ccode = msch_err (sch->irq, &sch->schib);
+               ccode = msch_err (sch->schid, &sch->schib);
                if (ccode < 0)  /* -EIO if msch gets a program check. */
                        return ccode;
                switch (ccode) {
        CIO_TRACE_EVENT (2, "ensch");
        CIO_TRACE_EVENT (2, sch->dev.bus_id);
 
-       ccode = stsch (sch->irq, &sch->schib);
+       ccode = stsch (sch->schid, &sch->schib);
        if (ccode)
                return -ENODEV;
 
                         */
                        sch->schib.pmcw.csense = 0;
                if (ret == 0) {
-                       stsch (sch->irq, &sch->schib);
+                       stsch (sch->schid, &sch->schib);
                        if (sch->schib.pmcw.ena)
                                break;
                }
                if (ret == -EBUSY) {
                        struct irb irb;
-                       if (tsch(sch->irq, &irb) != 0)
+                       if (tsch(sch->schid, &irb) != 0)
                                break;
                }
        }
        CIO_TRACE_EVENT (2, "dissch");
        CIO_TRACE_EVENT (2, sch->dev.bus_id);
 
-       ccode = stsch (sch->irq, &sch->schib);
+       ccode = stsch (sch->schid, &sch->schib);
        if (ccode == 3)         /* Not operational. */
                return -ENODEV;
 
                         */
                        break;
                if (ret == 0) {
-                       stsch (sch->irq, &sch->schib);
+                       stsch (sch->schid, &sch->schib);
                        if (!sch->schib.pmcw.ena)
                                break;
                }
  *   -ENODEV for subchannels with invalid device number or blacklisted devices
  */
 int
-cio_validate_subchannel (struct subchannel *sch, unsigned int irq)
+cio_validate_subchannel (struct subchannel *sch, struct subchannel_id schid)
 {
        char dbf_txt[15];
        int ccode;
 
-       sprintf (dbf_txt, "valsch%x", irq);
+       sprintf (dbf_txt, "valsch%x", schid.sch_no);
        CIO_TRACE_EVENT (4, dbf_txt);
 
        /* Nuke all fields. */
        spin_lock_init(&sch->lock);
 
        /* Set a name for the subchannel */
-       snprintf (sch->dev.bus_id, BUS_ID_SIZE, "0.0.%04x", irq);
+       snprintf (sch->dev.bus_id, BUS_ID_SIZE, "0.0.%04x", schid.sch_no);
 
        /*
         * The first subchannel that is not-operational (ccode==3)
         *  indicates that there aren't any more devices available.
         */
-       sch->irq = irq;
-       ccode = stsch (irq, &sch->schib);
+       ccode = stsch (schid, &sch->schib);
        if (ccode)
                return -ENXIO;
 
+       sch->schid = schid;
        /* Copy subchannel type from path management control word. */
        sch->st = sch->schib.pmcw.st;
 
                CIO_DEBUG(KERN_INFO, 0,
                          "Subchannel %04X reports "
                          "non-I/O subchannel type %04X\n",
-                         sch->irq, sch->st);
+                         sch->schid.sch_no, sch->st);
                /* We stop here for non-io subchannels. */
                return sch->st;
        }
        CIO_DEBUG(KERN_INFO, 0,
                  "Detected device %04X on subchannel %04X"
                  " - PIM = %02X, PAM = %02X, POM = %02X\n",
-                 sch->schib.pmcw.dev, sch->irq, sch->schib.pmcw.pim,
+                 sch->schib.pmcw.dev, sch->schid.sch_no, sch->schib.pmcw.pim,
                  sch->schib.pmcw.pam, sch->schib.pmcw.pom);
 
        /*
                if (sch)
                        spin_lock(&sch->lock);
                /* Store interrupt response block to lowcore. */
-               if (tsch (tpi_info->irq, irb) == 0 && sch) {
+               if (tsch (tpi_info->schid, irb) == 0 && sch) {
                        /* Keep subchannel information word up to date. */
                        memcpy (&sch->schib.scsw, &irb->scsw,
                                sizeof (irb->scsw));
 static int
 cio_console_irq(void)
 {
-       int irq;
+       struct subchannel_id schid;
        
+       init_subchannel_id(&schid);
        if (console_irq != -1) {
                /* VM provided us with the irq number of the console. */
-               if (stsch(console_irq, &console_subchannel.schib) != 0 ||
+               schid.sch_no = console_irq;
+               if (stsch(schid, &console_subchannel.schib) != 0 ||
                    !console_subchannel.schib.pmcw.dnv)
                        return -1;
                console_devno = console_subchannel.schib.pmcw.dev;
        } else if (console_devno != -1) {
                /* At least the console device number is known. */
-               for (irq = 0; irq < __MAX_SUBCHANNELS; irq++) {
-                       if (stsch(irq, &console_subchannel.schib) != 0)
+               do {
+                       if (stsch(schid, &console_subchannel.schib) != 0)
                                break;
                        if (console_subchannel.schib.pmcw.dnv &&
                            console_subchannel.schib.pmcw.dev ==
                            console_devno) {
-                               console_irq = irq;
+                               console_irq = schid.sch_no;
                                break;
                        }
-               }
+               } while (schid.sch_no++ < __MAX_SUBCHANNEL);
                if (console_irq == -1)
                        return -1;
        } else {
 cio_probe_console(void)
 {
        int irq, ret;
+       struct subchannel_id schid;
 
        if (xchg(&console_subchannel_in_use, 1) != 0)
                return ERR_PTR(-EBUSY);
                return ERR_PTR(-ENODEV);
        }
        memset(&console_subchannel, 0, sizeof(struct subchannel));
-       ret = cio_validate_subchannel(&console_subchannel, irq);
+       init_subchannel_id(&schid);
+       schid.sch_no = irq;
+       ret = cio_validate_subchannel(&console_subchannel, schid);
        if (ret) {
                console_subchannel_in_use = 0;
                return ERR_PTR(-ENODEV);
 
 /* Bah... hack to catch console special sausages. */
 int
-cio_is_console(int irq)
+cio_is_console(struct subchannel_id schid)
 {
        if (!console_subchannel_in_use)
                return 0;
-       return (irq == console_subchannel.irq);
+       return schid_equal(&schid, &console_subchannel.schid);
 }
 
 struct subchannel *
 
 #endif
 static inline int
-__disable_subchannel_easy(unsigned int schid, struct schib *schib)
+__disable_subchannel_easy(struct subchannel_id schid, struct schib *schib)
 {
        int retry, cc;
 
 }
 
 static inline int
-__clear_subchannel_easy(unsigned int schid)
+__clear_subchannel_easy(struct subchannel_id schid)
 {
        int retry;
 
                struct tpi_info ti;
 
                if (tpi(&ti)) {
-                       tsch(ti.irq, (struct irb *)__LC_IRB);
-                       if (ti.irq == schid)
+                       tsch(ti.schid, (struct irb *)__LC_IRB);
+                       if (schid_equal(&ti.schid, &schid))
                                return 0;
                }
                udelay(100);
 void
 clear_all_subchannels(void)
 {
-       unsigned int schid;
+       struct subchannel_id schid;
 
        local_irq_disable();
-       for (schid=0;schid<=highest_subchannel;schid++) {
+       init_subchannel_id(&schid);
+       do {
                struct schib schib;
                if (stsch(schid, &schib))
                        break; /* break out of the loop */
                        stsch(schid, &schib);
                        __disable_subchannel_easy(schid, &schib);
                }
-       }
+       } while (schid.sch_no++ < __MAX_SUBCHANNEL);
 }
 
 /* Make sure all subchannels are quiet before we re-ipl an lpar. */
 
 #ifndef S390_CIO_H
 #define S390_CIO_H
 
+#include "schid.h"
+
 /*
  * where we put the ssd info
  */
 
 /* subchannel data structure used by I/O subroutines */
 struct subchannel {
-       unsigned int irq;       /* aka. subchannel number */
+       struct subchannel_id schid;
        spinlock_t lock;        /* subchannel lock */
 
        enum {
 
 #define to_subchannel(n) container_of(n, struct subchannel, dev)
 
-extern int cio_validate_subchannel (struct subchannel *, unsigned int);
+extern int cio_validate_subchannel (struct subchannel *, struct subchannel_id);
 extern int cio_enable_subchannel (struct subchannel *, unsigned int);
 extern int cio_disable_subchannel (struct subchannel *);
 extern int cio_cancel (struct subchannel *);
 extern int cio_set_options (struct subchannel *, int);
 extern int cio_get_options (struct subchannel *);
 extern int cio_modify (struct subchannel *);
+
 /* Use with care. */
 #ifdef CONFIG_CCW_CONSOLE
 extern struct subchannel *cio_probe_console(void);
 extern void cio_release_console(void);
-extern int cio_is_console(int irq);
+extern int cio_is_console(struct subchannel_id);
 extern struct subchannel *cio_get_console_subchannel(void);
 #else
-#define cio_is_console(irq) 0
+#define cio_is_console(schid) 0
 #define cio_get_console_subchannel() NULL
 #endif
 
 
 /*
- * linux/drivers/s390/cio/cmf.c ($Revision: 1.16 $)
+ * linux/drivers/s390/cio/cmf.c ($Revision: 1.19 $)
  *
  * Linux on zSeries Channel Measurement Facility support
  *
        /* msch can silently fail, so do it again if necessary */
        for (retry = 0; retry < 3; retry++) {
                /* prepare schib */
-               stsch(sch->irq, schib);
+               stsch(sch->schid, schib);
                schib->pmcw.mme  = mme;
                schib->pmcw.mbfc = mbfc;
                /* address can be either a block address or a block index */
                        schib->pmcw.mbi = address;
 
                /* try to submit it */
-               switch(ret = msch_err(sch->irq, schib)) {
+               switch(ret = msch_err(sch->schid, schib)) {
                        case 0:
                                break;
                        case 1:
                                ret = -EINVAL;
                                break;
                }
-               stsch(sch->irq, schib); /* restore the schib */
+               stsch(sch->schid, schib); /* restore the schib */
 
                if (ret)
                        break;
 
 };
 
 static struct subchannel *
-css_alloc_subchannel(int irq)
+css_alloc_subchannel(struct subchannel_id schid)
 {
        struct subchannel *sch;
        int ret;
        sch = kmalloc (sizeof (*sch), GFP_KERNEL | GFP_DMA);
        if (sch == NULL)
                return ERR_PTR(-ENOMEM);
-       ret = cio_validate_subchannel (sch, irq);
+       ret = cio_validate_subchannel (sch, schid);
        if (ret < 0) {
                kfree(sch);
                return ERR_PTR(ret);
        }
-       if (irq > highest_subchannel)
-               highest_subchannel = irq;
 
        if (sch->st != SUBCHANNEL_TYPE_IO) {
                /* For now we ignore all non-io subchannels. */
        struct subchannel *sch;
 
        sch = to_subchannel(dev);
-       if (!cio_is_console(sch->irq))
+       if (!cio_is_console(sch->schid))
                kfree(sch);
 }
 
 }
 
 int
-css_probe_device(int irq)
+css_probe_device(struct subchannel_id schid)
 {
        int ret;
        struct subchannel *sch;
 
-       sch = css_alloc_subchannel(irq);
+       sch = css_alloc_subchannel(schid);
        if (IS_ERR(sch))
                return PTR_ERR(sch);
        ret = css_register_subchannel(sch);
 check_subchannel(struct device * dev, void * data)
 {
        struct subchannel *sch;
-       int irq = (unsigned long)data;
+       struct subchannel_id *schid = data;
 
        sch = to_subchannel(dev);
-       return (sch->irq == irq);
+       return schid_equal(&sch->schid, schid);
 }
 
 struct subchannel *
-get_subchannel_by_schid(int irq)
+get_subchannel_by_schid(struct subchannel_id schid)
 {
        struct device *dev;
 
        dev = bus_find_device(&css_bus_type, NULL,
-                             (void *)(unsigned long)irq, check_subchannel);
+                             (void *)&schid, check_subchannel);
 
        return dev ? to_subchannel(dev) : NULL;
 }
 
 
 static inline int
-css_get_subchannel_status(struct subchannel *sch, int schid)
+css_get_subchannel_status(struct subchannel *sch, struct subchannel_id schid)
 {
        struct schib schib;
        int cc;
 }
        
 static int
-css_evaluate_subchannel(int irq, int slow)
+css_evaluate_subchannel(struct subchannel_id schid, int slow)
 {
        int event, ret, disc;
        struct subchannel *sch;
        unsigned long flags;
 
-       sch = get_subchannel_by_schid(irq);
+       sch = get_subchannel_by_schid(schid);
        disc = sch ? device_is_disconnected(sch) : 0;
        if (disc && slow) {
                if (sch)
                        put_device(&sch->dev);
                return -EAGAIN; /* Will be done on the slow path. */
        }
-       event = css_get_subchannel_status(sch, irq);
+       event = css_get_subchannel_status(sch, schid);
        CIO_MSG_EVENT(4, "Evaluating schid %04x, event %d, %s, %s path.\n",
-                     irq, event, sch?(disc?"disconnected":"normal"):"unknown",
+                     schid.sch_no, event,
+                     sch?(disc?"disconnected":"normal"):"unknown",
                      slow?"slow":"fast");
        switch (event) {
        case CIO_NO_PATH:
                        sch->schib.pmcw.intparm = 0;
                        cio_modify(sch);
                        put_device(&sch->dev);
-                       ret = css_probe_device(irq);
+                       ret = css_probe_device(schid);
                } else {
                        /*
                         * We can't immediately deregister the disconnected
                        device_trigger_reprobe(sch);
                        spin_unlock_irqrestore(&sch->lock, flags);
                }
-               ret = sch ? 0 : css_probe_device(irq);
+               ret = sch ? 0 : css_probe_device(schid);
                break;
        default:
                BUG();
 static void
 css_rescan_devices(void)
 {
-       int irq, ret;
+       int ret;
+       struct subchannel_id schid;
 
-       for (irq = 0; irq < __MAX_SUBCHANNELS; irq++) {
-               ret = css_evaluate_subchannel(irq, 1);
+       init_subchannel_id(&schid);
+       do {
+               ret = css_evaluate_subchannel(schid, 1);
                /* No more memory. It doesn't make sense to continue. No
                 * panic because this can happen in midflight and just
                 * because we can't use a new device is no reason to crash
                /* -ENXIO indicates that there are no more subchannels. */
                if (ret == -ENXIO)
                        break;
-       }
+       } while (schid.sch_no++ < __MAX_SUBCHANNEL);
 }
 
 struct slow_subchannel {
        struct list_head slow_list;
-       unsigned long schid;
+       struct subchannel_id schid;
 };
 
 static LIST_HEAD(slow_subchannels_head);
 css_process_crw(int irq)
 {
        int ret;
+       struct subchannel_id mchk_schid;
 
        CIO_CRW_EVENT(2, "source is subchannel %04X\n", irq);
 
        if (need_rescan)
                /* We need to iterate all subchannels anyway. */
                return -EAGAIN;
+
+       init_subchannel_id(&mchk_schid);
+       mchk_schid.sch_no = irq;
        /* 
         * Since we are always presented with IPI in the CRW, we have to
         * use stsch() to find out if the subchannel in question has come
         * or gone.
         */
-       ret = css_evaluate_subchannel(irq, 0);
+       ret = css_evaluate_subchannel(mchk_schid, 0);
        if (ret == -EAGAIN) {
-               if (css_enqueue_subchannel_slow(irq)) {
+               if (css_enqueue_subchannel_slow(mchk_schid)) {
                        css_clear_subchannel_slow_list();
                        need_rescan = 1;
                }
 static int __init
 init_channel_subsystem (void)
 {
-       int ret, irq;
+       int ret;
+       struct subchannel_id schid;
 
        if (chsc_determine_css_characteristics() == 0)
                css_characteristics_avail = 1;
 
        ctl_set_bit(6, 28);
 
-       for (irq = 0; irq < __MAX_SUBCHANNELS; irq++) {
+       init_subchannel_id(&schid);
+       do {
                struct subchannel *sch;
 
-               if (cio_is_console(irq))
+               if (cio_is_console(schid))
                        sch = cio_get_console_subchannel();
                else {
-                       sch = css_alloc_subchannel(irq);
+                       sch = css_alloc_subchannel(schid);
                        if (IS_ERR(sch))
                                ret = PTR_ERR(sch);
                        else
                 * console subchannel.
                 */
                css_register_subchannel(sch);
-       }
+       } while (schid.sch_no++ < __MAX_SUBCHANNEL);
        return 0;
 
 out_bus:
 subsys_initcall(init_channel_subsystem);
 
 int
-css_enqueue_subchannel_slow(unsigned long schid)
+css_enqueue_subchannel_slow(struct subchannel_id schid)
 {
        struct slow_subchannel *new_slow_sch;
        unsigned long flags;
 
 
 #include <asm/cio.h>
 
+#include "schid.h"
+
 /*
  * path grouping stuff
  */
        atomic_t onoff;
        unsigned long registered;
        __u16 devno;            /* device number */
-       __u16 irq;              /* subchannel number */
+       __u16 sch_no;           /* subchannel number */
        __u8 imask;             /* lpm mask for SNID/SID/SPGID */
        int iretry;             /* retry counter SNID/SID/SPGID */
        struct {
 extern struct bus_type css_bus_type;
 extern struct css_driver io_subchannel_driver;
 
-int css_probe_device(int irq);
-extern struct subchannel * get_subchannel_by_schid(int irq);
-extern unsigned int highest_subchannel;
+extern int css_probe_device(struct subchannel_id);
+extern struct subchannel * get_subchannel_by_schid(struct subchannel_id);
 extern int css_init_done;
 
-#define __MAX_SUBCHANNELS 65536
+#define __MAX_SUBCHANNEL 65535
 
 extern struct bus_type css_bus_type;
 extern struct device css_bus_device;
 void device_kill_pending_timer(struct subchannel *);
 
 /* Helper functions to build lists for the slow path. */
-int css_enqueue_subchannel_slow(unsigned long schid);
+extern int css_enqueue_subchannel_slow(struct subchannel_id schid);
 void css_walk_subchannel_slow_list(void (*fn)(unsigned long));
 void css_clear_subchannel_slow_list(void);
 int css_slow_subchannels_exist(void);
 
 
                        other_sch = to_subchannel(other_cdev->dev.parent);
                        if (get_device(&other_sch->dev)) {
-                               stsch(other_sch->irq, &other_sch->schib);
+                               stsch(other_sch->schid, &other_sch->schib);
                                if (other_sch->schib.pmcw.dnv) {
                                        other_sch->schib.pmcw.intparm = 0;
                                        cio_modify(other_sch);
        /* Init private data. */
        priv = cdev->private;
        priv->devno = sch->schib.pmcw.dev;
-       priv->irq = sch->irq;
+       priv->sch_no = sch->schid.sch_no;
        priv->state = DEV_STATE_NOT_OPER;
        INIT_LIST_HEAD(&priv->cmb_list);
        init_waitqueue_head(&priv->wait_q);
        sch = to_subchannel(dev);
        cdev = dev->driver_data;
 
-       if (cio_is_console(sch->irq))
+       if (cio_is_console(sch->schid))
                return;
        if (!sch->schib.pmcw.ena)
                /* Nothing to do. */
        driver_unregister(&cdriver->driver);
 }
 
+/* Helper func for qdio. */
+struct subchannel_id
+ccw_device_get_subchannel_id(struct ccw_device *cdev)
+{
+       struct subchannel *sch;
+
+       sch = to_subchannel(cdev->dev.parent);
+       return sch->schid;
+}
+
 MODULE_LICENSE("GPL");
 EXPORT_SYMBOL(ccw_device_set_online);
 EXPORT_SYMBOL(ccw_device_set_offline);
 EXPORT_SYMBOL(ccw_bus_type);
 EXPORT_SYMBOL(ccw_device_work);
 EXPORT_SYMBOL(ccw_device_notify_work);
+EXPORT_SYMBOL_GPL(ccw_device_get_subchannel_id);
 
 
 /* qdio needs this. */
 void ccw_device_set_timeout(struct ccw_device *, int);
+extern struct subchannel_id ccw_device_get_subchannel_id(struct ccw_device *);
 
 void retry_set_schib(struct ccw_device *cdev);
 #endif
 
        int ret;
 
        sch = to_subchannel(cdev->dev.parent);
-       ret = stsch(sch->irq, &sch->schib);
+       ret = stsch(sch->schid, &sch->schib);
        if (ret || !sch->schib.pmcw.dnv)
                return -ENODEV; 
        if (!sch->schib.pmcw.ena || sch->schib.scsw.actl == 0)
         * through ssch() and the path information is up to date.
         */
        old_lpm = sch->lpm;
-       stsch(sch->irq, &sch->schib);
+       stsch(sch->schid, &sch->schib);
        sch->lpm = sch->schib.pmcw.pim &
                sch->schib.pmcw.pam &
                sch->schib.pmcw.pom &
        case DEV_STATE_NOT_OPER:
                CIO_DEBUG(KERN_WARNING, 2,
                          "SenseID : unknown device %04x on subchannel %04x\n",
-                         cdev->private->devno, sch->irq);
+                         cdev->private->devno, sch->schid.sch_no);
                break;
        case DEV_STATE_OFFLINE:
                if (cdev->private->state == DEV_STATE_DISCONNECTED_SENSE_ID) {
        case DEV_STATE_BOXED:
                CIO_DEBUG(KERN_WARNING, 2,
                          "SenseID : boxed device %04x on subchannel %04x\n",
-                         cdev->private->devno, sch->irq);
+                         cdev->private->devno, sch->schid.sch_no);
                break;
        }
        cdev->private->state = state;
        if (state == DEV_STATE_BOXED)
                CIO_DEBUG(KERN_WARNING, 2,
                          "Boxed device %04x on subchannel %04x\n",
-                         cdev->private->devno, sch->irq);
+                         cdev->private->devno, sch->schid.sch_no);
 
        if (cdev->private->flags.donotify) {
                cdev->private->flags.donotify = 0;
        struct subchannel *sch;
 
        sch = to_subchannel(cdev->dev.parent);
-       if (stsch(sch->irq, &sch->schib) || !sch->schib.pmcw.dnv)
+       if (stsch(sch->schid, &sch->schib) || !sch->schib.pmcw.dnv)
                return -ENODEV;
        if (cdev->private->state != DEV_STATE_ONLINE) {
                if (sch->schib.scsw.actl != 0)
         * Since we might not just be coming from an interrupt from the
         * subchannel we have to update the schib.
         */
-       stsch(sch->irq, &sch->schib);
+       stsch(sch->schid, &sch->schib);
 
        if (sch->schib.scsw.actl != 0 ||
            (cdev->private->irb.scsw.stctl & SCSW_STCTL_STATUS_PEND)) {
 
        /* Iff device is idle, reset timeout. */
        sch = to_subchannel(cdev->dev.parent);
-       if (!stsch(sch->irq, &sch->schib))
+       if (!stsch(sch->schid, &sch->schib))
                if (sch->schib.scsw.actl == 0)
                        ccw_device_set_timeout(cdev, 0);
        /* Call the handler. */
                return;
 
        /* Update some values. */
-       if (stsch(sch->irq, &sch->schib))
+       if (stsch(sch->schid, &sch->schib))
                return;
 
        /*
 
                 */
                CIO_MSG_EVENT(2, "SenseID : device %04x on Subchannel %04x "
                              "reports cmd reject\n",
-                             cdev->private->devno, sch->irq);
+                             cdev->private->devno, sch->schid.sch_no);
                return -EOPNOTSUPP;
        }
        if (irb->esw.esw0.erw.cons) {
                        CIO_MSG_EVENT(2, "SenseID : path %02X for device %04x on"
                                      " subchannel %04x is 'not operational'\n",
                                      sch->orb.lpm, cdev->private->devno,
-                                     sch->irq);
+                                     sch->schid.sch_no);
                return -EACCES;
        }
        /* Hmm, whatever happened, try again. */
        CIO_MSG_EVENT(2, "SenseID : start_IO() for device %04x on "
                      "subchannel %04x returns status %02X%02X\n",
-                     cdev->private->devno, sch->irq,
+                     cdev->private->devno, sch->schid.sch_no,
                      irb->scsw.dstat, irb->scsw.cstat);
        return -EAGAIN;
 }
 
 /*
  *  drivers/s390/cio/device_ops.c
  *
- *   $Revision: 1.57 $
+ *   $Revision: 1.58 $
  *
  *    Copyright (C) 2002 IBM Deutschland Entwicklung GmbH,
  *                      IBM Corporation
 int
 _ccw_device_get_subchannel_number(struct ccw_device *cdev)
 {
-       return cdev->private->irq;
+       return cdev->private->sch_no;
 }
 
 int
 
                        CIO_MSG_EVENT(2, "SNID - Device %04x on Subchannel "
                                      "%04x, lpm %02X, became 'not "
                                      "operational'\n",
-                                     cdev->private->devno, sch->irq,
+                                     cdev->private->devno, sch->schid.sch_no,
                                      cdev->private->imask);
 
                }
        if (irb->scsw.cc == 3) {
                CIO_MSG_EVENT(2, "SNID - Device %04x on Subchannel "
                              "%04x, lpm %02X, became 'not operational'\n",
-                             cdev->private->devno, sch->irq, sch->orb.lpm);
+                             cdev->private->devno, sch->schid.sch_no,
+                             sch->orb.lpm);
                return -EACCES;
        }
        if (cdev->private->pgid.inf.ps.state2 == SNID_STATE2_RESVD_ELSE) {
                CIO_MSG_EVENT(2, "SNID - Device %04x on Subchannel %04x "
                              "is reserved by someone else\n",
-                             cdev->private->devno, sch->irq);
+                             cdev->private->devno, sch->schid.sch_no);
                return -EUSERS;
        }
        return 0;
        sch->vpm &= ~cdev->private->imask;
        CIO_MSG_EVENT(2, "SPID - Device %04x on Subchannel "
                      "%04x, lpm %02X, became 'not operational'\n",
-                     cdev->private->devno, sch->irq, cdev->private->imask);
+                     cdev->private->devno, sch->schid.sch_no, cdev->private->imask);
        return ret;
 }
 
        if (irb->scsw.cc == 3) {
                CIO_MSG_EVENT(2, "SPID - Device %04x on Subchannel "
                              "%04x, lpm %02X, became 'not operational'\n",
-                             cdev->private->devno, sch->irq,
+                             cdev->private->devno, sch->schid.sch_no,
                              cdev->private->imask);
                return -EACCES;
        }
         * Update sch->lpm with current values to catch paths becoming
         * available again.
         */
-       if (stsch(sch->irq, &sch->schib)) {
+       if (stsch(sch->schid, &sch->schib)) {
                ccw_device_verify_done(cdev, -ENODEV);
                return;
        }
 
                      "received"
                      " ... device %04X on subchannel %04X, dev_stat "
                      ": %02X sch_stat : %02X\n",
-                     cdev->private->devno, cdev->private->irq,
+                     cdev->private->devno, cdev->private->sch_no,
                      irb->scsw.dstat, irb->scsw.cstat);
 
        if (irb->scsw.cc != 3) {
                char dbf_text[15];
 
-               sprintf(dbf_text, "chk%x", cdev->private->irq);
+               sprintf(dbf_text, "chk%x", cdev->private->sch_no);
                CIO_TRACE_EVENT(0, dbf_text);
                CIO_HEX_EVENT(0, irb, sizeof (struct irb));
        }
        struct subchannel *sch;
 
        sch = to_subchannel(cdev->dev.parent);
-       stsch (sch->irq, &sch->schib);
+       stsch (sch->schid, &sch->schib);
 
        CIO_MSG_EVENT(0, "%s(%04x) - path(s) %02x are "
-                     "not operational \n", __FUNCTION__, sch->irq,
+                     "not operational \n", __FUNCTION__, sch->schid.sch_no,
                      sch->schib.pmcw.pnom);
 
        sch->lpm &= ~sch->schib.pmcw.pnom;
 
 #ifndef S390_CIO_IOASM_H
 #define S390_CIO_IOASM_H
 
+#include "schid.h"
+
 /*
  * TPI info structure
  */
 struct tpi_info {
-       __u32 reserved1  : 16;   /* reserved 0x00000001 */
-       __u32 irq        : 16;   /* aka. subchannel number */
+       struct subchannel_id schid;
        __u32 intparm;           /* interruption parameter */
        __u32 adapter_IO : 1;
        __u32 reserved2  : 1;
  * Some S390 specific IO instructions as inline
  */
 
-static inline int stsch(int irq, volatile struct schib *addr)
+static inline int stsch(struct subchannel_id schid,
+                           volatile struct schib *addr)
 {
        int ccode;
 
                "   ipm   %0\n"
                "   srl   %0,28"
                : "=d" (ccode)
-               : "d" (irq | 0x10000), "a" (addr)
+               : "d" (schid), "a" (addr), "m" (*addr)
                : "cc", "1" );
        return ccode;
 }
 
-static inline int msch(int irq, volatile struct schib *addr)
+static inline int msch(struct subchannel_id schid,
+                          volatile struct schib *addr)
 {
        int ccode;
 
                "   ipm   %0\n"
                "   srl   %0,28"
                : "=d" (ccode)
-               : "d" (irq | 0x10000L), "a" (addr)
+               : "d" (schid), "a" (addr), "m" (*addr)
                : "cc", "1" );
        return ccode;
 }
 
-static inline int msch_err(int irq, volatile struct schib *addr)
+static inline int msch_err(struct subchannel_id schid,
+                              volatile struct schib *addr)
 {
        int ccode;
 
                ".previous"
 #endif
                : "=&d" (ccode)
-               : "d" (irq | 0x10000L), "a" (addr), "K" (-EIO)
+               : "d" (schid), "a" (addr), "K" (-EIO), "m" (*addr)
                : "cc", "1" );
        return ccode;
 }
 
-static inline int tsch(int irq, volatile struct irb *addr)
+static inline int tsch(struct subchannel_id schid,
+                          volatile struct irb *addr)
 {
        int ccode;
 
                "   ipm   %0\n"
                "   srl   %0,28"
                : "=d" (ccode)
-               : "d" (irq | 0x10000L), "a" (addr)
+               : "d" (schid), "a" (addr), "m" (*addr)
                : "cc", "1" );
        return ccode;
 }
                "   ipm   %0\n"
                "   srl   %0,28"
                : "=d" (ccode)
-               : "a" (addr)
+               : "a" (addr), "m" (*addr)
                : "cc", "1" );
        return ccode;
 }
 
-static inline int ssch(int irq, volatile struct orb *addr)
+static inline int ssch(struct subchannel_id schid,
+                          volatile struct orb *addr)
 {
        int ccode;
 
                "   ipm   %0\n"
                "   srl   %0,28"
                : "=d" (ccode)
-               : "d" (irq | 0x10000L), "a" (addr)
+               : "d" (schid), "a" (addr), "m" (*addr)
                : "cc", "1" );
        return ccode;
 }
 
-static inline int rsch(int irq)
+static inline int rsch(struct subchannel_id schid)
 {
        int ccode;
 
                "   ipm   %0\n"
                "   srl   %0,28"
                : "=d" (ccode)
-               : "d" (irq | 0x10000L)
+               : "d" (schid)
                : "cc", "1" );
        return ccode;
 }
 
-static inline int csch(int irq)
+static inline int csch(struct subchannel_id schid)
 {
        int ccode;
 
                "   ipm   %0\n"
                "   srl   %0,28"
                : "=d" (ccode)
-               : "d" (irq | 0x10000L)
+               : "d" (schid)
                : "cc", "1" );
        return ccode;
 }
 
-static inline int hsch(int irq)
+static inline int hsch(struct subchannel_id schid)
 {
        int ccode;
 
                "   ipm   %0\n"
                "   srl   %0,28"
                : "=d" (ccode)
-               : "d" (irq | 0x10000L)
+               : "d" (schid)
                : "cc", "1" );
        return ccode;
 }
 
-static inline int xsch(int irq)
+static inline int xsch(struct subchannel_id schid)
 {
        int ccode;
 
                "   ipm   %0\n"
                "   srl   %0,28"
                : "=d" (ccode)
-               : "d" (irq | 0x10000L)
+               : "d" (schid)
                : "cc", "1" );
        return ccode;
 }
 
 static inline int chsc(void *chsc_area)
 {
+       typedef struct { char _[4096]; } addr_type;
        int cc;
 
        __asm__ __volatile__ (
-               ".insn  rre,0xb25f0000,%1,0     \n\t"
+               ".insn  rre,0xb25f0000,%2,0     \n\t"
                "ipm    %0      \n\t"
                "srl    %0,28   \n\t"
-               : "=d" (cc)
-               : "d" (chsc_area)
+               : "=d" (cc), "=m" (*(addr_type *) chsc_area)
+               : "d" (chsc_area), "m" (*(addr_type *) chsc_area)
                : "cc" );
 
        return cc;
 
        perf_stats.siga_syncs++;
 #endif /* QDIO_PERFORMANCE_STATS */
 
-       cc = do_siga_sync(0x10000|q->irq, gpr2, gpr3);
+       cc = do_siga_sync(q->schid, gpr2, gpr3);
        if (cc)
                QDIO_DBF_HEX3(0,trace,&cc,sizeof(int*));
 
 {
        struct qdio_irq *irq;
        unsigned int fc = 0;
+       unsigned long schid;
 
        irq = (struct qdio_irq *) q->irq_ptr;
        if (!irq->is_qebsm)
-               return do_siga_output(0x10000|q->irq, q->mask, busy_bit, fc);
-       fc |= 0x80;
-       return do_siga_output(irq->sch_token, q->mask, busy_bit, fc);
+              schid = *((u32 *)&q->schid);
+       else {
+              schid = irq->sch_token;
+              fc |= 0x80;
+       }
+       return do_siga_output(schid, q->mask, busy_bit, fc);
 }
 
 /* 
        perf_stats.siga_ins++;
 #endif /* QDIO_PERFORMANCE_STATS */
 
-       cc = do_siga_input(0x10000|q->irq, q->mask);
+       cc = do_siga_input(q->schid, q->mask);
        
        if (cc)
                QDIO_DBF_HEX3(0,trace,&cc,sizeof(int*));
                /* went smooth this time, reset timestamp */
 #ifdef CONFIG_QDIO_DEBUG
                QDIO_DBF_TEXT3(0,trace,"cc2reslv");
-               sprintf(dbf_text,"%4x%2x%2x",q->irq,q->q_no,
+               sprintf(dbf_text,"%4x%2x%2x",q->schid.sch_no,q->q_no,
                        atomic_read(&q->busy_siga_counter));
                QDIO_DBF_TEXT3(0,trace,dbf_text);
 #endif /* CONFIG_QDIO_DEBUG */
                }
                QDIO_DBF_TEXT2(0,trace,"cc2REPRT");
 #ifdef CONFIG_QDIO_DEBUG
-               sprintf(dbf_text,"%4x%2x%2x",q->irq,q->q_no,
+               sprintf(dbf_text,"%4x%2x%2x",q->schid.sch_no,q->q_no,
                        atomic_read(&q->busy_siga_counter));
                QDIO_DBF_TEXT3(0,trace,dbf_text);
 #endif /* CONFIG_QDIO_DEBUG */
        void *ptr;
        int available;
 
-       sprintf(dbf_text,"qfqs%4x",cdev->private->irq);
+       sprintf(dbf_text,"qfqs%4x",cdev->private->sch_no);
        QDIO_DBF_TEXT0(0,setup,dbf_text);
        for (i=0;i<no_input_qs;i++) {
                q=irq_ptr->input_qs[i];
 
                 q->queue_type=q_format;
                q->int_parm=int_parm;
-               q->irq=irq_ptr->irq;
+               q->schid = irq_ptr->schid;
                q->irq_ptr = irq_ptr;
                q->cdev = cdev;
                q->mask=1<<(31-i);
                 q->queue_type=q_format;
                q->int_parm=int_parm;
                q->is_input_q=0;
-               q->irq=irq_ptr->irq;
+               q->schid = irq_ptr->schid;
                q->cdev = cdev;
                q->irq_ptr = irq_ptr;
                q->mask=1<<(31-i);
        char dbf_text[15];
 
        QDIO_DBF_TEXT5(0,trace,"newstate");
-       sprintf(dbf_text,"%4x%4x",irq_ptr->irq,state);
+       sprintf(dbf_text,"%4x%4x",irq_ptr->schid.sch_no,state);
        QDIO_DBF_TEXT5(0,trace,dbf_text);
 #endif /* CONFIG_QDIO_DEBUG */
 
 }
 
 static inline void
-qdio_irq_check_sense(int irq, struct irb *irb)
+qdio_irq_check_sense(struct subchannel_id schid, struct irb *irb)
 {
        char dbf_text[15];
 
        if (irb->esw.esw0.erw.cons) {
-               sprintf(dbf_text,"sens%4x",irq);
+               sprintf(dbf_text,"sens%4x",schid.sch_no);
                QDIO_DBF_TEXT2(1,trace,dbf_text);
                QDIO_DBF_HEX0(0,sense,irb,QDIO_DBF_SENSE_LEN);
 
        switch (irq_ptr->state) {
        case QDIO_IRQ_STATE_INACTIVE:
                QDIO_PRINT_ERR("establish queues on irq %04x: timed out\n",
-                              irq_ptr->irq);
+                              irq_ptr->schid.sch_no);
                QDIO_DBF_TEXT2(1,setup,"eq:timeo");
                qdio_set_state(irq_ptr, QDIO_IRQ_STATE_ERR);
                break;
        case QDIO_IRQ_STATE_CLEANUP:
                QDIO_PRINT_INFO("Did not get interrupt on cleanup, irq=0x%x.\n",
-                               irq_ptr->irq);
+                               irq_ptr->schid.sch_no);
                qdio_set_state(irq_ptr, QDIO_IRQ_STATE_ERR);
                break;
        case QDIO_IRQ_STATE_ESTABLISHED:
        case QDIO_IRQ_STATE_ACTIVE:
                /* I/O has been terminated by common I/O layer. */
                QDIO_PRINT_INFO("Queues on irq %04x killed by cio.\n",
-                               irq_ptr->irq);
+                               irq_ptr->schid.sch_no);
                QDIO_DBF_TEXT2(1, trace, "cio:term");
                qdio_set_state(irq_ptr, QDIO_IRQ_STATE_STOPPED);
                if (get_device(&cdev->dev)) {
                }
        }
 
-       qdio_irq_check_sense(irq_ptr->irq, irb);
+       qdio_irq_check_sense(irq_ptr->schid, irb);
 
 #ifdef CONFIG_QDIO_DEBUG
        sprintf(dbf_text, "state:%d", irq_ptr->state);
                return -ENODEV;
 
 #ifdef CONFIG_QDIO_DEBUG
-       *((int*)(&dbf_text[4])) = irq_ptr->irq;
+       *((int*)(&dbf_text[4])) = irq_ptr->schid.sch_no;
        QDIO_DBF_HEX4(0,trace,dbf_text,QDIO_DBF_TRACE_LEN);
        *((int*)(&dbf_text[0]))=flags;
        *((int*)(&dbf_text[4]))=queue_number;
                if (!q)
                        return -EINVAL;
                if (!(irq_ptr->is_qebsm))
-                       cc = do_siga_sync(0x10000|q->irq, 0, q->mask);
+                       cc = do_siga_sync(q->schid, 0, q->mask);
        } else if (flags&QDIO_FLAG_SYNC_OUTPUT) {
                q=irq_ptr->output_qs[queue_number];
                if (!q)
                        return -EINVAL;
                if (!(irq_ptr->is_qebsm))
-                       cc = do_siga_sync(0x10000|q->irq, q->mask, 0);
+                       cc = do_siga_sync(q->schid, q->mask, 0);
        } else 
                return -EINVAL;
 
        ssqd_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
        if (!ssqd_area) {
                QDIO_PRINT_WARN("Could not get memory for chsc. Using all " \
-                               "SIGAs for sch x%x.\n", irq_ptr->irq);
+                               "SIGAs for sch x%x.\n", irq_ptr->schid.sch_no);
                irq_ptr->qdioac = CHSC_FLAG_SIGA_INPUT_NECESSARY ||
                                  CHSC_FLAG_SIGA_OUTPUT_NECESSARY ||
                                  CHSC_FLAG_SIGA_SYNC_NECESSARY; /* all flags set */
                .length = 0x0010,
                .code   = 0x0024,
        };
-       ssqd_area->first_sch = irq_ptr->irq;
-       ssqd_area->last_sch = irq_ptr->irq;
+       ssqd_area->first_sch = irq_ptr->schid.sch_no;
+       ssqd_area->last_sch = irq_ptr->schid.sch_no;
        result = chsc(ssqd_area);
 
        if (result) {
                QDIO_PRINT_WARN("CHSC returned cc %i. Using all " \
                                "SIGAs for sch x%x.\n",
-                               result, irq_ptr->irq);
+                               result, irq_ptr->schid.sch_no);
                qdioac = CHSC_FLAG_SIGA_INPUT_NECESSARY ||
                        CHSC_FLAG_SIGA_OUTPUT_NECESSARY ||
                        CHSC_FLAG_SIGA_SYNC_NECESSARY; /* all flags set */
        if (ssqd_area->response.code != QDIO_CHSC_RESPONSE_CODE_OK) {
                QDIO_PRINT_WARN("response upon checking SIGA needs " \
                                "is 0x%x. Using all SIGAs for sch x%x.\n",
-                               ssqd_area->response.code, irq_ptr->irq);
+                               ssqd_area->response.code, irq_ptr->schid.sch_no);
                qdioac = CHSC_FLAG_SIGA_INPUT_NECESSARY ||
                        CHSC_FLAG_SIGA_OUTPUT_NECESSARY ||
                        CHSC_FLAG_SIGA_SYNC_NECESSARY; /* all flags set */
        }
        if (!(ssqd_area->flags & CHSC_FLAG_QDIO_CAPABILITY) ||
            !(ssqd_area->flags & CHSC_FLAG_VALIDITY) ||
-           (ssqd_area->sch != irq_ptr->irq)) {
+           (ssqd_area->sch != irq_ptr->schid.sch_no)) {
                QDIO_PRINT_WARN("huh? problems checking out sch x%x... " \
-                               "using all SIGAs.\n",irq_ptr->irq);
+                               "using all SIGAs.\n",irq_ptr->schid.sch_no);
                qdioac = CHSC_FLAG_SIGA_INPUT_NECESSARY |
                        CHSC_FLAG_SIGA_OUTPUT_NECESSARY |
                        CHSC_FLAG_SIGA_SYNC_NECESSARY; /* worst case */
                /* set to 0x10000000 to enable
                 * time delay disablement facility */
                u32 reserved5;
-               u32 subsystem_id;
+               struct subchannel_id schid;
                u32 reserved6[1004];
                struct chsc_header response;
                u32 reserved7;
        scssc_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
        if (!scssc_area) {
                QDIO_PRINT_WARN("No memory for setting indicators on " \
-                               "subchannel x%x.\n", irq_ptr->irq);
+                               "subchannel x%x.\n", irq_ptr->schid.sch_no);
                return -ENOMEM;
        }
        scssc_area->request = (struct chsc_header) {
        scssc_area->ks = QDIO_STORAGE_KEY;
        scssc_area->kc = QDIO_STORAGE_KEY;
        scssc_area->isc = TIQDIO_THININT_ISC;
-       scssc_area->subsystem_id = (1<<16) + irq_ptr->irq;
+       scssc_area->schid = irq_ptr->schid;
        /* enables the time delay disablement facility. Don't care
         * whether it is really there (i.e. we haven't checked for
         * it) */
                QDIO_PRINT_WARN("Time delay disablement facility " \
                                "not available\n");
 
-
-
        result = chsc(scssc_area);
        if (result) {
                QDIO_PRINT_WARN("could not set indicators on irq x%x, " \
-                               "cc=%i.\n",irq_ptr->irq,result);
+                               "cc=%i.\n",irq_ptr->schid.sch_no,result);
                result = -EIO;
                goto out;
        }
        scsscf_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
        if (!scsscf_area) {
                QDIO_PRINT_WARN("No memory for setting delay target on " \
-                               "subchannel x%x.\n", irq_ptr->irq);
+                               "subchannel x%x.\n", irq_ptr->schid.sch_no);
                return -ENOMEM;
        }
        scsscf_area->request = (struct chsc_header) {
        result=chsc(scsscf_area);
        if (result) {
                QDIO_PRINT_WARN("could not set delay target on irq x%x, " \
-                               "cc=%i. Continuing.\n",irq_ptr->irq,result);
+                               "cc=%i. Continuing.\n",irq_ptr->schid.sch_no,
+                               result);
                result = -EIO;
                goto out;
        }
        if (!irq_ptr)
                return -ENODEV;
 
-       sprintf(dbf_text,"qcln%4x",irq_ptr->irq);
+       sprintf(dbf_text,"qcln%4x",irq_ptr->schid.sch_no);
        QDIO_DBF_TEXT1(0,trace,dbf_text);
        QDIO_DBF_TEXT0(0,setup,dbf_text);
 
 
        down(&irq_ptr->setting_up_sema);
 
-       sprintf(dbf_text,"qsqs%4x",irq_ptr->irq);
+       sprintf(dbf_text,"qsqs%4x",irq_ptr->schid.sch_no);
        QDIO_DBF_TEXT1(0,trace,dbf_text);
        QDIO_DBF_TEXT0(0,setup,dbf_text);
 
 
        down(&irq_ptr->setting_up_sema);
 
-       sprintf(dbf_text,"qfqs%4x",irq_ptr->irq);
+       sprintf(dbf_text,"qfqs%4x",irq_ptr->schid.sch_no);
        QDIO_DBF_TEXT1(0,trace,dbf_text);
        QDIO_DBF_TEXT0(0,setup,dbf_text);
 
        irq_ptr = cdev->private->qdio_data;
 
        if (cstat || (dstat & ~(DEV_STAT_CHN_END|DEV_STAT_DEV_END))) {
-               sprintf(dbf_text,"ick1%4x",irq_ptr->irq);
+               sprintf(dbf_text,"ick1%4x",irq_ptr->schid.sch_no);
                QDIO_DBF_TEXT2(1,trace,dbf_text);
                QDIO_DBF_HEX2(0,trace,&dstat,sizeof(int));
                QDIO_DBF_HEX2(0,trace,&cstat,sizeof(int));
                QDIO_PRINT_ERR("received check condition on establish " \
                               "queues on irq 0x%x (cs=x%x, ds=x%x).\n",
-                              irq_ptr->irq,cstat,dstat);
+                              irq_ptr->schid.sch_no,cstat,dstat);
                qdio_set_state(irq_ptr,QDIO_IRQ_STATE_ERR);
        }
        
                QDIO_DBF_HEX2(0,setup,&cstat, sizeof(cstat));
                QDIO_PRINT_ERR("establish queues on irq %04x: didn't get "
                               "device end: dstat=%02x, cstat=%02x\n",
-                              irq_ptr->irq, dstat, cstat);
+                              irq_ptr->schid.sch_no, dstat, cstat);
                qdio_set_state(irq_ptr, QDIO_IRQ_STATE_ERR);
                return 1;
        }
                QDIO_PRINT_ERR("establish queues on irq %04x: got "
                               "the following devstat: dstat=%02x, "
                               "cstat=%02x\n",
-                              irq_ptr->irq, dstat, cstat);
+                              irq_ptr->schid.sch_no, dstat, cstat);
                qdio_set_state(irq_ptr, QDIO_IRQ_STATE_ERR);
                return 1;
        }
 
        irq_ptr = cdev->private->qdio_data;
 
-       sprintf(dbf_text,"qehi%4x",cdev->private->irq);
+       sprintf(dbf_text,"qehi%4x",cdev->private->sch_no);
        QDIO_DBF_TEXT0(0,setup,dbf_text);
        QDIO_DBF_TEXT0(0,trace,dbf_text);
 
        int rc;
        char dbf_text[15];
 
-       sprintf(dbf_text,"qini%4x",init_data->cdev->private->irq);
+       sprintf(dbf_text,"qini%4x",init_data->cdev->private->sch_no);
        QDIO_DBF_TEXT0(0,setup,dbf_text);
        QDIO_DBF_TEXT0(0,trace,dbf_text);
 
        struct qdio_irq *irq_ptr;
        char dbf_text[15];
 
-       sprintf(dbf_text,"qalc%4x",init_data->cdev->private->irq);
+       sprintf(dbf_text,"qalc%4x",init_data->cdev->private->sch_no);
        QDIO_DBF_TEXT0(0,setup,dbf_text);
        QDIO_DBF_TEXT0(0,trace,dbf_text);
        if ( (init_data->no_input_qs>QDIO_MAX_QUEUES_PER_IRQ) ||
 
        irq_ptr->int_parm=init_data->int_parm;
 
-       irq_ptr->irq = init_data->cdev->private->irq;
+       irq_ptr->schid = ccw_device_get_subchannel_id(init_data->cdev);
        irq_ptr->no_input_qs=init_data->no_input_qs;
        irq_ptr->no_output_qs=init_data->no_output_qs;
 
                QDIO_DBF_HEX1(0,setup,&irq_ptr->dev_st_chg_ind,sizeof(void*));
                if (!irq_ptr->dev_st_chg_ind) {
                        QDIO_PRINT_WARN("no indicator location available " \
-                                       "for irq 0x%x\n",irq_ptr->irq);
+                                       "for irq 0x%x\n",irq_ptr->schid.sch_no);
                        qdio_release_irq_memory(irq_ptr);
                        return -ENOBUFS;
                }
                tiqdio_set_delay_target(irq_ptr,TIQDIO_DELAY_TARGET);
        }
 
-       sprintf(dbf_text,"qest%4x",cdev->private->irq);
+       sprintf(dbf_text,"qest%4x",cdev->private->sch_no);
        QDIO_DBF_TEXT0(0,setup,dbf_text);
        QDIO_DBF_TEXT0(0,trace,dbf_text);
 
                }
                QDIO_PRINT_WARN("establish queues on irq %04x: do_IO " \
                            "returned %i, next try returned %i\n",
-                           irq_ptr->irq,result,result2);
+                           irq_ptr->schid.sch_no,result,result2);
                result=result2;
                if (result)
                        ccw_device_set_timeout(cdev, 0);
                goto out;
        }
 
-       sprintf(dbf_text,"qact%4x", irq_ptr->irq);
+       sprintf(dbf_text,"qact%4x", irq_ptr->schid.sch_no);
        QDIO_DBF_TEXT2(0,setup,dbf_text);
        QDIO_DBF_TEXT2(0,trace,dbf_text);
 
                }
                QDIO_PRINT_WARN("activate queues on irq %04x: do_IO " \
                            "returned %i, next try returned %i\n",
-                           irq_ptr->irq,result,result2);
+                           irq_ptr->schid.sch_no,result,result2);
                result=result2;
        }
 
 #ifdef CONFIG_QDIO_DEBUG
        char dbf_text[20];
 
-       sprintf(dbf_text,"doQD%04x",cdev->private->irq);
+       sprintf(dbf_text,"doQD%04x",cdev->private->sch_no);
        QDIO_DBF_TEXT3(0,trace,dbf_text);
 #endif /* CONFIG_QDIO_DEBUG */
 
 
 
 #include <asm/page.h>
 
-#define VERSION_CIO_QDIO_H "$Revision: 1.37 $"
+#include "schid.h"
+
+#define VERSION_CIO_QDIO_H "$Revision: 1.40 $"
 
 #ifdef CONFIG_QDIO_DEBUG
 #define QDIO_VERBOSE_LEVEL 9
 
 
 static inline int
-do_siga_sync(unsigned int irq, unsigned int mask1, unsigned int mask2)
+do_siga_sync(struct subchannel_id schid, unsigned int mask1, unsigned int mask2)
 {
        int cc;
 
                "ipm    %0      \n\t"
                "srl    %0,28   \n\t"
                : "=d" (cc)
-               : "d" (irq), "d" (mask1), "d" (mask2)
+               : "d" (schid), "d" (mask1), "d" (mask2)
                : "cc", "0", "1", "2", "3"
                );
 #else /* CONFIG_ARCH_S390X */
                "ipm    %0      \n\t"
                "srl    %0,28   \n\t"
                : "=d" (cc)
-               : "d" (irq), "d" (mask1), "d" (mask2)
+               : "d" (schid), "d" (mask1), "d" (mask2)
                : "cc", "0", "1", "2", "3"
                );
 #endif /* CONFIG_ARCH_S390X */
 }
 
 static inline int
-do_siga_input(unsigned int irq, unsigned int mask)
+do_siga_input(struct subchannel_id schid, unsigned int mask)
 {
        int cc;
 
                "ipm    %0      \n\t"
                "srl    %0,28   \n\t"
                : "=d" (cc)
-               : "d" (irq), "d" (mask)
+               : "d" (schid), "d" (mask)
                : "cc", "0", "1", "2", "memory"
                );
 #else /* CONFIG_ARCH_S390X */
                "ipm    %0      \n\t"
                "srl    %0,28   \n\t"
                : "=d" (cc)
-               : "d" (irq), "d" (mask)
+               : "d" (schid), "d" (mask)
                : "cc", "0", "1", "2", "memory"
                );
 #endif /* CONFIG_ARCH_S390X */
 }
 
 static inline int
-do_siga_output(unsigned long irq, unsigned long mask, __u32 *bb,
+do_siga_output(unsigned long schid, unsigned long mask, __u32 *bb,
               unsigned int fc)
 {
        int cc;
                ".long  0b,2b   \n\t"
                ".previous      \n\t"
                : "=d" (cc), "=d" (busy_bit)
-               : "d" (irq), "d" (mask),
+               : "d" (schid), "d" (mask),
                "i" (QDIO_SIGA_ERROR_ACCESS_EXCEPTION)
                : "cc", "0", "1", "2", "memory"
                );
                ".quad  0b,1b   \n\t"
                ".previous      \n\t"
                : "=d" (cc), "=d" (busy_bit)
-               : "d" (irq), "d" (mask),
+               : "d" (schid), "d" (mask),
                "i" (QDIO_SIGA_ERROR_ACCESS_EXCEPTION), "d" (fc)
                : "cc", "0", "1", "2", "memory"
                );
        __u32 * dev_st_chg_ind;
 
        int is_input_q;
-       int irq;
+       struct subchannel_id schid;
        struct ccw_device *cdev;
 
        unsigned int is_iqdio_q;
        __u32 * volatile dev_st_chg_ind;
 
        unsigned long int_parm;
-       int irq;
+       struct subchannel_id schid;
 
        unsigned int is_iqdio_irq;
        unsigned int is_thinint_irq;
 
--- /dev/null
+#ifndef S390_SCHID_H
+#define S390_SCHID_H
+
+struct subchannel_id {
+       __u32 reserved:15;
+       __u32 one:1;
+       __u32 sch_no:16;
+} __attribute__ ((packed,aligned(4)));
+
+
+/* Helper function for sane state of pre-allocated subchannel_id. */
+static inline void
+init_subchannel_id(struct subchannel_id *schid)
+{
+       memset(schid, 0, sizeof(struct subchannel_id));
+       schid->one = 1;
+}
+
+static inline int
+schid_equal(struct subchannel_id *schid1, struct subchannel_id *schid2)
+{
+       return !memcmp(schid1, schid2, sizeof(struct subchannel_id));
+}
+
+#endif /* S390_SCHID_H */