|
@@ -2,8 +2,7 @@
|
|
|
* drivers/s390/cio/css.c
|
|
|
* driver for channel subsystem
|
|
|
*
|
|
|
- * Copyright (C) 2002 IBM Deutschland Entwicklung GmbH,
|
|
|
- * IBM Corporation
|
|
|
+ * Copyright IBM Corp. 2002,2008
|
|
|
* Author(s): Arnd Bergmann (arndb@de.ibm.com)
|
|
|
* Cornelia Huck (cornelia.huck@de.ibm.com)
|
|
|
*/
|
|
@@ -210,6 +209,41 @@ void css_update_ssd_info(struct subchannel *sch)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+static ssize_t type_show(struct device *dev, struct device_attribute *attr,
|
|
|
+ char *buf)
|
|
|
+{
|
|
|
+ struct subchannel *sch = to_subchannel(dev);
|
|
|
+
|
|
|
+ return sprintf(buf, "%01x\n", sch->st);
|
|
|
+}
|
|
|
+
|
|
|
+static DEVICE_ATTR(type, 0444, type_show, NULL);
|
|
|
+
|
|
|
+static ssize_t modalias_show(struct device *dev, struct device_attribute *attr,
|
|
|
+ char *buf)
|
|
|
+{
|
|
|
+ struct subchannel *sch = to_subchannel(dev);
|
|
|
+
|
|
|
+ return sprintf(buf, "css:t%01X\n", sch->st);
|
|
|
+}
|
|
|
+
|
|
|
+static DEVICE_ATTR(modalias, 0444, modalias_show, NULL);
|
|
|
+
|
|
|
+static struct attribute *subch_attrs[] = {
|
|
|
+ &dev_attr_type.attr,
|
|
|
+ &dev_attr_modalias.attr,
|
|
|
+ NULL,
|
|
|
+};
|
|
|
+
|
|
|
+static struct attribute_group subch_attr_group = {
|
|
|
+ .attrs = subch_attrs,
|
|
|
+};
|
|
|
+
|
|
|
+static struct attribute_group *default_subch_attr_groups[] = {
|
|
|
+ &subch_attr_group,
|
|
|
+ NULL,
|
|
|
+};
|
|
|
+
|
|
|
static int css_register_subchannel(struct subchannel *sch)
|
|
|
{
|
|
|
int ret;
|
|
@@ -218,16 +252,17 @@ static int css_register_subchannel(struct subchannel *sch)
|
|
|
sch->dev.parent = &channel_subsystems[0]->device;
|
|
|
sch->dev.bus = &css_bus_type;
|
|
|
sch->dev.release = &css_subchannel_release;
|
|
|
- sch->dev.groups = subch_attr_groups;
|
|
|
+ sch->dev.groups = default_subch_attr_groups;
|
|
|
/*
|
|
|
* We don't want to generate uevents for I/O subchannels that don't
|
|
|
* have a working ccw device behind them since they will be
|
|
|
* unregistered before they can be used anyway, so we delay the add
|
|
|
* uevent until after device recognition was successful.
|
|
|
+ * Note that we suppress the uevent for all subchannel types;
|
|
|
+ * the subchannel driver can decide itself when it wants to inform
|
|
|
+ * userspace of its existence.
|
|
|
*/
|
|
|
- if (!cio_is_console(sch->schid))
|
|
|
- /* Console is special, no need to suppress. */
|
|
|
- sch->dev.uevent_suppress = 1;
|
|
|
+ sch->dev.uevent_suppress = 1;
|
|
|
css_update_ssd_info(sch);
|
|
|
/* make it known to the system */
|
|
|
ret = css_sch_device_register(sch);
|
|
@@ -236,6 +271,15 @@ static int css_register_subchannel(struct subchannel *sch)
|
|
|
sch->schid.ssid, sch->schid.sch_no, ret);
|
|
|
return ret;
|
|
|
}
|
|
|
+ if (!sch->driver) {
|
|
|
+ /*
|
|
|
+ * No driver matched. Generate the uevent now so that
|
|
|
+ * a fitting driver module may be loaded based on the
|
|
|
+ * modalias.
|
|
|
+ */
|
|
|
+ sch->dev.uevent_suppress = 0;
|
|
|
+ kobject_uevent(&sch->dev.kobj, KOBJ_ADD);
|
|
|
+ }
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
@@ -926,12 +970,25 @@ static void css_shutdown(struct device *dev)
|
|
|
sch->driver->shutdown(sch);
|
|
|
}
|
|
|
|
|
|
+static int css_uevent(struct device *dev, struct kobj_uevent_env *env)
|
|
|
+{
|
|
|
+ struct subchannel *sch = to_subchannel(dev);
|
|
|
+ int ret;
|
|
|
+
|
|
|
+ ret = add_uevent_var(env, "ST=%01X", sch->st);
|
|
|
+ if (ret)
|
|
|
+ return ret;
|
|
|
+ ret = add_uevent_var(env, "MODALIAS=css:t%01X", sch->st);
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
struct bus_type css_bus_type = {
|
|
|
.name = "css",
|
|
|
.match = css_bus_match,
|
|
|
.probe = css_probe,
|
|
|
.remove = css_remove,
|
|
|
.shutdown = css_shutdown,
|
|
|
+ .uevent = css_uevent,
|
|
|
};
|
|
|
|
|
|
/**
|