fedora core 6 1.2949 + vserver 2.2.0
[linux-2.6.git] / drivers / s390 / cio / qdio.c
index 9ed37dc..6fd1940 100644 (file)
@@ -30,7 +30,6 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
-#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/init.h>
 
@@ -38,6 +37,7 @@
 #include <linux/kernel.h>
 #include <linux/proc_fs.h>
 #include <linux/timer.h>
+#include <linux/mempool.h>
 
 #include <asm/ccwdev.h>
 #include <asm/io.h>
@@ -46,6 +46,7 @@
 #include <asm/timex.h>
 
 #include <asm/debug.h>
+#include <asm/s390_rdev.h>
 #include <asm/qdio.h>
 
 #include "cio.h"
@@ -65,12 +66,12 @@ MODULE_LICENSE("GPL");
 /******************** HERE WE GO ***********************************/
 
 static const char version[] = "QDIO base support version 2";
+extern struct bus_type ccw_bus_type;
 
-#ifdef QDIO_PERFORMANCE_STATS
+static int qdio_performance_stats = 0;
 static int proc_perf_file_registration;
 static unsigned long i_p_c, i_p_nc, o_p_c, o_p_nc, ii_p_c, ii_p_nc;
 static struct qdio_perf_stats perf_stats;
-#endif /* QDIO_PERFORMANCE_STATS */
 
 static int hydra_thinints;
 static int is_passthrough = 0;
@@ -80,6 +81,8 @@ static int indicator_used[INDICATORS_PER_CACHELINE];
 static __u32 * volatile indicators;
 static __u32 volatile spare_indicator;
 static atomic_t spare_indicator_usecount;
+#define QDIO_MEMPOOL_SCSSC_ELEMENTS 2
+static mempool_t *qdio_mempool_scssc;
 
 static debug_info_t *qdio_dbf_setup;
 static debug_info_t *qdio_dbf_sbal;
@@ -113,7 +116,7 @@ qdio_min(int a,int b)
 static inline __u64 
 qdio_get_micros(void)
 {
-        return (get_clock() >> 10); /* time>>12 is microseconds */
+       return (get_clock() >> 12); /* time>>12 is microseconds */
 }
 
 /* 
@@ -273,9 +276,8 @@ qdio_siga_sync(struct qdio_q *q, unsigned int gpr2,
        QDIO_DBF_TEXT4(0,trace,"sigasync");
        QDIO_DBF_HEX4(0,trace,&q,sizeof(void*));
 
-#ifdef QDIO_PERFORMANCE_STATS
-       perf_stats.siga_syncs++;
-#endif /* QDIO_PERFORMANCE_STATS */
+       if (qdio_performance_stats)
+               perf_stats.siga_syncs++;
 
        cc = do_siga_sync(q->schid, gpr2, gpr3);
        if (cc)
@@ -320,9 +322,8 @@ qdio_siga_output(struct qdio_q *q)
        __u32 busy_bit;
        __u64 start_time=0;
 
-#ifdef QDIO_PERFORMANCE_STATS
-       perf_stats.siga_outs++;
-#endif /* QDIO_PERFORMANCE_STATS */
+       if (qdio_performance_stats)
+               perf_stats.siga_outs++;
 
        QDIO_DBF_TEXT4(0,trace,"sigaout");
        QDIO_DBF_HEX4(0,trace,&q,sizeof(void*));
@@ -356,9 +357,8 @@ qdio_siga_input(struct qdio_q *q)
        QDIO_DBF_TEXT4(0,trace,"sigain");
        QDIO_DBF_HEX4(0,trace,&q,sizeof(void*));
 
-#ifdef QDIO_PERFORMANCE_STATS
-       perf_stats.siga_ins++;
-#endif /* QDIO_PERFORMANCE_STATS */
+       if (qdio_performance_stats)
+               perf_stats.siga_ins++;
 
        cc = do_siga_input(q->schid, q->mask);
        
@@ -479,7 +479,7 @@ qdio_stop_polling(struct qdio_q *q)
        unsigned char state = 0;
        struct qdio_irq *irq = (struct qdio_irq *) q->irq_ptr;
 
-       if (!atomic_swap(&q->polling,0)) 
+       if (!atomic_xchg(&q->polling,0))
                return 1;
 
        QDIO_DBF_TEXT4(0,trace,"stoppoll");
@@ -952,9 +952,8 @@ __qdio_outbound_processing(struct qdio_q *q)
 
        if (unlikely(qdio_reserve_q(q))) {
                qdio_release_q(q);
-#ifdef QDIO_PERFORMANCE_STATS
-               o_p_c++;
-#endif /* QDIO_PERFORMANCE_STATS */
+               if (qdio_performance_stats)
+                       o_p_c++;
                /* as we're sissies, we'll check next time */
                if (likely(!atomic_read(&q->is_in_shutdown))) {
                        qdio_mark_q(q);
@@ -962,10 +961,10 @@ __qdio_outbound_processing(struct qdio_q *q)
                }
                return;
        }
