+static int __init
+__init_channel_subsystem(struct subchannel_id schid, void *data)
+{
+ struct subchannel *sch;
+ int ret;
+
+ if (cio_is_console(schid))
+ sch = cio_get_console_subchannel();
+ else {
+ sch = css_alloc_subchannel(schid);
+ if (IS_ERR(sch))
+ ret = PTR_ERR(sch);
+ else
+ ret = 0;
+ switch (ret) {
+ case 0:
+ break;
+ case -ENOMEM:
+ panic("Out of memory in init_channel_subsystem\n");
+ /* -ENXIO: no more subchannels. */
+ case -ENXIO:
+ return ret;
+ /* -EIO: this subchannel set not supported. */
+ case -EIO:
+ return ret;
+ default:
+ return 0;
+ }
+ }
+ /*
+ * We register ALL valid subchannels in ioinfo, even those
+ * that have been present before init_channel_subsystem.
+ * These subchannels can't have been registered yet (kmalloc
+ * not working) so we do it now. This is true e.g. for the
+ * console subchannel.
+ */
+ css_register_subchannel(sch);
+ return 0;
+}
+
+static void __init
+css_generate_pgid(struct channel_subsystem *css, u32 tod_high)
+{
+ if (css_characteristics_avail && css_general_characteristics.mcss) {
+ css->global_pgid.pgid_high.ext_cssid.version = 0x80;
+ css->global_pgid.pgid_high.ext_cssid.cssid = css->cssid;
+ } else {
+#ifdef CONFIG_SMP
+ css->global_pgid.pgid_high.cpu_addr = hard_smp_processor_id();
+#else
+ css->global_pgid.pgid_high.cpu_addr = 0;
+#endif
+ }
+ css->global_pgid.cpu_id = ((cpuid_t *) __LC_CPUID)->ident;
+ css->global_pgid.cpu_model = ((cpuid_t *) __LC_CPUID)->machine;
+ css->global_pgid.tod_high = tod_high;
+
+}
+
+static void
+channel_subsystem_release(struct device *dev)
+{
+ struct channel_subsystem *css;
+
+ css = to_css(dev);
+ mutex_destroy(&css->mutex);
+ kfree(css);
+}
+
+static ssize_t
+css_cm_enable_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct channel_subsystem *css = to_css(dev);
+
+ if (!css)
+ return 0;
+ return sprintf(buf, "%x\n", css->cm_enabled);
+}
+
+static ssize_t
+css_cm_enable_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct channel_subsystem *css = to_css(dev);
+ int ret;
+
+ switch (buf[0]) {
+ case '0':
+ ret = css->cm_enabled ? chsc_secm(css, 0) : 0;
+ break;
+ case '1':
+ ret = css->cm_enabled ? 0 : chsc_secm(css, 1);
+ break;
+ default:
+ ret = -EINVAL;
+ }
+ return ret < 0 ? ret : count;
+}
+
+static DEVICE_ATTR(cm_enable, 0644, css_cm_enable_show, css_cm_enable_store);
+
+static inline int __init setup_css(int nr)
+{
+ u32 tod_high;
+ int ret;
+
+ memset(css[nr], 0, sizeof(struct channel_subsystem));
+ css[nr]->pseudo_subchannel =
+ kzalloc(sizeof(*css[nr]->pseudo_subchannel), GFP_KERNEL);
+ if (!css[nr]->pseudo_subchannel)
+ return -ENOMEM;
+ css[nr]->pseudo_subchannel->dev.parent = &css[nr]->device;
+ css[nr]->pseudo_subchannel->dev.release = css_subchannel_release;
+ sprintf(css[nr]->pseudo_subchannel->dev.bus_id, "defunct");
+ ret = cio_create_sch_lock(css[nr]->pseudo_subchannel);
+ if (ret) {
+ kfree(css[nr]->pseudo_subchannel);
+ return ret;
+ }
+ mutex_init(&css[nr]->mutex);
+ css[nr]->valid = 1;
+ css[nr]->cssid = nr;
+ sprintf(css[nr]->device.bus_id, "css%x", nr);
+ css[nr]->device.release = channel_subsystem_release;
+ tod_high = (u32) (get_clock() >> 32);
+ css_generate_pgid(css[nr], tod_high);
+ return 0;
+}
+