aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/s390
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/s390')
-rw-r--r--drivers/s390/cio/cio.h1
-rw-r--r--drivers/s390/cio/css.c69
-rw-r--r--drivers/s390/cio/css.h2
-rw-r--r--drivers/s390/cio/device.c47
4 files changed, 95 insertions, 24 deletions
diff --git a/drivers/s390/cio/cio.h b/drivers/s390/cio/cio.h
index 6e933aebe013..4062748e8346 100644
--- a/drivers/s390/cio/cio.h
+++ b/drivers/s390/cio/cio.h
@@ -3,6 +3,7 @@
3 3
4#include <linux/mutex.h> 4#include <linux/mutex.h>
5#include <linux/device.h> 5#include <linux/device.h>
6#include <linux/mod_devicetable.h>
6#include <asm/chpid.h> 7#include <asm/chpid.h>
7#include "chsc.h" 8#include "chsc.h"
8#include "schid.h" 9#include "schid.h"
diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c
index b7f4b52c5a9a..53e7496dc90c 100644
--- a/drivers/s390/cio/css.c
+++ b/drivers/s390/cio/css.c
@@ -2,8 +2,7 @@
2 * drivers/s390/cio/css.c 2 * drivers/s390/cio/css.c
3 * driver for channel subsystem 3 * driver for channel subsystem
4 * 4 *
5 * Copyright (C) 2002 IBM Deutschland Entwicklung GmbH, 5 * Copyright IBM Corp. 2002,2008
6 * IBM Corporation
7 * Author(s): Arnd Bergmann (arndb@de.ibm.com) 6 * Author(s): Arnd Bergmann (arndb@de.ibm.com)
8 * Cornelia Huck (cornelia.huck@de.ibm.com) 7 * Cornelia Huck (cornelia.huck@de.ibm.com)
9 */ 8 */
@@ -210,6 +209,41 @@ void css_update_ssd_info(struct subchannel *sch)
210 } 209 }
211} 210}
212 211
212static ssize_t type_show(struct device *dev, struct device_attribute *attr,
213 char *buf)
214{
215 struct subchannel *sch = to_subchannel(dev);
216
217 return sprintf(buf, "%01x\n", sch->st);
218}
219
220static DEVICE_ATTR(type, 0444, type_show, NULL);
221
222static ssize_t modalias_show(struct device *dev, struct device_attribute *attr,
223 char *buf)
224{
225 struct subchannel *sch = to_subchannel(dev);
226
227 return sprintf(buf, "css:t%01X\n", sch->st);
228}
229
230static DEVICE_ATTR(modalias, 0444, modalias_show, NULL);
231
232static struct attribute *subch_attrs[] = {
233 &dev_attr_type.attr,
234 &dev_attr_modalias.attr,
235 NULL,
236};
237
238static struct attribute_group subch_attr_group = {
239 .attrs = subch_attrs,
240};
241
242static struct attribute_group *default_subch_attr_groups[] = {
243 &subch_attr_group,
244 NULL,
245};
246
213static int css_register_subchannel(struct subchannel *sch) 247static int css_register_subchannel(struct subchannel *sch)
214{ 248{
215 int ret; 249 int ret;
@@ -218,16 +252,17 @@ static int css_register_subchannel(struct subchannel *sch)
218 sch->dev.parent = &channel_subsystems[0]->device; 252 sch->dev.parent = &channel_subsystems[0]->device;
219 sch->dev.bus = &css_bus_type; 253 sch->dev.bus = &css_bus_type;
220 sch->dev.release = &css_subchannel_release; 254 sch->dev.release = &css_subchannel_release;
221 sch->dev.groups = subch_attr_groups; 255 sch->dev.groups = default_subch_attr_groups;
222 /* 256 /*
223 * We don't want to generate uevents for I/O subchannels that don't 257 * We don't want to generate uevents for I/O subchannels that don't
224 * have a working ccw device behind them since they will be 258 * have a working ccw device behind them since they will be
225 * unregistered before they can be used anyway, so we delay the add 259 * unregistered before they can be used anyway, so we delay the add
226 * uevent until after device recognition was successful. 260 * uevent until after device recognition was successful.
261 * Note that we suppress the uevent for all subchannel types;
262 * the subchannel driver can decide itself when it wants to inform
263 * userspace of its existence.
227 */ 264 */
228 if (!cio_is_console(sch->schid)) 265 sch->dev.uevent_suppress = 1;
229 /* Console is special, no need to suppress. */
230 sch->dev.uevent_suppress = 1;
231 css_update_ssd_info(sch); 266 css_update_ssd_info(sch);
232 /* make it known to the system */ 267 /* make it known to the system */
233 ret = css_sch_device_register(sch); 268 ret = css_sch_device_register(sch);
@@ -236,6 +271,15 @@ static int css_register_subchannel(struct subchannel *sch)
236 sch->schid.ssid, sch->schid.sch_no, ret); 271 sch->schid.ssid, sch->schid.sch_no, ret);
237 return ret; 272 return ret;
238 } 273 }
274 if (!sch->driver) {
275 /*
276 * No driver matched. Generate the uevent now so that
277 * a fitting driver module may be loaded based on the
278 * modalias.
279 */
280 sch->dev.uevent_suppress = 0;
281 kobject_uevent(&sch->dev.kobj, KOBJ_ADD);
282 }
239 return ret; 283 return ret;
240} 284}
241 285
@@ -926,12 +970,25 @@ static void css_shutdown(struct device *dev)
926 sch->driver->shutdown(sch); 970 sch->driver->shutdown(sch);
927} 971}
928 972
973static int css_uevent(struct device *dev, struct kobj_uevent_env *env)
974{
975 struct subchannel *sch = to_subchannel(dev);
976 int ret;
977
978 ret = add_uevent_var(env, "ST=%01X", sch->st);
979 if (ret)
980 return ret;
981 ret = add_uevent_var(env, "MODALIAS=css:t%01X", sch->st);
982 return ret;
983}
984
929struct bus_type css_bus_type = { 985struct bus_type css_bus_type = {
930 .name = "css", 986 .name = "css",
931 .match = css_bus_match, 987 .match = css_bus_match,
932 .probe = css_probe, 988 .probe = css_probe,
933 .remove = css_remove, 989 .remove = css_remove,
934 .shutdown = css_shutdown, 990 .shutdown = css_shutdown,
991 .uevent = css_uevent,
935}; 992};
936 993
937/** 994/**
diff --git a/drivers/s390/cio/css.h b/drivers/s390/cio/css.h
index bfe0ada43f2c..e0fc7b499784 100644
--- a/drivers/s390/cio/css.h
+++ b/drivers/s390/cio/css.h
@@ -143,6 +143,4 @@ int css_sch_is_valid(struct schib *);
143 143
144extern struct workqueue_struct *slow_path_wq; 144extern struct workqueue_struct *slow_path_wq;
145void css_wait_for_slow_path(void); 145void css_wait_for_slow_path(void);
146
147extern struct attribute_group *subch_attr_groups[];
148#endif 146#endif
diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c
index 0ed5a81260bc..23b129fd4d8d 100644
--- a/drivers/s390/cio/device.c
+++ b/drivers/s390/cio/device.c
@@ -585,19 +585,14 @@ static DEVICE_ATTR(modalias, 0444, modalias_show, NULL);
585static DEVICE_ATTR(online, 0644, online_show, online_store); 585static DEVICE_ATTR(online, 0644, online_show, online_store);
586static DEVICE_ATTR(availability, 0444, available_show, NULL); 586static DEVICE_ATTR(availability, 0444, available_show, NULL);
587 587
588static struct attribute * subch_attrs[] = { 588static struct attribute *io_subchannel_attrs[] = {
589 &dev_attr_chpids.attr, 589 &dev_attr_chpids.attr,
590 &dev_attr_pimpampom.attr, 590 &dev_attr_pimpampom.attr,
591 NULL, 591 NULL,
592}; 592};
593 593
594static struct attribute_group subch_attr_group = { 594static struct attribute_group io_subchannel_attr_group = {
595 .attrs = subch_attrs, 595 .attrs = io_subchannel_attrs,
596};
597
598struct attribute_group *subch_attr_groups[] = {
599 &subch_attr_group,
600 NULL,
601}; 596};
602 597
603static struct attribute * ccwdev_attrs[] = { 598static struct attribute * ccwdev_attrs[] = {
@@ -1157,11 +1152,21 @@ static int io_subchannel_probe(struct subchannel *sch)
1157 1152
1158 cdev = sch_get_cdev(sch); 1153 cdev = sch_get_cdev(sch);
1159 if (cdev) { 1154 if (cdev) {
1155 rc = sysfs_create_group(&sch->dev.kobj,
1156 &io_subchannel_attr_group);
1157 if (rc)
1158 CIO_MSG_EVENT(0, "Failed to create io subchannel "
1159 "attributes for subchannel "
1160 "0.%x.%04x (rc=%d)\n",
1161 sch->schid.ssid, sch->schid.sch_no, rc);
1160 /* 1162 /*
1161 * This subchannel already has an associated ccw_device. 1163 * This subchannel already has an associated ccw_device.
1162 * Register it and exit. This happens for all early 1164 * Throw the delayed uevent for the subchannel, register
1163 * device, e.g. the console. 1165 * the ccw_device and exit. This happens for all early
1166 * devices, e.g. the console.
1164 */ 1167 */
1168 sch->dev.uevent_suppress = 0;
1169 kobject_uevent(&sch->dev.kobj, KOBJ_ADD);
1165 cdev->dev.groups = ccwdev_attr_groups; 1170 cdev->dev.groups = ccwdev_attr_groups;
1166 device_initialize(&cdev->dev); 1171 device_initialize(&cdev->dev);
1167 ccw_device_register(cdev); 1172 ccw_device_register(cdev);
@@ -1184,11 +1189,17 @@ static int io_subchannel_probe(struct subchannel *sch)
1184 */ 1189 */
1185 dev_id.devno = sch->schib.pmcw.dev; 1190 dev_id.devno = sch->schib.pmcw.dev;
1186 dev_id.ssid = sch->schid.ssid; 1191 dev_id.ssid = sch->schid.ssid;
1192 rc = sysfs_create_group(&sch->dev.kobj,
1193 &io_subchannel_attr_group);
1194 if (rc)
1195 return rc;
1187 /* Allocate I/O subchannel private data. */ 1196 /* Allocate I/O subchannel private data. */
1188 sch->private = kzalloc(sizeof(struct io_subchannel_private), 1197 sch->private = kzalloc(sizeof(struct io_subchannel_private),
1189 GFP_KERNEL | GFP_DMA); 1198 GFP_KERNEL | GFP_DMA);
1190 if (!sch->private) 1199 if (!sch->private) {
1191 return -ENOMEM; 1200 rc = -ENOMEM;
1201 goto out_err;
1202 }
1192 cdev = get_disc_ccwdev_by_dev_id(&dev_id, NULL); 1203 cdev = get_disc_ccwdev_by_dev_id(&dev_id, NULL);
1193 if (!cdev) 1204 if (!cdev)
1194 cdev = get_orphaned_ccwdev_by_dev_id(to_css(sch->dev.parent), 1205 cdev = get_orphaned_ccwdev_by_dev_id(to_css(sch->dev.parent),
@@ -1207,8 +1218,8 @@ static int io_subchannel_probe(struct subchannel *sch)
1207 } 1218 }
1208 cdev = io_subchannel_create_ccwdev(sch); 1219 cdev = io_subchannel_create_ccwdev(sch);
1209 if (IS_ERR(cdev)) { 1220 if (IS_ERR(cdev)) {
1210 kfree(sch->private); 1221 rc = PTR_ERR(cdev);
1211 return PTR_ERR(cdev); 1222 goto out_err;
1212 } 1223 }
1213 rc = io_subchannel_recog(cdev, sch); 1224 rc = io_subchannel_recog(cdev, sch);
1214 if (rc) { 1225 if (rc) {
@@ -1217,9 +1228,12 @@ static int io_subchannel_probe(struct subchannel *sch)
1217 spin_unlock_irqrestore(sch->lock, flags); 1228 spin_unlock_irqrestore(sch->lock, flags);
1218 if (cdev->dev.release) 1229 if (cdev->dev.release)
1219 cdev->dev.release(&cdev->dev); 1230 cdev->dev.release(&cdev->dev);
1220 kfree(sch->private); 1231 goto out_err;
1221 } 1232 }
1222 1233 return 0;
1234out_err:
1235 kfree(sch->private);
1236 sysfs_remove_group(&sch->dev.kobj, &io_subchannel_attr_group);
1223 return rc; 1237 return rc;
1224} 1238}
1225 1239
@@ -1240,6 +1254,7 @@ io_subchannel_remove (struct subchannel *sch)
1240 ccw_device_unregister(cdev); 1254 ccw_device_unregister(cdev);
1241 put_device(&cdev->dev); 1255 put_device(&cdev->dev);
1242 kfree(sch->private); 1256 kfree(sch->private);
1257 sysfs_remove_group(&sch->dev.kobj, &io_subchannel_attr_group);
1243 return 0; 1258 return 0;
1244} 1259}
1245 1260