-#ifdef QDIO_PERFORMANCE_STATS
-       o_p_nc++;
-       perf_stats.tl_runs++;
-#endif /* QDIO_PERFORMANCE_STATS */
+       if (qdio_performance_stats) {
+               o_p_nc++;
+               perf_stats.tl_runs++;
+       }
 
        /* see comment in qdio_kick_outbound_q */
        siga_attempts=atomic_read(&q->busy_siga_counter);
@@ -980,12 +979,11 @@ __qdio_outbound_processing(struct qdio_q *q)
 
        if (q->is_iqdio_q) {
                /* 
-                * for asynchronous queues, we better check, if the fill
-                * level is too high. for synchronous queues, the fill
-                * level will never be that high. 
+                * for asynchronous queues, we better check, if the sent
+                * buffer is already switched from PRIMED to EMPTY.
                 */
-               if (atomic_read(&q->number_of_buffers_used)>
-                   IQDIO_FILL_LEVEL_TO_POLL)
+               if ((q->queue_type == QDIO_IQDIO_QFMT_ASYNCH) &&
+                   !qdio_is_outbound_q_done(q))
                        qdio_mark_q(q);
 
        } else if (!q->hydra_gives_outbound_pcis)
@@ -1127,7 +1125,7 @@ out:
 
 #ifdef QDIO_USE_PROCESSING_STATE
        if (last_position>=0)
-               set_slsb(q, &last_position, SLSB_P_INPUT_NOT_INIT, &count);
+               set_slsb(q, &last_position, SLSB_P_INPUT_PROCESSING, &count);
 #endif /* QDIO_USE_PROCESSING_STATE */
 
        QDIO_DBF_HEX4(0,trace,&q->first_to_check,sizeof(int));
