/*
* drivers/s390/cio/chsc.c
* S/390 common I/O routines -- channel subsystem call
- * $Revision: 1.110 $
+ * $Revision: 1.115 $
*
* Copyright (C) 1999-2002 IBM Deutschland Entwicklung GmbH,
* IBM Corporation
#include "ioasm.h"
#include "chsc.h"
-#define CHPID_LONGS (256 / (8 * sizeof(long))) /* 256 chpids */
static struct channel_path *chps[NR_CHPIDS];
static void *sei_page;
int state;
state = get_chp_status(chp);
- if (state < 0)
- new_channel_path(chp);
- else
+ if (state < 0) {
+ need_rescan = 1;
+ queue_work(slow_path_wq, &slow_path_work);
+ } else
WARN_ON(!state);
- /* FIXME: should notify other subchannels here */
}
/* FIXME: this is _always_ called for every subchannel. shouldn't we
out_unreg:
spin_unlock(&sch->lock);
sch->lpm = 0;
- /* We can't block here. */
- device_call_nopath_notify(sch);
+ if (css_enqueue_subchannel_slow(sch->irq)) {
+ css_clear_subchannel_slow_list();
+ need_rescan = 1;
+ }
return 0;
}
bus_for_each_dev(&css_bus_type, NULL, &chpid,
s390_subchannel_remove_chpid);
+
+ if (need_rescan || css_slow_subchannels_exist())
+ queue_work(slow_path_wq, &slow_path_work);
}
static int
* can successfully terminate, even using the
* just varied off path. Then kill it.
*/
- if (!__check_for_io_and_kill(sch, chp) && !sch->lpm)
- /* Get over with it now. */
- device_call_nopath_notify(sch);
- else if (sch->driver && sch->driver->verify)
+ if (!__check_for_io_and_kill(sch, chp) && !sch->lpm) {
+ if (css_enqueue_subchannel_slow(sch->irq)) {
+ css_clear_subchannel_slow_list();
+ need_rescan = 1;
+ }
+ } else if (sch->driver && sch->driver->verify)
sch->driver->verify(&sch->dev);
}
break;
return 0;
}
-extern void css_trigger_slow_path(void);
-typedef void (*workfunc)(void *);
-static DECLARE_WORK(varyonoff_work, (workfunc)css_trigger_slow_path,
- NULL);
-
/*
* Function: s390_vary_chpid
* Varies the specified chpid online or offline
s390_subchannel_vary_chpid_on :
s390_subchannel_vary_chpid_off);
if (!on)
- return 0;
+ goto out;
/* Scan for new devices on varied on path. */
for (irq = 0; irq < __MAX_SUBCHANNELS; irq++) {
struct schib schib;
need_rescan = 1;
}
}
+out:
if (need_rescan || css_slow_subchannels_exist())
- schedule_work(&varyonoff_work);
+ queue_work(slow_path_wq, &slow_path_work);
return 0;
}
return -ENOMEM;
memset(chp, 0, sizeof(struct channel_path));
- chps[chpid] = chp;
-
/* fill in status, etc. */
chp->id = chpid;
chp->state = 1;
if (ret) {
printk(KERN_WARNING "%s: could not register %02x\n",
__func__, chpid);
- return ret;
+ goto out_free;
}
ret = device_create_file(&chp->dev, &dev_attr_status);
- if (ret)
+ if (ret) {
device_unregister(&chp->dev);
-
+ goto out_free;
+ } else
+ chps[chpid] = chp;
+ return ret;
+out_free:
+ kfree(chp);
return ret;
}
}
subsys_initcall(chsc_alloc_sei_area);
+
+struct css_general_char css_general_characteristics;
+struct css_chsc_char css_chsc_characteristics;
+
+int __init
+chsc_determine_css_characteristics(void)
+{
+ int result;
+ struct {
+ struct chsc_header request;
+ u32 reserved1;
+ u32 reserved2;
+ u32 reserved3;
+ struct chsc_header response;
+ u32 reserved4;
+ u32 general_char[510];
+ u32 chsc_char[518];
+ } *scsc_area;
+
+ scsc_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
+ if (!scsc_area) {
+ printk(KERN_WARNING"cio: Was not able to determine available" \
+ "CHSCs due to no memory.\n");
+ return -ENOMEM;
+ }
+
+ scsc_area->request = (struct chsc_header) {
+ .length = 0x0010,
+ .code = 0x0010,
+ };
+
+ result = chsc(scsc_area);
+ if (result) {
+ printk(KERN_WARNING"cio: Was not able to determine " \
+ "available CHSCs, cc=%i.\n", result);
+ result = -EIO;
+ goto exit;
+ }
+
+ if (scsc_area->response.code != 1) {
+ printk(KERN_WARNING"cio: Was not able to determine " \
+ "available CHSCs.\n");
+ result = -EIO;
+ goto exit;
+ }
+ memcpy(&css_general_characteristics, scsc_area->general_char,
+ sizeof(css_general_characteristics));
+ memcpy(&css_chsc_characteristics, scsc_area->chsc_char,
+ sizeof(css_chsc_characteristics));
+exit:
+ free_page ((unsigned long) scsc_area);
+ return result;
+}
+
+EXPORT_SYMBOL_GPL(css_general_characteristics);
+EXPORT_SYMBOL_GPL(css_chsc_characteristics);