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 @@
* drivers/s390/cio/airq.c
* S/390 common I/O routines -- support for adapter interruptions
*
* $Revision: 1.10 $
* $Revision: 1.11 $
*
* Copyright (C) 1999-2002 IBM Deutschland Entwicklung GmbH,
* IBM Corporation
......@@ -87,14 +87,14 @@ s390_unregister_adapter_interrupt (adapter_int_handler_t handler)
}
void
do_adapter_IO (__u32 intparm)
do_adapter_IO (void)
{
CIO_TRACE_EVENT (4, "doaio");
spin_lock (&adapter_lock);
if (adapter_handler)
(*adapter_handler) (intparm);
(*adapter_handler) ();
spin_unlock (&adapter_lock);
......
#ifndef 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_unregister_adapter_interrupt(adapter_int_handler_t handler);
extern void do_adapter_IO (__u32 intparm);
extern void do_adapter_IO (void);
#endif
This diff is collapsed.
......@@ -12,85 +12,10 @@
#define CHSC_SEI_ACC_LINKADDR 2
#define CHSC_SEI_ACC_FULLLINKADDR 3
struct sei_area {
struct {
/* word 0 */
__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 chsc_header {
u16 length;
u16 code;
};
struct channel_path {
int id;
......
/*
* drivers/s390/cio/cio.c
* 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,
* IBM Corporation
......@@ -176,13 +176,13 @@ cio_start_handle_notoper(struct subchannel *sch, __u8 lpm)
CIO_TRACE_EVENT(0, dbf_text);
CIO_HEX_EVENT(0, &sch->schib, sizeof (struct schib));
return -ENODEV;
return (sch->lpm ? -EACCES : -ENODEV);
}
int
cio_start (struct subchannel *sch, /* subchannel structure */
struct ccw1 * cpa, /* logical channel prog addr */
unsigned long intparm, /* interruption parameter */
unsigned int intparm, /* interruption parameter */
__u8 lpm) /* logical path mask */
{
char dbf_txt[15];
......@@ -191,7 +191,7 @@ cio_start (struct subchannel *sch, /* subchannel structure */
sprintf (dbf_txt, "stIO%x", sch->irq);
CIO_TRACE_EVENT (4, dbf_txt);
sch->orb.intparm = (__u32) (long) &sch->u_intparm;
sch->orb.intparm = intparm;
sch->orb.fmt = 1;
sch->orb.pfch = sch->options.prefetch == 0;
......@@ -219,7 +219,6 @@ cio_start (struct subchannel *sch, /* subchannel structure */
/*
* initialize device status information
*/
sch->u_intparm = intparm;
sch->schib.scsw.actl |= SCSW_ACTL_START_PEND;
return 0;
case 1: /* status pending */
......@@ -265,13 +264,10 @@ cio_resume (struct subchannel *sch)
}
/*
* Note: The "intparm" parameter is not used by the halt_IO() function
* 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.
* halt I/O operation
*/
int
cio_halt(struct subchannel *sch, unsigned long intparm)
cio_halt(struct subchannel *sch)
{
char dbf_txt[15];
int ccode;
......@@ -297,7 +293,6 @@ cio_halt(struct subchannel *sch, unsigned long intparm)
switch (ccode) {
case 0:
sch->u_intparm = intparm;
sch->schib.scsw.actl |= SCSW_ACTL_HALT_PEND;
return 0;
case 1: /* status pending */
......@@ -309,13 +304,10 @@ cio_halt(struct subchannel *sch, unsigned long intparm)
}
/*
* Note: The "intparm" parameter is not used by the clear_IO() function
* 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.
* Clear I/O operation
*/
int
cio_clear(struct subchannel *sch, unsigned long intparm)
cio_clear(struct subchannel *sch)
{
char dbf_txt[15];
int ccode;
......@@ -340,7 +332,6 @@ cio_clear(struct subchannel *sch, unsigned long intparm)
switch (ccode) {
case 0:
sch->u_intparm = intparm;
sch->schib.scsw.actl |= SCSW_ACTL_CLEAR_PEND;
return 0;
default: /* device not operational */
......@@ -374,6 +365,8 @@ cio_cancel (struct subchannel *sch)
switch (ccode) {
case 0: /* success */
/* Update information in scsw. */
stsch (sch->irq, &sch->schib);
return 0;
case 1: /* status pending */
return -EBUSY;
......@@ -620,7 +613,7 @@ do_IRQ (struct pt_regs regs)
*/
if (tpi_info->adapter_IO == 1 &&
tpi_info->int_type == IO_INTERRUPT_TYPE) {
do_adapter_IO (tpi_info->intparm);
do_adapter_IO();
continue;
}
sch = ioinfo[tpi_info->irq];
......
......@@ -98,8 +98,6 @@ struct subchannel {
__u8 vpm; /* verified 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 orb orb; /* operation request block */
struct ccw1 sense_ccw; /* static ccw for sense command */
......@@ -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_disable_subchannel (struct subchannel *);
extern int cio_cancel (struct subchannel *);
extern int cio_clear (struct subchannel *, unsigned long);
extern int cio_do_io (struct subchannel *, struct ccw1 *, unsigned long, __u8);
extern int cio_clear (struct subchannel *);
extern int cio_resume (struct subchannel *);
extern int cio_halt (struct subchannel *, unsigned long);
extern int cio_start (struct subchannel *, struct ccw1 *, unsigned long, __u8);
extern int cio_halt (struct subchannel *);
extern int cio_start (struct subchannel *, struct ccw1 *, unsigned int, __u8);
extern int cio_cancel (struct subchannel *);
extern int cio_set_options (struct subchannel *, int);
extern int cio_get_options (struct subchannel *);
......
/*
* drivers/s390/cio/css.c
* driver for channel subsystem
* $Revision: 1.40 $
* $Revision: 1.43 $
*
* Copyright (C) 2002 IBM Deutschland Entwicklung GmbH,
* IBM Corporation
......@@ -41,7 +41,7 @@ css_alloc_subchannel(int irq)
/* There already is a struct subchannel for this irq. */
return -EBUSY;
sch = kmalloc (sizeof (*sch), GFP_DMA);
sch = kmalloc (sizeof (*sch), GFP_KERNEL | GFP_DMA);
if (sch == NULL)
return -ENOMEM;
ret = cio_validate_subchannel (sch, irq);
......@@ -161,7 +161,7 @@ css_process_crw(int irq)
sch = ioinfo[irq];
if (sch == NULL) {
schedule_work(&work);
queue_work(ccw_device_work, &work);
return;
}
if (!sch->dev.driver_data)
......@@ -172,7 +172,7 @@ css_process_crw(int irq)
ccode = stsch(irq, &sch->schib);
if (!ccode)
if (devno != sch->schib.pmcw.dev)
schedule_work(&work);
queue_work(ccw_device_work, &work);
}
/*
......
......@@ -79,6 +79,7 @@ struct ccw_device_private {
unsigned int esid:1; /* Ext. SenseID supported by HW */
unsigned int dosense:1; /* delayed SENSE required */
} __attribute__((packed)) flags;
unsigned long intparm; /* user interruption parameter */
struct qdio_irq *qdio_data;
struct irb irb; /* device status */
struct senseid senseid; /* SenseID info */
......
/*
* drivers/s390/cio/device.c
* bus driver for ccw devices
* $Revision: 1.50 $
* $Revision: 1.53 $
*
* Copyright (C) 2002 IBM Deutschland Entwicklung GmbH,
* IBM Corporation
......@@ -18,6 +18,7 @@
#include <linux/slab.h>
#include <linux/list.h>
#include <linux/device.h>
#include <linux/workqueue.h>
#include <asm/ccwdev.h>
#include <asm/cio.h>
......@@ -126,14 +127,32 @@ static struct css_driver io_subchannel_driver = {
.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
init_ccw_bus_type (void)
{
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)))
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
......@@ -141,6 +160,7 @@ cleanup_ccw_bus_type (void)
{
driver_unregister(&io_subchannel_driver.drv);
bus_unregister(&ccw_bus_type);
destroy_workqueue(ccw_device_work);
}
subsys_initcall(init_ccw_bus_type);
......@@ -360,7 +380,7 @@ ccw_device_release(struct device *dev)
/*
* Register recognized device.
*/
void
static void
io_subchannel_register(void *data)
{
struct ccw_device *cdev;
......@@ -389,6 +409,42 @@ io_subchannel_register(void *data)
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
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. */
device_initialize(&cdev->dev);
/* Increase counter of devices currently in recognition. */
atomic_inc(&ccw_device_init_count);
/* Start async. device sensing. */
spin_lock_irq(cdev->ccwlock);
rc = ccw_device_recognition(cdev);
......@@ -428,6 +487,8 @@ io_subchannel_recog(struct ccw_device *cdev, struct subchannel *sch)
put_device(&sch->dev);
if (cdev->dev.release)
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)
if (!cdev)
return -ENOMEM;
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) {
kfree(cdev);
return -ENOMEM;
......
......@@ -14,13 +14,11 @@ enum dev_state {
DEV_STATE_W4SENSE,
DEV_STATE_DISBAND_PGID,
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 */
DEV_STATE_ONLINE_VERIFY,
DEV_STATE_W4SENSE_VERIFY,
DEV_STATE_CLEAR_VERIFY,
DEV_STATE_TIMEOUT_KILL,
/* last element! */
NR_DEV_STATES
};
......@@ -63,7 +61,9 @@ dev_fsm_final_state(struct ccw_device *cdev)
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_online(struct ccw_device *);
......
This diff is collapsed.
......@@ -198,11 +198,13 @@ __ccw_device_sense_id_start(struct ccw_device *cdev)
/* 0x00E2C9C4 == ebcdic "SID" */
ret = cio_start (sch, cdev->private->iccws,
0x00E2C9C4, cdev->private->imask);
/* ret is 0, -EBUSY or -ENODEV */
if (ret != -EBUSY)
/* ret is 0, -EBUSY, -EACCES or -ENODEV */
if (ret == -EBUSY) {
udelay(100);
continue;
}
if (ret != -EACCES)
return ret;
udelay(100);
continue;
}
cdev->private->imask >>= 1;
cdev->private->iretry = 5;
......
......@@ -49,12 +49,15 @@ ccw_device_clear(struct ccw_device *cdev, unsigned long intparm)
return -ENODEV;
if (cdev->private->state != DEV_STATE_ONLINE &&
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;
sch = to_subchannel(cdev->dev.parent);
if (!sch)
return -ENODEV;
ret = cio_clear(sch, intparm);
ret = cio_clear(sch);
if (ret == 0)
cdev->private->intparm = intparm;
return ret;
}
......@@ -67,17 +70,35 @@ ccw_device_start(struct ccw_device *cdev, struct ccw1 *cpa,
if (!cdev)
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);
if (!sch)
return -ENODEV;
if (cdev->private->state != DEV_STATE_ONLINE ||
sch->schib.scsw.actl != 0)
return -EBUSY;
ret = cio_set_options (sch, flags);
if (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;
}
......@@ -90,12 +111,16 @@ ccw_device_halt(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_ONLINE_VERIFY &&
cdev->private->state != DEV_STATE_W4SENSE_VERIFY)
return -EINVAL;
sch = to_subchannel(cdev->dev.parent);
if (!sch)
return -ENODEV;
ret = cio_halt(sch, intparm);
ret = cio_halt(sch);
if (ret == 0)
cdev->private->intparm = intparm;
return ret;
}
......@@ -106,12 +131,12 @@ ccw_device_resume(struct ccw_device *cdev)
if (!cdev)
return -ENODEV;
if (cdev->private->state != DEV_STATE_ONLINE &&
cdev->private->state != DEV_STATE_W4SENSE)
return -EINVAL;
sch = to_subchannel(cdev->dev.parent);
if (!sch)
return -ENODEV;
if (cdev->private->state != DEV_STATE_ONLINE ||
!(sch->schib.scsw.actl & SCSW_ACTL_SUSPENDED))
return -EINVAL;
return cio_resume(sch);
}
......@@ -123,15 +148,6 @@ 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);
......@@ -154,8 +170,9 @@ ccw_device_call_handler(struct ccw_device *cdev)
/*
* Now we are ready to call the device driver interrupt handler.
*/
if (handler)
handler(cdev, sch->u_intparm, &cdev->private->irb);
if (cdev->handler)
cdev->handler(cdev, cdev->private->intparm,
&cdev->private->irb);
/*
* Clear the old and now useless interrupt response block.
......@@ -192,6 +209,11 @@ ccw_device_get_path_mask(struct ccw_device *cdev)
static void
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);
}
......@@ -218,8 +240,7 @@ read_dev_chars (struct ccw_device *cdev, void **buffer, int length)
if (!cdev)
return -ENODEV;
if (cdev->private->state != DEV_STATE_ONLINE &&
cdev->private->state != DEV_STATE_W4SENSE)
if (cdev->private->state != DEV_STATE_ONLINE)
return -EINVAL;
if (!buffer || !length)
return -EINVAL;
......@@ -251,7 +272,13 @@ 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. */
/* 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;
}
}
......@@ -281,8 +308,7 @@ read_conf_data (struct ccw_device *cdev, void **buffer, int *length)
if (!cdev)
return -ENODEV;
if (cdev->private->state != DEV_STATE_ONLINE &&
cdev->private->state != DEV_STATE_W4SENSE)
if (cdev->private->state != DEV_STATE_ONLINE)
return -EINVAL;
if (cdev->private->flags.esid == 0)
return -EOPNOTSUPP;
......@@ -300,7 +326,7 @@ read_conf_data (struct ccw_device *cdev, void **buffer, int *length)
if (!ciw || ciw->cmd == 0)
return -EOPNOTSUPP;
rcd_buf = kmalloc(ciw->count, GFP_DMA);
rcd_buf = kmalloc(ciw->count, GFP_KERNEL | GFP_DMA);
if (!rcd_buf)
return -ENOMEM;
memset (rcd_buf, 0, ciw->count);
......@@ -325,7 +351,13 @@ 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. */
/* 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;
}
/* Restore interrupt handler. */
......@@ -363,13 +395,15 @@ _ccw_device_get_device_number(struct ccw_device *cdev)
MODULE_LICENSE("GPL");
EXPORT_SYMBOL(ccw_device_set_options);
EXPORT_SYMBOL(ccw_device_clear);
EXPORT_SYMBOL(ccw_device_halt);
EXPORT_SYMBOL(ccw_device_resume);
EXPORT_SYMBOL(ccw_device_start_timeout);
EXPORT_SYMBOL(ccw_device_start);
EXPORT_SYMBOL(ccw_device_get_ciw);
EXPORT_SYMBOL(ccw_device_get_path_mask);
EXPORT_SYMBOL (read_conf_data);
EXPORT_SYMBOL (read_dev_chars);
EXPORT_SYMBOL(read_conf_data);
EXPORT_SYMBOL(read_dev_chars);
EXPORT_SYMBOL(_ccw_device_get_subchannel_number);
EXPORT_SYMBOL(_ccw_device_get_device_number);
......@@ -51,14 +51,23 @@ __ccw_device_sense_pgid_start(struct ccw_device *cdev)
/* 0xe2d5c9c4 == ebcdic "SNID" */
ret = cio_start (sch, cdev->private->iccws,
0xE2D5C9C4, cdev->private->imask);
/* ret is 0, -EBUSY or -ENODEV */
if (ret != -EBUSY)
/* ret is 0, -EBUSY, -EACCES or -ENODEV */
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;
CIO_MSG_EVENT(2, "SNID - device %04X, start_io() "
"reports rc : %d, retrying ...\n",
sch->schib.pmcw.dev, ret);
udelay(100);
continue;
CIO_MSG_EVENT(2, "SNID - Device %04X on Subchannel "
"%04X, lpm %02X, became 'not "
"operational'\n",
sch->schib.pmcw.dev, sch->irq,
cdev->private->imask);
}
cdev->private->imask >>= 1;
cdev->private->iretry = 5;
......@@ -231,7 +240,9 @@ __ccw_device_do_pgid(struct ccw_device *cdev, __u8 func)
/* 0xE2D7C9C4 == ebcdic "SPID" */
ret = cio_start (sch, cdev->private->iccws,
0xE2D7C9C4, cdev->private->imask);
/* ret is 0, -EBUSY or -ENODEV */
/* ret is 0, -EBUSY, -EACCES or -ENODEV */
if (ret == -EACCES)
break;
if (ret != -EBUSY)
return ret;
udelay(100);
......
......@@ -167,7 +167,7 @@ ccw_device_accumulate_esw(struct ccw_device *cdev, struct irb *irb)
/* Copy authorization bit. */
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;
/* Copy concurrent sense bit. */
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)
sch->sense_ccw.flags = CCW_FLAG_SLI;
/* 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
#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
......@@ -48,25 +48,25 @@
#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
of the queue to 0 */
#define QDIO_ESTABLISH_TIMEOUT 1000
#define QDIO_ACTIVATE_TIMEOUT 100
#define QDIO_ACTIVATE_TIMEOUT 5
#define QDIO_CLEANUP_CLEAR_TIMEOUT 20000
#define QDIO_CLEANUP_HALT_TIMEOUT 10000
#define QDIO_IRQ_STATE_FRESH 0 /* must be 0 -> memset has set it to 0 */
#define QDIO_IRQ_STATE_INACTIVE 1
#define QDIO_IRQ_STATE_ESTABLISHED 2
#define QDIO_IRQ_STATE_ACTIVE 3
#define QDIO_IRQ_STATE_STOPPED 4
enum qdio_irq_states {
QDIO_IRQ_STATE_INACTIVE,
QDIO_IRQ_STATE_ESTABLISHED,
QDIO_IRQ_STATE_ACTIVE,
QDIO_IRQ_STATE_STOPPED,
QDIO_IRQ_STATE_CLEANUP,
QDIO_IRQ_STATE_ERR,
NR_QDIO_IRQ_STATES,
};
/* used as intparm in do_IO: */
#define QDIO_DOING_SENSEID 0
......@@ -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_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
struct qdio_perf_stats {
unsigned int tl_runs;
......@@ -623,7 +548,7 @@ struct qdio_q {
struct tasklet_struct tasklet;
#endif /* QDIO_USE_TIMERS_FOR_POLLING */
unsigned int state;
enum qdio_irq_states state;
/* used to store the error condition during a data transfer */
unsigned int qdio_error;
......@@ -674,7 +599,7 @@ struct qdio_irq {
unsigned int hydra_gives_outbound_pcis;
unsigned int sync_done_on_outb_pcis;
unsigned int state;
enum qdio_irq_states state;
struct semaphore setting_up_sema;
unsigned int no_input_qs;
......@@ -694,13 +619,8 @@ struct qdio_irq {
struct qib qib;
/* Functions called via the generic cio layer */
void (*cleanup_irq) (struct ccw_device *, 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 *);
void (*original_int_handler) (struct ccw_device *,
unsigned long, struct irb *);
};
#endif
......@@ -44,7 +44,11 @@ init_IRQ(void)
/*
* 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_model = ((cpuid_t *) __LC_CPUID)->machine;
global_pgid.tod_high = (__u32) (get_clock() >> 32);
......
......@@ -21,7 +21,7 @@
extern void css_process_crw(int);
extern void chsc_process_crw(void);
extern void chp_process_crw(int);
extern void chp_process_crw(int, int);
static void
s390_handle_damage(char *msg)
......@@ -62,7 +62,17 @@ s390_collect_crw_info(void)
break;
case CRW_RSC_CPATH:
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;
case CRW_RSC_CONFIG:
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