aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/s390/cio/device.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/s390/cio/device.c')
-rw-r--r--drivers/s390/cio/device.c246
1 files changed, 111 insertions, 135 deletions
diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c
index e322111fb369..03355902c582 100644
--- a/drivers/s390/cio/device.c
+++ b/drivers/s390/cio/device.c
@@ -56,13 +56,12 @@ ccw_bus_match (struct device * dev, struct device_driver * drv)
56/* Store modalias string delimited by prefix/suffix string into buffer with 56/* Store modalias string delimited by prefix/suffix string into buffer with
57 * specified size. Return length of resulting string (excluding trailing '\0') 57 * specified size. Return length of resulting string (excluding trailing '\0')
58 * even if string doesn't fit buffer (snprintf semantics). */ 58 * even if string doesn't fit buffer (snprintf semantics). */
59static int snprint_alias(char *buf, size_t size, const char *prefix, 59static int snprint_alias(char *buf, size_t size,
60 struct ccw_device_id *id, const char *suffix) 60 struct ccw_device_id *id, const char *suffix)
61{ 61{
62 int len; 62 int len;
63 63
64 len = snprintf(buf, size, "%sccw:t%04Xm%02X", prefix, id->cu_type, 64 len = snprintf(buf, size, "ccw:t%04Xm%02X", id->cu_type, id->cu_model);
65 id->cu_model);
66 if (len > size) 65 if (len > size)
67 return len; 66 return len;
68 buf += len; 67 buf += len;
@@ -85,53 +84,40 @@ static int ccw_uevent(struct device *dev, char **envp, int num_envp,
85 struct ccw_device *cdev = to_ccwdev(dev); 84 struct ccw_device *cdev = to_ccwdev(dev);
86 struct ccw_device_id *id = &(cdev->id); 85 struct ccw_device_id *id = &(cdev->id);
87 int i = 0; 86 int i = 0;
88 int len; 87 int len = 0;
88 int ret;
89 char modalias_buf[30];
89 90
90 /* CU_TYPE= */ 91 /* CU_TYPE= */
91 len = snprintf(buffer, buffer_size, "CU_TYPE=%04X", id->cu_type) + 1; 92 ret = add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &len,
92 if (len > buffer_size || i >= num_envp) 93 "CU_TYPE=%04X", id->cu_type);
93 return -ENOMEM; 94 if (ret)
94 envp[i++] = buffer; 95 return ret;
95 buffer += len;
96 buffer_size -= len;
97 96
98 /* CU_MODEL= */ 97 /* CU_MODEL= */
99 len = snprintf(buffer, buffer_size, "CU_MODEL=%02X", id->cu_model) + 1; 98 ret = add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &len,
100 if (len > buffer_size || i >= num_envp) 99 "CU_MODEL=%02X", id->cu_model);
101 return -ENOMEM; 100 if (ret)
102 envp[i++] = buffer; 101 return ret;
103 buffer += len;
104 buffer_size -= len;
105 102
106 /* The next two can be zero, that's ok for us */ 103 /* The next two can be zero, that's ok for us */
107 /* DEV_TYPE= */ 104 /* DEV_TYPE= */
108 len = snprintf(buffer, buffer_size, "DEV_TYPE=%04X", id->dev_type) + 1; 105 ret = add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &len,
109 if (len > buffer_size || i >= num_envp) 106 "DEV_TYPE=%04X", id->dev_type);
110 return -ENOMEM; 107 if (ret)
111 envp[i++] = buffer; 108 return ret;
112 buffer += len;
113 buffer_size -= len;
114 109
115 /* DEV_MODEL= */ 110 /* DEV_MODEL= */
116 len = snprintf(buffer, buffer_size, "DEV_MODEL=%02X", 111 ret = add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &len,
117 (unsigned char) id->dev_model) + 1; 112 "DEV_MODEL=%02X", id->dev_model);
118 if (len > buffer_size || i >= num_envp) 113 if (ret)
119 return -ENOMEM; 114 return ret;
120 envp[i++] = buffer;
121 buffer += len;
122 buffer_size -= len;
123 115
124 /* MODALIAS= */ 116 /* MODALIAS= */
125 len = snprint_alias(buffer, buffer_size, "MODALIAS=", id, "") + 1; 117 snprint_alias(modalias_buf, sizeof(modalias_buf), id, "");
126 if (len > buffer_size || i >= num_envp) 118 ret = add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &len,
127 return -ENOMEM; 119 "MODALIAS=%s", modalias_buf);
128 envp[i++] = buffer; 120 return ret;
129 buffer += len;
130 buffer_size -= len;
131
132 envp[i] = NULL;
133
134 return 0;
135} 121}
136 122
137struct bus_type ccw_bus_type; 123struct bus_type ccw_bus_type;
@@ -230,12 +216,18 @@ static ssize_t
230chpids_show (struct device * dev, struct device_attribute *attr, char * buf) 216chpids_show (struct device * dev, struct device_attribute *attr, char * buf)
231{ 217{
232 struct subchannel *sch = to_subchannel(dev); 218 struct subchannel *sch = to_subchannel(dev);
233 struct ssd_info *ssd = &sch->ssd_info; 219 struct chsc_ssd_info *ssd = &sch->ssd_info;
234 ssize_t ret = 0; 220 ssize_t ret = 0;
235 int chp; 221 int chp;
222 int mask;
236 223
237 for (chp = 0; chp < 8; chp++) 224 for (chp = 0; chp < 8; chp++) {
238 ret += sprintf (buf+ret, "%02x ", ssd->chpid[chp]); 225 mask = 0x80 >> chp;
226 if (ssd->path_mask & mask)
227 ret += sprintf(buf + ret, "%02x ", ssd->chpid[chp].id);
228 else
229 ret += sprintf(buf + ret, "00 ");
230 }
239 ret += sprintf (buf+ret, "\n"); 231 ret += sprintf (buf+ret, "\n");
240 return min((ssize_t)PAGE_SIZE, ret); 232 return min((ssize_t)PAGE_SIZE, ret);
241} 233}
@@ -280,7 +272,7 @@ modalias_show (struct device *dev, struct device_attribute *attr, char *buf)
280 struct ccw_device_id *id = &(cdev->id); 272 struct ccw_device_id *id = &(cdev->id);
281 int len; 273 int len;
282 274
283 len = snprint_alias(buf, PAGE_SIZE, "", id, "\n") + 1; 275 len = snprint_alias(buf, PAGE_SIZE, id, "\n") + 1;
284 276
285 return len > PAGE_SIZE ? PAGE_SIZE : len; 277 return len > PAGE_SIZE ? PAGE_SIZE : len;
286} 278}
@@ -298,16 +290,10 @@ int ccw_device_is_orphan(struct ccw_device *cdev)
298 return sch_is_pseudo_sch(to_subchannel(cdev->dev.parent)); 290 return sch_is_pseudo_sch(to_subchannel(cdev->dev.parent));
299} 291}
300 292
301static void ccw_device_unregister(struct work_struct *work) 293static void ccw_device_unregister(struct ccw_device *cdev)
302{ 294{
303 struct ccw_device_private *priv;
304 struct ccw_device *cdev;
305
306 priv = container_of(work, struct ccw_device_private, kick_work);
307 cdev = priv->cdev;
308 if (test_and_clear_bit(1, &cdev->private->registered)) 295 if (test_and_clear_bit(1, &cdev->private->registered))
309 device_unregister(&cdev->dev); 296 device_del(&cdev->dev);
310 put_device(&cdev->dev);
311} 297}
312 298
313static void 299static void
@@ -324,11 +310,8 @@ ccw_device_remove_disconnected(struct ccw_device *cdev)
324 spin_lock_irqsave(cdev->ccwlock, flags); 310 spin_lock_irqsave(cdev->ccwlock, flags);
325 cdev->private->state = DEV_STATE_NOT_OPER; 311 cdev->private->state = DEV_STATE_NOT_OPER;
326 spin_unlock_irqrestore(cdev->ccwlock, flags); 312 spin_unlock_irqrestore(cdev->ccwlock, flags);
327 if (get_device(&cdev->dev)) { 313 ccw_device_unregister(cdev);
328 PREPARE_WORK(&cdev->private->kick_work, 314 put_device(&cdev->dev);
329 ccw_device_unregister);
330 queue_work(ccw_device_work, &cdev->private->kick_work);
331 }
332 return ; 315 return ;
333 } 316 }
334 sch = to_subchannel(cdev->dev.parent); 317 sch = to_subchannel(cdev->dev.parent);
@@ -413,11 +396,60 @@ ccw_device_set_online(struct ccw_device *cdev)
413 return (ret == 0) ? -ENODEV : ret; 396 return (ret == 0) ? -ENODEV : ret;
414} 397}
415 398
416static ssize_t 399static void online_store_handle_offline(struct ccw_device *cdev)
417online_store (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) 400{
401 if (cdev->private->state == DEV_STATE_DISCONNECTED)
402 ccw_device_remove_disconnected(cdev);
403 else if (cdev->drv && cdev->drv->set_offline)
404 ccw_device_set_offline(cdev);
405}
406
407static int online_store_recog_and_online(struct ccw_device *cdev)
408{
409 int ret;
410
411 /* Do device recognition, if needed. */
412 if (cdev->id.cu_type == 0) {
413 ret = ccw_device_recognition(cdev);
414 if (ret) {
415 printk(KERN_WARNING"Couldn't start recognition "
416 "for device %s (ret=%d)\n",
417 cdev->dev.bus_id, ret);
418 return ret;
419 }
420 wait_event(cdev->private->wait_q,
421 cdev->private->flags.recog_done);
422 }
423 if (cdev->drv && cdev->drv->set_online)
424 ccw_device_set_online(cdev);
425 return 0;
426}
427static void online_store_handle_online(struct ccw_device *cdev, int force)
428{
429 int ret;
430
431 ret = online_store_recog_and_online(cdev);
432 if (ret)
433 return;
434 if (force && cdev->private->state == DEV_STATE_BOXED) {
435 ret = ccw_device_stlck(cdev);
436 if (ret) {
437 printk(KERN_WARNING"ccw_device_stlck for device %s "
438 "returned %d!\n", cdev->dev.bus_id, ret);
439 return;
440 }
441 if (cdev->id.cu_type == 0)
442 cdev->private->state = DEV_STATE_NOT_OPER;
443 online_store_recog_and_online(cdev);
444 }
445
446}
447
448static ssize_t online_store (struct device *dev, struct device_attribute *attr,
449 const char *buf, size_t count)
418{ 450{
419 struct ccw_device *cdev = to_ccwdev(dev); 451 struct ccw_device *cdev = to_ccwdev(dev);
420 int i, force, ret; 452 int i, force;
421 char *tmp; 453 char *tmp;
422 454
423 if (atomic_cmpxchg(&cdev->private->onoff, 0, 1) != 0) 455 if (atomic_cmpxchg(&cdev->private->onoff, 0, 1) != 0)
@@ -434,51 +466,17 @@ online_store (struct device *dev, struct device_attribute *attr, const char *buf
434 force = 0; 466 force = 0;
435 i = simple_strtoul(buf, &tmp, 16); 467 i = simple_strtoul(buf, &tmp, 16);
436 } 468 }
437 if (i == 1) { 469
438 /* Do device recognition, if needed. */ 470 switch (i) {
439 if (cdev->id.cu_type == 0) { 471 case 0:
440 ret = ccw_device_recognition(cdev); 472 online_store_handle_offline(cdev);
441 if (ret) { 473 break;
442 printk(KERN_WARNING"Couldn't start recognition " 474 case 1:
443 "for device %s (ret=%d)\n", 475 online_store_handle_online(cdev, force);
444 cdev->dev.bus_id, ret); 476 break;
445 goto out; 477 default:
446 } 478 count = -EINVAL;
447 wait_event(cdev->private->wait_q,
448 cdev->private->flags.recog_done);
449 }
450 if (cdev->drv && cdev->drv->set_online)
451 ccw_device_set_online(cdev);
452 } else if (i == 0) {
453 if (cdev->private->state == DEV_STATE_DISCONNECTED)
454 ccw_device_remove_disconnected(cdev);
455 else if (cdev->drv && cdev->drv->set_offline)
456 ccw_device_set_offline(cdev);
457 }
458 if (force && cdev->private->state == DEV_STATE_BOXED) {
459 ret = ccw_device_stlck(cdev);
460 if (ret) {
461 printk(KERN_WARNING"ccw_device_stlck for device %s "
462 "returned %d!\n", cdev->dev.bus_id, ret);
463 goto out;
464 }
465 /* Do device recognition, if needed. */
466 if (cdev->id.cu_type == 0) {
467 cdev->private->state = DEV_STATE_NOT_OPER;
468 ret = ccw_device_recognition(cdev);
469 if (ret) {
470 printk(KERN_WARNING"Couldn't start recognition "
471 "for device %s (ret=%d)\n",
472 cdev->dev.bus_id, ret);
473 goto out;
474 }
475 wait_event(cdev->private->wait_q,
476 cdev->private->flags.recog_done);
477 }
478 if (cdev->drv && cdev->drv->set_online)
479 ccw_device_set_online(cdev);
480 } 479 }
481 out:
482 if (cdev->drv) 480 if (cdev->drv)
483 module_put(cdev->drv->owner); 481 module_put(cdev->drv->owner);
484 atomic_set(&cdev->private->onoff, 0); 482 atomic_set(&cdev->private->onoff, 0);
@@ -548,17 +546,10 @@ static struct attribute_group ccwdev_attr_group = {
548 .attrs = ccwdev_attrs, 546 .attrs = ccwdev_attrs,
549}; 547};
550 548
551static int 549struct attribute_group *ccwdev_attr_groups[] = {
552device_add_files (struct device *dev) 550 &ccwdev_attr_group,
553{ 551 NULL,
554 return sysfs_create_group(&dev->kobj, &ccwdev_attr_group); 552};
555}
556
557static void
558device_remove_files(struct device *dev)
559{
560 sysfs_remove_group(&dev->kobj, &ccwdev_attr_group);
561}
562 553
563/* this is a simple abstraction for device_register that sets the 554/* this is a simple abstraction for device_register that sets the
564 * correct bus type and adds the bus specific files */ 555 * correct bus type and adds the bus specific files */
@@ -573,10 +564,6 @@ static int ccw_device_register(struct ccw_device *cdev)
573 return ret; 564 return ret;
574 565
575 set_bit(1, &cdev->private->registered); 566 set_bit(1, &cdev->private->registered);
576 if ((ret = device_add_files(dev))) {
577 if (test_and_clear_bit(1, &cdev->private->registered))
578 device_del(dev);
579 }
580 return ret; 567 return ret;
581} 568}
582 569
@@ -648,10 +635,6 @@ ccw_device_add_changed(struct work_struct *work)
648 return; 635 return;
649 } 636 }
650 set_bit(1, &cdev->private->registered); 637 set_bit(1, &cdev->private->registered);
651 if (device_add_files(&cdev->dev)) {
652 if (test_and_clear_bit(1, &cdev->private->registered))
653 device_unregister(&cdev->dev);
654 }
655} 638}
656 639
657void ccw_device_do_unreg_rereg(struct work_struct *work) 640void ccw_device_do_unreg_rereg(struct work_struct *work)
@@ -664,9 +647,7 @@ void ccw_device_do_unreg_rereg(struct work_struct *work)
664 cdev = priv->cdev; 647 cdev = priv->cdev;
665 sch = to_subchannel(cdev->dev.parent); 648 sch = to_subchannel(cdev->dev.parent);
666 649
667 device_remove_files(&cdev->dev); 650 ccw_device_unregister(cdev);
668 if (test_and_clear_bit(1, &cdev->private->registered))
669 device_del(&cdev->dev);
670 PREPARE_WORK(&cdev->private->kick_work, 651 PREPARE_WORK(&cdev->private->kick_work,
671 ccw_device_add_changed); 652 ccw_device_add_changed);
672 queue_work(ccw_device_work, &cdev->private->kick_work); 653 queue_work(ccw_device_work, &cdev->private->kick_work);
@@ -705,6 +686,7 @@ static int io_subchannel_initialize_dev(struct subchannel *sch,
705 cdev->dev.parent = &sch->dev; 686 cdev->dev.parent = &sch->dev;
706 cdev->dev.release = ccw_device_release; 687 cdev->dev.release = ccw_device_release;
707 INIT_LIST_HEAD(&cdev->private->kick_work.entry); 688 INIT_LIST_HEAD(&cdev->private->kick_work.entry);
689 cdev->dev.groups = ccwdev_attr_groups;
708 /* Do first half of device_register. */ 690 /* Do first half of device_register. */
709 device_initialize(&cdev->dev); 691 device_initialize(&cdev->dev);
710 if (!get_device(&sch->dev)) { 692 if (!get_device(&sch->dev)) {
@@ -736,6 +718,7 @@ static int io_subchannel_recog(struct ccw_device *, struct subchannel *);
736static void sch_attach_device(struct subchannel *sch, 718static void sch_attach_device(struct subchannel *sch,
737 struct ccw_device *cdev) 719 struct ccw_device *cdev)
738{ 720{
721 css_update_ssd_info(sch);
739 spin_lock_irq(sch->lock); 722 spin_lock_irq(sch->lock);
740 sch->dev.driver_data = cdev; 723 sch->dev.driver_data = cdev;
741 cdev->private->schid = sch->schid; 724 cdev->private->schid = sch->schid;
@@ -871,7 +854,7 @@ io_subchannel_register(struct work_struct *work)
871 priv = container_of(work, struct ccw_device_private, kick_work); 854 priv = container_of(work, struct ccw_device_private, kick_work);
872 cdev = priv->cdev; 855 cdev = priv->cdev;
873 sch = to_subchannel(cdev->dev.parent); 856 sch = to_subchannel(cdev->dev.parent);
874 857 css_update_ssd_info(sch);
875 /* 858 /*
876 * io_subchannel_register() will also be called after device 859 * io_subchannel_register() will also be called after device
877 * recognition has been done for a boxed device (which will already 860 * recognition has been done for a boxed device (which will already
@@ -1133,15 +1116,8 @@ io_subchannel_remove (struct subchannel *sch)
1133 sch->dev.driver_data = NULL; 1116 sch->dev.driver_data = NULL;
1134 cdev->private->state = DEV_STATE_NOT_OPER; 1117 cdev->private->state = DEV_STATE_NOT_OPER;
1135 spin_unlock_irqrestore(cdev->ccwlock, flags); 1118 spin_unlock_irqrestore(cdev->ccwlock, flags);
1136 /* 1119 ccw_device_unregister(cdev);
1137 * Put unregistration on workqueue to avoid livelocks on the css bus 1120 put_device(&cdev->dev);
1138 * semaphore.
1139 */
1140 if (get_device(&cdev->dev)) {
1141 PREPARE_WORK(&cdev->private->kick_work,
1142 ccw_device_unregister);
1143 queue_work(ccw_device_work, &cdev->private->kick_work);
1144 }
1145 return 0; 1121 return 0;
1146} 1122}
1147 1123