From f26fd5d6e5006eae75a389c7ce74ed16761d094b Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Tue, 16 Sep 2008 09:32:18 -0700 Subject: [S390] cio: Fix driver_data handling for ccwgroup devices. Since 16f7f9564c3ae190954f2ec55f385a268b93ac4d, we've seen oopses when grouping/ungrouping devices: Unable to handle kernel pointer dereference at virtual kernel address 0000000000 114000 Oops: 0004 [#1] PREEMPT SMP Modules linked in: bonding qeth_l2 dm_multipath sunrpc qeth_l3 dm_mod qeth chsc_ sch ccwgroup CPU: 1 Not tainted 2.6.26-29.x.20080815-s390xdefault #1 Process iperf (pid: 24412, task: 000000003f446038, ksp: 000000003c929e08) Krnl PSW : 0404d00180000000 000003e00006f6e6 (qeth_irq+0xda/0xb28 [qeth]) R:0 T:1 IO:0 EX:0 Key:0 M:1 W:0 P:0 AS:3 CC:1 PM:0 EA:3 Krnl GPRS: 0000000000000000 000003e000000003 0000000000000000 0000000000114ccc 000000003fb82e48 000003e00006f60c 000000000000000c 000000003ce72100 0000000000114944 000000003fb82e48 0000000000114ccc 000000003fe8fd28 000003e000066000 000003e000076128 000000003fe8fdb8 000000003fe8fd28 Krnl Code: 000003e00006f6da: bf3f2024 icm %r3,15,36(%r2) 000003e00006f6de: a774023c brc 7,3e00006fb56 000003e00006f6e2: a7280000 lhi %r2,0 >000003e00006f6e6: 5020a1a0 st %r2,416(%r10) 000003e00006f6ea: 58109000 l %r1,0(%r9) 000003e00006f6ee: a7111000 tmll %r1,4096 000003e00006f6f2: a77400f9 brc 7,3e00006f8e4 000003e00006f6f6: 8810000c srl %r1,12 Call Trace: ([<000000003fe8fd20>] 0x3fe8fd20) [<000000000033bf2a>] ccw_device_call_handler+0xb2/0xd8 [<0000000000339e1c>] ccw_device_irq+0x124/0x164 [<0000000000339758>] io_subchannel_irq+0x8c/0x118 [<00000000003309ba>] do_IRQ+0x192/0x1bc [<0000000000114f66>] io_return+0x0/0x8 [<00000000001149cc>] sysc_do_svc+0x0/0x22 ([<0000000000114a18>] sysc_noemu+0x10/0x16) [<00000200002e047c>] 0x200002e047c Last Breaking-Event-Address: [<000003e00006f6d6>] qeth_irq+0xca/0xb28 [qeth] The problem is that dev->driver_data for a ccw device is NULL, while it should point to the ccwgroup device it is a member of. This happened due to incorrect cleanup if creating a ccwgroup device failed because the ccw devices were already grouped. Fix this by setting cdev[i] to NULL in the error handling of ccwgroup_create_from_string() after we give up our reference and by checking if the driver_data points to the ccwgroup device in ccwgroup_release() just to be really sure. Signed-off-by: Cornelia Huck Signed-off-by: Martin Schwidefsky --- drivers/s390/cio/ccwgroup.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/s390/cio') diff --git a/drivers/s390/cio/ccwgroup.c b/drivers/s390/cio/ccwgroup.c index e0ce65fca4e..9a50f245774 100644 --- a/drivers/s390/cio/ccwgroup.c +++ b/drivers/s390/cio/ccwgroup.c @@ -113,7 +113,8 @@ ccwgroup_release (struct device *dev) for (i = 0; i < gdev->count; i++) { if (gdev->cdev[i]) { - dev_set_drvdata(&gdev->cdev[i]->dev, NULL); + if (dev_get_drvdata(&gdev->cdev[i]->dev) == gdev) + dev_set_drvdata(&gdev->cdev[i]->dev, NULL); put_device(&gdev->cdev[i]->dev); } } @@ -296,6 +297,7 @@ error: if (dev_get_drvdata(&gdev->cdev[i]->dev) == gdev) dev_set_drvdata(&gdev->cdev[i]->dev, NULL); put_device(&gdev->cdev[i]->dev); + gdev->cdev[i] = NULL; } mutex_unlock(&gdev->reg_mutex); put_device(&gdev->dev); -- cgit v1.2.3-70-g09d2 From 9adb8c1d4f0ac78b3469e377ce5f8a846cbaedaf Mon Sep 17 00:00:00 2001 From: Stefan Weinhuber Date: Tue, 16 Sep 2008 09:32:19 -0700 Subject: [S390] cio: fix orb initialization in cio_start_key The functions cio_tm_start_key and cio_start_key use the same private orb structure of a subchannel, so the orb needs to be cleared of old data before it is used again. A respective memset is missing from cio_start_key and hereby added. Signed-off-by: Stefan Weinhuber Acked-by: Cornelia Huck Signed-off-by: Martin Schwidefsky --- drivers/s390/cio/cio.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/s390/cio') diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c index 5954b905e3c..326f4cc7f92 100644 --- a/drivers/s390/cio/cio.c +++ b/drivers/s390/cio/cio.c @@ -174,6 +174,7 @@ cio_start_key (struct subchannel *sch, /* subchannel structure */ CIO_TRACE_EVENT(4, sch->dev.bus_id); orb = &to_io_private(sch)->orb; + memset(orb, 0, sizeof(union orb)); /* sch is always under 2G. */ orb->cmd.intparm = (u32)(addr_t)sch; orb->cmd.fmt = 1; -- cgit v1.2.3-70-g09d2 From 75f6276187e5ce5a312a0619fba2fe56c9290b48 Mon Sep 17 00:00:00 2001 From: Jan Glauber Date: Fri, 3 Oct 2008 21:55:00 +0200 Subject: [S390] qdio: prevent stack clobber Don't print more information than fits into the string on the stack. Combine the informational output of qdio to fit into one line. Signed-off-by: Jan Glauber Signed-off-by: Martin Schwidefsky --- drivers/s390/cio/qdio_setup.c | 55 ++++++++++++++++--------------------------- 1 file changed, 20 insertions(+), 35 deletions(-) (limited to 'drivers/s390/cio') diff --git a/drivers/s390/cio/qdio_setup.c b/drivers/s390/cio/qdio_setup.c index 1679e2f91c9..a0b6b46e746 100644 --- a/drivers/s390/cio/qdio_setup.c +++ b/drivers/s390/cio/qdio_setup.c @@ -447,51 +447,36 @@ void qdio_print_subchannel_info(struct qdio_irq *irq_ptr, { char s[80]; - sprintf(s, "%s sc:%x ", cdev->dev.bus_id, irq_ptr->schid.sch_no); - + sprintf(s, "qdio: %s ", dev_name(&cdev->dev)); switch (irq_ptr->qib.qfmt) { case QDIO_QETH_QFMT: - sprintf(s + strlen(s), "OSADE "); + sprintf(s + strlen(s), "OSA "); break; case QDIO_ZFCP_QFMT: sprintf(s + strlen(s), "ZFCP "); break; case QDIO_IQDIO_QFMT: - sprintf(s + strlen(s), "HiperSockets "); + sprintf(s + strlen(s), "HS "); break; } - sprintf(s + strlen(s), "using: "); - - if (!is_thinint_irq(irq_ptr)) - sprintf(s + strlen(s), "no"); - sprintf(s + strlen(s), "AdapterInterrupts "); - if (!(irq_ptr->sch_token != 0)) - sprintf(s + strlen(s), "no"); - sprintf(s + strlen(s), "QEBSM "); - if (!(irq_ptr->qib.ac & QIB_AC_OUTBOUND_PCI_SUPPORTED)) - sprintf(s + strlen(s), "no"); - sprintf(s + strlen(s), "OutboundPCI "); - if (!css_general_characteristics.aif_tdd) - sprintf(s + strlen(s), "no"); - sprintf(s + strlen(s), "TDD\n"); - printk(KERN_INFO "qdio: %s", s); - - memset(s, 0, sizeof(s)); - sprintf(s, "%s SIGA required: ", cdev->dev.bus_id); - if (irq_ptr->siga_flag.input) - sprintf(s + strlen(s), "Read "); - if (irq_ptr->siga_flag.output) - sprintf(s + strlen(s), "Write "); - if (irq_ptr->siga_flag.sync) - sprintf(s + strlen(s), "Sync "); - if (!irq_ptr->siga_flag.no_sync_ti) - sprintf(s + strlen(s), "SyncAI "); - if (!irq_ptr->siga_flag.no_sync_out_ti) - sprintf(s + strlen(s), "SyncOutAI "); - if (!irq_ptr->siga_flag.no_sync_out_pci) - sprintf(s + strlen(s), "SyncOutPCI"); + sprintf(s + strlen(s), "on SC %x using ", irq_ptr->schid.sch_no); + sprintf(s + strlen(s), "AI:%d ", is_thinint_irq(irq_ptr)); + sprintf(s + strlen(s), "QEBSM:%d ", (irq_ptr->sch_token) ? 1 : 0); + sprintf(s + strlen(s), "PCI:%d ", + (irq_ptr->qib.ac & QIB_AC_OUTBOUND_PCI_SUPPORTED) ? 1 : 0); + sprintf(s + strlen(s), "TDD:%d ", css_general_characteristics.aif_tdd); + sprintf(s + strlen(s), "SIGA:"); + sprintf(s + strlen(s), "%s", (irq_ptr->siga_flag.input) ? "R" : " "); + sprintf(s + strlen(s), "%s", (irq_ptr->siga_flag.output) ? "W" : " "); + sprintf(s + strlen(s), "%s", (irq_ptr->siga_flag.sync) ? "S" : " "); + sprintf(s + strlen(s), "%s", + (!irq_ptr->siga_flag.no_sync_ti) ? "A" : " "); + sprintf(s + strlen(s), "%s", + (!irq_ptr->siga_flag.no_sync_out_ti) ? "O" : " "); + sprintf(s + strlen(s), "%s", + (!irq_ptr->siga_flag.no_sync_out_pci) ? "P" : " "); sprintf(s + strlen(s), "\n"); - printk(KERN_INFO "qdio: %s", s); + printk(KERN_INFO "%s", s); } int __init qdio_setup_init(void) -- cgit v1.2.3-70-g09d2