diff options
Diffstat (limited to 'drivers/s390/cio/device.c')
-rw-r--r-- | drivers/s390/cio/device.c | 237 |
1 files changed, 158 insertions, 79 deletions
diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c index 4e4008325e28..23d5752349b5 100644 --- a/drivers/s390/cio/device.c +++ b/drivers/s390/cio/device.c | |||
@@ -376,19 +376,23 @@ int ccw_device_set_offline(struct ccw_device *cdev) | |||
376 | dev_fsm_event(cdev, DEV_EVENT_NOTOPER); | 376 | dev_fsm_event(cdev, DEV_EVENT_NOTOPER); |
377 | } | 377 | } |
378 | spin_unlock_irq(cdev->ccwlock); | 378 | spin_unlock_irq(cdev->ccwlock); |
379 | /* Give up reference from ccw_device_set_online(). */ | ||
380 | put_device(&cdev->dev); | ||
379 | return ret; | 381 | return ret; |
380 | } | 382 | } |
381 | spin_unlock_irq(cdev->ccwlock); | 383 | spin_unlock_irq(cdev->ccwlock); |
382 | if (ret == 0) | 384 | if (ret == 0) { |
383 | wait_event(cdev->private->wait_q, dev_fsm_final_state(cdev)); | 385 | wait_event(cdev->private->wait_q, dev_fsm_final_state(cdev)); |
384 | else { | 386 | /* Give up reference from ccw_device_set_online(). */ |
387 | put_device(&cdev->dev); | ||
388 | } else { | ||
385 | CIO_MSG_EVENT(0, "ccw_device_offline returned %d, " | 389 | CIO_MSG_EVENT(0, "ccw_device_offline returned %d, " |
386 | "device 0.%x.%04x\n", | 390 | "device 0.%x.%04x\n", |
387 | ret, cdev->private->dev_id.ssid, | 391 | ret, cdev->private->dev_id.ssid, |
388 | cdev->private->dev_id.devno); | 392 | cdev->private->dev_id.devno); |
389 | cdev->online = 1; | 393 | cdev->online = 1; |
390 | } | 394 | } |
391 | return ret; | 395 | return ret; |
392 | } | 396 | } |
393 | 397 | ||
394 | /** | 398 | /** |
@@ -411,6 +415,9 @@ int ccw_device_set_online(struct ccw_device *cdev) | |||
411 | return -ENODEV; | 415 | return -ENODEV; |
412 | if (cdev->online || !cdev->drv) | 416 | if (cdev->online || !cdev->drv) |
413 | return -EINVAL; | 417 | return -EINVAL; |
418 | /* Hold on to an extra reference while device is online. */ | ||
419 | if (!get_device(&cdev->dev)) | ||
420 | return -ENODEV; | ||
414 | 421 | ||
415 | spin_lock_irq(cdev->ccwlock); | 422 | spin_lock_irq(cdev->ccwlock); |
416 | ret = ccw_device_online(cdev); | 423 | ret = ccw_device_online(cdev); |
@@ -422,10 +429,15 @@ int ccw_device_set_online(struct ccw_device *cdev) | |||
422 | "device 0.%x.%04x\n", | 429 | "device 0.%x.%04x\n", |
423 | ret, cdev->private->dev_id.ssid, | 430 | ret, cdev->private->dev_id.ssid, |
424 | cdev->private->dev_id.devno); | 431 | cdev->private->dev_id.devno); |
432 | /* Give up online reference since onlining failed. */ | ||
433 | put_device(&cdev->dev); | ||
425 | return ret; | 434 | return ret; |
426 | } | 435 | } |
427 | if (cdev->private->state != DEV_STATE_ONLINE) | 436 | if (cdev->private->state != DEV_STATE_ONLINE) { |
437 | /* Give up online reference since onlining failed. */ | ||
438 | put_device(&cdev->dev); | ||
428 | return -ENODEV; | 439 | return -ENODEV; |
440 | } | ||
429 | if (!cdev->drv->set_online || cdev->drv->set_online(cdev) == 0) { | 441 | if (!cdev->drv->set_online || cdev->drv->set_online(cdev) == 0) { |
430 | cdev->online = 1; | 442 | cdev->online = 1; |
431 | return 0; | 443 | return 0; |
@@ -440,6 +452,8 @@ int ccw_device_set_online(struct ccw_device *cdev) | |||
440 | "device 0.%x.%04x\n", | 452 | "device 0.%x.%04x\n", |
441 | ret, cdev->private->dev_id.ssid, | 453 | ret, cdev->private->dev_id.ssid, |
442 | cdev->private->dev_id.devno); | 454 | cdev->private->dev_id.devno); |
455 | /* Give up online reference since onlining failed. */ | ||
456 | put_device(&cdev->dev); | ||
443 | return (ret == 0) ? -ENODEV : ret; | 457 | return (ret == 0) ? -ENODEV : ret; |
444 | } | 458 | } |
445 | 459 | ||
@@ -704,6 +718,8 @@ ccw_device_release(struct device *dev) | |||
704 | struct ccw_device *cdev; | 718 | struct ccw_device *cdev; |
705 | 719 | ||
706 | cdev = to_ccwdev(dev); | 720 | cdev = to_ccwdev(dev); |
721 | /* Release reference of parent subchannel. */ | ||
722 | put_device(cdev->dev.parent); | ||
707 | kfree(cdev->private); | 723 | kfree(cdev->private); |
708 | kfree(cdev); | 724 | kfree(cdev); |
709 | } | 725 | } |
@@ -735,8 +751,8 @@ static int io_subchannel_initialize_dev(struct subchannel *sch, | |||
735 | /* Do first half of device_register. */ | 751 | /* Do first half of device_register. */ |
736 | device_initialize(&cdev->dev); | 752 | device_initialize(&cdev->dev); |
737 | if (!get_device(&sch->dev)) { | 753 | if (!get_device(&sch->dev)) { |
738 | if (cdev->dev.release) | 754 | /* Release reference from device_initialize(). */ |
739 | cdev->dev.release(&cdev->dev); | 755 | put_device(&cdev->dev); |
740 | return -ENODEV; | 756 | return -ENODEV; |
741 | } | 757 | } |
742 | return 0; | 758 | return 0; |
@@ -778,37 +794,55 @@ static void sch_attach_disconnected_device(struct subchannel *sch, | |||
778 | struct subchannel *other_sch; | 794 | struct subchannel *other_sch; |
779 | int ret; | 795 | int ret; |
780 | 796 | ||
781 | other_sch = to_subchannel(get_device(cdev->dev.parent)); | 797 | /* Get reference for new parent. */ |
798 | if (!get_device(&sch->dev)) | ||
799 | return; | ||
800 | other_sch = to_subchannel(cdev->dev.parent); | ||
801 | /* Note: device_move() changes cdev->dev.parent */ | ||
782 | ret = device_move(&cdev->dev, &sch->dev); | 802 | ret = device_move(&cdev->dev, &sch->dev); |
783 | if (ret) { | 803 | if (ret) { |
784 | CIO_MSG_EVENT(0, "Moving disconnected device 0.%x.%04x failed " | 804 | CIO_MSG_EVENT(0, "Moving disconnected device 0.%x.%04x failed " |
785 | "(ret=%d)!\n", cdev->private->dev_id.ssid, | 805 | "(ret=%d)!\n", cdev->private->dev_id.ssid, |
786 | cdev->private->dev_id.devno, ret); | 806 | cdev->private->dev_id.devno, ret); |
787 | put_device(&other_sch->dev); | 807 | /* Put reference for new parent. */ |
808 | put_device(&sch->dev); | ||
788 | return; | 809 | return; |
789 | } | 810 | } |
790 | sch_set_cdev(other_sch, NULL); | 811 | sch_set_cdev(other_sch, NULL); |
791 | /* No need to keep a subchannel without ccw device around. */ | 812 | /* No need to keep a subchannel without ccw device around. */ |
792 | css_sch_device_unregister(other_sch); | 813 | css_sch_device_unregister(other_sch); |
793 | put_device(&other_sch->dev); | ||
794 | sch_attach_device(sch, cdev); | 814 | sch_attach_device(sch, cdev); |
815 | /* Put reference for old parent. */ | ||
816 | put_device(&other_sch->dev); | ||
795 | } | 817 | } |
796 | 818 | ||
797 | static void sch_attach_orphaned_device(struct subchannel *sch, | 819 | static void sch_attach_orphaned_device(struct subchannel *sch, |
798 | struct ccw_device *cdev) | 820 | struct ccw_device *cdev) |
799 | { | 821 | { |
800 | int ret; | 822 | int ret; |
823 | struct subchannel *pseudo_sch; | ||
801 | 824 | ||
802 | /* Try to move the ccw device to its new subchannel. */ | 825 | /* Get reference for new parent. */ |
826 | if (!get_device(&sch->dev)) | ||
827 | return; | ||
828 | pseudo_sch = to_subchannel(cdev->dev.parent); | ||
829 | /* | ||
830 | * Try to move the ccw device to its new subchannel. | ||
831 | * Note: device_move() changes cdev->dev.parent | ||
832 | */ | ||
803 | ret = device_move(&cdev->dev, &sch->dev); | 833 | ret = device_move(&cdev->dev, &sch->dev); |
804 | if (ret) { | 834 | if (ret) { |
805 | CIO_MSG_EVENT(0, "Moving device 0.%x.%04x from orphanage " | 835 | CIO_MSG_EVENT(0, "Moving device 0.%x.%04x from orphanage " |
806 | "failed (ret=%d)!\n", | 836 | "failed (ret=%d)!\n", |
807 | cdev->private->dev_id.ssid, | 837 | cdev->private->dev_id.ssid, |
808 | cdev->private->dev_id.devno, ret); | 838 | cdev->private->dev_id.devno, ret); |
839 | /* Put reference for new parent. */ | ||
840 | put_device(&sch->dev); | ||
809 | return; | 841 | return; |
810 | } | 842 | } |
811 | sch_attach_device(sch, cdev); | 843 | sch_attach_device(sch, cdev); |
844 | /* Put reference on pseudo subchannel. */ | ||
845 | put_device(&pseudo_sch->dev); | ||
812 | } | 846 | } |
813 | 847 | ||
814 | static void sch_create_and_recog_new_device(struct subchannel *sch) | 848 | static void sch_create_and_recog_new_device(struct subchannel *sch) |
@@ -830,9 +864,11 @@ static void sch_create_and_recog_new_device(struct subchannel *sch) | |||
830 | spin_lock_irq(sch->lock); | 864 | spin_lock_irq(sch->lock); |
831 | sch_set_cdev(sch, NULL); | 865 | sch_set_cdev(sch, NULL); |
832 | spin_unlock_irq(sch->lock); | 866 | spin_unlock_irq(sch->lock); |
833 | if (cdev->dev.release) | ||
834 | cdev->dev.release(&cdev->dev); | ||
835 | css_sch_device_unregister(sch); | 867 | css_sch_device_unregister(sch); |
868 | /* Put reference from io_subchannel_create_ccwdev(). */ | ||
869 | put_device(&sch->dev); | ||
870 | /* Give up initial reference. */ | ||
871 | put_device(&cdev->dev); | ||
836 | } | 872 | } |
837 | } | 873 | } |
838 | 874 | ||
@@ -854,15 +890,20 @@ void ccw_device_move_to_orphanage(struct work_struct *work) | |||
854 | dev_id.devno = sch->schib.pmcw.dev; | 890 | dev_id.devno = sch->schib.pmcw.dev; |
855 | dev_id.ssid = sch->schid.ssid; | 891 | dev_id.ssid = sch->schid.ssid; |
856 | 892 | ||
893 | /* Increase refcount for pseudo subchannel. */ | ||
894 | get_device(&css->pseudo_subchannel->dev); | ||
857 | /* | 895 | /* |
858 | * Move the orphaned ccw device to the orphanage so the replacing | 896 | * Move the orphaned ccw device to the orphanage so the replacing |
859 | * ccw device can take its place on the subchannel. | 897 | * ccw device can take its place on the subchannel. |
898 | * Note: device_move() changes cdev->dev.parent | ||
860 | */ | 899 | */ |
861 | ret = device_move(&cdev->dev, &css->pseudo_subchannel->dev); | 900 | ret = device_move(&cdev->dev, &css->pseudo_subchannel->dev); |
862 | if (ret) { | 901 | if (ret) { |
863 | CIO_MSG_EVENT(0, "Moving device 0.%x.%04x to orphanage failed " | 902 | CIO_MSG_EVENT(0, "Moving device 0.%x.%04x to orphanage failed " |
864 | "(ret=%d)!\n", cdev->private->dev_id.ssid, | 903 | "(ret=%d)!\n", cdev->private->dev_id.ssid, |
865 | cdev->private->dev_id.devno, ret); | 904 | cdev->private->dev_id.devno, ret); |
905 | /* Decrease refcount for pseudo subchannel again. */ | ||
906 | put_device(&css->pseudo_subchannel->dev); | ||
866 | return; | 907 | return; |
867 | } | 908 | } |
868 | cdev->ccwlock = css->pseudo_subchannel->lock; | 909 | cdev->ccwlock = css->pseudo_subchannel->lock; |
@@ -875,17 +916,23 @@ void ccw_device_move_to_orphanage(struct work_struct *work) | |||
875 | if (replacing_cdev) { | 916 | if (replacing_cdev) { |
876 | sch_attach_disconnected_device(sch, replacing_cdev); | 917 | sch_attach_disconnected_device(sch, replacing_cdev); |
877 | /* Release reference from get_disc_ccwdev_by_dev_id() */ | 918 | /* Release reference from get_disc_ccwdev_by_dev_id() */ |
878 | put_device(&cdev->dev); | 919 | put_device(&replacing_cdev->dev); |
920 | /* Release reference of subchannel from old cdev. */ | ||
921 | put_device(&sch->dev); | ||
879 | return; | 922 | return; |
880 | } | 923 | } |
881 | replacing_cdev = get_orphaned_ccwdev_by_dev_id(css, &dev_id); | 924 | replacing_cdev = get_orphaned_ccwdev_by_dev_id(css, &dev_id); |
882 | if (replacing_cdev) { | 925 | if (replacing_cdev) { |
883 | sch_attach_orphaned_device(sch, replacing_cdev); | 926 | sch_attach_orphaned_device(sch, replacing_cdev); |
884 | /* Release reference from get_orphaned_ccwdev_by_dev_id() */ | 927 | /* Release reference from get_orphaned_ccwdev_by_dev_id() */ |
885 | put_device(&cdev->dev); | 928 | put_device(&replacing_cdev->dev); |
929 | /* Release reference of subchannel from old cdev. */ | ||
930 | put_device(&sch->dev); | ||
886 | return; | 931 | return; |
887 | } | 932 | } |
888 | sch_create_and_recog_new_device(sch); | 933 | sch_create_and_recog_new_device(sch); |
934 | /* Release reference of subchannel from old cdev. */ | ||
935 | put_device(&sch->dev); | ||
889 | } | 936 | } |
890 | 937 | ||
891 | /* | 938 | /* |
@@ -903,6 +950,14 @@ io_subchannel_register(struct work_struct *work) | |||
903 | priv = container_of(work, struct ccw_device_private, kick_work); | 950 | priv = container_of(work, struct ccw_device_private, kick_work); |
904 | cdev = priv->cdev; | 951 | cdev = priv->cdev; |
905 | sch = to_subchannel(cdev->dev.parent); | 952 | sch = to_subchannel(cdev->dev.parent); |
953 | /* | ||
954 | * Check if subchannel is still registered. It may have become | ||
955 | * unregistered if a machine check hit us after finishing | ||
956 | * device recognition but before the register work could be | ||
957 | * queued. | ||
958 | */ | ||
959 | if (!device_is_registered(&sch->dev)) | ||
960 | goto out_err; | ||
906 | css_update_ssd_info(sch); | 961 | css_update_ssd_info(sch); |
907 | /* | 962 | /* |
908 | * io_subchannel_register() will also be called after device | 963 | * io_subchannel_register() will also be called after device |
@@ -910,7 +965,7 @@ io_subchannel_register(struct work_struct *work) | |||
910 | * be registered). We need to reprobe since we may now have sense id | 965 | * be registered). We need to reprobe since we may now have sense id |
911 | * information. | 966 | * information. |
912 | */ | 967 | */ |
913 | if (klist_node_attached(&cdev->dev.knode_parent)) { | 968 | if (device_is_registered(&cdev->dev)) { |
914 | if (!cdev->drv) { | 969 | if (!cdev->drv) { |
915 | ret = device_reprobe(&cdev->dev); | 970 | ret = device_reprobe(&cdev->dev); |
916 | if (ret) | 971 | if (ret) |
@@ -934,22 +989,19 @@ io_subchannel_register(struct work_struct *work) | |||
934 | CIO_MSG_EVENT(0, "Could not register ccw dev 0.%x.%04x: %d\n", | 989 | CIO_MSG_EVENT(0, "Could not register ccw dev 0.%x.%04x: %d\n", |
935 | cdev->private->dev_id.ssid, | 990 | cdev->private->dev_id.ssid, |
936 | cdev->private->dev_id.devno, ret); | 991 | cdev->private->dev_id.devno, ret); |
937 | put_device(&cdev->dev); | ||
938 | spin_lock_irqsave(sch->lock, flags); | 992 | spin_lock_irqsave(sch->lock, flags); |
939 | sch_set_cdev(sch, NULL); | 993 | sch_set_cdev(sch, NULL); |
940 | spin_unlock_irqrestore(sch->lock, flags); | 994 | spin_unlock_irqrestore(sch->lock, flags); |
941 | kfree (cdev->private); | 995 | /* Release initial device reference. */ |
942 | kfree (cdev); | 996 | put_device(&cdev->dev); |
943 | put_device(&sch->dev); | 997 | goto out_err; |
944 | if (atomic_dec_and_test(&ccw_device_init_count)) | ||
945 | wake_up(&ccw_device_init_wq); | ||
946 | return; | ||
947 | } | 998 | } |
948 | put_device(&cdev->dev); | ||
949 | out: | 999 | out: |
950 | cdev->private->flags.recog_done = 1; | 1000 | cdev->private->flags.recog_done = 1; |
951 | put_device(&sch->dev); | ||
952 | wake_up(&cdev->private->wait_q); | 1001 | wake_up(&cdev->private->wait_q); |
1002 | out_err: | ||
1003 | /* Release reference for workqueue processing. */ | ||
1004 | put_device(&cdev->dev); | ||
953 | if (atomic_dec_and_test(&ccw_device_init_count)) | 1005 | if (atomic_dec_and_test(&ccw_device_init_count)) |
954 | wake_up(&ccw_device_init_wq); | 1006 | wake_up(&ccw_device_init_wq); |
955 | } | 1007 | } |
@@ -968,8 +1020,8 @@ static void ccw_device_call_sch_unregister(struct work_struct *work) | |||
968 | sch = to_subchannel(cdev->dev.parent); | 1020 | sch = to_subchannel(cdev->dev.parent); |
969 | css_sch_device_unregister(sch); | 1021 | css_sch_device_unregister(sch); |
970 | /* Reset intparm to zeroes. */ | 1022 | /* Reset intparm to zeroes. */ |
971 | sch->schib.pmcw.intparm = 0; | 1023 | sch->config.intparm = 0; |
972 | cio_modify(sch); | 1024 | cio_commit_config(sch); |
973 | /* Release cdev reference for workqueue processing.*/ | 1025 | /* Release cdev reference for workqueue processing.*/ |
974 | put_device(&cdev->dev); | 1026 | put_device(&cdev->dev); |
975 | /* Release subchannel reference for local processing. */ | 1027 | /* Release subchannel reference for local processing. */ |
@@ -998,8 +1050,6 @@ io_subchannel_recog_done(struct ccw_device *cdev) | |||
998 | PREPARE_WORK(&cdev->private->kick_work, | 1050 | PREPARE_WORK(&cdev->private->kick_work, |
999 | ccw_device_call_sch_unregister); | 1051 | ccw_device_call_sch_unregister); |
1000 | queue_work(slow_path_wq, &cdev->private->kick_work); | 1052 | queue_work(slow_path_wq, &cdev->private->kick_work); |
1001 | /* Release subchannel reference for asynchronous recognition. */ | ||
1002 | put_device(&sch->dev); | ||
1003 | if (atomic_dec_and_test(&ccw_device_init_count)) | 1053 | if (atomic_dec_and_test(&ccw_device_init_count)) |
1004 | wake_up(&ccw_device_init_wq); | 1054 | wake_up(&ccw_device_init_wq); |
1005 | break; | 1055 | break; |
@@ -1070,10 +1120,15 @@ static void ccw_device_move_to_sch(struct work_struct *work) | |||
1070 | priv = container_of(work, struct ccw_device_private, kick_work); | 1120 | priv = container_of(work, struct ccw_device_private, kick_work); |
1071 | sch = priv->sch; | 1121 | sch = priv->sch; |
1072 | cdev = priv->cdev; | 1122 | cdev = priv->cdev; |
1073 | former_parent = ccw_device_is_orphan(cdev) ? | 1123 | former_parent = to_subchannel(cdev->dev.parent); |
1074 | NULL : to_subchannel(get_device(cdev->dev.parent)); | 1124 | /* Get reference for new parent. */ |
1125 | if (!get_device(&sch->dev)) | ||
1126 | return; | ||
1075 | mutex_lock(&sch->reg_mutex); | 1127 | mutex_lock(&sch->reg_mutex); |
1076 | /* Try to move the ccw device to its new subchannel. */ | 1128 | /* |
1129 | * Try to move the ccw device to its new subchannel. | ||
1130 | * Note: device_move() changes cdev->dev.parent | ||
1131 | */ | ||
1077 | rc = device_move(&cdev->dev, &sch->dev); | 1132 | rc = device_move(&cdev->dev, &sch->dev); |
1078 | mutex_unlock(&sch->reg_mutex); | 1133 | mutex_unlock(&sch->reg_mutex); |
1079 | if (rc) { | 1134 | if (rc) { |
@@ -1083,21 +1138,23 @@ static void ccw_device_move_to_sch(struct work_struct *work) | |||
1083 | cdev->private->dev_id.devno, sch->schid.ssid, | 1138 | cdev->private->dev_id.devno, sch->schid.ssid, |
1084 | sch->schid.sch_no, rc); | 1139 | sch->schid.sch_no, rc); |
1085 | css_sch_device_unregister(sch); | 1140 | css_sch_device_unregister(sch); |
1141 | /* Put reference for new parent again. */ | ||
1142 | put_device(&sch->dev); | ||
1086 | goto out; | 1143 | goto out; |
1087 | } | 1144 | } |
1088 | if (former_parent) { | 1145 | if (!sch_is_pseudo_sch(former_parent)) { |
1089 | spin_lock_irq(former_parent->lock); | 1146 | spin_lock_irq(former_parent->lock); |
1090 | sch_set_cdev(former_parent, NULL); | 1147 | sch_set_cdev(former_parent, NULL); |
1091 | spin_unlock_irq(former_parent->lock); | 1148 | spin_unlock_irq(former_parent->lock); |
1092 | css_sch_device_unregister(former_parent); | 1149 | css_sch_device_unregister(former_parent); |
1093 | /* Reset intparm to zeroes. */ | 1150 | /* Reset intparm to zeroes. */ |
1094 | former_parent->schib.pmcw.intparm = 0; | 1151 | former_parent->config.intparm = 0; |
1095 | cio_modify(former_parent); | 1152 | cio_commit_config(former_parent); |
1096 | } | 1153 | } |
1097 | sch_attach_device(sch, cdev); | 1154 | sch_attach_device(sch, cdev); |
1098 | out: | 1155 | out: |
1099 | if (former_parent) | 1156 | /* Put reference for old parent. */ |
1100 | put_device(&former_parent->dev); | 1157 | put_device(&former_parent->dev); |
1101 | put_device(&cdev->dev); | 1158 | put_device(&cdev->dev); |
1102 | } | 1159 | } |
1103 | 1160 | ||
@@ -1113,6 +1170,15 @@ static void io_subchannel_irq(struct subchannel *sch) | |||
1113 | dev_fsm_event(cdev, DEV_EVENT_INTERRUPT); | 1170 | dev_fsm_event(cdev, DEV_EVENT_INTERRUPT); |
1114 | } | 1171 | } |
1115 | 1172 | ||
1173 | void io_subchannel_init_config(struct subchannel *sch) | ||
1174 | { | ||
1175 | memset(&sch->config, 0, sizeof(sch->config)); | ||
1176 | sch->config.csense = 1; | ||
1177 | /* Use subchannel mp mode when there is more than 1 installed CHPID. */ | ||
1178 | if ((sch->schib.pmcw.pim & (sch->schib.pmcw.pim - 1)) != 0) | ||
1179 | sch->config.mp = 1; | ||
1180 | } | ||
1181 | |||
1116 | static void io_subchannel_init_fields(struct subchannel *sch) | 1182 | static void io_subchannel_init_fields(struct subchannel *sch) |
1117 | { | 1183 | { |
1118 | if (cio_is_console(sch->schid)) | 1184 | if (cio_is_console(sch->schid)) |
@@ -1127,18 +1193,34 @@ static void io_subchannel_init_fields(struct subchannel *sch) | |||
1127 | sch->schib.pmcw.dev, sch->schid.ssid, | 1193 | sch->schib.pmcw.dev, sch->schid.ssid, |
1128 | sch->schid.sch_no, sch->schib.pmcw.pim, | 1194 | sch->schid.sch_no, sch->schib.pmcw.pim, |
1129 | sch->schib.pmcw.pam, sch->schib.pmcw.pom); | 1195 | sch->schib.pmcw.pam, sch->schib.pmcw.pom); |
1130 | /* Initially set up some fields in the pmcw. */ | 1196 | |
1131 | sch->schib.pmcw.ena = 0; | 1197 | io_subchannel_init_config(sch); |
1132 | sch->schib.pmcw.csense = 1; /* concurrent sense */ | ||
1133 | if ((sch->lpm & (sch->lpm - 1)) != 0) | ||
1134 | sch->schib.pmcw.mp = 1; /* multipath mode */ | ||
1135 | /* clean up possible residual cmf stuff */ | ||
1136 | sch->schib.pmcw.mme = 0; | ||
1137 | sch->schib.pmcw.mbfc = 0; | ||
1138 | sch->schib.pmcw.mbi = 0; | ||
1139 | sch->schib.mba = 0; | ||
1140 | } | 1198 | } |
1141 | 1199 | ||
1200 | static void io_subchannel_do_unreg(struct work_struct *work) | ||
1201 | { | ||
1202 | struct subchannel *sch; | ||
1203 | |||
1204 | sch = container_of(work, struct subchannel, work); | ||
1205 | css_sch_device_unregister(sch); | ||
1206 | /* Reset intparm to zeroes. */ | ||
1207 | sch->config.intparm = 0; | ||
1208 | cio_commit_config(sch); | ||
1209 | put_device(&sch->dev); | ||
1210 | } | ||
1211 | |||
1212 | /* Schedule unregister if we have no cdev. */ | ||
1213 | static void io_subchannel_schedule_removal(struct subchannel *sch) | ||
1214 | { | ||
1215 | get_device(&sch->dev); | ||
1216 | INIT_WORK(&sch->work, io_subchannel_do_unreg); | ||
1217 | queue_work(slow_path_wq, &sch->work); | ||
1218 | } | ||
1219 | |||
1220 | /* | ||
1221 | * Note: We always return 0 so that we bind to the device even on error. | ||
1222 | * This is needed so that our remove function is called on unregister. | ||
1223 | */ | ||
1142 | static int io_subchannel_probe(struct subchannel *sch) | 1224 | static int io_subchannel_probe(struct subchannel *sch) |
1143 | { | 1225 | { |
1144 | struct ccw_device *cdev; | 1226 | struct ccw_device *cdev; |
@@ -1168,9 +1250,8 @@ static int io_subchannel_probe(struct subchannel *sch) | |||
1168 | ccw_device_register(cdev); | 1250 | ccw_device_register(cdev); |
1169 | /* | 1251 | /* |
1170 | * Check if the device is already online. If it is | 1252 | * Check if the device is already online. If it is |
1171 | * the reference count needs to be corrected | 1253 | * the reference count needs to be corrected since we |
1172 | * (see ccw_device_online and css_init_done for the | 1254 | * didn't obtain a reference in ccw_device_set_online. |
1173 | * ugly details). | ||
1174 | */ | 1255 | */ |
1175 | if (cdev->private->state != DEV_STATE_NOT_OPER && | 1256 | if (cdev->private->state != DEV_STATE_NOT_OPER && |
1176 | cdev->private->state != DEV_STATE_OFFLINE && | 1257 | cdev->private->state != DEV_STATE_OFFLINE && |
@@ -1179,23 +1260,24 @@ static int io_subchannel_probe(struct subchannel *sch) | |||
1179 | return 0; | 1260 | return 0; |
1180 | } | 1261 | } |
1181 | io_subchannel_init_fields(sch); | 1262 | io_subchannel_init_fields(sch); |
1182 | /* | 1263 | rc = cio_commit_config(sch); |
1183 | * First check if a fitting device may be found amongst the | 1264 | if (rc) |
1184 | * disconnected devices or in the orphanage. | 1265 | goto out_schedule; |
1185 | */ | ||
1186 | dev_id.devno = sch->schib.pmcw.dev; | ||
1187 | dev_id.ssid = sch->schid.ssid; | ||
1188 | rc = sysfs_create_group(&sch->dev.kobj, | 1266 | rc = sysfs_create_group(&sch->dev.kobj, |
1189 | &io_subchannel_attr_group); | 1267 | &io_subchannel_attr_group); |
1190 | if (rc) | 1268 | if (rc) |
1191 | return rc; | 1269 | goto out_schedule; |
1192 | /* Allocate I/O subchannel private data. */ | 1270 | /* Allocate I/O subchannel private data. */ |
1193 | sch->private = kzalloc(sizeof(struct io_subchannel_private), | 1271 | sch->private = kzalloc(sizeof(struct io_subchannel_private), |
1194 | GFP_KERNEL | GFP_DMA); | 1272 | GFP_KERNEL | GFP_DMA); |
1195 | if (!sch->private) { | 1273 | if (!sch->private) |
1196 | rc = -ENOMEM; | ||
1197 | goto out_err; | 1274 | goto out_err; |
1198 | } | 1275 | /* |
1276 | * First check if a fitting device may be found amongst the | ||
1277 | * disconnected devices or in the orphanage. | ||
1278 | */ | ||
1279 | dev_id.devno = sch->schib.pmcw.dev; | ||
1280 | dev_id.ssid = sch->schid.ssid; | ||
1199 | cdev = get_disc_ccwdev_by_dev_id(&dev_id, NULL); | 1281 | cdev = get_disc_ccwdev_by_dev_id(&dev_id, NULL); |
1200 | if (!cdev) | 1282 | if (!cdev) |
1201 | cdev = get_orphaned_ccwdev_by_dev_id(to_css(sch->dev.parent), | 1283 | cdev = get_orphaned_ccwdev_by_dev_id(to_css(sch->dev.parent), |
@@ -1213,24 +1295,21 @@ static int io_subchannel_probe(struct subchannel *sch) | |||
1213 | return 0; | 1295 | return 0; |
1214 | } | 1296 | } |
1215 | cdev = io_subchannel_create_ccwdev(sch); | 1297 | cdev = io_subchannel_create_ccwdev(sch); |
1216 | if (IS_ERR(cdev)) { | 1298 | if (IS_ERR(cdev)) |
1217 | rc = PTR_ERR(cdev); | ||
1218 | goto out_err; | 1299 | goto out_err; |
1219 | } | ||
1220 | rc = io_subchannel_recog(cdev, sch); | 1300 | rc = io_subchannel_recog(cdev, sch); |
1221 | if (rc) { | 1301 | if (rc) { |
1222 | spin_lock_irqsave(sch->lock, flags); | 1302 | spin_lock_irqsave(sch->lock, flags); |
1223 | sch_set_cdev(sch, NULL); | 1303 | io_subchannel_recog_done(cdev); |
1224 | spin_unlock_irqrestore(sch->lock, flags); | 1304 | spin_unlock_irqrestore(sch->lock, flags); |
1225 | if (cdev->dev.release) | ||
1226 | cdev->dev.release(&cdev->dev); | ||
1227 | goto out_err; | ||
1228 | } | 1305 | } |
1229 | return 0; | 1306 | return 0; |
1230 | out_err: | 1307 | out_err: |
1231 | kfree(sch->private); | 1308 | kfree(sch->private); |
1232 | sysfs_remove_group(&sch->dev.kobj, &io_subchannel_attr_group); | 1309 | sysfs_remove_group(&sch->dev.kobj, &io_subchannel_attr_group); |
1233 | return rc; | 1310 | out_schedule: |
1311 | io_subchannel_schedule_removal(sch); | ||
1312 | return 0; | ||
1234 | } | 1313 | } |
1235 | 1314 | ||
1236 | static int | 1315 | static int |
@@ -1275,10 +1354,7 @@ static void io_subchannel_verify(struct subchannel *sch) | |||
1275 | 1354 | ||
1276 | static int check_for_io_on_path(struct subchannel *sch, int mask) | 1355 | static int check_for_io_on_path(struct subchannel *sch, int mask) |
1277 | { | 1356 | { |
1278 | int cc; | 1357 | if (cio_update_schib(sch)) |
1279 | |||
1280 | cc = stsch(sch->schid, &sch->schib); | ||
1281 | if (cc) | ||
1282 | return 0; | 1358 | return 0; |
1283 | if (scsw_actl(&sch->schib.scsw) && sch->schib.pmcw.lpum == mask) | 1359 | if (scsw_actl(&sch->schib.scsw) && sch->schib.pmcw.lpum == mask) |
1284 | return 1; | 1360 | return 1; |
@@ -1347,15 +1423,13 @@ static int io_subchannel_chp_event(struct subchannel *sch, | |||
1347 | io_subchannel_verify(sch); | 1423 | io_subchannel_verify(sch); |
1348 | break; | 1424 | break; |
1349 | case CHP_OFFLINE: | 1425 | case CHP_OFFLINE: |
1350 | if (stsch(sch->schid, &sch->schib)) | 1426 | if (cio_update_schib(sch)) |
1351 | return -ENXIO; | ||
1352 | if (!css_sch_is_valid(&sch->schib)) | ||
1353 | return -ENODEV; | 1427 | return -ENODEV; |
1354 | io_subchannel_terminate_path(sch, mask); | 1428 | io_subchannel_terminate_path(sch, mask); |
1355 | break; | 1429 | break; |
1356 | case CHP_ONLINE: | 1430 | case CHP_ONLINE: |
1357 | if (stsch(sch->schid, &sch->schib)) | 1431 | if (cio_update_schib(sch)) |
1358 | return -ENXIO; | 1432 | return -ENODEV; |
1359 | sch->lpm |= mask & sch->opm; | 1433 | sch->lpm |= mask & sch->opm; |
1360 | io_subchannel_verify(sch); | 1434 | io_subchannel_verify(sch); |
1361 | break; | 1435 | break; |
@@ -1610,8 +1684,8 @@ static int io_subchannel_sch_event(struct subchannel *sch, int slow) | |||
1610 | spin_lock_irqsave(sch->lock, flags); | 1684 | spin_lock_irqsave(sch->lock, flags); |
1611 | 1685 | ||
1612 | /* Reset intparm to zeroes. */ | 1686 | /* Reset intparm to zeroes. */ |
1613 | sch->schib.pmcw.intparm = 0; | 1687 | sch->config.intparm = 0; |
1614 | cio_modify(sch); | 1688 | cio_commit_config(sch); |
1615 | break; | 1689 | break; |
1616 | case REPROBE: | 1690 | case REPROBE: |
1617 | ccw_device_trigger_reprobe(cdev); | 1691 | ccw_device_trigger_reprobe(cdev); |
@@ -1652,6 +1726,9 @@ static int ccw_device_console_enable(struct ccw_device *cdev, | |||
1652 | sch->private = cio_get_console_priv(); | 1726 | sch->private = cio_get_console_priv(); |
1653 | memset(sch->private, 0, sizeof(struct io_subchannel_private)); | 1727 | memset(sch->private, 0, sizeof(struct io_subchannel_private)); |
1654 | io_subchannel_init_fields(sch); | 1728 | io_subchannel_init_fields(sch); |
1729 | rc = cio_commit_config(sch); | ||
1730 | if (rc) | ||
1731 | return rc; | ||
1655 | sch->driver = &io_subchannel_driver; | 1732 | sch->driver = &io_subchannel_driver; |
1656 | /* Initialize the ccw_device structure. */ | 1733 | /* Initialize the ccw_device structure. */ |
1657 | cdev->dev.parent= &sch->dev; | 1734 | cdev->dev.parent= &sch->dev; |
@@ -1723,7 +1800,7 @@ __ccwdev_check_busid(struct device *dev, void *id) | |||
1723 | 1800 | ||
1724 | bus_id = id; | 1801 | bus_id = id; |
1725 | 1802 | ||
1726 | return (strncmp(bus_id, dev_name(dev), BUS_ID_SIZE) == 0); | 1803 | return (strcmp(bus_id, dev_name(dev)) == 0); |
1727 | } | 1804 | } |
1728 | 1805 | ||
1729 | 1806 | ||
@@ -1806,6 +1883,8 @@ ccw_device_remove (struct device *dev) | |||
1806 | "device 0.%x.%04x\n", | 1883 | "device 0.%x.%04x\n", |
1807 | ret, cdev->private->dev_id.ssid, | 1884 | ret, cdev->private->dev_id.ssid, |
1808 | cdev->private->dev_id.devno); | 1885 | cdev->private->dev_id.devno); |
1886 | /* Give up reference obtained in ccw_device_set_online(). */ | ||
1887 | put_device(&cdev->dev); | ||
1809 | } | 1888 | } |
1810 | ccw_device_set_timeout(cdev, 0); | 1889 | ccw_device_set_timeout(cdev, 0); |
1811 | cdev->drv = NULL; | 1890 | cdev->drv = NULL; |