Commit 01613ea0 authored by Martin Schwidefsky's avatar Martin Schwidefsky Committed by Linus Torvalds

[PATCH] s390: common i/o layer.

updates for the channel subsystem and qdio driver

This adds the missing support for chp machine checks, i.e.
enabling or disabling a set of devices from the service element.
Some minor bugs in the driver are fixed as well.
parent cbc67add
/*
* drivers/s390/cio/ccwgroup.c
* bus driver for ccwgroup
* $Revision: 1.5 $
* $Revision: 1.6 $
*
* Copyright (C) 2002 IBM Deutschland Entwicklung GmbH,
* IBM Corporation
......
/*
* drivers/s390/cio/chsc.c
* S/390 common I/O routines -- channel subsystem call
* $Revision: 1.46 $
* $Revision: 1.57 $
*
* Copyright (C) 1999-2002 IBM Deutschland Entwicklung GmbH,
* IBM Corporation
......@@ -53,12 +53,6 @@ chsc_chpid_logical (struct subchannel *sch, int chp)
return test_bit (sch->schib.pmcw.chpid[chp], chpids_logical);
}
static inline void
chsc_clear_chpid(struct subchannel *sch, int chp)
{
clear_bit(sch->schib.pmcw.chpid[chp], chpids);
}
void
chsc_validate_chpids(struct subchannel *sch)
{
......@@ -69,17 +63,10 @@ chsc_validate_chpids(struct subchannel *sch)
for (chp = 0; chp <= 7; chp++) {
mask = 0x80 >> chp;
if (sch->lpm & mask) {
if (sch->lpm & mask)
if (!chsc_chpid_logical(sch, chp))
/* disable using this path */
sch->lpm &= ~mask;
} else {
/* This chpid is not
* available to us */
chsc_clear_chpid(sch, chp);
if (test_bit(chp, chpids_known))
set_chp_status(chp, CHP_STANDBY);
}
}
}
......@@ -278,6 +265,7 @@ s390_set_chpid_offline( __u8 chpid)
sch = ioinfo[irq];
if (sch == NULL)
continue; /* we don't know the device anyway */
/* FIXME: Kill pending I/O. */
s390_subchannel_remove_chpid(sch, chpid);
}
#endif
......@@ -381,6 +369,7 @@ s390_process_res_acc (u8 chpid, __u16 fla, u32 fla_mask)
continue;
}
/* FIXME: Kill pending I/O. */
spin_lock_irq(&sch->lock);
chp_mask = s390_process_res_acc_sch(chpid, fla, fla_mask, sch);
......@@ -413,7 +402,7 @@ s390_process_res_acc (u8 chpid, __u16 fla, u32 fla_mask)
static void
do_process_crw(void *ignore)
{
int ccode;
int do_sei;
/*
* build the chsc request block for store event information
......@@ -438,39 +427,57 @@ do_process_crw(void *ignore)
CIO_TRACE_EVENT( 2, "prcss");
do_sei = 1;
while (do_sei) {
int ccode;
ccode = chsc(&chsc_area_sei);
if (ccode > 0)
return;
switch (chsc_area_sei.response_block.response_code) {
switch (sei_res->response_code) {
/* for debug purposes, check for problems */
case 0x0001:
break; /* everything ok */
case 0x0002:
CIO_CRW_EVENT(2, "chsc_process_crw:invalid command!\n");
CIO_CRW_EVENT(2,
"chsc_process_crw: invalid command!\n");
return;
case 0x0003:
CIO_CRW_EVENT(2, "chsc_process_crw: error in chsc "
"request block!\n");
return;
case 0x0005:
CIO_CRW_EVENT(2, "chsc_process_crw: no event information "
"stored\n");
CIO_CRW_EVENT(2, "chsc_process_crw: no event "
"information stored\n");
return;
default:
CIO_CRW_EVENT(2, "chsc_process_crw: chsc response %d\n",
chsc_area_sei.response_block.response_code);
sei_res->response_code);
return;
}
CIO_CRW_EVENT(4, "chsc_process_crw: event information successfully "
"stored\n");
CIO_CRW_EVENT(4, "chsc_process_crw: event information "
"successfully stored\n");
/* Check if there is more event information pending. */
if (sei_res->flags & 0x80)
CIO_CRW_EVENT( 2, "chsc_process_crw: "
"further event information pending\n");
else
do_sei = 0;
/* Check if we might have lost some information. */
if (sei_res->flags & 0x40)
CIO_CRW_EVENT( 2, "chsc_process_crw: Event information "
"has been lost due to overflow!\n");
if (sei_res->rs != 4) {
CIO_CRW_EVENT(2, "chsc_process_crw: "
"reporting source (%04X) isn't a chpid!"
"Aborting processing of machine check...\n",
CIO_CRW_EVENT(2, "chsc_process_crw: reporting source "
"(%04X) isn't a chpid!\n",
sei_res->rsid);
return;
continue;
}
/* which kind of information was stored? */
......@@ -487,8 +494,8 @@ do_process_crw(void *ignore)
CIO_CRW_EVENT(4, "chsc_process_crw: "
"channel subsystem reports some I/O "
"devices may have become accessible\n");
pr_debug( KERN_DEBUG "Data received after sei: \n");
pr_debug( KERN_DEBUG "Validity flags: %x\n", sei_res->vf);
pr_debug("Data received after sei: \n");
pr_debug("Validity flags: %x\n", sei_res->vf);
/* allocate a new channel path structure, if needed */
if (chps[sei_res->rsid] == NULL)
......@@ -497,27 +504,34 @@ do_process_crw(void *ignore)
set_chp_status(sei_res->rsid, CHP_ONLINE);
if ((sei_res->vf & 0x80) == 0) {
pr_debug( KERN_DEBUG "chpid: %x\n", sei_res->rsid);
pr_debug("chpid: %x\n", sei_res->rsid);
s390_process_res_acc(sei_res->rsid, 0, 0);
} else if ((sei_res->vf & 0xc0) == 0x80) {
pr_debug( KERN_DEBUG "chpid: %x link addr: %x\n",
pr_debug("chpid: %x link addr: %x\n",
sei_res->rsid, sei_res->fla);
s390_process_res_acc(sei_res->rsid, sei_res->fla,
0xff00);
s390_process_res_acc(sei_res->rsid,
sei_res->fla, 0xff00);
} else if ((sei_res->vf & 0xc0) == 0xc0) {
pr_debug( KERN_DEBUG "chpid: %x full link addr: %x\n",
pr_debug("chpid: %x full link addr: %x\n",
sei_res->rsid, sei_res->fla);
s390_process_res_acc(sei_res->rsid, sei_res->fla,
0xffff);
s390_process_res_acc(sei_res->rsid,
sei_res->fla, 0xffff);
}
pr_debug( KERN_DEBUG "\n");
pr_debug("\n");
break;
default: /* other stuff */
CIO_CRW_EVENT(4, "chsc_process_crw: event %d\n", sei_res->cc);
CIO_CRW_EVENT(4, "chsc_process_crw: event %d\n",
sei_res->cc);
break;
}
if (do_sei) {
memset(&chsc_area_sei, 0, sizeof(struct sei_area));
chsc_area_sei.request_block.command_code1 = 0x0010;
chsc_area_sei.request_block.command_code2 = 0x000e;
}
}
}
void
......@@ -528,6 +542,99 @@ chsc_process_crw(void)
schedule_work(&work);
}
static void
chp_add(int chpid)
{
struct subchannel *sch;
int irq, ret;
char dbf_txt[15];
if (!test_bit(chpid, chpids_logical))
return; /* no need to do the rest */
sprintf(dbf_txt, "cadd%x", chpid);
CIO_TRACE_EVENT(2, dbf_txt);
for (irq = 0; irq <= __MAX_SUBCHANNELS; irq++) {
int i;
sch = ioinfo[irq];
if (!sch) {
ret = css_probe_device(irq);
if (ret == -ENXIO)
/* We're through */
return;
continue;
}
/* FIXME: Kill pending I/O. */
spin_lock(&sch->lock);
for (i=0; i<8; i++)
if (sch->schib.pmcw.chpid[i] == chpid) {
if (stsch(sch->irq, &sch->schib) != 0) {
/* Endgame. */
spin_unlock(&sch->lock);
return;
}
break;
}
if (i==8) {
spin_unlock(&sch->lock);
return;
}
sch->lpm = (sch->schib.pmcw.pim &
sch->schib.pmcw.pam &
sch->schib.pmcw.pom)
| 0x80 >> i;
chsc_validate_chpids(sch);
dev_fsm_event(sch->dev.driver_data, DEV_EVENT_VERIFY);
spin_unlock(&sch->lock);
}
}
/*
* Handling of crw machine checks with channel path source.
*/
void
chp_process_crw(int chpid)
{
/*
* Update our descriptions. We need this since we don't always
* get machine checks for path come and can't rely on our information
* being consistent otherwise.
*/
chsc_get_sch_descriptions();
if (!cio_chsc_desc_avail) {
/*
* Something went wrong...
* We can't reliably say whether a path was there before.
*/
CIO_CRW_EVENT(0, "Error: Could not retrieve "
"subchannel descriptions, will not process chp"
"machine check...\n");
return;
}
if (!test_bit(chpid, chpids)) {
/* Path has gone. We use the link incident routine.*/
s390_set_chpid_offline(chpid);
} else {
/*
* Path has come. Allocate a new channel path structure,
* if needed.
*/
if (chps[chpid] == NULL)
new_channel_path(chpid, CHP_ONLINE);
else
set_chp_status(chpid, CHP_ONLINE);
/* Avoid the extra overhead in process_rec_acc. */
chp_add(chpid);
}
}
/*
* Function: s390_vary_chpid
* Varies the specified chpid online or offline
......@@ -608,8 +715,7 @@ s390_vary_chpid( __u8 chpid, int on)
static ssize_t
chp_status_show(struct device *dev, char *buf)
{
struct sys_device *sdev = container_of(dev, struct sys_device, dev);
struct channel_path *chp = container_of(sdev, struct channel_path, sdev);
struct channel_path *chp = container_of(dev, struct channel_path, dev);
if (!chp)
return 0;
......@@ -631,8 +737,7 @@ chp_status_show(struct device *dev, char *buf)
static ssize_t
chp_status_write(struct device *dev, const char *buf, size_t count)
{
struct sys_device *sdev = container_of(dev, struct sys_device, dev);
struct channel_path *cp = container_of(sdev, struct channel_path, sdev);
struct channel_path *cp = container_of(dev, struct channel_path, dev);
char cmd[10];
int num_args;
int error;
......@@ -667,29 +772,29 @@ new_channel_path(int chpid, int status)
chp = kmalloc(sizeof(struct channel_path), GFP_KERNEL);
if (!chp)
return -ENOMEM;
memset(chp, 0, sizeof(struct channel_path));
chps[chpid] = chp;
/* fill in status, etc. */
chp->id = chpid;
chp->state = status;
chp->dev.parent = &css_bus_device;
snprintf(chp->sdev.dev.name, DEVICE_NAME_SIZE,
snprintf(chp->dev.name, DEVICE_NAME_SIZE,
"channel path %x", chpid);
chp->sdev.name = "channel_path";
chp->sdev.id = chpid;
snprintf(chp->dev.bus_id, DEVICE_ID_SIZE, "chp%x", chpid);
/* make it known to the system */
ret = sys_device_register(&chp->sdev);
ret = device_register(&chp->dev);
if (ret) {
printk(KERN_WARNING "%s: could not register %02x\n",
__func__, chpid);
return ret;
}
ret = device_create_file(&chp->sdev.dev, &dev_attr_status);
ret = device_create_file(&chp->dev, &dev_attr_status);
if (ret)
sys_device_unregister(&chp->sdev);
device_unregister(&chp->dev);
return ret;
}
......
......@@ -95,7 +95,7 @@ struct ssd_area {
struct channel_path {
int id;
int state;
struct sys_device sdev;
struct device dev;
};
extern struct channel_path *chps[];
......
/*
* drivers/s390/cio/cio.c
* S/390 common I/O routines -- low level i/o calls
* $Revision: 1.90 $
* $Revision: 1.91 $
*
* Copyright (C) 1999-2002 IBM Deutschland Entwicklung GmbH,
* IBM Corporation
......@@ -197,8 +197,7 @@ cio_start (struct subchannel *sch, /* subchannel structure */
sch->orb.pfch = sch->options.prefetch == 0;
sch->orb.spnd = sch->options.suspend;
sch->orb.ssic = sch->options.suspend && sch->options.inter;
sch->orb.lpm = (lpm != 0) ? (lpm & sch->lpm) : sch->lpm;
sch->orb.lpm = (lpm != 0) ? lpm : sch->lpm;
#ifdef CONFIG_ARCH_S390X
/*
* for 64 bit we always support 64 bit IDAWs with 4k page size only
......
/*
* drivers/s390/cio/device.c
* bus driver for ccw devices
* $Revision: 1.45 $
* $Revision: 1.50 $
*
* Copyright (C) 2002 IBM Deutschland Entwicklung GmbH,
* IBM Corporation
......@@ -215,6 +215,8 @@ online_show (struct device *dev, char *buf)
void
ccw_device_set_offline(struct ccw_device *cdev)
{
int ret;
if (!cdev)
return;
if (!cdev->online || !cdev->drv)
......@@ -226,23 +228,36 @@ ccw_device_set_offline(struct ccw_device *cdev)
cdev->online = 0;
spin_lock_irq(cdev->ccwlock);
ccw_device_offline(cdev);
ret = ccw_device_offline(cdev);
spin_unlock_irq(cdev->ccwlock);
if (ret == 0)
wait_event(cdev->private->wait_q, dev_fsm_final_state(cdev));
else
//FIXME: we can't fail!
pr_debug("ccw_device_offline returned %d, device %s\n",
ret, cdev->dev.bus_id);
}
void
ccw_device_set_online(struct ccw_device *cdev)
{
if (!cdev || !cdev->handler)
int ret;
if (!cdev)
return;
if (cdev->online || !cdev->drv)
return;
spin_lock_irq(cdev->ccwlock);
ccw_device_online(cdev);
ret = ccw_device_online(cdev);
spin_unlock_irq(cdev->ccwlock);
if (ret == 0)
wait_event(cdev->private->wait_q, dev_fsm_final_state(cdev));
else {
pr_debug("ccw_device_online returned %d, device %s\n",
ret, cdev->dev.bus_id);
return;
}
if (cdev->private->state != DEV_STATE_ONLINE)
return;
if (!cdev->drv->set_online || cdev->drv->set_online(cdev) == 0) {
......@@ -250,9 +265,13 @@ ccw_device_set_online(struct ccw_device *cdev)
return;
}
spin_lock_irq(cdev->ccwlock);
ccw_device_offline(cdev);
ret = ccw_device_offline(cdev);
spin_unlock_irq(cdev->ccwlock);
if (ret == 0)
wait_event(cdev->private->wait_q, dev_fsm_final_state(cdev));
else
pr_debug("ccw_device_offline returned %d, device %s\n",
ret, cdev->dev.bus_id);
}
static ssize_t
......@@ -574,7 +593,7 @@ ccw_device_remove (struct device *dev)
* doubled code.
* This is safe because of the checks in ccw_device_set_offline.
*/
pr_debug(KERN_INFO "removing device %s, sch %d, devno %x\n",
pr_debug("removing device %s, sch %d, devno %x\n",
cdev->dev.name,
cdev->private->irq,
cdev->private->devno);
......
......@@ -136,7 +136,7 @@ VM_virtual_device_info (__u16 devno, struct senseid *ps)
ccode = diag210 (&diag_data);
ps->reserved = 0xff;
/* Special case for bloddy osa devices. */
/* Special case for bloody osa devices. */
if (diag_data.vrdcvcla == 0x02 &&
diag_data.vrdcvtyp == 0x20) {
ps->cu_type = 0x3088;
......
......@@ -48,7 +48,8 @@ ccw_device_clear(struct ccw_device *cdev, unsigned long intparm)
if (!cdev)
return -ENODEV;
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)
return -EINVAL;
sch = to_subchannel(cdev->dev.parent);
if (!sch)
......@@ -122,6 +123,15 @@ ccw_device_call_handler(struct ccw_device *cdev)
{
struct subchannel *sch;
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);
......@@ -144,13 +154,9 @@ ccw_device_call_handler(struct ccw_device *cdev)
/*
* Now we are ready to call the device driver interrupt handler.
*/
if (cdev->private->state == DEV_STATE_QDIO_ACTIVE) {
if (cdev->private->qdio_data &&
cdev->private->qdio_data->handler)
cdev->private->qdio_data->handler(cdev, sch->u_intparm,
&cdev->private->irb);
} else
cdev->handler (cdev, sch->u_intparm, &cdev->private->irb);
if (handler)
handler(cdev, sch->u_intparm, &cdev->private->irb);
/*
* Clear the old and now useless interrupt response block.
*/
......@@ -245,6 +251,8 @@ read_dev_chars (struct ccw_device *cdev, void **buffer, int length)
wait_event(cdev->private->wait_q,
sch->schib.scsw.actl == 0);
spin_lock_irqsave(&sch->lock, flags);
/* FIXME: Check if we got sensible stuff. */
break;
}
}
/* Restore interrupt handler. */
......@@ -317,6 +325,8 @@ read_conf_data (struct ccw_device *cdev, void **buffer, int *length)
spin_unlock_irqrestore(&sch->lock, flags);
wait_event(cdev->private->wait_q, sch->schib.scsw.actl == 0);
spin_lock_irqsave(&sch->lock, flags);
/* FIXME: Check if we got sensible stuff. */
break;
}
/* Restore interrupt handler. */
cdev->handler = handler;
......
......@@ -141,6 +141,8 @@ ccw_device_sense_pgid_irq(struct ccw_device *cdev, enum dev_event dev_event)
struct subchannel *sch;
struct irb *irb;
int ret;
int opm;
int i;
irb = (struct irb *) __LC_IRB;
/* Ignore unsolicited interrupts. */
......@@ -154,6 +156,16 @@ ccw_device_sense_pgid_irq(struct ccw_device *cdev, enum dev_event dev_event)
/* 0, -ETIME, -EOPNOTSUPP, -EAGAIN, -EACCES or -EUSERS */
case 0: /* Sense Path Group ID successful. */
cdev->private->flags.pgid_supp = 1;
opm = sch->schib.pmcw.pim &
sch->schib.pmcw.pam &
sch->schib.pmcw.pom;
for (i=0;i<8;i++) {
if (opm == (0x80 << i)) {
/* Don't group single path devices. */
cdev->private->flags.pgid_supp = 0;
break;
}
}
if (cdev->private->pgid.inf.ps.state1 == SNID_STATE1_RESET)
memcpy(&cdev->private->pgid, &global_pgid,
sizeof(struct pgid));
......
......@@ -62,8 +62,9 @@ ccw_device_path_notoper(struct ccw_device *cdev)
sch = to_subchannel(cdev->dev.parent);
stsch (sch->irq, &sch->schib);
CIO_MSG_EVENT(0, "cio_process_irq(%04X) - path(s) %02x are "
"not operational ", sch->irq, sch->schib.pmcw.pnom);
CIO_MSG_EVENT(0, "%s(%04X) - path(s) %02x are "
"not operational \n", __FUNCTION__, sch->irq,
sch->schib.pmcw.pnom);
sch->lpm &= ~sch->schib.pmcw.pnom;
dev_fsm_event(cdev, DEV_EVENT_VERIFY);
......@@ -289,7 +290,7 @@ ccw_device_do_sense(struct ccw_device *cdev, struct irb *irb)
sch = to_subchannel(cdev->dev.parent);
/* A sense is required, can we do it now ? */
if (irb->scsw.actl != 0)
if ((irb->scsw.actl & (SCSW_ACTL_DEVACT | SCSW_ACTL_SCHACT)) != 0)
/*
* we received an Unit Check but we have no final
* status yet, therefore we must delay the SENSE
......@@ -348,7 +349,7 @@ int
ccw_device_accumulate_and_sense(struct ccw_device *cdev, struct irb *irb)
{
ccw_device_accumulate_irb(cdev, irb);
if (irb->scsw.actl != 0)
if ((irb->scsw.actl & (SCSW_ACTL_DEVACT | SCSW_ACTL_SCHACT)) != 0)
return -EBUSY;
/* Check for basic sense. */
if (cdev->private->flags.dosense &&
......
#ifndef S390_CIO_IOASM_H
#define S390_CIO_IOASM_H
/*
* area for channel subsystem call
*/
struct chsc_area {
struct {
/* word 0 */
__u16 command_code1;
__u16 command_code2;
union {
struct {
/* word 1 */
__u32 reserved1;
/* word 2 */
__u32 reserved2;
} __attribute__ ((packed,aligned(8))) sei_req;
struct {
/* word 1 */
__u16 reserved1;
__u16 f_sch; /* first subchannel */
/* word 2 */
__u16 reserved2;
__u16 l_sch; /* last subchannel */
} __attribute__ ((packed,aligned(8))) ssd_req;
} request_block_data;
/* word 3 */
__u32 reserved3;
} __attribute__ ((packed,aligned(8))) request_block;
struct {
/* word 0 */
__u16 length;
__u16 response_code;
/* word 1 */
__u32 reserved1;
union {
struct {
/* 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))) sei_res;
struct {
/* 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))) ssd_res;
} response_block_data;
} __attribute__ ((packed,aligned(8))) response_block;
} __attribute__ ((packed,aligned(PAGE_SIZE)));
/*
* TPI info structure
*/
......
......@@ -55,7 +55,7 @@
#include "qdio.h"
#include "ioasm.h"
#define VERSION_QDIO_C "$Revision: 1.18 $"
#define VERSION_QDIO_C "$Revision: 1.34 $"
/****************** MODULE PARAMETER VARIABLES ********************/
MODULE_AUTHOR("Utz Bacher <utz.bacher@de.ibm.com>");
......@@ -87,8 +87,6 @@ static debug_info_t *qdio_dbf_slsb_out;
static debug_info_t *qdio_dbf_slsb_in;
#endif /* QDIO_DBF_LIKE_HELL */
static struct semaphore init_sema;
static struct qdio_chsc_area *chsc_area;
/* iQDIO stuff: */
static volatile struct qdio_q *iq_list=NULL; /* volatile as it could change
......@@ -752,7 +750,7 @@ qdio_kick_inbound_handler(struct qdio_q *q)
#endif /* QDIO_DBF_LIKE_HELL */
if (q->state==QDIO_IRQ_STATE_ACTIVE)
q->handler(q->irq,
q->handler(q->cdev,
QDIO_STATUS_INBOUND_INT|q->error_status_flags,
q->qdio_error,q->siga_error,q->q_no,start,count,
q->int_parm);
......@@ -1039,7 +1037,7 @@ qdio_kick_outbound_handler(struct qdio_q *q)
#endif /* QDIO_DBF_LIKE_HELL */
if (q->state==QDIO_IRQ_STATE_ACTIVE)
q->handler(q->irq,QDIO_STATUS_OUTBOUND_INT|
q->handler(q->cdev,QDIO_STATUS_OUTBOUND_INT|
q->error_status_flags,
q->qdio_error,q->siga_error,q->q_no,start,count,
q->int_parm);
......@@ -1283,7 +1281,8 @@ qdio_set_impl_params(struct qdio_irq *irq_ptr,
}
static int
qdio_alloc_qs(struct qdio_irq *irq_ptr, int no_input_qs, int no_output_qs,
qdio_alloc_qs(struct qdio_irq *irq_ptr, struct ccw_device *cdev,
int no_input_qs, int no_output_qs,
qdio_handler_t *input_handler,
qdio_handler_t *output_handler,
unsigned long int_parm,int q_format,
......@@ -1327,6 +1326,7 @@ qdio_alloc_qs(struct qdio_irq *irq_ptr, int no_input_qs, int no_output_qs,
q->int_parm=int_parm;
irq_ptr->input_qs[i]=q;
q->irq=irq_ptr->irq;
q->cdev = cdev;
q->mask=1<<(31-i);
q->q_no=i;
q->is_input_q=1;
......@@ -1403,6 +1403,7 @@ qdio_alloc_qs(struct qdio_irq *irq_ptr, int no_input_qs, int no_output_qs,
irq_ptr->output_qs[i]=q;
q->is_input_q=0;
q->irq=irq_ptr->irq;
q->cdev = cdev;
q->mask=1<<(31-i);
q->q_no=i;
q->first_to_check=0;
......@@ -1626,7 +1627,7 @@ qdio_handler(struct ccw_device *cdev, unsigned long intparm, struct irb *irb)
"device %s!?\n", cdev->dev.bus_id);
goto omit_handler_call;
}
q->handler(q->irq,QDIO_STATUS_ACTIVATE_CHECK_CONDITION|
q->handler(q->cdev,QDIO_STATUS_ACTIVATE_CHECK_CONDITION|
QDIO_STATUS_LOOK_FOR_ERROR,
0,0,0,-1,-1,q->int_parm);
omit_handler_call:
......@@ -1636,7 +1637,6 @@ qdio_handler(struct ccw_device *cdev, unsigned long intparm, struct irb *irb)
}
/* this is for mp3 */
int
qdio_synchronize(struct ccw_device *cdev, unsigned int flags,
unsigned int queue_number)
......@@ -1882,10 +1882,8 @@ int
qdio_cleanup(struct ccw_device *cdev, int how)
{
struct qdio_irq *irq_ptr;
int i,result;
unsigned long flags;
int timeout;
char dbf_text[15]="12345678";
char dbf_text[15];
int rc;
irq_ptr = cdev->private->qdio_data;
if (!irq_ptr)
......@@ -1895,9 +1893,31 @@ qdio_cleanup(struct ccw_device *cdev, int how)
QDIO_DBF_TEXT1(0,trace,dbf_text);
QDIO_DBF_TEXT0(0,setup,dbf_text);
spin_lock(&irq_ptr->setting_up_lock);
rc = qdio_shutdown(cdev, how);
if (rc == 0)
rc = qdio_free(cdev);
return rc;
}
result=0;
int
qdio_shutdown(struct ccw_device *cdev, int how)
{
struct qdio_irq *irq_ptr;
int i;
int result = 0;
unsigned long flags;
int timeout;
char dbf_text[15]="12345678";
irq_ptr = cdev->private->qdio_data;
if (!irq_ptr)
return -ENODEV;
down(&irq_ptr->setting_up_sema);
sprintf(dbf_text,"qsqs%4x",irq_ptr->irq);
QDIO_DBF_TEXT1(0,trace,dbf_text);
QDIO_DBF_TEXT0(0,setup,dbf_text);
/* mark all qs as uninteresting */
for (i=0;i<irq_ptr->no_input_qs;i++)
......@@ -1913,6 +1933,13 @@ qdio_cleanup(struct ccw_device *cdev, int how)
tasklet_kill(&irq_ptr->input_qs[i]->tasklet);
if (qdio_wait_for_no_use_count(&irq_ptr->input_qs[i]->
use_count))
/*
* FIXME:
* nobody cares about such retval,
* does a timeout make sense at all?
* can this case be eliminated?
* mutex should be released anyway, shouldn't it?
*/
result=-EINPROGRESS;
}
......@@ -1920,9 +1947,19 @@ qdio_cleanup(struct ccw_device *cdev, int how)
tasklet_kill(&irq_ptr->output_qs[i]->tasklet);
if (qdio_wait_for_no_use_count(&irq_ptr->output_qs[i]->
use_count))
/*
* FIXME:
* nobody cares about such retval,
* does a timeout make sense at all?
* can this case be eliminated?
* mutex should be released anyway, shouldn't it?
*/
result=-EINPROGRESS;
}
if (result)
goto out;
/* cleanup subchannel */
spin_lock_irqsave(get_ccwdev_lock(cdev),flags);
if (how&QDIO_FLAG_CLEANUP_USING_CLEAR) {
......@@ -1940,7 +1977,10 @@ qdio_cleanup(struct ccw_device *cdev, int how)
spin_unlock_irqrestore(get_ccwdev_lock(cdev),flags);
wait_event(cdev->private->wait_q, dev_fsm_final_state(cdev));
return 0;
out:
up(&irq_ptr->setting_up_sema);
return result;
}
static inline void
......@@ -1955,6 +1995,34 @@ qdio_cleanup_finish(struct qdio_irq *irq_ptr)
qdio_set_state(irq_ptr,QDIO_IRQ_STATE_INACTIVE);
}
int
qdio_free(struct ccw_device *cdev)
{
struct qdio_irq *irq_ptr;
char dbf_text[15];
irq_ptr = cdev->private->qdio_data;
if (!irq_ptr)
return -ENODEV;
down(&irq_ptr->setting_up_sema);
sprintf(dbf_text,"qfqs%4x",irq_ptr->irq);
QDIO_DBF_TEXT1(0,trace,dbf_text);
QDIO_DBF_TEXT0(0,setup,dbf_text);
if (cdev->private->state != DEV_STATE_ONLINE)
return -EINVAL;
qdio_cleanup_finish(irq_ptr);
cdev->private->qdio_data = 0;
up(&irq_ptr->setting_up_sema);
qdio_release_irq_memory(irq_ptr);
return 0;
}
static void
qdio_cleanup_handle_timeout(struct ccw_device *cdev)
{
......@@ -1967,14 +2035,8 @@ qdio_cleanup_handle_timeout(struct ccw_device *cdev)
QDIO_PRINT_INFO("Did not get interrupt on cleanup, irq=0x%x.\n",
irq_ptr->irq);
qdio_cleanup_finish(irq_ptr);
spin_unlock_irqrestore(get_ccwdev_lock(cdev),flags);
spin_unlock(&irq_ptr->setting_up_lock);
cdev->private->qdio_data = 0;
qdio_release_irq_memory(irq_ptr);
cdev->private->state = DEV_STATE_ONLINE;
wake_up(&cdev->private->wait_q);
}
......@@ -1984,10 +2046,6 @@ qdio_cleanup_handle_irq(struct ccw_device *cdev, unsigned long intparm,
struct irb *irb)
{
struct qdio_irq *irq_ptr;
int cstat,dstat;
cstat = irb->scsw.cstat;
dstat = irb->scsw.dstat;
if (intparm == 0)
QDIO_PRINT_WARN("Got unsolicited interrupt on cleanup "
......@@ -1997,22 +2055,16 @@ qdio_cleanup_handle_irq(struct ccw_device *cdev, unsigned long intparm,
qdio_irq_check_sense(irq_ptr->irq, irb);
qdio_cleanup_finish(irq_ptr);
spin_unlock(&irq_ptr->setting_up_lock);
cdev->private->qdio_data = 0;
qdio_release_irq_memory(irq_ptr);
cdev->private->state = DEV_STATE_ONLINE;
wake_up(&cdev->private->wait_q);
}
static inline void
qdio_initialize_do_dbf(struct qdio_initialize *init_data)
qdio_allocate_do_dbf(struct qdio_initialize *init_data)
{
char dbf_text[20]; /* if a printf would print out more than 8 chars */
sprintf(dbf_text,"qini%4x",init_data->cdev->private->irq);
sprintf(dbf_text,"qalc%4x",init_data->cdev->private->irq);
QDIO_DBF_TEXT0(0,setup,dbf_text);
QDIO_DBF_TEXT0(0,trace,dbf_text);
sprintf(dbf_text,"qfmt:%x",init_data->q_format);
......@@ -2045,7 +2097,7 @@ qdio_initialize_do_dbf(struct qdio_initialize *init_data)
}
static inline void
qdio_initialize_fill_input_desc(struct qdio_irq *irq_ptr, int i, int iqfmt)
qdio_allocate_fill_input_desc(struct qdio_irq *irq_ptr, int i, int iqfmt)
{
irq_ptr->input_qs[i]->is_iqdio_q = iqfmt;
......@@ -2063,7 +2115,7 @@ qdio_initialize_fill_input_desc(struct qdio_irq *irq_ptr, int i, int iqfmt)
}
static inline void
qdio_initialize_fill_output_desc(struct qdio_irq *irq_ptr, int i,
qdio_allocate_fill_output_desc(struct qdio_irq *irq_ptr, int i,
int j, int iqfmt)
{
irq_ptr->output_qs[i]->is_iqdio_q = iqfmt;
......@@ -2092,10 +2144,13 @@ qdio_establish_handle_timeout(struct ccw_device *cdev)
QDIO_PRINT_ERR("establish queues on irq %04x: timed out\n",
irq_ptr->irq);
QDIO_DBF_TEXT2(1,setup,"eq:timeo");
spin_unlock(&irq_ptr->setting_up_lock);
qdio_cleanup(cdev,QDIO_FLAG_CLEANUP_USING_CLEAR);
up(&init_sema);
/*
* FIXME:
* this is broken,
* we are in the context of a timer interrupt and
* qdio_shutdown calls schedule
*/
qdio_shutdown(cdev,QDIO_FLAG_CLEANUP_USING_CLEAR);
}
static inline void
......@@ -2163,9 +2218,13 @@ qdio_establish_irq_check_for_errors(struct ccw_device *cdev, int cstat,
QDIO_PRINT_ERR("establish queues on irq %04x: didn't get "
"device end: dstat=%02x, cstat=%02x\n",
irq_ptr->irq, dstat, cstat);
spin_unlock(&irq_ptr->setting_up_lock);
qdio_cleanup(cdev,QDIO_FLAG_CLEANUP_USING_CLEAR);
up(&init_sema);
/*
* FIXME:
* this is broken,
* we are probably in the context of an i/o interrupt and
* qdio_shutdown calls schedule
*/
qdio_shutdown(cdev,QDIO_FLAG_CLEANUP_USING_CLEAR);
return 1;
}
......@@ -2178,9 +2237,6 @@ qdio_establish_irq_check_for_errors(struct ccw_device *cdev, int cstat,
"cstat=%02x\n",
irq_ptr->irq, dstat, cstat);
cdev->private->state = DEV_STATE_ONLINE;
spin_unlock(&irq_ptr->setting_up_lock);
up(&init_sema);
return 1;
}
return 0;
......@@ -2202,7 +2258,7 @@ qdio_establish_handle_irq(struct ccw_device *cdev, unsigned long intparm,
if (intparm == 0) {
QDIO_PRINT_WARN("Got unsolicited interrupt on establish "
"queues (irq 0x%x).\n", cdev->private->irq);
goto out;
return;
}
qdio_irq_check_sense(irq_ptr->irq, irb);
......@@ -2231,46 +2287,51 @@ qdio_establish_handle_irq(struct ccw_device *cdev, unsigned long intparm,
qdio_initialize_set_siga_flags_output(irq_ptr);
qdio_set_state(irq_ptr,QDIO_IRQ_STATE_ESTABLISHED);
}
out:
if (irq_ptr)
spin_unlock(&irq_ptr->setting_up_lock);
int
qdio_initialize(struct qdio_initialize *init_data)
{
int rc;
char dbf_text[15];
up(&init_sema);
sprintf(dbf_text,"qini%4x",init_data->cdev->private->irq);
QDIO_DBF_TEXT0(0,setup,dbf_text);
QDIO_DBF_TEXT0(0,trace,dbf_text);
rc = qdio_allocate(init_data);
if (rc == 0) {
rc = qdio_establish(init_data->cdev);
if (rc != 0)
qdio_free(init_data->cdev);
}
return rc;
}
int
qdio_initialize(struct qdio_initialize *init_data)
qdio_allocate(struct qdio_initialize *init_data)
{
int i;
unsigned long saveflags;
struct qdio_irq *irq_ptr;
struct ciw *ciw;
int result,result2;
int result;
int is_iqdio;
char dbf_text[20]; /* if a printf would print out more than 8 chars */
down_interruptible(&init_sema);
if ( (init_data->no_input_qs>QDIO_MAX_QUEUES_PER_IRQ) ||
(init_data->no_output_qs>QDIO_MAX_QUEUES_PER_IRQ) ||
((init_data->no_input_qs) && (!init_data->input_handler)) ||
((init_data->no_output_qs) && (!init_data->output_handler)) ) {
result=-EINVAL;
goto out;
}
((init_data->no_output_qs) && (!init_data->output_handler)) )
return -EINVAL;
if (!init_data->input_sbal_addr_array) {
result=-EINVAL;
goto out;
}
if (!init_data->output_sbal_addr_array) {
result=-EINVAL;
goto out;
}
if (!init_data->input_sbal_addr_array)
return -EINVAL;
if (!init_data->output_sbal_addr_array)
return -EINVAL;
qdio_initialize_do_dbf(init_data);
qdio_allocate_do_dbf(init_data);
/* create irq */
irq_ptr=kmalloc(sizeof(struct qdio_irq),GFP_DMA);
......@@ -2280,8 +2341,7 @@ qdio_initialize(struct qdio_initialize *init_data)
if (!irq_ptr) {
QDIO_PRINT_ERR("kmalloc of irq_ptr failed!\n");
result=-ENOMEM;
goto out;
return -ENOMEM;
}
memset(irq_ptr,0,sizeof(struct qdio_irq));
......@@ -2292,8 +2352,7 @@ qdio_initialize(struct qdio_initialize *init_data)
kfree(irq_ptr->qdr);
kfree(irq_ptr);
QDIO_PRINT_ERR("kmalloc of irq_ptr->qdr failed!\n");
result=-ENOMEM;
goto out;
return -ENOMEM;
}
memset(irq_ptr->qdr,0,sizeof(struct qdr));
QDIO_DBF_TEXT0(0,setup,"qdr:");
......@@ -2313,9 +2372,13 @@ qdio_initialize(struct qdio_initialize *init_data)
if (!irq_ptr->dev_st_chg_ind) {
QDIO_PRINT_WARN("no indicator location available " \
"for irq 0x%x\n",irq_ptr->irq);
/*
* FIXME:
* qdio_release_irq_memory does MOD_DEC_USE_COUNT
* in an unbalanced fashion (see 30 lines farther down)
*/
qdio_release_irq_memory(irq_ptr);
result=-ENOBUFS;
goto out;
return -ENOBUFS;
}
}
......@@ -2325,26 +2388,29 @@ qdio_initialize(struct qdio_initialize *init_data)
irq_ptr->aqueue.cmd=DEFAULT_ACTIVATE_QS_CMD;
irq_ptr->aqueue.count=DEFAULT_ACTIVATE_QS_COUNT;
if (!qdio_alloc_qs(irq_ptr,init_data->no_input_qs,
if (!qdio_alloc_qs(irq_ptr, init_data->cdev,
init_data->no_input_qs,
init_data->no_output_qs,
init_data->input_handler,
init_data->output_handler,init_data->int_parm,
init_data->q_format,init_data->flags,
init_data->input_sbal_addr_array,
init_data->output_sbal_addr_array)) {
/*
* FIXME:
* qdio_release_irq_memory does MOD_DEC_USE_COUNT
* in an unbalanced fashion (see 10 lines farther down)
*/
qdio_release_irq_memory(irq_ptr);
result=-ENOMEM;
goto out;
return -ENOMEM;
}
qdio_set_state(irq_ptr,QDIO_IRQ_STATE_INACTIVE);
irq_ptr->setting_up_lock=SPIN_LOCK_UNLOCKED;
MOD_INC_USE_COUNT;
QDIO_DBF_TEXT3(0,setup,"MOD_INC_");
spin_lock(&irq_ptr->setting_up_lock);
init_MUTEX_LOCKED(&irq_ptr->setting_up_sema);
init_data->cdev->private->qdio_data = irq_ptr;
......@@ -2383,10 +2449,10 @@ qdio_initialize(struct qdio_initialize *init_data)
/* first input descriptors, then output descriptors */
is_iqdio = (init_data->q_format == QDIO_IQDIO_QFMT) ? 1 : 0;
for (i=0;i<init_data->no_input_qs;i++)
qdio_initialize_fill_input_desc(irq_ptr, i, is_iqdio);
qdio_allocate_fill_input_desc(irq_ptr, i, is_iqdio);
for (i=0;i<init_data->no_output_qs;i++)
qdio_initialize_fill_output_desc(irq_ptr, i,
qdio_allocate_fill_output_desc(irq_ptr, i,
init_data->no_input_qs,
is_iqdio);
......@@ -2418,9 +2484,15 @@ qdio_initialize(struct qdio_initialize *init_data)
}
result=iqdio_set_subchannel_ind(irq_ptr,0);
if (result) {
spin_unlock(&irq_ptr->setting_up_lock);
up(&irq_ptr->setting_up_sema);
/*
* FIXME:
* need some callback pointers to be set already,
* i.e. irq_ptr->cleanup_irq and irq_ptr->cleanup_timeout?
* (see 10 lines farther down)
*/
qdio_cleanup(init_data->cdev, QDIO_FLAG_CLEANUP_USING_CLEAR);
goto out2;
return result;
}
iqdio_set_delay_target(irq_ptr,IQDIO_DELAY_TARGET);
}
......@@ -2432,20 +2504,46 @@ qdio_initialize(struct qdio_initialize *init_data)
irq_ptr->establish_timeout = qdio_establish_handle_timeout;
irq_ptr->handler = qdio_handler;
up(&irq_ptr->setting_up_sema);
return 0;
}
int
qdio_establish(struct ccw_device *cdev)
{
struct qdio_irq *irq_ptr;
unsigned long saveflags;
int result, result2;
char dbf_text[20];
irq_ptr = cdev->private->qdio_data;
if (!irq_ptr)
return -EINVAL;
if (cdev->private->state != DEV_STATE_ONLINE)
return -EINVAL;
down(&irq_ptr->setting_up_sema);
sprintf(dbf_text,"qest%4x",cdev->private->irq);
QDIO_DBF_TEXT0(0,setup,dbf_text);
QDIO_DBF_TEXT0(0,trace,dbf_text);
/* establish q */
irq_ptr->ccw.cmd_code=irq_ptr->equeue.cmd;
irq_ptr->ccw.flags=CCW_FLAG_SLI;
irq_ptr->ccw.count=irq_ptr->equeue.count;
irq_ptr->ccw.cda=QDIO_GET_ADDR(irq_ptr->qdr);
spin_lock_irqsave(get_ccwdev_lock(init_data->cdev),saveflags);
spin_lock_irqsave(get_ccwdev_lock(cdev),saveflags);
ccw_device_set_timeout(init_data->cdev, QDIO_ESTABLISH_TIMEOUT);
ccw_device_set_options(init_data->cdev, 0);
result=ccw_device_start(init_data->cdev,&irq_ptr->ccw,
ccw_device_set_timeout(cdev, QDIO_ESTABLISH_TIMEOUT);
ccw_device_set_options(cdev, 0);
result=ccw_device_start(cdev,&irq_ptr->ccw,
QDIO_DOING_ESTABLISH,0,0);
if (result) {
result2=ccw_device_start(init_data->cdev,&irq_ptr->ccw,
result2=ccw_device_start(cdev,&irq_ptr->ccw,
QDIO_DOING_ESTABLISH,0,0);
sprintf(dbf_text,"eq:io%4x",result);
QDIO_DBF_TEXT2(1,setup,dbf_text);
......@@ -2459,28 +2557,25 @@ qdio_initialize(struct qdio_initialize *init_data)
result=result2;
}
if (result == 0)
init_data->cdev->private->state = DEV_STATE_QDIO_INIT;
spin_unlock_irqrestore(get_ccwdev_lock(init_data->cdev),saveflags);
cdev->private->state = DEV_STATE_QDIO_INIT;
spin_unlock_irqrestore(get_ccwdev_lock(cdev),saveflags);
if (result) {
spin_unlock(&irq_ptr->setting_up_lock);
qdio_cleanup(init_data->cdev,QDIO_FLAG_CLEANUP_USING_CLEAR);
goto out2;
up(&irq_ptr->setting_up_sema);
qdio_shutdown(cdev,QDIO_FLAG_CLEANUP_USING_CLEAR);
return result;
}
wait_event(init_data->cdev->private->wait_q,
dev_fsm_final_state(init_data->cdev) ||
wait_event(cdev->private->wait_q,
dev_fsm_final_state(cdev) ||
(irq_ptr->state == QDIO_IRQ_STATE_ESTABLISHED));
if (init_data->cdev->private->state == DEV_STATE_QDIO_INIT)
return 0;
if (cdev->private->state == DEV_STATE_QDIO_INIT)
result = 0;
else
result = -EIO;
out:
if (irq_ptr)
spin_unlock(&irq_ptr->setting_up_lock);
out2:
up(&init_sema);
up(&irq_ptr->setting_up_sema);
return result;
......@@ -2501,7 +2596,7 @@ qdio_activate(struct ccw_device *cdev, int flags)
if (cdev->private->state != DEV_STATE_QDIO_INIT)
return -EINVAL;
spin_lock(&irq_ptr->setting_up_lock);
down(&irq_ptr->setting_up_sema);
if (irq_ptr->state==QDIO_IRQ_STATE_INACTIVE) {
result=-EBUSY;
goto out;
......@@ -2564,10 +2659,12 @@ qdio_activate(struct ccw_device *cdev, int flags)
}
}
qdio_wait_nonbusy(QDIO_ACTIVATE_DELAY);
qdio_set_state(irq_ptr,QDIO_IRQ_STATE_ACTIVE);
out:
spin_unlock(&irq_ptr->setting_up_lock);
up(&irq_ptr->setting_up_sema);
return result;
}
......@@ -3016,8 +3113,6 @@ init_QDIO(void)
if (res)
return res;
sema_init(&init_sema,1);
res = qdio_register_dbf_views();
if (res)
return res;
......@@ -3051,8 +3146,12 @@ cleanup_QDIO(void)
module_init(init_QDIO);
module_exit(cleanup_QDIO);
EXPORT_SYMBOL(qdio_allocate);
EXPORT_SYMBOL(qdio_establish);
EXPORT_SYMBOL(qdio_initialize);
EXPORT_SYMBOL(qdio_activate);
EXPORT_SYMBOL(do_QDIO);
EXPORT_SYMBOL(qdio_shutdown);
EXPORT_SYMBOL(qdio_free);
EXPORT_SYMBOL(qdio_cleanup);
EXPORT_SYMBOL(qdio_synchronize);
#ifndef _CIO_QDIO_H
#define _CIO_QDIO_H
#define VERSION_CIO_QDIO_H "$Revision: 1.8 $"
#define VERSION_CIO_QDIO_H "$Revision: 1.11 $"
//#define QDIO_DBF_LIKE_HELL
......@@ -48,6 +48,10 @@
#define QDIO_STATS_CLASSES 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_TIMEOUT 1000 /* wait for 1 sec on each q before
exiting without having use_count
......@@ -579,6 +583,7 @@ struct qdio_q {
int is_input_q;
int irq;
struct ccw_device *cdev;
unsigned int is_iqdio_q;
......@@ -670,7 +675,7 @@ struct qdio_irq {
unsigned int sync_done_on_outb_pcis;
unsigned int state;
spinlock_t setting_up_lock;
struct semaphore setting_up_sema;
unsigned int no_input_qs;
unsigned int no_output_qs;
......
......@@ -21,6 +21,7 @@
extern void css_process_crw(int);
extern void chsc_process_crw(void);
extern void chp_process_crw(int);
static void
s390_handle_damage(char *msg)
......@@ -53,29 +54,25 @@ s390_collect_crw_info(void)
crw.erc, crw.rsid);
switch (crw.rsc) {
case CRW_RSC_SCH:
pr_debug(KERN_NOTICE, "source is subchannel %04X\n",
crw.rsid);
pr_debug("source is subchannel %04X\n", crw.rsid);
css_process_crw (crw.rsid);
break;
case CRW_RSC_MONITOR:
pr_debug(KERN_NOTICE,
"source is monitoring facility\n");
pr_debug("source is monitoring facility\n");
break;
case CRW_RSC_CPATH:
pr_debug(KERN_NOTICE,
"source is channel path %02X\n",
pcrwe->crw.rsid);
pr_debug("source is channel path %02X\n", crw.rsid);
chp_process_crw(crw.rsid);
break;
case CRW_RSC_CONFIG:
pr_debug(KERN_NOTICE,
"source is configuration-alert facility\n");
pr_debug("source is configuration-alert facility\n");
break;
case CRW_RSC_CSS:
pr_debug(KERN_NOTICE, "source is channel subsystem\n");
pr_debug("source is channel subsystem\n");
chsc_process_crw();
break;
default:
pr_debug(KERN_NOTICE, "unknown source\n");
pr_debug("unknown source\n");
break;
}
} while (crw.chn);
......
......@@ -50,11 +50,11 @@ struct qdio_buffer{
} __attribute__ ((packed,aligned(256)));
/* params are: irq, status, qdio_error, siga_error,
/* params are: ccw_device, status, qdio_error, siga_error,
queue_number, first element processed, number of elements processed,
int_parm */
typedef void qdio_handler_t(int,unsigned int,unsigned int,unsigned int,
unsigned int,int,int,unsigned long);
typedef void qdio_handler_t(struct ccw_device *,unsigned int,unsigned int,
unsigned int,unsigned int,int,int,unsigned long);
#define QDIO_STATUS_INBOUND_INT 0x01
......@@ -100,6 +100,8 @@ struct qdio_initialize{
void **output_sbal_addr_array; /* addr of n*128 void ptrs */
};
extern int qdio_initialize(struct qdio_initialize *init_data);
extern int qdio_allocate(struct qdio_initialize *init_data);
extern int qdio_establish(struct ccw_device *);
extern int qdio_activate(struct ccw_device *,int flags);
......@@ -127,6 +129,8 @@ extern int qdio_synchronize(struct ccw_device*, unsigned int flags,
unsigned int queue_number);
extern int qdio_cleanup(struct ccw_device*, int how);
extern int qdio_shutdown(struct ccw_device*, int how);
extern int qdio_free(struct ccw_device*);
unsigned char qdio_get_slsb_state(struct ccw_device*, unsigned int flag,
unsigned int queue_number,
......
......@@ -50,11 +50,11 @@ struct qdio_buffer{
} __attribute__ ((packed,aligned(256)));
/* params are: irq, status, qdio_error, siga_error,
/* params are: ccw_device, status, qdio_error, siga_error,
queue_number, first element processed, number of elements processed,
int_parm */
typedef void qdio_handler_t(int,unsigned int,unsigned int,unsigned int,
unsigned int,int,int,unsigned long);
typedef void qdio_handler_t(struct ccw_device *,unsigned int,unsigned int,
unsigned int,unsigned int,int,int,unsigned long);
#define QDIO_STATUS_INBOUND_INT 0x01
......@@ -100,6 +100,8 @@ struct qdio_initialize{
void **output_sbal_addr_array; /* addr of n*128 void ptrs */
};
extern int qdio_initialize(struct qdio_initialize *init_data);
extern int qdio_allocate(struct qdio_initialize *init_data);
extern int qdio_establish(struct ccw_device *);
extern int qdio_activate(struct ccw_device *,int flags);
......@@ -127,6 +129,8 @@ extern int qdio_synchronize(struct ccw_device*, unsigned int flags,
unsigned int queue_number);
extern int qdio_cleanup(struct ccw_device*, int how);
extern int qdio_shutdown(struct ccw_device*, int how);
extern int qdio_free(struct ccw_device*);
unsigned char qdio_get_slsb_state(struct ccw_device*, unsigned int flag,
unsigned int queue_number,
......
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