diff options
Diffstat (limited to 'drivers/s390/cio')
-rw-r--r-- | drivers/s390/cio/blacklist.c | 11 | ||||
-rw-r--r-- | drivers/s390/cio/device.c | 40 | ||||
-rw-r--r-- | drivers/s390/cio/device.h | 1 |
3 files changed, 48 insertions, 4 deletions
diff --git a/drivers/s390/cio/blacklist.c b/drivers/s390/cio/blacklist.c index 0bfcbbe375c4..2f547b840ef0 100644 --- a/drivers/s390/cio/blacklist.c +++ b/drivers/s390/cio/blacklist.c | |||
@@ -24,6 +24,7 @@ | |||
24 | #include "cio.h" | 24 | #include "cio.h" |
25 | #include "cio_debug.h" | 25 | #include "cio_debug.h" |
26 | #include "css.h" | 26 | #include "css.h" |
27 | #include "device.h" | ||
27 | 28 | ||
28 | /* | 29 | /* |
29 | * "Blacklisting" of certain devices: | 30 | * "Blacklisting" of certain devices: |
@@ -191,9 +192,9 @@ static int blacklist_parse_parameters(char *str, range_action action, | |||
191 | rc = blacklist_range(ra, from_ssid, to_ssid, from, to, | 192 | rc = blacklist_range(ra, from_ssid, to_ssid, from, to, |
192 | msgtrigger); | 193 | msgtrigger); |
193 | if (rc) | 194 | if (rc) |
194 | totalrc = 1; | 195 | totalrc = -EINVAL; |
195 | } else | 196 | } else |
196 | totalrc = 1; | 197 | totalrc = -EINVAL; |
197 | } | 198 | } |
198 | 199 | ||
199 | return totalrc; | 200 | return totalrc; |
@@ -240,8 +241,10 @@ static int blacklist_parse_proc_parameters(char *buf) | |||
240 | rc = blacklist_parse_parameters(buf, free, 0); | 241 | rc = blacklist_parse_parameters(buf, free, 0); |
241 | else if (strcmp("add", parm) == 0) | 242 | else if (strcmp("add", parm) == 0) |
242 | rc = blacklist_parse_parameters(buf, add, 0); | 243 | rc = blacklist_parse_parameters(buf, add, 0); |
244 | else if (strcmp("purge", parm) == 0) | ||
245 | return ccw_purge_blacklisted(); | ||
243 | else | 246 | else |
244 | return 1; | 247 | return -EINVAL; |
245 | 248 | ||
246 | css_schedule_reprobe(); | 249 | css_schedule_reprobe(); |
247 | 250 | ||
@@ -353,7 +356,7 @@ cio_ignore_write(struct file *file, const char __user *user_buf, | |||
353 | } | 356 | } |
354 | ret = blacklist_parse_proc_parameters(buf); | 357 | ret = blacklist_parse_proc_parameters(buf); |
355 | if (ret) | 358 | if (ret) |
356 | rc = -EINVAL; | 359 | rc = ret; |
357 | else | 360 | else |
358 | rc = user_len; | 361 | rc = user_len; |
359 | 362 | ||
diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c index 38a79ecfc743..8575d263b13e 100644 --- a/drivers/s390/cio/device.c +++ b/drivers/s390/cio/device.c | |||
@@ -31,6 +31,7 @@ | |||
31 | #include "device.h" | 31 | #include "device.h" |
32 | #include "ioasm.h" | 32 | #include "ioasm.h" |
33 | #include "io_sch.h" | 33 | #include "io_sch.h" |
34 | #include "blacklist.h" | ||
34 | 35 | ||
35 | static struct timer_list recovery_timer; | 36 | static struct timer_list recovery_timer; |
36 | static DEFINE_SPINLOCK(recovery_lock); | 37 | static DEFINE_SPINLOCK(recovery_lock); |
@@ -1470,6 +1471,45 @@ static void ccw_device_schedule_recovery(void) | |||
1470 | spin_unlock_irqrestore(&recovery_lock, flags); | 1471 | spin_unlock_irqrestore(&recovery_lock, flags); |
1471 | } | 1472 | } |
1472 | 1473 | ||
1474 | static int purge_fn(struct device *dev, void *data) | ||
1475 | { | ||
1476 | struct ccw_device *cdev = to_ccwdev(dev); | ||
1477 | struct ccw_device_private *priv = cdev->private; | ||
1478 | int unreg; | ||
1479 | |||
1480 | spin_lock_irq(cdev->ccwlock); | ||
1481 | unreg = is_blacklisted(priv->dev_id.ssid, priv->dev_id.devno) && | ||
1482 | (priv->state == DEV_STATE_OFFLINE); | ||
1483 | spin_unlock_irq(cdev->ccwlock); | ||
1484 | if (!unreg) | ||
1485 | goto out; | ||
1486 | if (!get_device(&cdev->dev)) | ||
1487 | goto out; | ||
1488 | CIO_MSG_EVENT(3, "ccw: purging 0.%x.%04x\n", priv->dev_id.ssid, | ||
1489 | priv->dev_id.devno); | ||
1490 | PREPARE_WORK(&cdev->private->kick_work, ccw_device_call_sch_unregister); | ||
1491 | queue_work(slow_path_wq, &cdev->private->kick_work); | ||
1492 | |||
1493 | out: | ||
1494 | /* Abort loop in case of pending signal. */ | ||
1495 | if (signal_pending(current)) | ||
1496 | return -EINTR; | ||
1497 | |||
1498 | return 0; | ||
1499 | } | ||
1500 | |||
1501 | /** | ||
1502 | * ccw_purge_blacklisted - purge unused, blacklisted devices | ||
1503 | * | ||
1504 | * Unregister all ccw devices that are offline and on the blacklist. | ||
1505 | */ | ||
1506 | int ccw_purge_blacklisted(void) | ||
1507 | { | ||
1508 | CIO_MSG_EVENT(2, "ccw: purging blacklisted devices\n"); | ||
1509 | bus_for_each_dev(&ccw_bus_type, NULL, NULL, purge_fn); | ||
1510 | return 0; | ||
1511 | } | ||
1512 | |||
1473 | static void device_set_disconnected(struct ccw_device *cdev) | 1513 | static void device_set_disconnected(struct ccw_device *cdev) |
1474 | { | 1514 | { |
1475 | if (!cdev) | 1515 | if (!cdev) |
diff --git a/drivers/s390/cio/device.h b/drivers/s390/cio/device.h index 6f5c3f2b3587..104ed669db43 100644 --- a/drivers/s390/cio/device.h +++ b/drivers/s390/cio/device.h | |||
@@ -86,6 +86,7 @@ int ccw_device_is_orphan(struct ccw_device *); | |||
86 | int ccw_device_recognition(struct ccw_device *); | 86 | int ccw_device_recognition(struct ccw_device *); |
87 | int ccw_device_online(struct ccw_device *); | 87 | int ccw_device_online(struct ccw_device *); |
88 | int ccw_device_offline(struct ccw_device *); | 88 | int ccw_device_offline(struct ccw_device *); |
89 | int ccw_purge_blacklisted(void); | ||
89 | 90 | ||
90 | /* Function prototypes for device status and basic sense stuff. */ | 91 | /* Function prototypes for device status and basic sense stuff. */ |
91 | void ccw_device_accumulate_irb(struct ccw_device *, struct irb *); | 92 | void ccw_device_accumulate_irb(struct ccw_device *, struct irb *); |