diff options
author | Cornelia Huck <cornelia.huck@de.ibm.com> | 2008-12-25 07:39:09 -0500 |
---|---|---|
committer | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2008-12-25 07:39:08 -0500 |
commit | 90ed2b692fa75272d7395c4e4c2de4423d52f506 (patch) | |
tree | 62b2d1a0595b73718dd0d39d331a4c3c9fa91f81 /drivers | |
parent | 5fb6b8544d9ccd2ed478af777f9e99e342eb8886 (diff) |
[S390] cio: Dont fail probe for I/O subchannels.
If we fail the probe for an I/O subchannel, we won't be able
to unregister it again since there are no sch_event()
callbacks for unbound subchannels. Just succeed the probe in
any case and schedule unregistering the subchannel.
Signed-off-by: Cornelia Huck <cornelia.huck@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/s390/cio/cio.h | 1 | ||||
-rw-r--r-- | drivers/s390/cio/device.c | 43 |
2 files changed, 32 insertions, 12 deletions
diff --git a/drivers/s390/cio/cio.h b/drivers/s390/cio/cio.h index 0fb24784e925..5db887e8f032 100644 --- a/drivers/s390/cio/cio.h +++ b/drivers/s390/cio/cio.h | |||
@@ -82,6 +82,7 @@ struct subchannel { | |||
82 | struct device dev; /* entry in device tree */ | 82 | struct device dev; /* entry in device tree */ |
83 | struct css_driver *driver; | 83 | struct css_driver *driver; |
84 | void *private; /* private per subchannel type data */ | 84 | void *private; /* private per subchannel type data */ |
85 | struct work_struct work; | ||
85 | } __attribute__ ((aligned(8))); | 86 | } __attribute__ ((aligned(8))); |
86 | 87 | ||
87 | #define IO_INTERRUPT_TYPE 0 /* I/O interrupt type */ | 88 | #define IO_INTERRUPT_TYPE 0 /* I/O interrupt type */ |
diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c index 91acea10840d..2d31f06a913e 100644 --- a/drivers/s390/cio/device.c +++ b/drivers/s390/cio/device.c | |||
@@ -1196,6 +1196,30 @@ static void io_subchannel_init_fields(struct subchannel *sch) | |||
1196 | sch->schib.mba = 0; | 1196 | sch->schib.mba = 0; |
1197 | } | 1197 | } |
1198 | 1198 | ||
1199 | static void io_subchannel_do_unreg(struct work_struct *work) | ||
1200 | { | ||
1201 | struct subchannel *sch; | ||
1202 | |||
1203 | sch = container_of(work, struct subchannel, work); | ||
1204 | css_sch_device_unregister(sch); | ||
1205 | /* Reset intparm to zeroes. */ | ||
1206 | sch->schib.pmcw.intparm = 0; | ||
1207 | cio_modify(sch); | ||
1208 | put_device(&sch->dev); | ||
1209 | } | ||
1210 | |||
1211 | /* Schedule unregister if we have no cdev. */ | ||
1212 | static void io_subchannel_schedule_removal(struct subchannel *sch) | ||
1213 | { | ||
1214 | get_device(&sch->dev); | ||
1215 | INIT_WORK(&sch->work, io_subchannel_do_unreg); | ||
1216 | queue_work(slow_path_wq, &sch->work); | ||
1217 | } | ||
1218 | |||
1219 | /* | ||
1220 | * Note: We always return 0 so that we bind to the device even on error. | ||
1221 | * This is needed so that our remove function is called on unregister. | ||
1222 | */ | ||
1199 | static int io_subchannel_probe(struct subchannel *sch) | 1223 | static int io_subchannel_probe(struct subchannel *sch) |
1200 | { | 1224 | { |
1201 | struct ccw_device *cdev; | 1225 | struct ccw_device *cdev; |
@@ -1238,14 +1262,12 @@ static int io_subchannel_probe(struct subchannel *sch) | |||
1238 | rc = sysfs_create_group(&sch->dev.kobj, | 1262 | rc = sysfs_create_group(&sch->dev.kobj, |
1239 | &io_subchannel_attr_group); | 1263 | &io_subchannel_attr_group); |
1240 | if (rc) | 1264 | if (rc) |
1241 | return rc; | 1265 | goto out_schedule; |
1242 | /* Allocate I/O subchannel private data. */ | 1266 | /* Allocate I/O subchannel private data. */ |
1243 | sch->private = kzalloc(sizeof(struct io_subchannel_private), | 1267 | sch->private = kzalloc(sizeof(struct io_subchannel_private), |
1244 | GFP_KERNEL | GFP_DMA); | 1268 | GFP_KERNEL | GFP_DMA); |
1245 | if (!sch->private) { | 1269 | if (!sch->private) |
1246 | rc = -ENOMEM; | ||
1247 | goto out_err; | 1270 | goto out_err; |
1248 | } | ||
1249 | /* | 1271 | /* |
1250 | * First check if a fitting device may be found amongst the | 1272 | * First check if a fitting device may be found amongst the |
1251 | * disconnected devices or in the orphanage. | 1273 | * disconnected devices or in the orphanage. |
@@ -1269,24 +1291,21 @@ static int io_subchannel_probe(struct subchannel *sch) | |||
1269 | return 0; | 1291 | return 0; |
1270 | } | 1292 | } |
1271 | cdev = io_subchannel_create_ccwdev(sch); | 1293 | cdev = io_subchannel_create_ccwdev(sch); |
1272 | if (IS_ERR(cdev)) { | 1294 | if (IS_ERR(cdev)) |
1273 | rc = PTR_ERR(cdev); | ||
1274 | goto out_err; | 1295 | goto out_err; |
1275 | } | ||
1276 | rc = io_subchannel_recog(cdev, sch); | 1296 | rc = io_subchannel_recog(cdev, sch); |
1277 | if (rc) { | 1297 | if (rc) { |
1278 | spin_lock_irqsave(sch->lock, flags); | 1298 | spin_lock_irqsave(sch->lock, flags); |
1279 | sch_set_cdev(sch, NULL); | 1299 | io_subchannel_recog_done(cdev); |
1280 | spin_unlock_irqrestore(sch->lock, flags); | 1300 | spin_unlock_irqrestore(sch->lock, flags); |
1281 | if (cdev->dev.release) | ||
1282 | cdev->dev.release(&cdev->dev); | ||
1283 | goto out_err; | ||
1284 | } | 1301 | } |
1285 | return 0; | 1302 | return 0; |
1286 | out_err: | 1303 | out_err: |
1287 | kfree(sch->private); | 1304 | kfree(sch->private); |
1288 | sysfs_remove_group(&sch->dev.kobj, &io_subchannel_attr_group); | 1305 | sysfs_remove_group(&sch->dev.kobj, &io_subchannel_attr_group); |
1289 | return rc; | 1306 | out_schedule: |
1307 | io_subchannel_schedule_removal(sch); | ||
1308 | return 0; | ||
1290 | } | 1309 | } |
1291 | 1310 | ||
1292 | static int | 1311 | static int |