aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCornelia Huck <cornelia.huck@de.ibm.com>2006-12-08 09:54:28 -0500
committerMartin Schwidefsky <schwidefsky@de.ibm.com>2006-12-08 09:54:28 -0500
commitd7b5a4c94f49131811112526f7d404a50f0b5ca7 (patch)
tree159cb6717e16339b821315c0bc6b17b6f5df5119
parent2ec2298412e1ab4674b3780005058d4f0b8bd858 (diff)
[S390] Support for disconnected devices reappearing on another subchannel.
- create a 'pseudo_subchannel' per channel subsystem (the 'orphanage') - use the orphanage as a shelter for ccw_devices that can't remain on the same subchannel Signed-off-by: Cornelia Huck <cornelia.huck@de.ibm.com> Cc: Greg KH <greg@kroah.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
-rw-r--r--drivers/s390/cio/cio.c6
-rw-r--r--drivers/s390/cio/cio.h2
-rw-r--r--drivers/s390/cio/css.c37
-rw-r--r--drivers/s390/cio/css.h4
-rw-r--r--drivers/s390/cio/device.c287
-rw-r--r--drivers/s390/cio/device.h2
-rw-r--r--drivers/s390/cio/device_fsm.c17
7 files changed, 296 insertions, 59 deletions
diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c
index e8d331493fd8..7835a714a405 100644
--- a/drivers/s390/cio/cio.c
+++ b/drivers/s390/cio/cio.c
@@ -415,6 +415,8 @@ cio_enable_subchannel (struct subchannel *sch, unsigned int isc)
415 CIO_TRACE_EVENT (2, "ensch"); 415 CIO_TRACE_EVENT (2, "ensch");
416 CIO_TRACE_EVENT (2, sch->dev.bus_id); 416 CIO_TRACE_EVENT (2, sch->dev.bus_id);
417 417
418 if (sch_is_pseudo_sch(sch))
419 return -EINVAL;
418 ccode = stsch (sch->schid, &sch->schib); 420 ccode = stsch (sch->schid, &sch->schib);
419 if (ccode) 421 if (ccode)
420 return -ENODEV; 422 return -ENODEV;
@@ -462,6 +464,8 @@ cio_disable_subchannel (struct subchannel *sch)
462 CIO_TRACE_EVENT (2, "dissch"); 464 CIO_TRACE_EVENT (2, "dissch");
463 CIO_TRACE_EVENT (2, sch->dev.bus_id); 465 CIO_TRACE_EVENT (2, sch->dev.bus_id);
464 466
467 if (sch_is_pseudo_sch(sch))
468 return 0;
465 ccode = stsch (sch->schid, &sch->schib); 469 ccode = stsch (sch->schid, &sch->schib);
466 if (ccode == 3) /* Not operational. */ 470 if (ccode == 3) /* Not operational. */
467 return -ENODEV; 471 return -ENODEV;
@@ -496,7 +500,7 @@ cio_disable_subchannel (struct subchannel *sch)
496 return ret; 500 return ret;
497} 501}
498 502
499static int cio_create_sch_lock(struct subchannel *sch) 503int cio_create_sch_lock(struct subchannel *sch)
500{ 504{
501 sch->lock = kmalloc(sizeof(spinlock_t), GFP_KERNEL); 505 sch->lock = kmalloc(sizeof(spinlock_t), GFP_KERNEL);
502 if (!sch->lock) 506 if (!sch->lock)
diff --git a/drivers/s390/cio/cio.h b/drivers/s390/cio/cio.h
index 7e7369b21a93..35154a210357 100644
--- a/drivers/s390/cio/cio.h
+++ b/drivers/s390/cio/cio.h
@@ -131,6 +131,8 @@ extern int cio_set_options (struct subchannel *, int);
131extern int cio_get_options (struct subchannel *); 131extern int cio_get_options (struct subchannel *);
132extern int cio_modify (struct subchannel *); 132extern int cio_modify (struct subchannel *);
133 133
134int cio_create_sch_lock(struct subchannel *);
135
134/* Use with care. */ 136/* Use with care. */
135#ifdef CONFIG_CCW_CONSOLE 137#ifdef CONFIG_CCW_CONSOLE
136extern struct subchannel *cio_probe_console(void); 138extern struct subchannel *cio_probe_console(void);
diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c
index 65939e2eb415..0bf716619378 100644
--- a/drivers/s390/cio/css.c
+++ b/drivers/s390/cio/css.c
@@ -580,12 +580,24 @@ css_cm_enable_store(struct device *dev, struct device_attribute *attr,
580 580
581static DEVICE_ATTR(cm_enable, 0644, css_cm_enable_show, css_cm_enable_store); 581static DEVICE_ATTR(cm_enable, 0644, css_cm_enable_show, css_cm_enable_store);
582 582
583static inline void __init 583static inline int __init setup_css(int nr)
584setup_css(int nr)
585{ 584{
586 u32 tod_high; 585 u32 tod_high;
586 int ret;
587 587
588 memset(css[nr], 0, sizeof(struct channel_subsystem)); 588 memset(css[nr], 0, sizeof(struct channel_subsystem));
589 css[nr]->pseudo_subchannel =
590 kzalloc(sizeof(*css[nr]->pseudo_subchannel), GFP_KERNEL);
591 if (!css[nr]->pseudo_subchannel)
592 return -ENOMEM;
593 css[nr]->pseudo_subchannel->dev.parent = &css[nr]->device;
594 css[nr]->pseudo_subchannel->dev.release = css_subchannel_release;
595 sprintf(css[nr]->pseudo_subchannel->dev.bus_id, "defunct");
596 ret = cio_create_sch_lock(css[nr]->pseudo_subchannel);
597 if (ret) {
598 kfree(css[nr]->pseudo_subchannel);
599 return ret;
600 }
589 mutex_init(&css[nr]->mutex); 601 mutex_init(&css[nr]->mutex);
590 css[nr]->valid = 1; 602 css[nr]->valid = 1;
591 css[nr]->cssid = nr; 603 css[nr]->cssid = nr;
@@ -593,6 +605,7 @@ setup_css(int nr)
593 css[nr]->device.release = channel_subsystem_release; 605 css[nr]->device.release = channel_subsystem_release;
594 tod_high = (u32) (get_clock() >> 32); 606 tod_high = (u32) (get_clock() >> 32);
595 css_generate_pgid(css[nr], tod_high); 607 css_generate_pgid(css[nr], tod_high);
608 return 0;
596} 609}
597 610
598/* 611/*
@@ -629,10 +642,12 @@ init_channel_subsystem (void)
629 ret = -ENOMEM; 642 ret = -ENOMEM;
630 goto out_unregister; 643 goto out_unregister;
631 } 644 }
632 setup_css(i); 645 ret = setup_css(i);
633 ret = device_register(&css[i]->device);
634 if (ret) 646 if (ret)
635 goto out_free; 647 goto out_free;
648 ret = device_register(&css[i]->device);
649 if (ret)
650 goto out_free_all;
636 if (css_characteristics_avail && 651 if (css_characteristics_avail &&
637 css_chsc_characteristics.secm) { 652 css_chsc_characteristics.secm) {
638 ret = device_create_file(&css[i]->device, 653 ret = device_create_file(&css[i]->device,
@@ -640,6 +655,9 @@ init_channel_subsystem (void)
640 if (ret) 655 if (ret)
641 goto out_device; 656 goto out_device;
642 } 657 }
658 ret = device_register(&css[i]->pseudo_subchannel->dev);
659 if (ret)
660 goto out_file;
643 } 661 }
644 css_init_done = 1; 662 css_init_done = 1;
645 663
@@ -647,13 +665,19 @@ init_channel_subsystem (void)
647 665
648 for_each_subchannel(__init_channel_subsystem, NULL); 666 for_each_subchannel(__init_channel_subsystem, NULL);
649 return 0; 667 return 0;
668out_file:
669 device_remove_file(&css[i]->device, &dev_attr_cm_enable);
650out_device: 670out_device:
651 device_unregister(&css[i]->device); 671 device_unregister(&css[i]->device);
672out_free_all:
673 kfree(css[i]->pseudo_subchannel->lock);
674 kfree(css[i]->pseudo_subchannel);
652out_free: 675out_free:
653 kfree(css[i]); 676 kfree(css[i]);
654out_unregister: 677out_unregister:
655 while (i > 0) { 678 while (i > 0) {
656 i--; 679 i--;
680 device_unregister(&css[i]->pseudo_subchannel->dev);
657 if (css_characteristics_avail && css_chsc_characteristics.secm) 681 if (css_characteristics_avail && css_chsc_characteristics.secm)
658 device_remove_file(&css[i]->device, 682 device_remove_file(&css[i]->device,
659 &dev_attr_cm_enable); 683 &dev_attr_cm_enable);
@@ -665,6 +689,11 @@ out:
665 return ret; 689 return ret;
666} 690}
667 691
692int sch_is_pseudo_sch(struct subchannel *sch)
693{
694 return sch == to_css(sch->dev.parent)->pseudo_subchannel;
695}
696
668/* 697/*
669 * find a driver for a subchannel. They identify by the subchannel 698 * find a driver for a subchannel. They identify by the subchannel
670 * type with the exception that the console subchannel driver has its own 699 * type with the exception that the console subchannel driver has its own
diff --git a/drivers/s390/cio/css.h b/drivers/s390/cio/css.h
index ac845c1ebf83..71fe380f86f6 100644
--- a/drivers/s390/cio/css.h
+++ b/drivers/s390/cio/css.h
@@ -160,6 +160,8 @@ struct channel_subsystem {
160 int cm_enabled; 160 int cm_enabled;
161 void *cub_addr1; 161 void *cub_addr1;
162 void *cub_addr2; 162 void *cub_addr2;
163 /* for orphaned ccw devices */
164 struct subchannel *pseudo_subchannel;
163}; 165};
164#define to_css(dev) container_of(dev, struct channel_subsystem, device) 166#define to_css(dev) container_of(dev, struct channel_subsystem, device)
165 167
@@ -187,6 +189,8 @@ void css_clear_subchannel_slow_list(void);
187int css_slow_subchannels_exist(void); 189int css_slow_subchannels_exist(void);
188extern int need_rescan; 190extern int need_rescan;
189 191
192int sch_is_pseudo_sch(struct subchannel *);
193
190extern struct workqueue_struct *slow_path_wq; 194extern struct workqueue_struct *slow_path_wq;
191extern struct work_struct slow_path_work; 195extern struct work_struct slow_path_work;
192 196
diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c
index 9a31239fe028..7fe1ccdc7812 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"
@@ -294,6 +295,11 @@ online_show (struct device *dev, struct device_attribute *attr, char *buf)
294 return sprintf(buf, cdev->online ? "1\n" : "0\n"); 295 return sprintf(buf, cdev->online ? "1\n" : "0\n");
295} 296}
296 297
298int ccw_device_is_orphan(struct ccw_device *cdev)
299{
300 return sch_is_pseudo_sch(to_subchannel(cdev->dev.parent));
301}
302
297static void ccw_device_unregister(struct work_struct *work) 303static void ccw_device_unregister(struct work_struct *work)
298{ 304{
299 struct ccw_device_private *priv; 305 struct ccw_device_private *priv;
@@ -310,10 +316,23 @@ static void
310ccw_device_remove_disconnected(struct ccw_device *cdev) 316ccw_device_remove_disconnected(struct ccw_device *cdev)
311{ 317{
312 struct subchannel *sch; 318 struct subchannel *sch;
319 unsigned long flags;
313 /* 320 /*
314 * Forced offline in disconnected state means 321 * Forced offline in disconnected state means
315 * 'throw away device'. 322 * 'throw away device'.
316 */ 323 */
324 if (ccw_device_is_orphan(cdev)) {
325 /* Deregister ccw device. */
326 spin_lock_irqsave(cdev->ccwlock, flags);
327 cdev->private->state = DEV_STATE_NOT_OPER;
328 spin_unlock_irqrestore(cdev->ccwlock, flags);
329 if (get_device(&cdev->dev)) {
330 PREPARE_WORK(&cdev->private->kick_work,
331 ccw_device_unregister);
332 queue_work(ccw_device_work, &cdev->private->kick_work);
333 }
334 return ;
335 }
317 sch = to_subchannel(cdev->dev.parent); 336 sch = to_subchannel(cdev->dev.parent);
318 css_sch_device_unregister(sch); 337 css_sch_device_unregister(sch);
319 /* Reset intparm to zeroes. */ 338 /* Reset intparm to zeroes. */
@@ -474,6 +493,8 @@ available_show (struct device *dev, struct device_attribute *attr, char *buf)
474 struct ccw_device *cdev = to_ccwdev(dev); 493 struct ccw_device *cdev = to_ccwdev(dev);
475 struct subchannel *sch; 494 struct subchannel *sch;
476 495
496 if (ccw_device_is_orphan(cdev))
497 return sprintf(buf, "no device\n");
477 switch (cdev->private->state) { 498 switch (cdev->private->state) {
478 case DEV_STATE_BOXED: 499 case DEV_STATE_BOXED:
479 return sprintf(buf, "boxed\n"); 500 return sprintf(buf, "boxed\n");
@@ -574,11 +595,10 @@ match_devno(struct device * dev, void * data)
574 595
575 cdev = to_ccwdev(dev); 596 cdev = to_ccwdev(dev);
576 if ((cdev->private->state == DEV_STATE_DISCONNECTED) && 597 if ((cdev->private->state == DEV_STATE_DISCONNECTED) &&
598 !ccw_device_is_orphan(cdev) &&
577 ccw_dev_id_is_equal(&cdev->private->dev_id, &d->dev_id) && 599 ccw_dev_id_is_equal(&cdev->private->dev_id, &d->dev_id) &&
578 (cdev != d->sibling)) { 600 (cdev != d->sibling))
579 cdev->private->state = DEV_STATE_NOT_OPER;
580 return 1; 601 return 1;
581 }
582 return 0; 602 return 0;
583} 603}
584 604
@@ -595,6 +615,28 @@ static struct ccw_device * get_disc_ccwdev_by_dev_id(struct ccw_dev_id *dev_id,
595 return dev ? to_ccwdev(dev) : NULL; 615 return dev ? to_ccwdev(dev) : NULL;
596} 616}
597 617
618static int match_orphan(struct device *dev, void *data)
619{
620 struct ccw_dev_id *dev_id;
621 struct ccw_device *cdev;
622
623 dev_id = data;
624 cdev = to_ccwdev(dev);
625 return ccw_dev_id_is_equal(&cdev->private->dev_id, dev_id);
626}
627
628static struct ccw_device *
629get_orphaned_ccwdev_by_dev_id(struct channel_subsystem *css,
630 struct ccw_dev_id *dev_id)
631{
632 struct device *dev;
633
634 dev = device_find_child(&css->pseudo_subchannel->dev, dev_id,
635 match_orphan);
636
637 return dev ? to_ccwdev(dev) : NULL;
638}
639
598static void 640static void
599ccw_device_add_changed(struct work_struct *work) 641ccw_device_add_changed(struct work_struct *work)
600{ 642{
@@ -614,64 +656,19 @@ ccw_device_add_changed(struct work_struct *work)
614 } 656 }
615} 657}
616 658
617extern int css_get_ssd_info(struct subchannel *sch); 659void ccw_device_do_unreg_rereg(struct work_struct *work)
618
619void
620ccw_device_do_unreg_rereg(struct work_struct *work)
621{ 660{
622 struct ccw_device_private *priv; 661 struct ccw_device_private *priv;
623 struct ccw_device *cdev; 662 struct ccw_device *cdev;
624 struct subchannel *sch; 663 struct subchannel *sch;
625 int need_rename;
626 664
627 priv = container_of(work, struct ccw_device_private, kick_work); 665 priv = container_of(work, struct ccw_device_private, kick_work);
628 cdev = priv->cdev; 666 cdev = priv->cdev;
629 sch = to_subchannel(cdev->dev.parent); 667 sch = to_subchannel(cdev->dev.parent);
630 if (cdev->private->dev_id.devno != sch->schib.pmcw.dev) { 668
631 /*
632 * The device number has changed. This is usually only when
633 * a device has been detached under VM and then re-appeared
634 * on another subchannel because of a different attachment
635 * order than before. Ideally, we should should just switch
636 * subchannels, but unfortunately, this is not possible with
637 * the current implementation.
638 * Instead, we search for the old subchannel for this device
639 * number and deregister so there are no collisions with the
640 * newly registered ccw_device.
641 * FIXME: Find another solution so the block layer doesn't
642 * get possibly sick...
643 */
644 struct ccw_device *other_cdev;
645 struct ccw_dev_id dev_id;
646
647 need_rename = 1;
648 dev_id.devno = sch->schib.pmcw.dev;
649 dev_id.ssid = sch->schid.ssid;
650 other_cdev = get_disc_ccwdev_by_dev_id(&dev_id, cdev);
651 if (other_cdev) {
652 struct subchannel *other_sch;
653
654 other_sch = to_subchannel(other_cdev->dev.parent);
655 if (get_device(&other_sch->dev)) {
656 stsch(other_sch->schid, &other_sch->schib);
657 if (other_sch->schib.pmcw.dnv) {
658 other_sch->schib.pmcw.intparm = 0;
659 cio_modify(other_sch);
660 }
661 css_sch_device_unregister(other_sch);
662 }
663 }
664 /* Update ssd info here. */
665 css_get_ssd_info(sch);
666 cdev->private->dev_id.devno = sch->schib.pmcw.dev;
667 } else
668 need_rename = 0;
669 device_remove_files(&cdev->dev); 669 device_remove_files(&cdev->dev);
670 if (test_and_clear_bit(1, &cdev->private->registered)) 670 if (test_and_clear_bit(1, &cdev->private->registered))
671 device_del(&cdev->dev); 671 device_del(&cdev->dev);
672 if (need_rename)
673 snprintf (cdev->dev.bus_id, BUS_ID_SIZE, "0.%x.%04x",
674 sch->schid.ssid, sch->schib.pmcw.dev);
675 PREPARE_WORK(&cdev->private->kick_work, 672 PREPARE_WORK(&cdev->private->kick_work,
676 ccw_device_add_changed); 673 ccw_device_add_changed);
677 queue_work(ccw_device_work, &cdev->private->kick_work); 674 queue_work(ccw_device_work, &cdev->private->kick_work);
@@ -736,6 +733,131 @@ static struct ccw_device * io_subchannel_create_ccwdev(struct subchannel *sch)
736 return cdev; 733 return cdev;
737} 734}
738 735
736static int io_subchannel_recog(struct ccw_device *, struct subchannel *);
737
738static void sch_attach_device(struct subchannel *sch,
739 struct ccw_device *cdev)
740{
741 spin_lock_irq(sch->lock);
742 sch->dev.driver_data = cdev;
743 cdev->private->schid = sch->schid;
744 cdev->ccwlock = sch->lock;
745 device_trigger_reprobe(sch);
746 spin_unlock_irq(sch->lock);
747}
748
749static void sch_attach_disconnected_device(struct subchannel *sch,
750 struct ccw_device *cdev)
751{
752 struct subchannel *other_sch;
753 int ret;
754
755 other_sch = to_subchannel(get_device(cdev->dev.parent));
756 ret = device_move(&cdev->dev, &sch->dev);
757 if (ret) {
758 CIO_MSG_EVENT(2, "Moving disconnected device 0.%x.%04x failed "
759 "(ret=%d)!\n", cdev->private->dev_id.ssid,
760 cdev->private->dev_id.devno, ret);
761 put_device(&other_sch->dev);
762 return;
763 }
764 other_sch->dev.driver_data = NULL;
765 /* No need to keep a subchannel without ccw device around. */
766 css_sch_device_unregister(other_sch);
767 put_device(&other_sch->dev);
768 sch_attach_device(sch, cdev);
769}
770
771static void sch_attach_orphaned_device(struct subchannel *sch,
772 struct ccw_device *cdev)
773{
774 int ret;
775
776 /* Try to move the ccw device to its new subchannel. */
777 ret = device_move(&cdev->dev, &sch->dev);
778 if (ret) {
779 CIO_MSG_EVENT(0, "Moving device 0.%x.%04x from orphanage "
780 "failed (ret=%d)!\n",
781 cdev->private->dev_id.ssid,
782 cdev->private->dev_id.devno, ret);
783 return;
784 }
785 sch_attach_device(sch, cdev);
786}
787
788static void sch_create_and_recog_new_device(struct subchannel *sch)
789{
790 struct ccw_device *cdev;
791
792 /* Need to allocate a new ccw device. */
793 cdev = io_subchannel_create_ccwdev(sch);
794 if (IS_ERR(cdev)) {
795 /* OK, we did everything we could... */
796 css_sch_device_unregister(sch);
797 return;
798 }
799 spin_lock_irq(sch->lock);
800 sch->dev.driver_data = cdev;
801 spin_unlock_irq(sch->lock);
802 /* Start recognition for the new ccw device. */
803 if (io_subchannel_recog(cdev, sch)) {
804 spin_lock_irq(sch->lock);
805 sch->dev.driver_data = NULL;
806 spin_unlock_irq(sch->lock);
807 if (cdev->dev.release)
808 cdev->dev.release(&cdev->dev);
809 css_sch_device_unregister(sch);
810 }
811}
812
813
814void ccw_device_move_to_orphanage(struct work_struct *work)
815{
816 struct ccw_device_private *priv;
817 struct ccw_device *cdev;
818 struct ccw_device *replacing_cdev;
819 struct subchannel *sch;
820 int ret;
821 struct channel_subsystem *css;
822 struct ccw_dev_id dev_id;
823
824 priv = container_of(work, struct ccw_device_private, kick_work);
825 cdev = priv->cdev;
826 sch = to_subchannel(cdev->dev.parent);
827 css = to_css(sch->dev.parent);
828 dev_id.devno = sch->schib.pmcw.dev;
829 dev_id.ssid = sch->schid.ssid;
830
831 /*
832 * Move the orphaned ccw device to the orphanage so the replacing
833 * ccw device can take its place on the subchannel.
834 */
835 ret = device_move(&cdev->dev, &css->pseudo_subchannel->dev);
836 if (ret) {
837 CIO_MSG_EVENT(0, "Moving device 0.%x.%04x to orphanage failed "
838 "(ret=%d)!\n", cdev->private->dev_id.ssid,
839 cdev->private->dev_id.devno, ret);
840 return;
841 }
842 cdev->ccwlock = css->pseudo_subchannel->lock;
843 /*
844 * Search for the replacing ccw device
845 * - among the disconnected devices
846 * - in the orphanage
847 */
848 replacing_cdev = get_disc_ccwdev_by_dev_id(&dev_id, cdev);
849 if (replacing_cdev) {
850 sch_attach_disconnected_device(sch, replacing_cdev);
851 return;
852 }
853 replacing_cdev = get_orphaned_ccwdev_by_dev_id(css, &dev_id);
854 if (replacing_cdev) {
855 sch_attach_orphaned_device(sch, replacing_cdev);
856 return;
857 }
858 sch_create_and_recog_new_device(sch);
859}
860
739/* 861/*
740 * Register recognized device. 862 * Register recognized device.
741 */ 863 */
@@ -890,12 +1012,55 @@ io_subchannel_recog(struct ccw_device *cdev, struct subchannel *sch)
890 return rc; 1012 return rc;
891} 1013}
892 1014
1015static void ccw_device_move_to_sch(struct work_struct *work)
1016{
1017 struct ccw_device_private *priv;
1018 int rc;
1019 struct subchannel *sch;
1020 struct ccw_device *cdev;
1021 struct subchannel *former_parent;
1022
1023 priv = container_of(work, struct ccw_device_private, kick_work);
1024 sch = priv->sch;
1025 cdev = priv->cdev;
1026 former_parent = ccw_device_is_orphan(cdev) ?
1027 NULL : to_subchannel(get_device(cdev->dev.parent));
1028 mutex_lock(&sch->reg_mutex);
1029 /* Try to move the ccw device to its new subchannel. */
1030 rc = device_move(&cdev->dev, &sch->dev);
1031 mutex_unlock(&sch->reg_mutex);
1032 if (rc) {
1033 CIO_MSG_EVENT(2, "Moving device 0.%x.%04x to subchannel "
1034 "0.%x.%04x failed (ret=%d)!\n",
1035 cdev->private->dev_id.ssid,
1036 cdev->private->dev_id.devno, sch->schid.ssid,
1037 sch->schid.sch_no, rc);
1038 css_sch_device_unregister(sch);
1039 goto out;
1040 }
1041 if (former_parent) {
1042 spin_lock_irq(former_parent->lock);
1043 former_parent->dev.driver_data = NULL;
1044 spin_unlock_irq(former_parent->lock);
1045 css_sch_device_unregister(former_parent);
1046 /* Reset intparm to zeroes. */
1047 former_parent->schib.pmcw.intparm = 0;
1048 cio_modify(former_parent);
1049 }
1050 sch_attach_device(sch, cdev);
1051out:
1052 if (former_parent)
1053 put_device(&former_parent->dev);
1054 put_device(&cdev->dev);
1055}
1056
893static int 1057static int
894io_subchannel_probe (struct subchannel *sch) 1058io_subchannel_probe (struct subchannel *sch)
895{ 1059{
896 struct ccw_device *cdev; 1060 struct ccw_device *cdev;
897 int rc; 1061 int rc;
898 unsigned long flags; 1062 unsigned long flags;
1063 struct ccw_dev_id dev_id;
899 1064
900 if (sch->dev.driver_data) { 1065 if (sch->dev.driver_data) {
901 /* 1066 /*
@@ -918,6 +1083,28 @@ io_subchannel_probe (struct subchannel *sch)
918 get_device(&cdev->dev); 1083 get_device(&cdev->dev);
919 return 0; 1084 return 0;
920 } 1085 }
1086 /*
1087 * First check if a fitting device may be found amongst the
1088 * disconnected devices or in the orphanage.
1089 */
1090 dev_id.devno = sch->schib.pmcw.dev;
1091 dev_id.ssid = sch->schid.ssid;
1092 cdev = get_disc_ccwdev_by_dev_id(&dev_id, NULL);
1093 if (!cdev)
1094 cdev = get_orphaned_ccwdev_by_dev_id(to_css(sch->dev.parent),
1095 &dev_id);
1096 if (cdev) {
1097 /*
1098 * Schedule moving the device until when we have a registered
1099 * subchannel to move to and succeed the probe. We can
1100 * unregister later again, when the probe is through.
1101 */
1102 cdev->private->sch = sch;
1103 PREPARE_WORK(&cdev->private->kick_work,
1104 ccw_device_move_to_sch);
1105 queue_work(slow_path_wq, &cdev->private->kick_work);
1106 return 0;
1107 }
921 cdev = io_subchannel_create_ccwdev(sch); 1108 cdev = io_subchannel_create_ccwdev(sch);
922 if (IS_ERR(cdev)) 1109 if (IS_ERR(cdev))
923 return PTR_ERR(cdev); 1110 return PTR_ERR(cdev);
diff --git a/drivers/s390/cio/device.h b/drivers/s390/cio/device.h
index d5fe95e04cfe..29db6341d632 100644
--- a/drivers/s390/cio/device.h
+++ b/drivers/s390/cio/device.h
@@ -80,6 +80,8 @@ int ccw_device_cancel_halt_clear(struct ccw_device *);
80 80
81void ccw_device_do_unreg_rereg(struct work_struct *); 81void ccw_device_do_unreg_rereg(struct work_struct *);
82void ccw_device_call_sch_unregister(struct work_struct *); 82void ccw_device_call_sch_unregister(struct work_struct *);
83void ccw_device_move_to_orphanage(struct work_struct *);
84int ccw_device_is_orphan(struct ccw_device *);
83 85
84int ccw_device_recognition(struct ccw_device *); 86int ccw_device_recognition(struct ccw_device *);
85int ccw_device_online(struct ccw_device *); 87int ccw_device_online(struct ccw_device *);
diff --git a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c
index a487fb0e7d3d..eed14572fc3b 100644
--- a/drivers/s390/cio/device_fsm.c
+++ b/drivers/s390/cio/device_fsm.c
@@ -186,13 +186,12 @@ ccw_device_handle_oper(struct ccw_device *cdev)
186 /* 186 /*
187 * Check if cu type and device type still match. If 187 * Check if cu type and device type still match. If
188 * not, it is certainly another device and we have to 188 * not, it is certainly another device and we have to
189 * de- and re-register. Also check here for non-matching devno. 189 * de- and re-register.
190 */ 190 */
191 if (cdev->id.cu_type != cdev->private->senseid.cu_type || 191 if (cdev->id.cu_type != cdev->private->senseid.cu_type ||
192 cdev->id.cu_model != cdev->private->senseid.cu_model || 192 cdev->id.cu_model != cdev->private->senseid.cu_model ||
193 cdev->id.dev_type != cdev->private->senseid.dev_type || 193 cdev->id.dev_type != cdev->private->senseid.dev_type ||
194 cdev->id.dev_model != cdev->private->senseid.dev_model || 194 cdev->id.dev_model != cdev->private->senseid.dev_model) {
195 cdev->private->dev_id.devno != sch->schib.pmcw.dev) {
196 PREPARE_WORK(&cdev->private->kick_work, 195 PREPARE_WORK(&cdev->private->kick_work,
197 ccw_device_do_unreg_rereg); 196 ccw_device_do_unreg_rereg);
198 queue_work(ccw_device_work, &cdev->private->kick_work); 197 queue_work(ccw_device_work, &cdev->private->kick_work);
@@ -676,6 +675,10 @@ ccw_device_offline(struct ccw_device *cdev)
676{ 675{
677 struct subchannel *sch; 676 struct subchannel *sch;
678 677
678 if (ccw_device_is_orphan(cdev)) {
679 ccw_device_done(cdev, DEV_STATE_OFFLINE);
680 return 0;
681 }
679 sch = to_subchannel(cdev->dev.parent); 682 sch = to_subchannel(cdev->dev.parent);
680 if (stsch(sch->schid, &sch->schib) || !sch->schib.pmcw.dnv) 683 if (stsch(sch->schid, &sch->schib) || !sch->schib.pmcw.dnv)
681 return -ENODEV; 684 return -ENODEV;
@@ -1121,7 +1124,13 @@ device_trigger_reprobe(struct subchannel *sch)
1121 sch->schib.pmcw.mp = 1; 1124 sch->schib.pmcw.mp = 1;
1122 sch->schib.pmcw.intparm = (__u32)(unsigned long)sch; 1125 sch->schib.pmcw.intparm = (__u32)(unsigned long)sch;
1123 /* We should also udate ssd info, but this has to wait. */ 1126 /* We should also udate ssd info, but this has to wait. */
1124 ccw_device_start_id(cdev, 0); 1127 /* Check if this is another device which appeared on the same sch. */
1128 if (sch->schib.pmcw.dev != cdev->private->dev_id.devno) {
1129 PREPARE_WORK(&cdev->private->kick_work,
1130 ccw_device_move_to_orphanage);
1131 queue_work(ccw_device_work, &cdev->private->kick_work);
1132 } else
1133 ccw_device_start_id(cdev, 0);
1125} 1134}
1126 1135
1127static void 1136static void