Commit 4e4eef31 authored by Martin Schwidefsky's avatar Martin Schwidefsky Committed by Linus Torvalds

[PATCH] s390: common i/o layer

From: Cornelia Huck <cohuck@de.ibm.com>
From: Steffen Thoss <thoss@de.ibm.com>

common i/o layer changes:
 - Delay re-registration of a subchannel with a different subchannel id
   until the ccw device removal triggered from the subchannels remove
   function has completed.
 - Fix check when to call unreg_rereg.
 - Fix get_disc_cdev_by_devno.
 - Activate the time delay disablement facility. This saves a few cycles
   in millicode processing.
 - Don't ifdef reset of busy start time.
Signed-off-by: default avatarMartin Schwidefsky <schwidefsky@de.ibm.com>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent ca2ab032
/* /*
* drivers/s390/cio/device.c * drivers/s390/cio/device.c
* bus driver for ccw devices * bus driver for ccw devices
* $Revision: 1.128 $ * $Revision: 1.129 $
* *
* Copyright (C) 2002 IBM Deutschland Entwicklung GmbH, * Copyright (C) 2002 IBM Deutschland Entwicklung GmbH,
* IBM Corporation * IBM Corporation
...@@ -525,8 +525,7 @@ get_disc_ccwdev_by_devno(unsigned int devno, struct ccw_device *sibling) ...@@ -525,8 +525,7 @@ get_disc_ccwdev_by_devno(unsigned int devno, struct ccw_device *sibling)
cdev = to_ccwdev(dev); cdev = to_ccwdev(dev);
if ((cdev->private->state == DEV_STATE_DISCONNECTED) && if ((cdev->private->state == DEV_STATE_DISCONNECTED) &&
(cdev->private->devno == devno) && (cdev->private->devno == devno) &&
(!strncmp(cdev->dev.bus_id, sibling->dev.bus_id, (cdev != sibling)) {
BUS_ID_SIZE))) {
cdev->private->state = DEV_STATE_NOT_OPER; cdev->private->state = DEV_STATE_NOT_OPER;
break; break;
} }
...@@ -539,6 +538,24 @@ get_disc_ccwdev_by_devno(unsigned int devno, struct ccw_device *sibling) ...@@ -539,6 +538,24 @@ get_disc_ccwdev_by_devno(unsigned int devno, struct ccw_device *sibling)
return cdev; return cdev;
} }
static void
ccw_device_add_changed(void *data)
{
struct ccw_device *cdev;
cdev = (struct ccw_device *)data;
if (device_add(&cdev->dev)) {
put_device(&cdev->dev);
return;
}
set_bit(1, &cdev->private->registered);
if (device_add_files(&cdev->dev)) {
if (test_and_clear_bit(1, &cdev->private->registered))
device_unregister(&cdev->dev);
}
}
extern int css_get_ssd_info(struct subchannel *sch); extern int css_get_ssd_info(struct subchannel *sch);
void void
...@@ -593,15 +610,9 @@ ccw_device_do_unreg_rereg(void *data) ...@@ -593,15 +610,9 @@ ccw_device_do_unreg_rereg(void *data)
if (need_rename) if (need_rename)
snprintf (cdev->dev.bus_id, BUS_ID_SIZE, "0.0.%04x", snprintf (cdev->dev.bus_id, BUS_ID_SIZE, "0.0.%04x",
sch->schib.pmcw.dev); sch->schib.pmcw.dev);
if (device_add(&cdev->dev)) { PREPARE_WORK(&cdev->private->kick_work,
put_device(&cdev->dev); ccw_device_add_changed, (void *)cdev);
return; queue_work(ccw_device_work, &cdev->private->kick_work);
}
set_bit(1, &cdev->private->registered);
if (device_add_files(&cdev->dev)) {
if (test_and_clear_bit(1, &cdev->private->registered))
device_unregister(&cdev->dev);
}
} }
static void static void
......
...@@ -154,7 +154,7 @@ ccw_device_cancel_halt_clear(struct ccw_device *cdev) ...@@ -154,7 +154,7 @@ ccw_device_cancel_halt_clear(struct ccw_device *cdev)
panic("Can't stop i/o on subchannel.\n"); panic("Can't stop i/o on subchannel.\n");
} }
static void static int
ccw_device_handle_oper(struct ccw_device *cdev) ccw_device_handle_oper(struct ccw_device *cdev)
{ {
struct subchannel *sch; struct subchannel *sch;
...@@ -174,9 +174,10 @@ ccw_device_handle_oper(struct ccw_device *cdev) ...@@ -174,9 +174,10 @@ ccw_device_handle_oper(struct ccw_device *cdev)
PREPARE_WORK(&cdev->private->kick_work, PREPARE_WORK(&cdev->private->kick_work,
ccw_device_do_unreg_rereg, (void *)cdev); ccw_device_do_unreg_rereg, (void *)cdev);
queue_work(ccw_device_work, &cdev->private->kick_work); queue_work(ccw_device_work, &cdev->private->kick_work);
return; return 0;
} }
cdev->private->flags.donotify = 1; cdev->private->flags.donotify = 1;
return 1;
} }
/* /*
...@@ -206,7 +207,7 @@ static void ...@@ -206,7 +207,7 @@ static void
ccw_device_recog_done(struct ccw_device *cdev, int state) ccw_device_recog_done(struct ccw_device *cdev, int state)
{ {
struct subchannel *sch; struct subchannel *sch;
int notify, old_lpm; int notify, old_lpm, same_dev;
sch = to_subchannel(cdev->dev.parent); sch = to_subchannel(cdev->dev.parent);
...@@ -236,6 +237,7 @@ ccw_device_recog_done(struct ccw_device *cdev, int state) ...@@ -236,6 +237,7 @@ ccw_device_recog_done(struct ccw_device *cdev, int state)
/* Boxed devices don't need extra treatment. */ /* Boxed devices don't need extra treatment. */
} }
notify = 0; notify = 0;
same_dev = 0; /* Keep the compiler quiet... */
switch (state) { switch (state) {
case DEV_STATE_NOT_OPER: case DEV_STATE_NOT_OPER:
CIO_DEBUG(KERN_WARNING, 2, CIO_DEBUG(KERN_WARNING, 2,
...@@ -244,7 +246,7 @@ ccw_device_recog_done(struct ccw_device *cdev, int state) ...@@ -244,7 +246,7 @@ ccw_device_recog_done(struct ccw_device *cdev, int state)
break; break;
case DEV_STATE_OFFLINE: case DEV_STATE_OFFLINE:
if (cdev->private->state == DEV_STATE_DISCONNECTED_SENSE_ID) { if (cdev->private->state == DEV_STATE_DISCONNECTED_SENSE_ID) {
ccw_device_handle_oper(cdev); same_dev = ccw_device_handle_oper(cdev);
notify = 1; notify = 1;
} }
/* fill out sense information */ /* fill out sense information */
...@@ -255,10 +257,12 @@ ccw_device_recog_done(struct ccw_device *cdev, int state) ...@@ -255,10 +257,12 @@ ccw_device_recog_done(struct ccw_device *cdev, int state)
.dev_model = cdev->private->senseid.dev_model, .dev_model = cdev->private->senseid.dev_model,
}; };
if (notify) { if (notify) {
/* Get device online again. */
cdev->private->state = DEV_STATE_OFFLINE; cdev->private->state = DEV_STATE_OFFLINE;
ccw_device_online(cdev); if (same_dev) {
wake_up(&cdev->private->wait_q); /* Get device online again. */
ccw_device_online(cdev);
wake_up(&cdev->private->wait_q);
}
return; return;
} }
/* Issue device info message. */ /* Issue device info message. */
......
...@@ -56,7 +56,7 @@ ...@@ -56,7 +56,7 @@
#include "ioasm.h" #include "ioasm.h"
#include "chsc.h" #include "chsc.h"
#define VERSION_QDIO_C "$Revision: 1.89 $" #define VERSION_QDIO_C "$Revision: 1.93 $"
/****************** MODULE PARAMETER VARIABLES ********************/ /****************** MODULE PARAMETER VARIABLES ********************/
MODULE_AUTHOR("Utz Bacher <utz.bacher@de.ibm.com>"); MODULE_AUTHOR("Utz Bacher <utz.bacher@de.ibm.com>");
...@@ -605,8 +605,8 @@ qdio_kick_outbound_q(struct qdio_q *q) ...@@ -605,8 +605,8 @@ qdio_kick_outbound_q(struct qdio_q *q)
sprintf(dbf_text,"%4x%2x%2x",q->irq,q->q_no, sprintf(dbf_text,"%4x%2x%2x",q->irq,q->q_no,
atomic_read(&q->busy_siga_counter)); atomic_read(&q->busy_siga_counter));
QDIO_DBF_TEXT3(0,trace,dbf_text); QDIO_DBF_TEXT3(0,trace,dbf_text);
q->timing.busy_start=0;
#endif /* CONFIG_QDIO_DEBUG */ #endif /* CONFIG_QDIO_DEBUG */
q->timing.busy_start=0;
break; break;
case (2|QDIO_SIGA_ERROR_B_BIT_SET): case (2|QDIO_SIGA_ERROR_B_BIT_SET):
/* cc=2 and busy bit: */ /* cc=2 and busy bit: */
...@@ -2088,7 +2088,10 @@ tiqdio_set_subchannel_ind(struct qdio_irq *irq_ptr, int reset_to_zero) ...@@ -2088,7 +2088,10 @@ tiqdio_set_subchannel_ind(struct qdio_irq *irq_ptr, int reset_to_zero)
u32 kc:4; u32 kc:4;
u32 reserved4:21; u32 reserved4:21;
u32 isc:3; u32 isc:3;
u32 reserved5[2]; u32 word_with_d_bit;
/* set to 0x10000000 to enable
* time delay disablement facility */
u32 reserved5;
u32 subsystem_id; u32 subsystem_id;
u32 reserved6[1004]; u32 reserved6[1004];
struct chsc_header response; struct chsc_header response;
...@@ -2126,6 +2129,12 @@ tiqdio_set_subchannel_ind(struct qdio_irq *irq_ptr, int reset_to_zero) ...@@ -2126,6 +2129,12 @@ tiqdio_set_subchannel_ind(struct qdio_irq *irq_ptr, int reset_to_zero)
scssc_area->kc = QDIO_STORAGE_KEY; scssc_area->kc = QDIO_STORAGE_KEY;
scssc_area->isc = TIQDIO_THININT_ISC; scssc_area->isc = TIQDIO_THININT_ISC;
scssc_area->subsystem_id = (1<<16) + irq_ptr->irq; scssc_area->subsystem_id = (1<<16) + irq_ptr->irq;
/* enables the time delay disablement facility. Don't care
* whether it is really there (i.e. we haven't checked for
* it) */
scssc_area->word_with_d_bit = 0x10000000;
result = chsc(scssc_area); result = chsc(scssc_area);
if (result) { if (result) {
...@@ -2620,6 +2629,7 @@ qdio_allocate(struct qdio_initialize *init_data) ...@@ -2620,6 +2629,7 @@ qdio_allocate(struct qdio_initialize *init_data)
init_MUTEX(&irq_ptr->setting_up_sema); init_MUTEX(&irq_ptr->setting_up_sema);
/* QDR must be in DMA area since CCW data address is only 32 bit */
irq_ptr->qdr=kmalloc(sizeof(struct qdr), GFP_KERNEL | GFP_DMA); irq_ptr->qdr=kmalloc(sizeof(struct qdr), GFP_KERNEL | GFP_DMA);
if (!(irq_ptr->qdr)) { if (!(irq_ptr->qdr)) {
kfree(irq_ptr); kfree(irq_ptr);
......
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