Commit fefe4ef5 authored by Martin Schwidefsky's avatar Martin Schwidefsky Committed by Linus Torvalds

[PATCH] s390: common i/o layer update.

Common i/o layer fixes:
 - Fix for path no operational condition in cio_start.
 - Fix handling of user interruption parameter.
 - Add code to wait for devices in init_ccw_bus_type.
 - Move qdio states out of main cio state machine.
 - Reworked chsc data structures.
 - Add ccw_device_start_timeout.
 - Handle path verification required flag.
parent 71e25a79
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
* drivers/s390/cio/airq.c * drivers/s390/cio/airq.c
* S/390 common I/O routines -- support for adapter interruptions * S/390 common I/O routines -- support for adapter interruptions
* *
* $Revision: 1.10 $ * $Revision: 1.11 $
* *
* Copyright (C) 1999-2002 IBM Deutschland Entwicklung GmbH, * Copyright (C) 1999-2002 IBM Deutschland Entwicklung GmbH,
* IBM Corporation * IBM Corporation
...@@ -87,14 +87,14 @@ s390_unregister_adapter_interrupt (adapter_int_handler_t handler) ...@@ -87,14 +87,14 @@ s390_unregister_adapter_interrupt (adapter_int_handler_t handler)
} }
void void
do_adapter_IO (__u32 intparm) do_adapter_IO (void)
{ {
CIO_TRACE_EVENT (4, "doaio"); CIO_TRACE_EVENT (4, "doaio");
spin_lock (&adapter_lock); spin_lock (&adapter_lock);
if (adapter_handler) if (adapter_handler)
(*adapter_handler) (intparm); (*adapter_handler) ();
spin_unlock (&adapter_lock); spin_unlock (&adapter_lock);
......
#ifndef S390_AINTERRUPT_H #ifndef S390_AINTERRUPT_H
#define S390_AINTERRUPT_H #define S390_AINTERRUPT_H
typedef int (*adapter_int_handler_t)(__u32 intparm); typedef int (*adapter_int_handler_t)(void);
extern int s390_register_adapter_interrupt(adapter_int_handler_t handler); extern int s390_register_adapter_interrupt(adapter_int_handler_t handler);
extern int s390_unregister_adapter_interrupt(adapter_int_handler_t handler); extern int s390_unregister_adapter_interrupt(adapter_int_handler_t handler);
extern void do_adapter_IO (__u32 intparm); extern void do_adapter_IO (void);
#endif #endif
This diff is collapsed.
...@@ -12,85 +12,10 @@ ...@@ -12,85 +12,10 @@
#define CHSC_SEI_ACC_LINKADDR 2 #define CHSC_SEI_ACC_LINKADDR 2
#define CHSC_SEI_ACC_FULLLINKADDR 3 #define CHSC_SEI_ACC_FULLLINKADDR 3
struct sei_area { struct chsc_header {
struct { u16 length;
/* word 0 */ u16 code;
__u16 command_code1; };
__u16 command_code2;
/* word 1 */
__u32 reserved1;
/* word 2 */
__u32 reserved2;
/* word 3 */
__u32 reserved3;
} __attribute__ ((packed,aligned(8))) request_block;
struct {
/* word 0 */
__u16 length;
__u16 response_code;
/* word 1 */
__u32 reserved1;
/* word 2 */
__u8 flags;
__u8 vf; /* validity flags */
__u8 rs; /* reporting source */
__u8 cc; /* content code */
/* word 3 */
__u16 fla; /* full link address */
__u16 rsid; /* reporting source id */
/* word 4 */
__u32 reserved2;
/* word 5 */
__u32 reserved3;
/* word 6 */
__u32 ccdf; /* content-code dependent field */
/* word 7 */
__u32 reserved4;
/* word 8 */
__u32 reserved5;
/* word 9 */
__u32 reserved6;
} __attribute__ ((packed,aligned(8))) response_block;
} __attribute__ ((packed,aligned(PAGE_SIZE)));
struct ssd_area {
struct {
/* word 0 */
__u16 command_code1;
__u16 command_code2;
/* word 1 */
__u16 reserved1;
__u16 f_sch; /* first subchannel */
/* word 2 */
__u16 reserved2;
__u16 l_sch; /* last subchannel */
/* word 3 */
__u32 reserved3;
} __attribute__ ((packed,aligned(8))) request_block;
struct {
/* word 0 */
__u16 length;
__u16 response_code;
/* word 1 */
__u32 reserved1;
/* word 2 */
__u8 sch_valid : 1;
__u8 dev_valid : 1;
__u8 st : 3; /* subchannel type */
__u8 zeroes : 3;
__u8 unit_addr; /* unit address */
__u16 devno; /* device number */
/* word 3 */
__u8 path_mask;
__u8 fla_valid_mask;
__u16 sch; /* subchannel */
/* words 4-5 */
__u8 chpid[8]; /* chpids 0-7 */
/* words 6-9 */
__u16 fla[8]; /* full link addresses 0-7 */
} __attribute__ ((packed,aligned(8))) response_block;
} __attribute__ ((packed,aligned(PAGE_SIZE)));
struct channel_path { struct channel_path {
int id; int id;
......
/* /*
* drivers/s390/cio/cio.c * drivers/s390/cio/cio.c
* S/390 common I/O routines -- low level i/o calls * S/390 common I/O routines -- low level i/o calls
* $Revision: 1.91 $ * $Revision: 1.97 $
* *
* Copyright (C) 1999-2002 IBM Deutschland Entwicklung GmbH, * Copyright (C) 1999-2002 IBM Deutschland Entwicklung GmbH,
* IBM Corporation * IBM Corporation
...@@ -176,13 +176,13 @@ cio_start_handle_notoper(struct subchannel *sch, __u8 lpm) ...@@ -176,13 +176,13 @@ cio_start_handle_notoper(struct subchannel *sch, __u8 lpm)
CIO_TRACE_EVENT(0, dbf_text); CIO_TRACE_EVENT(0, dbf_text);
CIO_HEX_EVENT(0, &sch->schib, sizeof (struct schib)); CIO_HEX_EVENT(0, &sch->schib, sizeof (struct schib));
return -ENODEV; return (sch->lpm ? -EACCES : -ENODEV);
} }
int int
cio_start (struct subchannel *sch, /* subchannel structure */ cio_start (struct subchannel *sch, /* subchannel structure */
struct ccw1 * cpa, /* logical channel prog addr */ struct ccw1 * cpa, /* logical channel prog addr */
unsigned long intparm, /* interruption parameter */ unsigned int intparm, /* interruption parameter */
__u8 lpm) /* logical path mask */ __u8 lpm) /* logical path mask */
{ {
char dbf_txt[15]; char dbf_txt[15];
...@@ -191,7 +191,7 @@ cio_start (struct subchannel *sch, /* subchannel structure */ ...@@ -191,7 +191,7 @@ cio_start (struct subchannel *sch, /* subchannel structure */
sprintf (dbf_txt, "stIO%x", sch->irq); sprintf (dbf_txt, "stIO%x", sch->irq);
CIO_TRACE_EVENT (4, dbf_txt); CIO_TRACE_EVENT (4, dbf_txt);
sch->orb.intparm = (__u32) (long) &sch->u_intparm; sch->orb.intparm = intparm;
sch->orb.fmt = 1; sch->orb.fmt = 1;
sch->orb.pfch = sch->options.prefetch == 0; sch->orb.pfch = sch->options.prefetch == 0;
...@@ -219,7 +219,6 @@ cio_start (struct subchannel *sch, /* subchannel structure */ ...@@ -219,7 +219,6 @@ cio_start (struct subchannel *sch, /* subchannel structure */
/* /*
* initialize device status information * initialize device status information
*/ */
sch->u_intparm = intparm;
sch->schib.scsw.actl |= SCSW_ACTL_START_PEND; sch->schib.scsw.actl |= SCSW_ACTL_START_PEND;
return 0; return 0;
case 1: /* status pending */ case 1: /* status pending */
...@@ -265,13 +264,10 @@ cio_resume (struct subchannel *sch) ...@@ -265,13 +264,10 @@ cio_resume (struct subchannel *sch)
} }
/* /*
* Note: The "intparm" parameter is not used by the halt_IO() function * halt I/O operation
* itself, as no ORB is built for the HSCH instruction. However,
* it allows the device interrupt handler to associate the upcoming
* interrupt with the halt_IO() request.
*/ */
int int
cio_halt(struct subchannel *sch, unsigned long intparm) cio_halt(struct subchannel *sch)
{ {
char dbf_txt[15]; char dbf_txt[15];
int ccode; int ccode;
...@@ -297,7 +293,6 @@ cio_halt(struct subchannel *sch, unsigned long intparm) ...@@ -297,7 +293,6 @@ cio_halt(struct subchannel *sch, unsigned long intparm)
switch (ccode) { switch (ccode) {
case 0: case 0:
sch->u_intparm = intparm;
sch->schib.scsw.actl |= SCSW_ACTL_HALT_PEND; sch->schib.scsw.actl |= SCSW_ACTL_HALT_PEND;
return 0; return 0;
case 1: /* status pending */ case 1: /* status pending */
...@@ -309,13 +304,10 @@ cio_halt(struct subchannel *sch, unsigned long intparm) ...@@ -309,13 +304,10 @@ cio_halt(struct subchannel *sch, unsigned long intparm)
} }
/* /*
* Note: The "intparm" parameter is not used by the clear_IO() function * Clear I/O operation
* itself, as no ORB is built for the CSCH instruction. However,
* it allows the device interrupt handler to associate the upcoming
* interrupt with the clear_IO() request.
*/ */
int int
cio_clear(struct subchannel *sch, unsigned long intparm) cio_clear(struct subchannel *sch)
{ {
char dbf_txt[15]; char dbf_txt[15];
int ccode; int ccode;
...@@ -340,7 +332,6 @@ cio_clear(struct subchannel *sch, unsigned long intparm) ...@@ -340,7 +332,6 @@ cio_clear(struct subchannel *sch, unsigned long intparm)
switch (ccode) { switch (ccode) {
case 0: case 0:
sch->u_intparm = intparm;
sch->schib.scsw.actl |= SCSW_ACTL_CLEAR_PEND; sch->schib.scsw.actl |= SCSW_ACTL_CLEAR_PEND;
return 0; return 0;
default: /* device not operational */ default: /* device not operational */
...@@ -374,6 +365,8 @@ cio_cancel (struct subchannel *sch) ...@@ -374,6 +365,8 @@ cio_cancel (struct subchannel *sch)
switch (ccode) { switch (ccode) {
case 0: /* success */ case 0: /* success */
/* Update information in scsw. */
stsch (sch->irq, &sch->schib);
return 0; return 0;
case 1: /* status pending */ case 1: /* status pending */
return -EBUSY; return -EBUSY;
...@@ -620,7 +613,7 @@ do_IRQ (struct pt_regs regs) ...@@ -620,7 +613,7 @@ do_IRQ (struct pt_regs regs)
*/ */
if (tpi_info->adapter_IO == 1 && if (tpi_info->adapter_IO == 1 &&
tpi_info->int_type == IO_INTERRUPT_TYPE) { tpi_info->int_type == IO_INTERRUPT_TYPE) {
do_adapter_IO (tpi_info->intparm); do_adapter_IO();
continue; continue;
} }
sch = ioinfo[tpi_info->irq]; sch = ioinfo[tpi_info->irq];
......
...@@ -98,8 +98,6 @@ struct subchannel { ...@@ -98,8 +98,6 @@ struct subchannel {
__u8 vpm; /* verified path mask */ __u8 vpm; /* verified path mask */
__u8 lpm; /* logical path mask */ __u8 lpm; /* logical path mask */
// TODO: intparm for second start i/o
unsigned long u_intparm; /* user interruption parameter */
struct schib schib; /* subchannel information block */ struct schib schib; /* subchannel information block */
struct orb orb; /* operation request block */ struct orb orb; /* operation request block */
struct ccw1 sense_ccw; /* static ccw for sense command */ struct ccw1 sense_ccw; /* static ccw for sense command */
...@@ -116,11 +114,10 @@ extern int cio_validate_subchannel (struct subchannel *, unsigned int); ...@@ -116,11 +114,10 @@ extern int cio_validate_subchannel (struct subchannel *, unsigned int);
extern int cio_enable_subchannel (struct subchannel *, unsigned int); extern int cio_enable_subchannel (struct subchannel *, unsigned int);
extern int cio_disable_subchannel (struct subchannel *); extern int cio_disable_subchannel (struct subchannel *);
extern int cio_cancel (struct subchannel *); extern int cio_cancel (struct subchannel *);
extern int cio_clear (struct subchannel *, unsigned long); extern int cio_clear (struct subchannel *);
extern int cio_do_io (struct subchannel *, struct ccw1 *, unsigned long, __u8);
extern int cio_resume (struct subchannel *); extern int cio_resume (struct subchannel *);
extern int cio_halt (struct subchannel *, unsigned long); extern int cio_halt (struct subchannel *);
extern int cio_start (struct subchannel *, struct ccw1 *, unsigned long, __u8); extern int cio_start (struct subchannel *, struct ccw1 *, unsigned int, __u8);
extern int cio_cancel (struct subchannel *); extern int cio_cancel (struct subchannel *);
extern int cio_set_options (struct subchannel *, int); extern int cio_set_options (struct subchannel *, int);
extern int cio_get_options (struct subchannel *); extern int cio_get_options (struct subchannel *);
......
/* /*
* drivers/s390/cio/css.c * drivers/s390/cio/css.c
* driver for channel subsystem * driver for channel subsystem
* $Revision: 1.40 $ * $Revision: 1.43 $
* *
* Copyright (C) 2002 IBM Deutschland Entwicklung GmbH, * Copyright (C) 2002 IBM Deutschland Entwicklung GmbH,
* IBM Corporation * IBM Corporation
...@@ -41,7 +41,7 @@ css_alloc_subchannel(int irq) ...@@ -41,7 +41,7 @@ css_alloc_subchannel(int irq)
/* There already is a struct subchannel for this irq. */ /* There already is a struct subchannel for this irq. */
return -EBUSY; return -EBUSY;
sch = kmalloc (sizeof (*sch), GFP_DMA); sch = kmalloc (sizeof (*sch), GFP_KERNEL | GFP_DMA);
if (sch == NULL) if (sch == NULL)
return -ENOMEM; return -ENOMEM;
ret = cio_validate_subchannel (sch, irq); ret = cio_validate_subchannel (sch, irq);
...@@ -161,7 +161,7 @@ css_process_crw(int irq) ...@@ -161,7 +161,7 @@ css_process_crw(int irq)
sch = ioinfo[irq]; sch = ioinfo[irq];
if (sch == NULL) { if (sch == NULL) {
schedule_work(&work); queue_work(ccw_device_work, &work);
return; return;
} }
if (!sch->dev.driver_data) if (!sch->dev.driver_data)
...@@ -172,7 +172,7 @@ css_process_crw(int irq) ...@@ -172,7 +172,7 @@ css_process_crw(int irq)
ccode = stsch(irq, &sch->schib); ccode = stsch(irq, &sch->schib);
if (!ccode) if (!ccode)
if (devno != sch->schib.pmcw.dev) if (devno != sch->schib.pmcw.dev)
schedule_work(&work); queue_work(ccw_device_work, &work);
} }
/* /*
......
...@@ -79,6 +79,7 @@ struct ccw_device_private { ...@@ -79,6 +79,7 @@ struct ccw_device_private {
unsigned int esid:1; /* Ext. SenseID supported by HW */ unsigned int esid:1; /* Ext. SenseID supported by HW */
unsigned int dosense:1; /* delayed SENSE required */ unsigned int dosense:1; /* delayed SENSE required */
} __attribute__((packed)) flags; } __attribute__((packed)) flags;
unsigned long intparm; /* user interruption parameter */
struct qdio_irq *qdio_data; struct qdio_irq *qdio_data;
struct irb irb; /* device status */ struct irb irb; /* device status */
struct senseid senseid; /* SenseID info */ struct senseid senseid; /* SenseID info */
......
/* /*
* drivers/s390/cio/device.c * drivers/s390/cio/device.c
* bus driver for ccw devices * bus driver for ccw devices
* $Revision: 1.50 $ * $Revision: 1.53 $
* *
* Copyright (C) 2002 IBM Deutschland Entwicklung GmbH, * Copyright (C) 2002 IBM Deutschland Entwicklung GmbH,
* IBM Corporation * IBM Corporation
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/list.h> #include <linux/list.h>
#include <linux/device.h> #include <linux/device.h>
#include <linux/workqueue.h>
#include <asm/ccwdev.h> #include <asm/ccwdev.h>
#include <asm/cio.h> #include <asm/cio.h>
...@@ -126,14 +127,32 @@ static struct css_driver io_subchannel_driver = { ...@@ -126,14 +127,32 @@ static struct css_driver io_subchannel_driver = {
.irq = io_subchannel_irq, .irq = io_subchannel_irq,
}; };
struct workqueue_struct *ccw_device_work;
static wait_queue_head_t ccw_device_init_wq;
static atomic_t ccw_device_init_count;
static int __init static int __init
init_ccw_bus_type (void) init_ccw_bus_type (void)
{ {
int ret; int ret;
init_waitqueue_head(&ccw_device_init_wq);
atomic_set(&ccw_device_init_count, 0);
ccw_device_work = create_workqueue("cio");
if (!ccw_device_work)
return -ENOMEM; /* FIXME: better errno ? */
if ((ret = bus_register (&ccw_bus_type))) if ((ret = bus_register (&ccw_bus_type)))
return ret; return ret;
return driver_register(&io_subchannel_driver.drv); if ((ret = driver_register(&io_subchannel_driver.drv)))
return ret;
wait_event(ccw_device_init_wq,
atomic_read(&ccw_device_init_count) == 0);
flush_workqueue(ccw_device_work);
return 0;
} }
static void __exit static void __exit
...@@ -141,6 +160,7 @@ cleanup_ccw_bus_type (void) ...@@ -141,6 +160,7 @@ cleanup_ccw_bus_type (void)
{ {
driver_unregister(&io_subchannel_driver.drv); driver_unregister(&io_subchannel_driver.drv);
bus_unregister(&ccw_bus_type); bus_unregister(&ccw_bus_type);
destroy_workqueue(ccw_device_work);
} }
subsys_initcall(init_ccw_bus_type); subsys_initcall(init_ccw_bus_type);
...@@ -360,7 +380,7 @@ ccw_device_release(struct device *dev) ...@@ -360,7 +380,7 @@ ccw_device_release(struct device *dev)
/* /*
* Register recognized device. * Register recognized device.
*/ */
void static void
io_subchannel_register(void *data) io_subchannel_register(void *data)
{ {
struct ccw_device *cdev; struct ccw_device *cdev;
...@@ -389,6 +409,42 @@ io_subchannel_register(void *data) ...@@ -389,6 +409,42 @@ io_subchannel_register(void *data)
put_device(&sch->dev); put_device(&sch->dev);
} }
/*
* subchannel recognition done. Called from the state machine.
*/
void
io_subchannel_recog_done(struct ccw_device *cdev)
{
struct subchannel *sch;
if (css_init_done == 0)
return;
switch (cdev->private->state) {
case DEV_STATE_NOT_OPER:
/* Remove device found not operational. */
sch = to_subchannel(cdev->dev.parent);
sch->dev.driver_data = 0;
put_device(&sch->dev);
if (cdev->dev.release)
cdev->dev.release(&cdev->dev);
break;
case DEV_STATE_OFFLINE:
/*
* We can't register the device in interrupt context so
* we schedule a work item.
*/
INIT_WORK(&cdev->private->kick_work,
io_subchannel_register, (void *) cdev);
queue_work(ccw_device_work, &cdev->private->kick_work);
break;
case DEV_STATE_BOXED:
/* Device did not respond in time. */
break;
}
if (atomic_dec_and_test(&ccw_device_init_count))
wake_up(&ccw_device_init_wq);
}
static void static void
io_subchannel_recog(struct ccw_device *cdev, struct subchannel *sch) io_subchannel_recog(struct ccw_device *cdev, struct subchannel *sch)
{ {
...@@ -419,6 +475,9 @@ io_subchannel_recog(struct ccw_device *cdev, struct subchannel *sch) ...@@ -419,6 +475,9 @@ io_subchannel_recog(struct ccw_device *cdev, struct subchannel *sch)
/* Do first half of device_register. */ /* Do first half of device_register. */
device_initialize(&cdev->dev); device_initialize(&cdev->dev);
/* Increase counter of devices currently in recognition. */
atomic_inc(&ccw_device_init_count);
/* Start async. device sensing. */ /* Start async. device sensing. */
spin_lock_irq(cdev->ccwlock); spin_lock_irq(cdev->ccwlock);
rc = ccw_device_recognition(cdev); rc = ccw_device_recognition(cdev);
...@@ -428,6 +487,8 @@ io_subchannel_recog(struct ccw_device *cdev, struct subchannel *sch) ...@@ -428,6 +487,8 @@ io_subchannel_recog(struct ccw_device *cdev, struct subchannel *sch)
put_device(&sch->dev); put_device(&sch->dev);
if (cdev->dev.release) if (cdev->dev.release)
cdev->dev.release(&cdev->dev); cdev->dev.release(&cdev->dev);
if (atomic_dec_and_test(&ccw_device_init_count))
wake_up(&ccw_device_init_wq);
} }
} }
...@@ -452,7 +513,8 @@ io_subchannel_probe (struct device *pdev) ...@@ -452,7 +513,8 @@ io_subchannel_probe (struct device *pdev)
if (!cdev) if (!cdev)
return -ENOMEM; return -ENOMEM;
memset(cdev, 0, sizeof(struct ccw_device)); memset(cdev, 0, sizeof(struct ccw_device));
cdev->private = kmalloc(sizeof(struct ccw_device_private), GFP_DMA); cdev->private = kmalloc(sizeof(struct ccw_device_private),
GFP_KERNEL | GFP_DMA);
if (!cdev->private) { if (!cdev->private) {
kfree(cdev); kfree(cdev);
return -ENOMEM; return -ENOMEM;
......
...@@ -14,13 +14,11 @@ enum dev_state { ...@@ -14,13 +14,11 @@ enum dev_state {
DEV_STATE_W4SENSE, DEV_STATE_W4SENSE,
DEV_STATE_DISBAND_PGID, DEV_STATE_DISBAND_PGID,
DEV_STATE_BOXED, DEV_STATE_BOXED,
/* special states for qdio */
DEV_STATE_QDIO_INIT,
DEV_STATE_QDIO_ACTIVE,
DEV_STATE_QDIO_CLEANUP,
/* states to wait for i/o completion before doing something */ /* states to wait for i/o completion before doing something */
DEV_STATE_ONLINE_VERIFY, DEV_STATE_ONLINE_VERIFY,
DEV_STATE_W4SENSE_VERIFY, DEV_STATE_W4SENSE_VERIFY,
DEV_STATE_CLEAR_VERIFY,
DEV_STATE_TIMEOUT_KILL,
/* last element! */ /* last element! */
NR_DEV_STATES NR_DEV_STATES
}; };
...@@ -63,7 +61,9 @@ dev_fsm_final_state(struct ccw_device *cdev) ...@@ -63,7 +61,9 @@ dev_fsm_final_state(struct ccw_device *cdev)
cdev->private->state == DEV_STATE_BOXED); cdev->private->state == DEV_STATE_BOXED);
} }
void io_subchannel_register(void *data); extern struct workqueue_struct *ccw_device_work;
void io_subchannel_recog_done(struct ccw_device *cdev);
int ccw_device_recognition(struct ccw_device *); int ccw_device_recognition(struct ccw_device *);
int ccw_device_online(struct ccw_device *); int ccw_device_online(struct ccw_device *);
......
This diff is collapsed.
...@@ -198,11 +198,13 @@ __ccw_device_sense_id_start(struct ccw_device *cdev) ...@@ -198,11 +198,13 @@ __ccw_device_sense_id_start(struct ccw_device *cdev)
/* 0x00E2C9C4 == ebcdic "SID" */ /* 0x00E2C9C4 == ebcdic "SID" */
ret = cio_start (sch, cdev->private->iccws, ret = cio_start (sch, cdev->private->iccws,
0x00E2C9C4, cdev->private->imask); 0x00E2C9C4, cdev->private->imask);
/* ret is 0, -EBUSY or -ENODEV */ /* ret is 0, -EBUSY, -EACCES or -ENODEV */
if (ret != -EBUSY) if (ret == -EBUSY) {
udelay(100);
continue;
}
if (ret != -EACCES)
return ret; return ret;
udelay(100);
continue;
} }
cdev->private->imask >>= 1; cdev->private->imask >>= 1;
cdev->private->iretry = 5; cdev->private->iretry = 5;
......
...@@ -49,12 +49,15 @@ ccw_device_clear(struct ccw_device *cdev, unsigned long intparm) ...@@ -49,12 +49,15 @@ ccw_device_clear(struct ccw_device *cdev, unsigned long intparm)
return -ENODEV; return -ENODEV;
if (cdev->private->state != DEV_STATE_ONLINE && if (cdev->private->state != DEV_STATE_ONLINE &&
cdev->private->state != DEV_STATE_W4SENSE && cdev->private->state != DEV_STATE_W4SENSE &&
cdev->private->state != DEV_STATE_QDIO_ACTIVE) cdev->private->state != DEV_STATE_ONLINE_VERIFY &&
cdev->private->state != DEV_STATE_W4SENSE_VERIFY)
return -EINVAL; return -EINVAL;
sch = to_subchannel(cdev->dev.parent); sch = to_subchannel(cdev->dev.parent);
if (!sch) if (!sch)
return -ENODEV; return -ENODEV;
ret = cio_clear(sch, intparm); ret = cio_clear(sch);
if (ret == 0)
cdev->private->intparm = intparm;
return ret; return ret;
} }
...@@ -67,17 +70,35 @@ ccw_device_start(struct ccw_device *cdev, struct ccw1 *cpa, ...@@ -67,17 +70,35 @@ ccw_device_start(struct ccw_device *cdev, struct ccw1 *cpa,
if (!cdev) if (!cdev)
return -ENODEV; return -ENODEV;
if (cdev->private->state != DEV_STATE_ONLINE &&
cdev->private->state != DEV_STATE_W4SENSE &&
cdev->private->state != DEV_STATE_QDIO_INIT)
return -EINVAL;
sch = to_subchannel(cdev->dev.parent); sch = to_subchannel(cdev->dev.parent);
if (!sch) if (!sch)
return -ENODEV; return -ENODEV;
if (cdev->private->state != DEV_STATE_ONLINE ||
sch->schib.scsw.actl != 0)
return -EBUSY;
ret = cio_set_options (sch, flags); ret = cio_set_options (sch, flags);
if (ret) if (ret)
return ret; return ret;
ret = cio_start (sch, cpa, intparm, lpm); /* 0xe4e2c5d9 == ebcdic "USER" */
ret = cio_start (sch, cpa, 0xe4e2c5d9, lpm);
if (ret == 0)
cdev->private->intparm = intparm;
return ret;
}
int
ccw_device_start_timeout(struct ccw_device *cdev, struct ccw1 *cpa,
unsigned long intparm, __u8 lpm, unsigned long flags,
int expires)
{
int ret;
if (!cdev)
return -ENODEV;
ccw_device_set_timeout(cdev, expires);
ret = ccw_device_start(cdev, cpa, intparm, lpm, flags);
if (ret != 0)
ccw_device_set_timeout(cdev, 0);
return ret; return ret;
} }
...@@ -90,12 +111,16 @@ ccw_device_halt(struct ccw_device *cdev, unsigned long intparm) ...@@ -90,12 +111,16 @@ ccw_device_halt(struct ccw_device *cdev, unsigned long intparm)
if (!cdev) if (!cdev)
return -ENODEV; return -ENODEV;
if (cdev->private->state != DEV_STATE_ONLINE && if (cdev->private->state != DEV_STATE_ONLINE &&
cdev->private->state != DEV_STATE_W4SENSE) cdev->private->state != DEV_STATE_W4SENSE &&
cdev->private->state != DEV_STATE_ONLINE_VERIFY &&
cdev->private->state != DEV_STATE_W4SENSE_VERIFY)
return -EINVAL; return -EINVAL;
sch = to_subchannel(cdev->dev.parent); sch = to_subchannel(cdev->dev.parent);
if (!sch) if (!sch)
return -ENODEV; return -ENODEV;
ret = cio_halt(sch, intparm); ret = cio_halt(sch);
if (ret == 0)
cdev->private->intparm = intparm;
return ret; return ret;
} }
...@@ -106,12 +131,12 @@ ccw_device_resume(struct ccw_device *cdev) ...@@ -106,12 +131,12 @@ ccw_device_resume(struct ccw_device *cdev)
if (!cdev) if (!cdev)
return -ENODEV; return -ENODEV;
if (cdev->private->state != DEV_STATE_ONLINE &&
cdev->private->state != DEV_STATE_W4SENSE)
return -EINVAL;
sch = to_subchannel(cdev->dev.parent); sch = to_subchannel(cdev->dev.parent);
if (!sch) if (!sch)
return -ENODEV; return -ENODEV;
if (cdev->private->state != DEV_STATE_ONLINE ||
!(sch->schib.scsw.actl & SCSW_ACTL_SUSPENDED))
return -EINVAL;
return cio_resume(sch); return cio_resume(sch);
} }
...@@ -123,15 +148,6 @@ ccw_device_call_handler(struct ccw_device *cdev) ...@@ -123,15 +148,6 @@ ccw_device_call_handler(struct ccw_device *cdev)
{ {
struct subchannel *sch; struct subchannel *sch;
unsigned int stctl; unsigned int stctl;
void (*handler)(struct ccw_device *, unsigned long, struct irb *);
if (cdev->private->state == DEV_STATE_QDIO_ACTIVE) {
if (cdev->private->qdio_data)
handler = cdev->private->qdio_data->handler;
else
handler = NULL;
} else
handler = cdev->handler;
sch = to_subchannel(cdev->dev.parent); sch = to_subchannel(cdev->dev.parent);
...@@ -154,8 +170,9 @@ ccw_device_call_handler(struct ccw_device *cdev) ...@@ -154,8 +170,9 @@ ccw_device_call_handler(struct ccw_device *cdev)
/* /*
* Now we are ready to call the device driver interrupt handler. * Now we are ready to call the device driver interrupt handler.
*/ */
if (handler) if (cdev->handler)
handler(cdev, sch->u_intparm, &cdev->private->irb); cdev->handler(cdev, cdev->private->intparm,
&cdev->private->irb);
/* /*
* Clear the old and now useless interrupt response block. * Clear the old and now useless interrupt response block.
...@@ -192,6 +209,11 @@ ccw_device_get_path_mask(struct ccw_device *cdev) ...@@ -192,6 +209,11 @@ ccw_device_get_path_mask(struct ccw_device *cdev)
static void static void
ccw_device_wake_up(struct ccw_device *cdev, unsigned long ip, struct irb *irb) ccw_device_wake_up(struct ccw_device *cdev, unsigned long ip, struct irb *irb)
{ {
struct subchannel *sch;
sch = to_subchannel(cdev->dev.parent);
if (!IS_ERR(irb))
memcpy(&sch->schib.scsw, &irb->scsw, sizeof(struct scsw));
wake_up(&cdev->private->wait_q); wake_up(&cdev->private->wait_q);
} }
...@@ -218,8 +240,7 @@ read_dev_chars (struct ccw_device *cdev, void **buffer, int length) ...@@ -218,8 +240,7 @@ read_dev_chars (struct ccw_device *cdev, void **buffer, int length)
if (!cdev) if (!cdev)
return -ENODEV; return -ENODEV;
if (cdev->private->state != DEV_STATE_ONLINE && if (cdev->private->state != DEV_STATE_ONLINE)
cdev->private->state != DEV_STATE_W4SENSE)
return -EINVAL; return -EINVAL;
if (!buffer || !length) if (!buffer || !length)
return -EINVAL; return -EINVAL;
...@@ -251,7 +272,13 @@ read_dev_chars (struct ccw_device *cdev, void **buffer, int length) ...@@ -251,7 +272,13 @@ read_dev_chars (struct ccw_device *cdev, void **buffer, int length)
wait_event(cdev->private->wait_q, wait_event(cdev->private->wait_q,
sch->schib.scsw.actl == 0); sch->schib.scsw.actl == 0);
spin_lock_irqsave(&sch->lock, flags); spin_lock_irqsave(&sch->lock, flags);
/* FIXME: Check if we got sensible stuff. */ /* Check at least for channel end / device end */
if ((sch->schib.scsw.dstat !=
(DEV_STAT_CHN_END|DEV_STAT_DEV_END)) ||
(sch->schib.scsw.cstat != 0)) {
ret = -EIO;
continue;
}
break; break;
} }
} }
...@@ -281,8 +308,7 @@ read_conf_data (struct ccw_device *cdev, void **buffer, int *length) ...@@ -281,8 +308,7 @@ read_conf_data (struct ccw_device *cdev, void **buffer, int *length)
if (!cdev) if (!cdev)
return -ENODEV; return -ENODEV;
if (cdev->private->state != DEV_STATE_ONLINE && if (cdev->private->state != DEV_STATE_ONLINE)
cdev->private->state != DEV_STATE_W4SENSE)
return -EINVAL; return -EINVAL;
if (cdev->private->flags.esid == 0) if (cdev->private->flags.esid == 0)
return -EOPNOTSUPP; return -EOPNOTSUPP;
...@@ -300,7 +326,7 @@ read_conf_data (struct ccw_device *cdev, void **buffer, int *length) ...@@ -300,7 +326,7 @@ read_conf_data (struct ccw_device *cdev, void **buffer, int *length)
if (!ciw || ciw->cmd == 0) if (!ciw || ciw->cmd == 0)
return -EOPNOTSUPP; return -EOPNOTSUPP;
rcd_buf = kmalloc(ciw->count, GFP_DMA); rcd_buf = kmalloc(ciw->count, GFP_KERNEL | GFP_DMA);
if (!rcd_buf) if (!rcd_buf)
return -ENOMEM; return -ENOMEM;
memset (rcd_buf, 0, ciw->count); memset (rcd_buf, 0, ciw->count);
...@@ -325,7 +351,13 @@ read_conf_data (struct ccw_device *cdev, void **buffer, int *length) ...@@ -325,7 +351,13 @@ read_conf_data (struct ccw_device *cdev, void **buffer, int *length)
spin_unlock_irqrestore(&sch->lock, flags); spin_unlock_irqrestore(&sch->lock, flags);
wait_event(cdev->private->wait_q, sch->schib.scsw.actl == 0); wait_event(cdev->private->wait_q, sch->schib.scsw.actl == 0);
spin_lock_irqsave(&sch->lock, flags); spin_lock_irqsave(&sch->lock, flags);
/* FIXME: Check if we got sensible stuff. */ /* Check at least for channel end / device end */
if ((sch->schib.scsw.dstat !=
(DEV_STAT_CHN_END|DEV_STAT_DEV_END)) ||
(sch->schib.scsw.cstat != 0)) {
ret = -EIO;
continue;
}
break; break;
} }
/* Restore interrupt handler. */ /* Restore interrupt handler. */
...@@ -363,13 +395,15 @@ _ccw_device_get_device_number(struct ccw_device *cdev) ...@@ -363,13 +395,15 @@ _ccw_device_get_device_number(struct ccw_device *cdev)
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
EXPORT_SYMBOL(ccw_device_set_options);
EXPORT_SYMBOL(ccw_device_clear); EXPORT_SYMBOL(ccw_device_clear);
EXPORT_SYMBOL(ccw_device_halt); EXPORT_SYMBOL(ccw_device_halt);
EXPORT_SYMBOL(ccw_device_resume); EXPORT_SYMBOL(ccw_device_resume);
EXPORT_SYMBOL(ccw_device_start_timeout);
EXPORT_SYMBOL(ccw_device_start); EXPORT_SYMBOL(ccw_device_start);
EXPORT_SYMBOL(ccw_device_get_ciw); EXPORT_SYMBOL(ccw_device_get_ciw);
EXPORT_SYMBOL(ccw_device_get_path_mask); EXPORT_SYMBOL(ccw_device_get_path_mask);
EXPORT_SYMBOL (read_conf_data); EXPORT_SYMBOL(read_conf_data);
EXPORT_SYMBOL (read_dev_chars); EXPORT_SYMBOL(read_dev_chars);
EXPORT_SYMBOL(_ccw_device_get_subchannel_number); EXPORT_SYMBOL(_ccw_device_get_subchannel_number);
EXPORT_SYMBOL(_ccw_device_get_device_number); EXPORT_SYMBOL(_ccw_device_get_device_number);
...@@ -51,14 +51,23 @@ __ccw_device_sense_pgid_start(struct ccw_device *cdev) ...@@ -51,14 +51,23 @@ __ccw_device_sense_pgid_start(struct ccw_device *cdev)
/* 0xe2d5c9c4 == ebcdic "SNID" */ /* 0xe2d5c9c4 == ebcdic "SNID" */
ret = cio_start (sch, cdev->private->iccws, ret = cio_start (sch, cdev->private->iccws,
0xE2D5C9C4, cdev->private->imask); 0xE2D5C9C4, cdev->private->imask);
/* ret is 0, -EBUSY or -ENODEV */ /* ret is 0, -EBUSY, -EACCES or -ENODEV */
if (ret != -EBUSY) if (ret == -EBUSY) {
CIO_MSG_EVENT(2,
"SNID - device %04X, start_io() "
"reports rc : %d, retrying ...\n",
sch->schib.pmcw.dev, ret);
udelay(100);
continue;
}
if (ret != -EACCES)
return ret; return ret;
CIO_MSG_EVENT(2, "SNID - device %04X, start_io() " CIO_MSG_EVENT(2, "SNID - Device %04X on Subchannel "
"reports rc : %d, retrying ...\n", "%04X, lpm %02X, became 'not "
sch->schib.pmcw.dev, ret); "operational'\n",
udelay(100); sch->schib.pmcw.dev, sch->irq,
continue; cdev->private->imask);
} }
cdev->private->imask >>= 1; cdev->private->imask >>= 1;
cdev->private->iretry = 5; cdev->private->iretry = 5;
...@@ -231,7 +240,9 @@ __ccw_device_do_pgid(struct ccw_device *cdev, __u8 func) ...@@ -231,7 +240,9 @@ __ccw_device_do_pgid(struct ccw_device *cdev, __u8 func)
/* 0xE2D7C9C4 == ebcdic "SPID" */ /* 0xE2D7C9C4 == ebcdic "SPID" */
ret = cio_start (sch, cdev->private->iccws, ret = cio_start (sch, cdev->private->iccws,
0xE2D7C9C4, cdev->private->imask); 0xE2D7C9C4, cdev->private->imask);
/* ret is 0, -EBUSY or -ENODEV */ /* ret is 0, -EBUSY, -EACCES or -ENODEV */
if (ret == -EACCES)
break;
if (ret != -EBUSY) if (ret != -EBUSY)
return ret; return ret;
udelay(100); udelay(100);
......
...@@ -167,7 +167,7 @@ ccw_device_accumulate_esw(struct ccw_device *cdev, struct irb *irb) ...@@ -167,7 +167,7 @@ ccw_device_accumulate_esw(struct ccw_device *cdev, struct irb *irb)
/* Copy authorization bit. */ /* Copy authorization bit. */
cdev_irb->esw.esw0.erw.auth = irb->esw.esw0.erw.auth; cdev_irb->esw.esw0.erw.auth = irb->esw.esw0.erw.auth;
/* Copy path verification required flag. FIXME: how to verify ?? */ /* Copy path verification required flag. */
cdev_irb->esw.esw0.erw.pvrf = irb->esw.esw0.erw.pvrf; cdev_irb->esw.esw0.erw.pvrf = irb->esw.esw0.erw.pvrf;
/* Copy concurrent sense bit. */ /* Copy concurrent sense bit. */
cdev_irb->esw.esw0.erw.cons = irb->esw.esw0.erw.cons; cdev_irb->esw.esw0.erw.cons = irb->esw.esw0.erw.cons;
...@@ -309,7 +309,7 @@ ccw_device_do_sense(struct ccw_device *cdev, struct irb *irb) ...@@ -309,7 +309,7 @@ ccw_device_do_sense(struct ccw_device *cdev, struct irb *irb)
sch->sense_ccw.flags = CCW_FLAG_SLI; sch->sense_ccw.flags = CCW_FLAG_SLI;
/* 0xe2C5D5E2 == "SENS" in ebcdic */ /* 0xe2C5D5E2 == "SENS" in ebcdic */
return cio_start (sch, &sch->sense_ccw, 0xE2C5D5E2, 0); return cio_start (sch, &sch->sense_ccw, 0xE2C5D5E2, 0xff);
} }
/* /*
......
This diff is collapsed.
#ifndef _CIO_QDIO_H #ifndef _CIO_QDIO_H
#define _CIO_QDIO_H #define _CIO_QDIO_H
#define VERSION_CIO_QDIO_H "$Revision: 1.11 $" #define VERSION_CIO_QDIO_H "$Revision: 1.16 $"
//#define QDIO_DBF_LIKE_HELL //#define QDIO_DBF_LIKE_HELL
...@@ -48,25 +48,25 @@ ...@@ -48,25 +48,25 @@
#define QDIO_STATS_CLASSES 2 #define QDIO_STATS_CLASSES 2
#define QDIO_STATS_COUNT_NEEDED 2*/ #define QDIO_STATS_COUNT_NEEDED 2*/
#define QDIO_ACTIVATE_DELAY 5 /* according to brenton belmar and paul
gioquindo it can take up to 5ms before
queues are really active */
#define QDIO_NO_USE_COUNT_TIME 10 #define QDIO_NO_USE_COUNT_TIME 10
#define QDIO_NO_USE_COUNT_TIMEOUT 1000 /* wait for 1 sec on each q before #define QDIO_NO_USE_COUNT_TIMEOUT 1000 /* wait for 1 sec on each q before
exiting without having use_count exiting without having use_count
of the queue to 0 */ of the queue to 0 */
#define QDIO_ESTABLISH_TIMEOUT 1000 #define QDIO_ESTABLISH_TIMEOUT 1000
#define QDIO_ACTIVATE_TIMEOUT 100 #define QDIO_ACTIVATE_TIMEOUT 5
#define QDIO_CLEANUP_CLEAR_TIMEOUT 20000 #define QDIO_CLEANUP_CLEAR_TIMEOUT 20000
#define QDIO_CLEANUP_HALT_TIMEOUT 10000 #define QDIO_CLEANUP_HALT_TIMEOUT 10000
#define QDIO_IRQ_STATE_FRESH 0 /* must be 0 -> memset has set it to 0 */ enum qdio_irq_states {
#define QDIO_IRQ_STATE_INACTIVE 1 QDIO_IRQ_STATE_INACTIVE,
#define QDIO_IRQ_STATE_ESTABLISHED 2 QDIO_IRQ_STATE_ESTABLISHED,
#define QDIO_IRQ_STATE_ACTIVE 3 QDIO_IRQ_STATE_ACTIVE,
#define QDIO_IRQ_STATE_STOPPED 4 QDIO_IRQ_STATE_STOPPED,
QDIO_IRQ_STATE_CLEANUP,
QDIO_IRQ_STATE_ERR,
NR_QDIO_IRQ_STATES,
};
/* used as intparm in do_IO: */ /* used as intparm in do_IO: */
#define QDIO_DOING_SENSEID 0 #define QDIO_DOING_SENSEID 0
...@@ -443,81 +443,6 @@ do_clear_global_summary(void) ...@@ -443,81 +443,6 @@ do_clear_global_summary(void)
#define CHSC_FLAG_SIGA_SYNC_DONE_ON_THININTS 0x08 #define CHSC_FLAG_SIGA_SYNC_DONE_ON_THININTS 0x08
#define CHSC_FLAG_SIGA_SYNC_DONE_ON_OUTB_PCIS 0x04 #define CHSC_FLAG_SIGA_SYNC_DONE_ON_OUTB_PCIS 0x04
struct qdio_chsc_area {
struct {
/* word 0 */
__u16 command_code1;
__u16 command_code2;
/* word 1 */
__u16 operation_code;
__u16 first_sch;
/* word 2 */
__u8 reserved1;
__u8 image_id;
__u16 last_sch;
/* word 3 */
__u32 reserved2;
/* word 4 */
union {
struct {
/* word 4&5 */
__u64 summary_indicator_addr;
/* word 6&7 */
__u64 subchannel_indicator_addr;
/* word 8 */
int ks:4;
int kc:4;
int reserved1:21;
int isc:3;
/* word 9&10 */
__u32 reserved2[2];
/* word 11 */
__u32 subsystem_id;
/* word 12-1015 */
__u32 reserved3[1004];
} __attribute__ ((packed,aligned(4))) set_chsc;
struct {
/* word 4&5 */
__u32 reserved1[2];
/* word 6 */
__u32 delay_target;
/* word 7-1015 */
__u32 reserved4[1009];
} __attribute__ ((packed,aligned(4))) set_chsc_fast;
struct {
/* word 0 */
__u16 length;
__u16 response_code;
/* word 1 */
__u32 reserved1;
/* words 2 to 9 for st sch qdio data */
__u8 flags;
__u8 reserved2;
__u16 sch;
__u8 qfmt;
__u8 reserved3;
__u8 qdioac;
__u8 sch_class;
__u8 reserved4;
__u8 icnt;
__u8 reserved5;
__u8 ocnt;
/* plus 5 words of reserved fields */
} __attribute__ ((packed,aligned(8)))
store_qdio_data_response;
} operation_data_area;
} __attribute__ ((packed,aligned(8))) request_block;
struct {
/* word 0 */
__u16 length;
__u16 response_code;
/* word 1 */
__u32 reserved1;
} __attribute__ ((packed,aligned(8))) response_block;
} __attribute__ ((packed,aligned(PAGE_SIZE)));
#ifdef QDIO_PERFORMANCE_STATS #ifdef QDIO_PERFORMANCE_STATS
struct qdio_perf_stats { struct qdio_perf_stats {
unsigned int tl_runs; unsigned int tl_runs;
...@@ -623,7 +548,7 @@ struct qdio_q { ...@@ -623,7 +548,7 @@ struct qdio_q {
struct tasklet_struct tasklet; struct tasklet_struct tasklet;
#endif /* QDIO_USE_TIMERS_FOR_POLLING */ #endif /* QDIO_USE_TIMERS_FOR_POLLING */
unsigned int state; enum qdio_irq_states state;
/* used to store the error condition during a data transfer */ /* used to store the error condition during a data transfer */
unsigned int qdio_error; unsigned int qdio_error;
...@@ -674,7 +599,7 @@ struct qdio_irq { ...@@ -674,7 +599,7 @@ struct qdio_irq {
unsigned int hydra_gives_outbound_pcis; unsigned int hydra_gives_outbound_pcis;
unsigned int sync_done_on_outb_pcis; unsigned int sync_done_on_outb_pcis;
unsigned int state; enum qdio_irq_states state;
struct semaphore setting_up_sema; struct semaphore setting_up_sema;
unsigned int no_input_qs; unsigned int no_input_qs;
...@@ -694,13 +619,8 @@ struct qdio_irq { ...@@ -694,13 +619,8 @@ struct qdio_irq {
struct qib qib; struct qib qib;
/* Functions called via the generic cio layer */ void (*original_int_handler) (struct ccw_device *,
void (*cleanup_irq) (struct ccw_device *, unsigned long, struct irb *); unsigned long, struct irb *);
void (*cleanup_timeout) (struct ccw_device *);
void (*establish_irq) (struct ccw_device *, unsigned long,
struct irb *);
void (*establish_timeout) (struct ccw_device *);
void (*handler) (struct ccw_device *, unsigned long, struct irb *);
}; };
#endif #endif
...@@ -44,7 +44,11 @@ init_IRQ(void) ...@@ -44,7 +44,11 @@ init_IRQ(void)
/* /*
* Let's build our path group ID here. * Let's build our path group ID here.
*/ */
global_pgid.cpu_addr = *(__u16 *) __LC_CPUADDR; #ifdef CONFIG_SMP
global_pgid.cpu_addr = hard_smp_processor_id();
#else
global_pgid.cpu_addr = 0;
#endif
global_pgid.cpu_id = ((cpuid_t *) __LC_CPUID)->ident; global_pgid.cpu_id = ((cpuid_t *) __LC_CPUID)->ident;
global_pgid.cpu_model = ((cpuid_t *) __LC_CPUID)->machine; global_pgid.cpu_model = ((cpuid_t *) __LC_CPUID)->machine;
global_pgid.tod_high = (__u32) (get_clock() >> 32); global_pgid.tod_high = (__u32) (get_clock() >> 32);
......
...@@ -21,7 +21,7 @@ ...@@ -21,7 +21,7 @@
extern void css_process_crw(int); extern void css_process_crw(int);
extern void chsc_process_crw(void); extern void chsc_process_crw(void);
extern void chp_process_crw(int); extern void chp_process_crw(int, int);
static void static void
s390_handle_damage(char *msg) s390_handle_damage(char *msg)
...@@ -62,7 +62,17 @@ s390_collect_crw_info(void) ...@@ -62,7 +62,17 @@ s390_collect_crw_info(void)
break; break;
case CRW_RSC_CPATH: case CRW_RSC_CPATH:
pr_debug("source is channel path %02X\n", crw.rsid); pr_debug("source is channel path %02X\n", crw.rsid);
chp_process_crw(crw.rsid); switch (crw.erc) {
case CRW_ERC_IPARM: /* Path has come. */
chp_process_crw(crw.rsid, 1);
break;
case CRW_ERC_PERRI: /* Path has gone. */
chp_process_crw(crw.rsid, 0);
break;
default:
pr_debug("Don't know how to handle erc=%x\n",
crw.erc);
}
break; break;
case CRW_RSC_CONFIG: case CRW_RSC_CONFIG:
pr_debug("source is configuration-alert facility\n"); pr_debug("source is configuration-alert facility\n");
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment