diff options
Diffstat (limited to 'drivers/s390/cio/device.c')
-rw-r--r-- | drivers/s390/cio/device.c | 47 |
1 files changed, 31 insertions, 16 deletions
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); | |||
585 | static DEVICE_ATTR(online, 0644, online_show, online_store); | 585 | static DEVICE_ATTR(online, 0644, online_show, online_store); |
586 | static DEVICE_ATTR(availability, 0444, available_show, NULL); | 586 | static DEVICE_ATTR(availability, 0444, available_show, NULL); |
587 | 587 | ||
588 | static struct attribute * subch_attrs[] = { | 588 | static 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 | ||
594 | static struct attribute_group subch_attr_group = { | 594 | static struct attribute_group io_subchannel_attr_group = { |
595 | .attrs = subch_attrs, | 595 | .attrs = io_subchannel_attrs, |
596 | }; | ||
597 | |||
598 | struct attribute_group *subch_attr_groups[] = { | ||
599 | &subch_attr_group, | ||
600 | NULL, | ||
601 | }; | 596 | }; |
602 | 597 | ||
603 | static struct attribute * ccwdev_attrs[] = { | 598 | static 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; | |
1234 | out_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 | ||