diff options
Diffstat (limited to 'drivers/s390/cio/device.c')
-rw-r--r-- | drivers/s390/cio/device.c | 456 |
1 files changed, 343 insertions, 113 deletions
diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c index d3d3716ff84b..803579053c2f 100644 --- a/drivers/s390/cio/device.c +++ b/drivers/s390/cio/device.c | |||
@@ -23,6 +23,7 @@ | |||
23 | #include <asm/param.h> /* HZ */ | 23 | #include <asm/param.h> /* HZ */ |
24 | 24 | ||
25 | #include "cio.h" | 25 | #include "cio.h" |
26 | #include "cio_debug.h" | ||
26 | #include "css.h" | 27 | #include "css.h" |
27 | #include "device.h" | 28 | #include "device.h" |
28 | #include "ioasm.h" | 29 | #include "ioasm.h" |
@@ -234,9 +235,11 @@ chpids_show (struct device * dev, struct device_attribute *attr, char * buf) | |||
234 | ssize_t ret = 0; | 235 | ssize_t ret = 0; |
235 | int chp; | 236 | int chp; |
236 | 237 | ||
237 | for (chp = 0; chp < 8; chp++) | 238 | if (ssd) |
238 | ret += sprintf (buf+ret, "%02x ", ssd->chpid[chp]); | 239 | for (chp = 0; chp < 8; chp++) |
239 | 240 | ret += sprintf (buf+ret, "%02x ", ssd->chpid[chp]); | |
241 | else | ||
242 | ret += sprintf (buf, "n/a"); | ||
240 | ret += sprintf (buf+ret, "\n"); | 243 | ret += sprintf (buf+ret, "\n"); |
241 | return min((ssize_t)PAGE_SIZE, ret); | 244 | return min((ssize_t)PAGE_SIZE, ret); |
242 | } | 245 | } |
@@ -294,14 +297,44 @@ online_show (struct device *dev, struct device_attribute *attr, char *buf) | |||
294 | return sprintf(buf, cdev->online ? "1\n" : "0\n"); | 297 | return sprintf(buf, cdev->online ? "1\n" : "0\n"); |
295 | } | 298 | } |
296 | 299 | ||
300 | int ccw_device_is_orphan(struct ccw_device *cdev) | ||
301 | { | ||
302 | return sch_is_pseudo_sch(to_subchannel(cdev->dev.parent)); | ||
303 | } | ||
304 | |||
305 | static void ccw_device_unregister(struct work_struct *work) | ||
306 | { | ||
307 | struct ccw_device_private *priv; | ||
308 | struct ccw_device *cdev; | ||
309 | |||
310 | priv = container_of(work, struct ccw_device_private, kick_work); | ||
311 | cdev = priv->cdev; | ||
312 | if (test_and_clear_bit(1, &cdev->private->registered)) | ||
313 | device_unregister(&cdev->dev); | ||
314 | put_device(&cdev->dev); | ||
315 | } | ||
316 | |||
297 | static void | 317 | static void |
298 | ccw_device_remove_disconnected(struct ccw_device *cdev) | 318 | ccw_device_remove_disconnected(struct ccw_device *cdev) |
299 | { | 319 | { |
300 | struct subchannel *sch; | 320 | struct subchannel *sch; |
321 | unsigned long flags; | ||
301 | /* | 322 | /* |
302 | * Forced offline in disconnected state means | 323 | * Forced offline in disconnected state means |
303 | * 'throw away device'. | 324 | * 'throw away device'. |
304 | */ | 325 | */ |
326 | if (ccw_device_is_orphan(cdev)) { | ||
327 | /* Deregister ccw device. */ | ||
328 | spin_lock_irqsave(cdev->ccwlock, flags); | ||
329 | cdev->private->state = DEV_STATE_NOT_OPER; | ||
330 | spin_unlock_irqrestore(cdev->ccwlock, flags); | ||
331 | if (get_device(&cdev->dev)) { | ||
332 | PREPARE_WORK(&cdev->private->kick_work, | ||
333 | ccw_device_unregister); | ||
334 | queue_work(ccw_device_work, &cdev->private->kick_work); | ||
335 | } | ||
336 | return ; | ||
337 | } | ||
305 | sch = to_subchannel(cdev->dev.parent); | 338 | sch = to_subchannel(cdev->dev.parent); |
306 | css_sch_device_unregister(sch); | 339 | css_sch_device_unregister(sch); |
307 | /* Reset intparm to zeroes. */ | 340 | /* Reset intparm to zeroes. */ |
@@ -462,6 +495,8 @@ available_show (struct device *dev, struct device_attribute *attr, char *buf) | |||
462 | struct ccw_device *cdev = to_ccwdev(dev); | 495 | struct ccw_device *cdev = to_ccwdev(dev); |
463 | struct subchannel *sch; | 496 | struct subchannel *sch; |
464 | 497 | ||
498 | if (ccw_device_is_orphan(cdev)) | ||
499 | return sprintf(buf, "no device\n"); | ||
465 | switch (cdev->private->state) { | 500 | switch (cdev->private->state) { |
466 | case DEV_STATE_BOXED: | 501 | case DEV_STATE_BOXED: |
467 | return sprintf(buf, "boxed\n"); | 502 | return sprintf(buf, "boxed\n"); |
@@ -498,11 +533,10 @@ static struct attribute_group subch_attr_group = { | |||
498 | .attrs = subch_attrs, | 533 | .attrs = subch_attrs, |
499 | }; | 534 | }; |
500 | 535 | ||
501 | static inline int | 536 | struct attribute_group *subch_attr_groups[] = { |
502 | subchannel_add_files (struct device *dev) | 537 | &subch_attr_group, |
503 | { | 538 | NULL, |
504 | return sysfs_create_group(&dev->kobj, &subch_attr_group); | 539 | }; |
505 | } | ||
506 | 540 | ||
507 | static struct attribute * ccwdev_attrs[] = { | 541 | static struct attribute * ccwdev_attrs[] = { |
508 | &dev_attr_devtype.attr, | 542 | &dev_attr_devtype.attr, |
@@ -563,11 +597,10 @@ match_devno(struct device * dev, void * data) | |||
563 | 597 | ||
564 | cdev = to_ccwdev(dev); | 598 | cdev = to_ccwdev(dev); |
565 | if ((cdev->private->state == DEV_STATE_DISCONNECTED) && | 599 | if ((cdev->private->state == DEV_STATE_DISCONNECTED) && |
600 | !ccw_device_is_orphan(cdev) && | ||
566 | ccw_dev_id_is_equal(&cdev->private->dev_id, &d->dev_id) && | 601 | ccw_dev_id_is_equal(&cdev->private->dev_id, &d->dev_id) && |
567 | (cdev != d->sibling)) { | 602 | (cdev != d->sibling)) |
568 | cdev->private->state = DEV_STATE_NOT_OPER; | ||
569 | return 1; | 603 | return 1; |
570 | } | ||
571 | return 0; | 604 | return 0; |
572 | } | 605 | } |
573 | 606 | ||
@@ -584,13 +617,36 @@ static struct ccw_device * get_disc_ccwdev_by_dev_id(struct ccw_dev_id *dev_id, | |||
584 | return dev ? to_ccwdev(dev) : NULL; | 617 | return dev ? to_ccwdev(dev) : NULL; |
585 | } | 618 | } |
586 | 619 | ||
587 | static void | 620 | static int match_orphan(struct device *dev, void *data) |
588 | ccw_device_add_changed(void *data) | 621 | { |
622 | struct ccw_dev_id *dev_id; | ||
623 | struct ccw_device *cdev; | ||
624 | |||
625 | dev_id = data; | ||
626 | cdev = to_ccwdev(dev); | ||
627 | return ccw_dev_id_is_equal(&cdev->private->dev_id, dev_id); | ||
628 | } | ||
629 | |||
630 | static struct ccw_device * | ||
631 | get_orphaned_ccwdev_by_dev_id(struct channel_subsystem *css, | ||
632 | struct ccw_dev_id *dev_id) | ||
589 | { | 633 | { |
634 | struct device *dev; | ||
590 | 635 | ||
636 | dev = device_find_child(&css->pseudo_subchannel->dev, dev_id, | ||
637 | match_orphan); | ||
638 | |||
639 | return dev ? to_ccwdev(dev) : NULL; | ||
640 | } | ||
641 | |||
642 | static void | ||
643 | ccw_device_add_changed(struct work_struct *work) | ||
644 | { | ||
645 | struct ccw_device_private *priv; | ||
591 | struct ccw_device *cdev; | 646 | struct ccw_device *cdev; |
592 | 647 | ||
593 | cdev = data; | 648 | priv = container_of(work, struct ccw_device_private, kick_work); |
649 | cdev = priv->cdev; | ||
594 | if (device_add(&cdev->dev)) { | 650 | if (device_add(&cdev->dev)) { |
595 | put_device(&cdev->dev); | 651 | put_device(&cdev->dev); |
596 | return; | 652 | return; |
@@ -602,64 +658,21 @@ ccw_device_add_changed(void *data) | |||
602 | } | 658 | } |
603 | } | 659 | } |
604 | 660 | ||
605 | extern int css_get_ssd_info(struct subchannel *sch); | 661 | void ccw_device_do_unreg_rereg(struct work_struct *work) |
606 | |||
607 | void | ||
608 | ccw_device_do_unreg_rereg(void *data) | ||
609 | { | 662 | { |
663 | struct ccw_device_private *priv; | ||
610 | struct ccw_device *cdev; | 664 | struct ccw_device *cdev; |
611 | struct subchannel *sch; | 665 | struct subchannel *sch; |
612 | int need_rename; | ||
613 | 666 | ||
614 | cdev = data; | 667 | priv = container_of(work, struct ccw_device_private, kick_work); |
668 | cdev = priv->cdev; | ||
615 | sch = to_subchannel(cdev->dev.parent); | 669 | sch = to_subchannel(cdev->dev.parent); |
616 | if (cdev->private->dev_id.devno != sch->schib.pmcw.dev) { | 670 | |
617 | /* | ||
618 | * The device number has changed. This is usually only when | ||
619 | * a device has been detached under VM and then re-appeared | ||
620 | * on another subchannel because of a different attachment | ||
621 | * order than before. Ideally, we should should just switch | ||
622 | * subchannels, but unfortunately, this is not possible with | ||
623 | * the current implementation. | ||
624 | * Instead, we search for the old subchannel for this device | ||
625 | * number and deregister so there are no collisions with the | ||
626 | * newly registered ccw_device. | ||
627 | * FIXME: Find another solution so the block layer doesn't | ||
628 | * get possibly sick... | ||
629 | */ | ||
630 | struct ccw_device *other_cdev; | ||
631 | struct ccw_dev_id dev_id; | ||
632 | |||
633 | need_rename = 1; | ||
634 | dev_id.devno = sch->schib.pmcw.dev; | ||
635 | dev_id.ssid = sch->schid.ssid; | ||
636 | other_cdev = get_disc_ccwdev_by_dev_id(&dev_id, cdev); | ||
637 | if (other_cdev) { | ||
638 | struct subchannel *other_sch; | ||
639 | |||
640 | other_sch = to_subchannel(other_cdev->dev.parent); | ||
641 | if (get_device(&other_sch->dev)) { | ||
642 | stsch(other_sch->schid, &other_sch->schib); | ||
643 | if (other_sch->schib.pmcw.dnv) { | ||
644 | other_sch->schib.pmcw.intparm = 0; | ||
645 | cio_modify(other_sch); | ||
646 | } | ||
647 | css_sch_device_unregister(other_sch); | ||
648 | } | ||
649 | } | ||
650 | /* Update ssd info here. */ | ||
651 | css_get_ssd_info(sch); | ||
652 | cdev->private->dev_id.devno = sch->schib.pmcw.dev; | ||
653 | } else | ||
654 | need_rename = 0; | ||
655 | device_remove_files(&cdev->dev); | 671 | device_remove_files(&cdev->dev); |
656 | if (test_and_clear_bit(1, &cdev->private->registered)) | 672 | if (test_and_clear_bit(1, &cdev->private->registered)) |
657 | device_del(&cdev->dev); | 673 | device_del(&cdev->dev); |
658 | if (need_rename) | ||
659 | snprintf (cdev->dev.bus_id, BUS_ID_SIZE, "0.%x.%04x", | ||
660 | sch->schid.ssid, sch->schib.pmcw.dev); | ||
661 | PREPARE_WORK(&cdev->private->kick_work, | 674 | PREPARE_WORK(&cdev->private->kick_work, |
662 | ccw_device_add_changed, cdev); | 675 | ccw_device_add_changed); |
663 | queue_work(ccw_device_work, &cdev->private->kick_work); | 676 | queue_work(ccw_device_work, &cdev->private->kick_work); |
664 | } | 677 | } |
665 | 678 | ||
@@ -673,18 +686,194 @@ ccw_device_release(struct device *dev) | |||
673 | kfree(cdev); | 686 | kfree(cdev); |
674 | } | 687 | } |
675 | 688 | ||
689 | static struct ccw_device * io_subchannel_allocate_dev(struct subchannel *sch) | ||
690 | { | ||
691 | struct ccw_device *cdev; | ||
692 | |||
693 | cdev = kzalloc(sizeof(*cdev), GFP_KERNEL); | ||
694 | if (cdev) { | ||
695 | cdev->private = kzalloc(sizeof(struct ccw_device_private), | ||
696 | GFP_KERNEL | GFP_DMA); | ||
697 | if (cdev->private) | ||
698 | return cdev; | ||
699 | } | ||
700 | kfree(cdev); | ||
701 | return ERR_PTR(-ENOMEM); | ||
702 | } | ||
703 | |||
704 | static int io_subchannel_initialize_dev(struct subchannel *sch, | ||
705 | struct ccw_device *cdev) | ||
706 | { | ||
707 | cdev->private->cdev = cdev; | ||
708 | atomic_set(&cdev->private->onoff, 0); | ||
709 | cdev->dev.parent = &sch->dev; | ||
710 | cdev->dev.release = ccw_device_release; | ||
711 | INIT_LIST_HEAD(&cdev->private->kick_work.entry); | ||
712 | /* Do first half of device_register. */ | ||
713 | device_initialize(&cdev->dev); | ||
714 | if (!get_device(&sch->dev)) { | ||
715 | if (cdev->dev.release) | ||
716 | cdev->dev.release(&cdev->dev); | ||
717 | return -ENODEV; | ||
718 | } | ||
719 | return 0; | ||
720 | } | ||
721 | |||
722 | static struct ccw_device * io_subchannel_create_ccwdev(struct subchannel *sch) | ||
723 | { | ||
724 | struct ccw_device *cdev; | ||
725 | int ret; | ||
726 | |||
727 | cdev = io_subchannel_allocate_dev(sch); | ||
728 | if (!IS_ERR(cdev)) { | ||
729 | ret = io_subchannel_initialize_dev(sch, cdev); | ||
730 | if (ret) { | ||
731 | kfree(cdev); | ||
732 | cdev = ERR_PTR(ret); | ||
733 | } | ||
734 | } | ||
735 | return cdev; | ||
736 | } | ||
737 | |||
738 | static int io_subchannel_recog(struct ccw_device *, struct subchannel *); | ||
739 | |||
740 | static void sch_attach_device(struct subchannel *sch, | ||
741 | struct ccw_device *cdev) | ||
742 | { | ||
743 | spin_lock_irq(sch->lock); | ||
744 | sch->dev.driver_data = cdev; | ||
745 | cdev->private->schid = sch->schid; | ||
746 | cdev->ccwlock = sch->lock; | ||
747 | device_trigger_reprobe(sch); | ||
748 | spin_unlock_irq(sch->lock); | ||
749 | } | ||
750 | |||
751 | static void sch_attach_disconnected_device(struct subchannel *sch, | ||
752 | struct ccw_device *cdev) | ||
753 | { | ||
754 | struct subchannel *other_sch; | ||
755 | int ret; | ||
756 | |||
757 | other_sch = to_subchannel(get_device(cdev->dev.parent)); | ||
758 | ret = device_move(&cdev->dev, &sch->dev); | ||
759 | if (ret) { | ||
760 | CIO_MSG_EVENT(2, "Moving disconnected device 0.%x.%04x failed " | ||
761 | "(ret=%d)!\n", cdev->private->dev_id.ssid, | ||
762 | cdev->private->dev_id.devno, ret); | ||
763 | put_device(&other_sch->dev); | ||
764 | return; | ||
765 | } | ||
766 | other_sch->dev.driver_data = NULL; | ||
767 | /* No need to keep a subchannel without ccw device around. */ | ||
768 | css_sch_device_unregister(other_sch); | ||
769 | put_device(&other_sch->dev); | ||
770 | sch_attach_device(sch, cdev); | ||
771 | } | ||
772 | |||
773 | static void sch_attach_orphaned_device(struct subchannel *sch, | ||
774 | struct ccw_device *cdev) | ||
775 | { | ||
776 | int ret; | ||
777 | |||
778 | /* Try to move the ccw device to its new subchannel. */ | ||
779 | ret = device_move(&cdev->dev, &sch->dev); | ||
780 | if (ret) { | ||
781 | CIO_MSG_EVENT(0, "Moving device 0.%x.%04x from orphanage " | ||
782 | "failed (ret=%d)!\n", | ||
783 | cdev->private->dev_id.ssid, | ||
784 | cdev->private->dev_id.devno, ret); | ||
785 | return; | ||
786 | } | ||
787 | sch_attach_device(sch, cdev); | ||
788 | } | ||
789 | |||
790 | static void sch_create_and_recog_new_device(struct subchannel *sch) | ||
791 | { | ||
792 | struct ccw_device *cdev; | ||
793 | |||
794 | /* Need to allocate a new ccw device. */ | ||
795 | cdev = io_subchannel_create_ccwdev(sch); | ||
796 | if (IS_ERR(cdev)) { | ||
797 | /* OK, we did everything we could... */ | ||
798 | css_sch_device_unregister(sch); | ||
799 | return; | ||
800 | } | ||
801 | spin_lock_irq(sch->lock); | ||
802 | sch->dev.driver_data = cdev; | ||
803 | spin_unlock_irq(sch->lock); | ||
804 | /* Start recognition for the new ccw device. */ | ||
805 | if (io_subchannel_recog(cdev, sch)) { | ||
806 | spin_lock_irq(sch->lock); | ||
807 | sch->dev.driver_data = NULL; | ||
808 | spin_unlock_irq(sch->lock); | ||
809 | if (cdev->dev.release) | ||
810 | cdev->dev.release(&cdev->dev); | ||
811 | css_sch_device_unregister(sch); | ||
812 | } | ||
813 | } | ||
814 | |||
815 | |||
816 | void ccw_device_move_to_orphanage(struct work_struct *work) | ||
817 | { | ||
818 | struct ccw_device_private *priv; | ||
819 | struct ccw_device *cdev; | ||
820 | struct ccw_device *replacing_cdev; | ||
821 | struct subchannel *sch; | ||
822 | int ret; | ||
823 | struct channel_subsystem *css; | ||
824 | struct ccw_dev_id dev_id; | ||
825 | |||
826 | priv = container_of(work, struct ccw_device_private, kick_work); | ||
827 | cdev = priv->cdev; | ||
828 | sch = to_subchannel(cdev->dev.parent); | ||
829 | css = to_css(sch->dev.parent); | ||
830 | dev_id.devno = sch->schib.pmcw.dev; | ||
831 | dev_id.ssid = sch->schid.ssid; | ||
832 | |||
833 | /* | ||
834 | * Move the orphaned ccw device to the orphanage so the replacing | ||
835 | * ccw device can take its place on the subchannel. | ||
836 | */ | ||
837 | ret = device_move(&cdev->dev, &css->pseudo_subchannel->dev); | ||
838 | if (ret) { | ||
839 | CIO_MSG_EVENT(0, "Moving device 0.%x.%04x to orphanage failed " | ||
840 | "(ret=%d)!\n", cdev->private->dev_id.ssid, | ||
841 | cdev->private->dev_id.devno, ret); | ||
842 | return; | ||
843 | } | ||
844 | cdev->ccwlock = css->pseudo_subchannel->lock; | ||
845 | /* | ||
846 | * Search for the replacing ccw device | ||
847 | * - among the disconnected devices | ||
848 | * - in the orphanage | ||
849 | */ | ||
850 | replacing_cdev = get_disc_ccwdev_by_dev_id(&dev_id, cdev); | ||
851 | if (replacing_cdev) { | ||
852 | sch_attach_disconnected_device(sch, replacing_cdev); | ||
853 | return; | ||
854 | } | ||
855 | replacing_cdev = get_orphaned_ccwdev_by_dev_id(css, &dev_id); | ||
856 | if (replacing_cdev) { | ||
857 | sch_attach_orphaned_device(sch, replacing_cdev); | ||
858 | return; | ||
859 | } | ||
860 | sch_create_and_recog_new_device(sch); | ||
861 | } | ||
862 | |||
676 | /* | 863 | /* |
677 | * Register recognized device. | 864 | * Register recognized device. |
678 | */ | 865 | */ |
679 | static void | 866 | static void |
680 | io_subchannel_register(void *data) | 867 | io_subchannel_register(struct work_struct *work) |
681 | { | 868 | { |
869 | struct ccw_device_private *priv; | ||
682 | struct ccw_device *cdev; | 870 | struct ccw_device *cdev; |
683 | struct subchannel *sch; | 871 | struct subchannel *sch; |
684 | int ret; | 872 | int ret; |
685 | unsigned long flags; | 873 | unsigned long flags; |
686 | 874 | ||
687 | cdev = data; | 875 | priv = container_of(work, struct ccw_device_private, kick_work); |
876 | cdev = priv->cdev; | ||
688 | sch = to_subchannel(cdev->dev.parent); | 877 | sch = to_subchannel(cdev->dev.parent); |
689 | 878 | ||
690 | /* | 879 | /* |
@@ -709,9 +898,9 @@ io_subchannel_register(void *data) | |||
709 | printk (KERN_WARNING "%s: could not register %s\n", | 898 | printk (KERN_WARNING "%s: could not register %s\n", |
710 | __func__, cdev->dev.bus_id); | 899 | __func__, cdev->dev.bus_id); |
711 | put_device(&cdev->dev); | 900 | put_device(&cdev->dev); |
712 | spin_lock_irqsave(&sch->lock, flags); | 901 | spin_lock_irqsave(sch->lock, flags); |
713 | sch->dev.driver_data = NULL; | 902 | sch->dev.driver_data = NULL; |
714 | spin_unlock_irqrestore(&sch->lock, flags); | 903 | spin_unlock_irqrestore(sch->lock, flags); |
715 | kfree (cdev->private); | 904 | kfree (cdev->private); |
716 | kfree (cdev); | 905 | kfree (cdev); |
717 | put_device(&sch->dev); | 906 | put_device(&sch->dev); |
@@ -719,11 +908,6 @@ io_subchannel_register(void *data) | |||
719 | wake_up(&ccw_device_init_wq); | 908 | wake_up(&ccw_device_init_wq); |
720 | return; | 909 | return; |
721 | } | 910 | } |
722 | |||
723 | ret = subchannel_add_files(cdev->dev.parent); | ||
724 | if (ret) | ||
725 | printk(KERN_WARNING "%s: could not add attributes to %s\n", | ||
726 | __func__, sch->dev.bus_id); | ||
727 | put_device(&cdev->dev); | 911 | put_device(&cdev->dev); |
728 | out: | 912 | out: |
729 | cdev->private->flags.recog_done = 1; | 913 | cdev->private->flags.recog_done = 1; |
@@ -734,11 +918,14 @@ out: | |||
734 | } | 918 | } |
735 | 919 | ||
736 | void | 920 | void |
737 | ccw_device_call_sch_unregister(void *data) | 921 | ccw_device_call_sch_unregister(struct work_struct *work) |
738 | { | 922 | { |
739 | struct ccw_device *cdev = data; | 923 | struct ccw_device_private *priv; |
924 | struct ccw_device *cdev; | ||
740 | struct subchannel *sch; | 925 | struct subchannel *sch; |
741 | 926 | ||
927 | priv = container_of(work, struct ccw_device_private, kick_work); | ||
928 | cdev = priv->cdev; | ||
742 | sch = to_subchannel(cdev->dev.parent); | 929 | sch = to_subchannel(cdev->dev.parent); |
743 | css_sch_device_unregister(sch); | 930 | css_sch_device_unregister(sch); |
744 | /* Reset intparm to zeroes. */ | 931 | /* Reset intparm to zeroes. */ |
@@ -768,7 +955,7 @@ io_subchannel_recog_done(struct ccw_device *cdev) | |||
768 | break; | 955 | break; |
769 | sch = to_subchannel(cdev->dev.parent); | 956 | sch = to_subchannel(cdev->dev.parent); |
770 | PREPARE_WORK(&cdev->private->kick_work, | 957 | PREPARE_WORK(&cdev->private->kick_work, |
771 | ccw_device_call_sch_unregister, cdev); | 958 | ccw_device_call_sch_unregister); |
772 | queue_work(slow_path_wq, &cdev->private->kick_work); | 959 | queue_work(slow_path_wq, &cdev->private->kick_work); |
773 | if (atomic_dec_and_test(&ccw_device_init_count)) | 960 | if (atomic_dec_and_test(&ccw_device_init_count)) |
774 | wake_up(&ccw_device_init_wq); | 961 | wake_up(&ccw_device_init_wq); |
@@ -783,7 +970,7 @@ io_subchannel_recog_done(struct ccw_device *cdev) | |||
783 | if (!get_device(&cdev->dev)) | 970 | if (!get_device(&cdev->dev)) |
784 | break; | 971 | break; |
785 | PREPARE_WORK(&cdev->private->kick_work, | 972 | PREPARE_WORK(&cdev->private->kick_work, |
786 | io_subchannel_register, cdev); | 973 | io_subchannel_register); |
787 | queue_work(slow_path_wq, &cdev->private->kick_work); | 974 | queue_work(slow_path_wq, &cdev->private->kick_work); |
788 | break; | 975 | break; |
789 | } | 976 | } |
@@ -797,7 +984,7 @@ io_subchannel_recog(struct ccw_device *cdev, struct subchannel *sch) | |||
797 | 984 | ||
798 | sch->dev.driver_data = cdev; | 985 | sch->dev.driver_data = cdev; |
799 | sch->driver = &io_subchannel_driver; | 986 | sch->driver = &io_subchannel_driver; |
800 | cdev->ccwlock = &sch->lock; | 987 | cdev->ccwlock = sch->lock; |
801 | 988 | ||
802 | /* Init private data. */ | 989 | /* Init private data. */ |
803 | priv = cdev->private; | 990 | priv = cdev->private; |
@@ -817,9 +1004,9 @@ io_subchannel_recog(struct ccw_device *cdev, struct subchannel *sch) | |||
817 | atomic_inc(&ccw_device_init_count); | 1004 | atomic_inc(&ccw_device_init_count); |
818 | 1005 | ||
819 | /* Start async. device sensing. */ | 1006 | /* Start async. device sensing. */ |
820 | spin_lock_irq(&sch->lock); | 1007 | spin_lock_irq(sch->lock); |
821 | rc = ccw_device_recognition(cdev); | 1008 | rc = ccw_device_recognition(cdev); |
822 | spin_unlock_irq(&sch->lock); | 1009 | spin_unlock_irq(sch->lock); |
823 | if (rc) { | 1010 | if (rc) { |
824 | if (atomic_dec_and_test(&ccw_device_init_count)) | 1011 | if (atomic_dec_and_test(&ccw_device_init_count)) |
825 | wake_up(&ccw_device_init_wq); | 1012 | wake_up(&ccw_device_init_wq); |
@@ -827,12 +1014,55 @@ io_subchannel_recog(struct ccw_device *cdev, struct subchannel *sch) | |||
827 | return rc; | 1014 | return rc; |
828 | } | 1015 | } |
829 | 1016 | ||
1017 | static void ccw_device_move_to_sch(struct work_struct *work) | ||
1018 | { | ||
1019 | struct ccw_device_private *priv; | ||
1020 | int rc; | ||
1021 | struct subchannel *sch; | ||
1022 | struct ccw_device *cdev; | ||
1023 | struct subchannel *former_parent; | ||
1024 | |||
1025 | priv = container_of(work, struct ccw_device_private, kick_work); | ||
1026 | sch = priv->sch; | ||
1027 | cdev = priv->cdev; | ||
1028 | former_parent = ccw_device_is_orphan(cdev) ? | ||
1029 | NULL : to_subchannel(get_device(cdev->dev.parent)); | ||
1030 | mutex_lock(&sch->reg_mutex); | ||
1031 | /* Try to move the ccw device to its new subchannel. */ | ||
1032 | rc = device_move(&cdev->dev, &sch->dev); | ||
1033 | mutex_unlock(&sch->reg_mutex); | ||
1034 | if (rc) { | ||
1035 | CIO_MSG_EVENT(2, "Moving device 0.%x.%04x to subchannel " | ||
1036 | "0.%x.%04x failed (ret=%d)!\n", | ||
1037 | cdev->private->dev_id.ssid, | ||
1038 | cdev->private->dev_id.devno, sch->schid.ssid, | ||
1039 | sch->schid.sch_no, rc); | ||
1040 | css_sch_device_unregister(sch); | ||
1041 | goto out; | ||
1042 | } | ||
1043 | if (former_parent) { | ||
1044 | spin_lock_irq(former_parent->lock); | ||
1045 | former_parent->dev.driver_data = NULL; | ||
1046 | spin_unlock_irq(former_parent->lock); | ||
1047 | css_sch_device_unregister(former_parent); | ||
1048 | /* Reset intparm to zeroes. */ | ||
1049 | former_parent->schib.pmcw.intparm = 0; | ||
1050 | cio_modify(former_parent); | ||
1051 | } | ||
1052 | sch_attach_device(sch, cdev); | ||
1053 | out: | ||
1054 | if (former_parent) | ||
1055 | put_device(&former_parent->dev); | ||
1056 | put_device(&cdev->dev); | ||
1057 | } | ||
1058 | |||
830 | static int | 1059 | static int |
831 | io_subchannel_probe (struct subchannel *sch) | 1060 | io_subchannel_probe (struct subchannel *sch) |
832 | { | 1061 | { |
833 | struct ccw_device *cdev; | 1062 | struct ccw_device *cdev; |
834 | int rc; | 1063 | int rc; |
835 | unsigned long flags; | 1064 | unsigned long flags; |
1065 | struct ccw_dev_id dev_id; | ||
836 | 1066 | ||
837 | if (sch->dev.driver_data) { | 1067 | if (sch->dev.driver_data) { |
838 | /* | 1068 | /* |
@@ -843,7 +1073,6 @@ io_subchannel_probe (struct subchannel *sch) | |||
843 | cdev = sch->dev.driver_data; | 1073 | cdev = sch->dev.driver_data; |
844 | device_initialize(&cdev->dev); | 1074 | device_initialize(&cdev->dev); |
845 | ccw_device_register(cdev); | 1075 | ccw_device_register(cdev); |
846 | subchannel_add_files(&sch->dev); | ||
847 | /* | 1076 | /* |
848 | * Check if the device is already online. If it is | 1077 | * Check if the device is already online. If it is |
849 | * the reference count needs to be corrected | 1078 | * the reference count needs to be corrected |
@@ -856,33 +1085,37 @@ io_subchannel_probe (struct subchannel *sch) | |||
856 | get_device(&cdev->dev); | 1085 | get_device(&cdev->dev); |
857 | return 0; | 1086 | return 0; |
858 | } | 1087 | } |
859 | cdev = kzalloc (sizeof(*cdev), GFP_KERNEL); | 1088 | /* |
1089 | * First check if a fitting device may be found amongst the | ||
1090 | * disconnected devices or in the orphanage. | ||
1091 | */ | ||
1092 | dev_id.devno = sch->schib.pmcw.dev; | ||
1093 | dev_id.ssid = sch->schid.ssid; | ||
1094 | cdev = get_disc_ccwdev_by_dev_id(&dev_id, NULL); | ||
860 | if (!cdev) | 1095 | if (!cdev) |
861 | return -ENOMEM; | 1096 | cdev = get_orphaned_ccwdev_by_dev_id(to_css(sch->dev.parent), |
862 | cdev->private = kzalloc(sizeof(struct ccw_device_private), | 1097 | &dev_id); |
863 | GFP_KERNEL | GFP_DMA); | 1098 | if (cdev) { |
864 | if (!cdev->private) { | 1099 | /* |
865 | kfree(cdev); | 1100 | * Schedule moving the device until when we have a registered |
866 | return -ENOMEM; | 1101 | * subchannel to move to and succeed the probe. We can |
867 | } | 1102 | * unregister later again, when the probe is through. |
868 | atomic_set(&cdev->private->onoff, 0); | 1103 | */ |
869 | cdev->dev.parent = &sch->dev; | 1104 | cdev->private->sch = sch; |
870 | cdev->dev.release = ccw_device_release; | 1105 | PREPARE_WORK(&cdev->private->kick_work, |
871 | INIT_LIST_HEAD(&cdev->private->kick_work.entry); | 1106 | ccw_device_move_to_sch); |
872 | /* Do first half of device_register. */ | 1107 | queue_work(slow_path_wq, &cdev->private->kick_work); |
873 | device_initialize(&cdev->dev); | 1108 | return 0; |
874 | |||
875 | if (!get_device(&sch->dev)) { | ||
876 | if (cdev->dev.release) | ||
877 | cdev->dev.release(&cdev->dev); | ||
878 | return -ENODEV; | ||
879 | } | 1109 | } |
1110 | cdev = io_subchannel_create_ccwdev(sch); | ||
1111 | if (IS_ERR(cdev)) | ||
1112 | return PTR_ERR(cdev); | ||
880 | 1113 | ||
881 | rc = io_subchannel_recog(cdev, sch); | 1114 | rc = io_subchannel_recog(cdev, sch); |
882 | if (rc) { | 1115 | if (rc) { |
883 | spin_lock_irqsave(&sch->lock, flags); | 1116 | spin_lock_irqsave(sch->lock, flags); |
884 | sch->dev.driver_data = NULL; | 1117 | sch->dev.driver_data = NULL; |
885 | spin_unlock_irqrestore(&sch->lock, flags); | 1118 | spin_unlock_irqrestore(sch->lock, flags); |
886 | if (cdev->dev.release) | 1119 | if (cdev->dev.release) |
887 | cdev->dev.release(&cdev->dev); | 1120 | cdev->dev.release(&cdev->dev); |
888 | } | 1121 | } |
@@ -890,17 +1123,6 @@ io_subchannel_probe (struct subchannel *sch) | |||
890 | return rc; | 1123 | return rc; |
891 | } | 1124 | } |
892 | 1125 | ||
893 | static void | ||
894 | ccw_device_unregister(void *data) | ||
895 | { | ||
896 | struct ccw_device *cdev; | ||
897 | |||
898 | cdev = (struct ccw_device *)data; | ||
899 | if (test_and_clear_bit(1, &cdev->private->registered)) | ||
900 | device_unregister(&cdev->dev); | ||
901 | put_device(&cdev->dev); | ||
902 | } | ||
903 | |||
904 | static int | 1126 | static int |
905 | io_subchannel_remove (struct subchannel *sch) | 1127 | io_subchannel_remove (struct subchannel *sch) |
906 | { | 1128 | { |
@@ -921,7 +1143,7 @@ io_subchannel_remove (struct subchannel *sch) | |||
921 | */ | 1143 | */ |
922 | if (get_device(&cdev->dev)) { | 1144 | if (get_device(&cdev->dev)) { |
923 | PREPARE_WORK(&cdev->private->kick_work, | 1145 | PREPARE_WORK(&cdev->private->kick_work, |
924 | ccw_device_unregister, cdev); | 1146 | ccw_device_unregister); |
925 | queue_work(ccw_device_work, &cdev->private->kick_work); | 1147 | queue_work(ccw_device_work, &cdev->private->kick_work); |
926 | } | 1148 | } |
927 | return 0; | 1149 | return 0; |
@@ -1003,6 +1225,13 @@ static struct ccw_device console_cdev; | |||
1003 | static struct ccw_device_private console_private; | 1225 | static struct ccw_device_private console_private; |
1004 | static int console_cdev_in_use; | 1226 | static int console_cdev_in_use; |
1005 | 1227 | ||
1228 | static DEFINE_SPINLOCK(ccw_console_lock); | ||
1229 | |||
1230 | spinlock_t * cio_get_console_lock(void) | ||
1231 | { | ||
1232 | return &ccw_console_lock; | ||
1233 | } | ||
1234 | |||
1006 | static int | 1235 | static int |
1007 | ccw_device_console_enable (struct ccw_device *cdev, struct subchannel *sch) | 1236 | ccw_device_console_enable (struct ccw_device *cdev, struct subchannel *sch) |
1008 | { | 1237 | { |
@@ -1048,6 +1277,7 @@ ccw_device_probe_console(void) | |||
1048 | memset(&console_cdev, 0, sizeof(struct ccw_device)); | 1277 | memset(&console_cdev, 0, sizeof(struct ccw_device)); |
1049 | memset(&console_private, 0, sizeof(struct ccw_device_private)); | 1278 | memset(&console_private, 0, sizeof(struct ccw_device_private)); |
1050 | console_cdev.private = &console_private; | 1279 | console_cdev.private = &console_private; |
1280 | console_private.cdev = &console_cdev; | ||
1051 | ret = ccw_device_console_enable(&console_cdev, sch); | 1281 | ret = ccw_device_console_enable(&console_cdev, sch); |
1052 | if (ret) { | 1282 | if (ret) { |
1053 | cio_release_console(); | 1283 | cio_release_console(); |