@@ -1140,15 +1138,16 @@ qdio_has_inbound_q_moved(struct qdio_q *q)
 {
        int i;
 
-#ifdef QDIO_PERFORMANCE_STATS
        static int old_pcis=0;
        static int old_thinints=0;
 
-       if ((old_pcis==perf_stats.pcis)&&(old_thinints==perf_stats.thinints))
-               perf_stats.start_time_inbound=NOW;
-       else
-               old_pcis=perf_stats.pcis;
-#endif /* QDIO_PERFORMANCE_STATS */
+       if (qdio_performance_stats) {
+               if ((old_pcis==perf_stats.pcis)&&
+                   (old_thinints==perf_stats.thinints))
+                       perf_stats.start_time_inbound=NOW;
+               else
+                       old_pcis=perf_stats.pcis;
+       }
 
        i=qdio_get_inbound_buffer_frontier(q);
        if ( (i!=GET_SAVED_FRONTIER(q)) ||
@@ -1338,10 +1337,10 @@ qdio_kick_inbound_handler(struct qdio_q *q)
        q->siga_error=0;
        q->error_status_flags=0;
 
-#ifdef QDIO_PERFORMANCE_STATS
-       perf_stats.inbound_time+=NOW-perf_stats.start_time_inbound;
-       perf_stats.inbound_cnt++;
-#endif /* QDIO_PERFORMANCE_STATS */
+       if (qdio_performance_stats) {
+               perf_stats.inbound_time+=NOW-perf_stats.start_time_inbound;
+               perf_stats.inbound_cnt++;
+       }
 }
 
 static inline void
@@ -1361,9 +1360,8 @@ __tiqdio_inbound_processing(struct qdio_q *q, int spare_ind_was_set)
         */
        if (unlikely(qdio_reserve_q(q))) {
                qdio_release_q(q);
-#ifdef QDIO_PERFORMANCE_STATS
-               ii_p_c++;
-#endif /* QDIO_PERFORMANCE_STATS */
+               if (qdio_performance_stats)
+                       ii_p_c++;
                /* 
                 * as we might just be about to stop polling, we make
                 * sure that we check again at least once more 
@@ -1371,9 +1369,8 @@ __tiqdio_inbound_processing(struct qdio_q *q, int spare_ind_was_set)
                tiqdio_sched_tl();
                return;
        }
-#ifdef QDIO_PERFORMANCE_STATS
-       ii_p_nc++;
-#endif /* QDIO_PERFORMANCE_STATS */
+       if (qdio_performance_stats)
+               ii_p_nc++;
        if (unlikely(atomic_read(&q->is_in_shutdown))) {
                qdio_unmark_q(q);
                goto out;
@@ -1414,11 +1411,11 @@ __tiqdio_inbound_processing(struct qdio_q *q, int spare_ind_was_set)
                irq_ptr = (struct qdio_irq*)q->irq_ptr;
                for (i=0;i<irq_ptr->no_output_qs;i++) {
                        oq = irq_ptr->output_qs[i];
-#ifdef QDIO_PERFORMANCE_STATS
-                       perf_stats.tl_runs--;
-#endif /* QDIO_PERFORMANCE_STATS */
-                       if (!qdio_is_outbound_q_done(oq))
+                       if (!qdio_is_outbound_q_done(oq)) {
+                               if (qdio_performance_stats)
+                                       perf_stats.tl_runs--;
                                __qdio_outbound_processing(oq);
+                       }
                }
        }
 
@@ -1455,9 +1452,8 @@ __qdio_inbound_processing(struct qdio_q *q)
 
        if (unlikely(qdio_reserve_q(q))) {
                qdio_release_q(q);
-#ifdef QDIO_PERFORMANCE_STATS
-               i_p_c++;
-#endif /* QDIO_PERFORMANCE_STATS */
+               if (qdio_performance_stats)
+                       i_p_c++;
                /* as we're sissies, we'll check next time */
                if (likely(!atomic_read(&q->is_in_shutdown))) {
                        qdio_mark_q(q);
@@ -1465,10 +1461,10 @@ __qdio_inbound_processing(struct qdio_q *q)
                }
                return;
        }
-#ifdef QDIO_PERFORMANCE_STATS
-       i_p_nc++;
-       perf_stats.tl_runs++;
-#endif /* QDIO_PERFORMANCE_STATS */
+       if (qdio_performance_stats) {
+               i_p_nc++;
+               perf_stats.tl_runs++;
+       }
 
 again:
        if (qdio_has_inbound_q_moved(q)) {
@@ -1514,9 +1510,8 @@ tiqdio_reset_processing_state(struct qdio_q *q, int q_laps)
 
        if (unlikely(qdio_reserve_q(q))) {
                qdio_release_q(q);
-#ifdef QDIO_PERFORMANCE_STATS
-               ii_p_c++;
-#endif /* QDIO_PERFORMANCE_STATS */
+               if (qdio_performance_stats)
+                       ii_p_c++;
                /* 
                 * as we might just be about to stop polling, we make
                 * sure that we check again at least once more 
@@ -1607,9 +1602,8 @@ tiqdio_tl(unsigned long data)
 {
        QDIO_DBF_TEXT4(0,trace,"iqdio_tl");
 
-#ifdef QDIO_PERFORMANCE_STATS
-       perf_stats.tl_runs++;
-#endif /* QDIO_PERFORMANCE_STATS */
+       if (qdio_performance_stats)
+               perf_stats.tl_runs++;
 
        tiqdio_inbound_checks();
 }
@@ -1637,7 +1631,7 @@ next:
 
        }
        kfree(irq_ptr->qdr);
-       kfree(irq_ptr);
+       free_page((unsigned long) irq_ptr);
 }
 
 static void
@@ -1686,16 +1680,14 @@ qdio_alloc_qs(struct qdio_irq *irq_ptr,
        int result=-ENOMEM;
 
        for (i=0;i<no_input_qs;i++) {
-               q=kmalloc(sizeof(struct qdio_q),GFP_KERNEL);
+               q = kzalloc(sizeof(struct qdio_q), GFP_KERNEL);
 
                if (!q) {
                        QDIO_PRINT_ERR("kmalloc of q failed!\n");
                        goto out;
                }
 
-               memset(q,0,sizeof(struct qdio_q));
-
-               q->slib=kmalloc(PAGE_SIZE,GFP_KERNEL);
+               q->slib = kmalloc(PAGE_SIZE, GFP_KERNEL);
                if (!q->slib) {
                        QDIO_PRINT_ERR("kmalloc of slib failed!\n");
                        goto out;
@@ -1705,14 +1697,12 @@ qdio_alloc_qs(struct qdio_irq *irq_ptr,
        }
 
        for (i=0;i<no_output_qs;i++) {
-               q=kmalloc(sizeof(struct qdio_q),GFP_KERNEL);
+               q = kzalloc(sizeof(struct qdio_q), GFP_KERNEL);
 
                if (!q) {
                        goto out;
                }
 
-               memset(q,0,sizeof(struct qdio_q));
-
                q->slib=kmalloc(PAGE_SIZE,GFP_KERNEL);
                if (!q->slib) {
                        QDIO_PRINT_ERR("kmalloc of slib failed!\n");
@@ -1743,7 +1733,7 @@ qdio_fill_qs(struct qdio_irq *irq_ptr, struct ccw_device *cdev,
        void *ptr;
        int available;
 
-       sprintf(dbf_text,"qfqs%4x",cdev->private->sch_no);
+       sprintf(dbf_text,"qfqs%4x",cdev->private->schid.sch_no);
        QDIO_DBF_TEXT0(0,setup,dbf_text);
        for (i=0;i<no_input_qs;i++) {
                q=irq_ptr->input_qs[i];
@@ -1834,6 +1824,10 @@ qdio_fill_qs(struct qdio_irq *irq_ptr, struct ccw_device *cdev,
                        q->sbal[j]=*(outbound_sbals_array++);
 
                 q->queue_type=q_format;
+               if ((q->queue_type == QDIO_IQDIO_QFMT) &&
+                   (no_output_qs > 1) &&
+                   (i == no_output_qs-1))
+                       q->queue_type = QDIO_IQDIO_QFMT_ASYNCH;
                q->int_parm=int_parm;
                q->is_input_q=0;
                q->schid = irq_ptr->schid;
@@ -1920,10 +1914,10 @@ tiqdio_thinint_handler(void)
 {
        QDIO_DBF_TEXT4(0,trace,"thin_int");
 
-#ifdef QDIO_PERFORMANCE_STATS
-       perf_stats.thinints++;
-       perf_stats.start_time_inbound=NOW;
-#endif /* QDIO_PERFORMANCE_STATS */
+       if (qdio_performance_stats) {
+               perf_stats.thinints++;
+               perf_stats.start_time_inbound=NOW;
+       }
 
        /* SVS only when needed:
         * issue SVS to benefit from iqdio interrupt avoidance
@@ -1966,8 +1960,8 @@ qdio_irq_check_sense(struct subchannel_id schid, struct irb *irb)
                QDIO_DBF_HEX0(0,sense,irb,QDIO_DBF_SENSE_LEN);
 
                QDIO_PRINT_WARN("sense data available on qdio channel.\n");
-               HEXDUMP16(WARN,"irb: ",irb);
-               HEXDUMP16(WARN,"sense data: ",irb->ecw);
+               QDIO_HEXDUMP16(WARN,"irb: ",irb);
+               QDIO_HEXDUMP16(WARN,"sense data: ",irb->ecw);
        }
                
 }
@@ -1978,18 +1972,17 @@ qdio_handle_pci(struct qdio_irq *irq_ptr)
        int i;
        struct qdio_q *q;
 
-#ifdef QDIO_PERFORMANCE_STATS
-       perf_stats.pcis++;
-       perf_stats.start_time_inbound=NOW;
-#endif /* QDIO_PERFORMANCE_STATS */
+       if (qdio_performance_stats) {
+               perf_stats.pcis++;
+               perf_stats.start_time_inbound=NOW;
+       }
        for (i=0;i<irq_ptr->no_input_qs;i++) {
                q=irq_ptr->input_qs[i];
                if (q->is_input_q&QDIO_FLAG_NO_INPUT_INTERRUPT_CONTEXT)
                        qdio_mark_q(q);
                else {
-#ifdef QDIO_PERFORMANCE_STATS
-                       perf_stats.tl_runs--;
-#endif /* QDIO_PERFORMANCE_STATS */
+                       if (qdio_performance_stats)
+                               perf_stats.tl_runs--;
                        __qdio_inbound_processing(q);
                }
        }
@@ -1997,11 +1990,10 @@ qdio_handle_pci(struct qdio_irq *irq_ptr)
                return;
        for (i=0;i<irq_ptr->no_output_qs;i++) {
                q=irq_ptr->output_qs[i];
-#ifdef QDIO_PERFORMANCE_STATS
-               perf_stats.tl_runs--;
-#endif /* QDIO_PERFORMANCE_STATS */
                if (qdio_is_outbound_q_done(q))
                        continue;
+               if (qdio_performance_stats)
+                       perf_stats.tl_runs--;
                if (!irq_ptr->sync_done_on_outb_pcis)
                        SYNC_MEMORY;
                __qdio_outbound_processing(q);
@@ -2047,11 +2039,13 @@ omit_handler_call:
 }
 
 static void
-qdio_call_shutdown(void *data)
+qdio_call_shutdown(struct work_struct *work)
 {
+       struct ccw_device_private *priv;
        struct ccw_device *cdev;
 
-       cdev = (struct ccw_device *)data;
+       priv = container_of(work, struct ccw_device_private, kick_work);
+       cdev = priv->cdev;
        qdio_shutdown(cdev, QDIO_FLAG_CLEANUP_USING_CLEAR);
        put_device(&cdev->dev);
 }
@@ -2093,7 +2087,7 @@ qdio_timeout_handler(struct ccw_device *cdev)
                if (get_device(&cdev->dev)) {
                        /* Can't call shutdown from interrupt context. */
                        PREPARE_WORK(&cdev->private->kick_work,
-                                    qdio_call_shutdown, (void *)cdev);
+                                    qdio_call_shutdown);
                        queue_work(ccw_device_work, &cdev->private->kick_work);
                }
                break;
@@ -2308,7 +2302,7 @@ qdio_get_ssqd_information(struct qdio_irq *irq_ptr)
 
        QDIO_DBF_TEXT0(0,setup,"getssqd");
        qdioac = 0;
-       ssqd_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
+       ssqd_area = mempool_alloc(qdio_mempool_scssc, GFP_ATOMIC);
        if (!ssqd_area) {
                QDIO_PRINT_WARN("Could not get memory for chsc. Using all " \
                                "SIGAs for sch x%x.\n", irq_ptr->schid.sch_no);
@@ -2368,7 +2362,7 @@ qdio_get_ssqd_information(struct qdio_irq *irq_ptr)
 out:
        qdio_check_subchannel_qebsm(irq_ptr, qdioac,
                                    ssqd_area->sch_token);
-       free_page ((unsigned long) ssqd_area);
+       mempool_free(ssqd_area, qdio_mempool_scssc);
        irq_ptr->qdioac = qdioac;
 }
 
@@ -2462,7 +2456,7 @@ tiqdio_set_subchannel_ind(struct qdio_irq *irq_ptr, int reset_to_zero)
                        virt_to_phys((volatile void *)irq_ptr->dev_st_chg_ind);
        }
 
-       scssc_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
+       scssc_area = mempool_alloc(qdio_mempool_scssc, GFP_ATOMIC);
        if (!scssc_area) {
                QDIO_PRINT_WARN("No memory for setting indicators on " \
                                "subchannel 0.%x.%x.\n",
@@ -2518,7 +2512,7 @@ tiqdio_set_subchannel_ind(struct qdio_irq *irq_ptr, int reset_to_zero)
        QDIO_DBF_HEX2(0,setup,&real_addr_dev_st_chg_ind,sizeof(unsigned long));
        result = 0;
 out:
-       free_page ((unsigned long) scssc_area);
+       mempool_free(scssc_area, qdio_mempool_scssc);
        return result;
 
 }
@@ -2547,7 +2541,7 @@ tiqdio_set_delay_target(struct qdio_irq *irq_ptr, unsigned long delay_target)
        if (!irq_ptr->is_thinint_irq)
                return -ENODEV;
 
-       scsscf_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
+       scsscf_area = mempool_alloc(qdio_mempool_scssc, GFP_ATOMIC);
        if (!scsscf_area) {
                QDIO_PRINT_WARN("No memory for setting delay target on " \
                                "subchannel 0.%x.%x.\n",
@@ -2585,7 +2579,7 @@ tiqdio_set_delay_target(struct qdio_irq *irq_ptr, unsigned long delay_target)
        QDIO_DBF_HEX2(0,trace,&delay_target,sizeof(unsigned long));
        result = 0; /* not critical */
 out:
-       free_page ((unsigned long) scsscf_area);
+       mempool_free(scsscf_area, qdio_mempool_scssc);
        return result;
 }
 
@@ -2737,7 +2731,7 @@ qdio_free(struct ccw_device *cdev)
        QDIO_DBF_TEXT1(0,trace,dbf_text);
        QDIO_DBF_TEXT0(0,setup,dbf_text);
 
-       cdev->private->qdio_data = 0;
+       cdev->private->qdio_data = NULL;
 
        up(&irq_ptr->setting_up_sema);
 
@@ -2926,7 +2920,7 @@ qdio_establish_handle_irq(struct ccw_device *cdev, int cstat, int dstat)
 
        irq_ptr = cdev->private->qdio_data;
 
-       sprintf(dbf_text,"qehi%4x",cdev->private->sch_no);
+       sprintf(dbf_text,"qehi%4x",cdev->private->schid.sch_no);
        QDIO_DBF_TEXT0(0,setup,dbf_text);
        QDIO_DBF_TEXT0(0,trace,dbf_text);
 
@@ -2945,7 +2939,7 @@ qdio_initialize(struct qdio_initialize *init_data)
        int rc;
        char dbf_text[15];
 
-       sprintf(dbf_text,"qini%4x",init_data->cdev->private->sch_no);
+       sprintf(dbf_text,"qini%4x",init_data->cdev->private->schid.sch_no);
        QDIO_DBF_TEXT0(0,setup,dbf_text);
        QDIO_DBF_TEXT0(0,trace,dbf_text);
 
@@ -2966,7 +2960,7 @@ qdio_allocate(struct qdio_initialize *init_data)
        struct qdio_irq *irq_ptr;
        char dbf_text[15];
 
-       sprintf(dbf_text,"qalc%4x",init_data->cdev->private->sch_no);
+       sprintf(dbf_text,"qalc%4x",init_data->cdev->private->schid.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) ||
@@ -2984,7 +2978,7 @@ qdio_allocate(struct qdio_initialize *init_data)
        qdio_allocate_do_dbf(init_data);
 
        /* create irq */
-       irq_ptr=kmalloc(sizeof(struct qdio_irq), GFP_KERNEL | GFP_DMA);
+       irq_ptr = (void *) get_zeroed_page(GFP_KERNEL | GFP_DMA);
 
        QDIO_DBF_TEXT0(0,setup,"irq_ptr:");
        QDIO_DBF_HEX0(0,setup,&irq_ptr,sizeof(void*));
@@ -2994,14 +2988,12 @@ qdio_allocate(struct qdio_initialize *init_data)
                return -ENOMEM;
        }
 
-       memset(irq_ptr,0,sizeof(struct qdio_irq));
-
        init_MUTEX(&irq_ptr->setting_up_sema);
 
        /* QDR must be in DMA area since CCW data address is only 32 bit */
        irq_ptr->qdr=kmalloc(sizeof(struct qdr), GFP_KERNEL | GFP_DMA);
        if (!(irq_ptr->qdr)) {
-               kfree(irq_ptr);
+               free_page((unsigned long) irq_ptr);
                QDIO_PRINT_ERR("kmalloc of irq_ptr->qdr failed!\n");
                return -ENOMEM;
                }
@@ -3191,7 +3183,7 @@ qdio_establish(struct qdio_initialize *init_data)
                tiqdio_set_delay_target(irq_ptr,TIQDIO_DELAY_TARGET);
        }
 
-       sprintf(dbf_text,"qest%4x",cdev->private->sch_no);
+       sprintf(dbf_text,"qest%4x",cdev->private->schid.sch_no);
        QDIO_DBF_TEXT0(0,setup,dbf_text);
        QDIO_DBF_TEXT0(0,trace,dbf_text);
 
@@ -3429,7 +3421,7 @@ do_qdio_handle_inbound(struct qdio_q *q, unsigned int callflags,
        
        if ((used_elements+count==QDIO_MAX_BUFFERS_PER_Q)&&
            (callflags&QDIO_FLAG_UNDER_INTERRUPT))
-               atomic_swap(&q->polling,0);
+               atomic_xchg(&q->polling,0);
        
        if (used_elements) 
                return;
@@ -3462,19 +3454,18 @@ do_qdio_handle_outbound(struct qdio_q *q, unsigned int callflags,
        struct qdio_irq *irq = (struct qdio_irq *) q->irq_ptr;
 
        /* This is the outbound handling of queues */
-#ifdef QDIO_PERFORMANCE_STATS
-       perf_stats.start_time_outbound=NOW;
-#endif /* QDIO_PERFORMANCE_STATS */
+       if (qdio_performance_stats)
+               perf_stats.start_time_outbound=NOW;
 
        qdio_do_qdio_fill_output(q,qidx,count,buffers);
 
        used_elements=atomic_add_return(count, &q->number_of_buffers_used) - count;
 
        if (callflags&QDIO_FLAG_DONT_SIGA) {
-#ifdef QDIO_PERFORMANCE_STATS
-               perf_stats.outbound_time+=NOW-perf_stats.start_time_outbound;
-               perf_stats.outbound_cnt++;
-#endif /* QDIO_PERFORMANCE_STATS */
+               if (qdio_performance_stats) {
+                       perf_stats.outbound_time+=NOW-perf_stats.start_time_outbound;
+                       perf_stats.outbound_cnt++;
+               }
                return;
        }
        if (q->is_iqdio_q) {
@@ -3504,9 +3495,8 @@ do_qdio_handle_outbound(struct qdio_q *q, unsigned int callflags,
                                qdio_kick_outbound_q(q);
                        } else {
                                QDIO_DBF_TEXT3(0,trace, "fast-req");
-#ifdef QDIO_PERFORMANCE_STATS
-                               perf_stats.fast_reqs++;
-#endif /* QDIO_PERFORMANCE_STATS */
+                               if (qdio_performance_stats)
+                                       perf_stats.fast_reqs++;
                        }
                }
                /* 
@@ -3517,10 +3507,10 @@ do_qdio_handle_outbound(struct qdio_q *q, unsigned int callflags,
                __qdio_outbound_processing(q);
        }
 
-#ifdef QDIO_PERFORMANCE_STATS
-       perf_stats.outbound_time+=NOW-perf_stats.start_time_outbound;
-       perf_stats.outbound_cnt++;
-#endif /* QDIO_PERFORMANCE_STATS */
+       if (qdio_performance_stats) {
+               perf_stats.outbound_time+=NOW-perf_stats.start_time_outbound;
+               perf_stats.outbound_cnt++;
+       }
 }
 
 /* count must be 1 in iqdio */
@@ -3533,7 +3523,7 @@ do_QDIO(struct ccw_device *cdev,unsigned int callflags,
 #ifdef CONFIG_QDIO_DEBUG
        char dbf_text[20];
 
-       sprintf(dbf_text,"doQD%04x",cdev->private->sch_no);
+       sprintf(dbf_text,"doQD%04x",cdev->private->schid.sch_no);
        QDIO_DBF_TEXT3(0,trace,dbf_text);
 #endif /* CONFIG_QDIO_DEBUG */
 
@@ -3578,7 +3568,6 @@ do_QDIO(struct ccw_device *cdev,unsigned int callflags,
        return 0;
 }
 
-#ifdef QDIO_PERFORMANCE_STATS
 static int
 qdio_perf_procfile_read(char *buffer, char **buffer_location, off_t offset,
                        int buffer_length, int *eof, void *data)
@@ -3594,29 +3583,29 @@ qdio_perf_procfile_read(char *buffer, char **buffer_location, off_t offset,
        _OUTP_IT("i_p_nc/c=%lu/%lu\n",i_p_nc,i_p_c);
        _OUTP_IT("ii_p_nc/c=%lu/%lu\n",ii_p_nc,ii_p_c);
        _OUTP_IT("o_p_nc/c=%lu/%lu\n",o_p_nc,o_p_c);
-       _OUTP_IT("Number of tasklet runs (total)                  : %u\n",
+       _OUTP_IT("Number of tasklet runs (total)                  : %lu\n",
                 perf_stats.tl_runs);
        _OUTP_IT("\n");
-       _OUTP_IT("Number of SIGA sync's issued                    : %u\n",
+       _OUTP_IT("Number of SIGA sync's issued                    : %lu\n",
                 perf_stats.siga_syncs);
-       _OUTP_IT("Number of SIGA in's issued                      : %u\n",
+       _OUTP_IT("Number of SIGA in's issued                      : %lu\n",
                 perf_stats.siga_ins);
-       _OUTP_IT("Number of SIGA out's issued                     : %u\n",
+       _OUTP_IT("Number of SIGA out's issued                     : %lu\n",
                 perf_stats.siga_outs);
-       _OUTP_IT("Number of PCIs caught                           : %u\n",
+       _OUTP_IT("Number of PCIs caught                           : %lu\n",
                 perf_stats.pcis);
-       _OUTP_IT("Number of adapter interrupts caught             : %u\n",
+       _OUTP_IT("Number of adapter interrupts caught             : %lu\n",
                 perf_stats.thinints);
-       _OUTP_IT("Number of fast requeues (outg. SBALs w/o SIGA)  : %u\n",
+       _OUTP_IT("Number of fast requeues (outg. SBALs w/o SIGA)  : %lu\n",
                 perf_stats.fast_reqs);
        _OUTP_IT("\n");
-       _OUTP_IT("Total time of all inbound actions (us) incl. UL : %u\n",
+       _OUTP_IT("Total time of all inbound actions (us) incl. UL : %lu\n",
                 perf_stats.inbound_time);
-       _OUTP_IT("Number of inbound transfers                     : %u\n",
+       _OUTP_IT("Number of inbound transfers                     : %lu\n",
                 perf_stats.inbound_cnt);
-       _OUTP_IT("Total time of all outbound do_QDIOs (us)        : %u\n",
+       _OUTP_IT("Total time of all outbound do_QDIOs (us)        : %lu\n",
                 perf_stats.outbound_time);
-       _OUTP_IT("Number of do_QDIOs outbound                     : %u\n",
+       _OUTP_IT("Number of do_QDIOs outbound                     : %lu\n",
                 perf_stats.outbound_cnt);
        _OUTP_IT("\n");
 
@@ -3624,12 +3613,10 @@ qdio_perf_procfile_read(char *buffer, char **buffer_location, off_t offset,
 }
 
 static struct proc_dir_entry *qdio_perf_proc_file;
-#endif /* QDIO_PERFORMANCE_STATS */
 
 static void
 qdio_add_procfs_entry(void)
 {
-#ifdef QDIO_PERFORMANCE_STATS
         proc_perf_file_registration=0;
        qdio_perf_proc_file=create_proc_entry(QDIO_PERF,
                                              S_IFREG|0444,&proc_root);
@@ -3641,20 +3628,58 @@ qdio_add_procfs_entry(void)
                 QDIO_PRINT_WARN("was not able to register perf. " \
                                "proc-file (%i).\n",
                                proc_perf_file_registration);
-#endif /* QDIO_PERFORMANCE_STATS */
 }
 
 static void
 qdio_remove_procfs_entry(void)
 {
-#ifdef QDIO_PERFORMANCE_STATS
        perf_stats.tl_runs=0;
 
         if (!proc_perf_file_registration) /* means if it went ok earlier */
                remove_proc_entry(QDIO_PERF,&proc_root);
-#endif /* QDIO_PERFORMANCE_STATS */
 }
 
+/**
+ * attributes in sysfs
+ *****************************************************************************/
+
+static ssize_t
+qdio_performance_stats_show(struct bus_type *bus, char *buf)
+{
+       return sprintf(buf, "%i\n", qdio_performance_stats ? 1 : 0);
+}
+
+static ssize_t
+qdio_performance_stats_store(struct bus_type *bus, const char *buf, size_t count)
+{
+       char *tmp;
+       int i;
+
+       i = simple_strtoul(buf, &tmp, 16);
+       if ((i == 0) || (i == 1)) {
+               if (i == qdio_performance_stats)
+                       return count;
+               qdio_performance_stats = i;
+               if (i==0) {
+                       /* reset perf. stat. info */
+                       i_p_nc = 0;
+                       i_p_c = 0;
+                       ii_p_nc = 0;
+                       ii_p_c = 0;
+                       o_p_nc = 0;
+                       o_p_c = 0;
+                       memset(&perf_stats, 0, sizeof(struct qdio_perf_stats));
+               }
+       } else {
+               QDIO_PRINT_WARN("QDIO performance_stats: write 0 or 1 to this file!\n");
+               return -EINVAL;
+       }
+       return count;
+}
+
+static BUS_ATTR(qdio_performance_stats, 0644, qdio_performance_stats_show,
+                       qdio_performance_stats_store);
+
 static void
 tiqdio_register_thinints(void)
 {
@@ -3686,10 +3711,10 @@ qdio_get_qdio_memory(void)
 
        for (i=1;i<INDICATORS_PER_CACHELINE;i++)
                indicator_used[i]=0;
-       indicators=(__u32*)kmalloc(sizeof(__u32)*(INDICATORS_PER_CACHELINE),
+       indicators = kzalloc(sizeof(__u32)*(INDICATORS_PER_CACHELINE),
                                   GFP_KERNEL);
-               if (!indicators) return -ENOMEM;
-       memset(indicators,0,sizeof(__u32)*(INDICATORS_PER_CACHELINE));
+               if (!indicators)
+               return -ENOMEM;
        return 0;
 }
 
@@ -3699,6 +3724,7 @@ qdio_release_qdio_memory(void)
        kfree(indicators);
 }
 
+
 static void
 qdio_unregister_dbf_views(void)
 {
@@ -3786,13 +3812,21 @@ oom:
        return -ENOMEM;
 }
 
+static void *qdio_mempool_alloc(gfp_t gfp_mask, void *size)
+{
+       return (void *) get_zeroed_page(gfp_mask|GFP_DMA);
+}
+
+static void qdio_mempool_free(void *element, void *size)
+{
+       free_page((unsigned long) element);
+}
+
 static int __init
 init_QDIO(void)
 {
        int res;
-#ifdef QDIO_PERFORMANCE_STATS
        void *ptr;
-#endif /* QDIO_PERFORMANCE_STATS */
 
        printk("qdio: loading %s\n",version);
 
@@ -3805,16 +3839,19 @@ init_QDIO(void)
                return res;
 
        QDIO_DBF_TEXT0(0,setup,"initQDIO");
+       res = bus_create_file(&ccw_bus_type, &bus_attr_qdio_performance_stats);
 
-#ifdef QDIO_PERFORMANCE_STATS
-               memset((void*)&perf_stats,0,sizeof(perf_stats));
+       memset((void*)&perf_stats,0,sizeof(perf_stats));
        QDIO_DBF_TEXT0(0,setup,"perfstat");
        ptr=&perf_stats;
        QDIO_DBF_HEX0(0,setup,&ptr,sizeof(void*));
-#endif /* QDIO_PERFORMANCE_STATS */
 
        qdio_add_procfs_entry();
 
+       qdio_mempool_scssc = mempool_create(QDIO_MEMPOOL_SCSSC_ELEMENTS,
+                                           qdio_mempool_alloc,
+                                           qdio_mempool_free, NULL);
+
        if (tiqdio_check_chsc_availability())
                QDIO_PRINT_ERR("Not all CHSCs supported. Continuing.\n");
 
@@ -3830,7 +3867,8 @@ cleanup_QDIO(void)
        qdio_remove_procfs_entry();
        qdio_release_qdio_memory();
        qdio_unregister_dbf_views();
-
+       mempool_destroy(qdio_mempool_scssc);
+       bus_remove_file(&ccw_bus_type, &bus_attr_qdio_performance_stats);
        printk("qdio: %s: module removed\n",version);
 }