diff options
Diffstat (limited to 'drivers/s390/cio/chsc_sch.c')
-rw-r--r-- | drivers/s390/cio/chsc_sch.c | 30 |
1 files changed, 20 insertions, 10 deletions
diff --git a/drivers/s390/cio/chsc_sch.c b/drivers/s390/cio/chsc_sch.c index a83877c664a6..e950f1ad4dd1 100644 --- a/drivers/s390/cio/chsc_sch.c +++ b/drivers/s390/cio/chsc_sch.c | |||
@@ -50,7 +50,7 @@ MODULE_LICENSE("GPL"); | |||
50 | 50 | ||
51 | static void chsc_subchannel_irq(struct subchannel *sch) | 51 | static void chsc_subchannel_irq(struct subchannel *sch) |
52 | { | 52 | { |
53 | struct chsc_private *private = sch->private; | 53 | struct chsc_private *private = dev_get_drvdata(&sch->dev); |
54 | struct chsc_request *request = private->request; | 54 | struct chsc_request *request = private->request; |
55 | struct irb *irb = (struct irb *)&S390_lowcore.irb; | 55 | struct irb *irb = (struct irb *)&S390_lowcore.irb; |
56 | 56 | ||
@@ -80,13 +80,14 @@ static int chsc_subchannel_probe(struct subchannel *sch) | |||
80 | private = kzalloc(sizeof(*private), GFP_KERNEL); | 80 | private = kzalloc(sizeof(*private), GFP_KERNEL); |
81 | if (!private) | 81 | if (!private) |
82 | return -ENOMEM; | 82 | return -ENOMEM; |
83 | dev_set_drvdata(&sch->dev, private); | ||
83 | ret = cio_enable_subchannel(sch, (u32)(unsigned long)sch); | 84 | ret = cio_enable_subchannel(sch, (u32)(unsigned long)sch); |
84 | if (ret) { | 85 | if (ret) { |
85 | CHSC_MSG(0, "Failed to enable 0.%x.%04x: %d\n", | 86 | CHSC_MSG(0, "Failed to enable 0.%x.%04x: %d\n", |
86 | sch->schid.ssid, sch->schid.sch_no, ret); | 87 | sch->schid.ssid, sch->schid.sch_no, ret); |
88 | dev_set_drvdata(&sch->dev, NULL); | ||
87 | kfree(private); | 89 | kfree(private); |
88 | } else { | 90 | } else { |
89 | sch->private = private; | ||
90 | if (dev_get_uevent_suppress(&sch->dev)) { | 91 | if (dev_get_uevent_suppress(&sch->dev)) { |
91 | dev_set_uevent_suppress(&sch->dev, 0); | 92 | dev_set_uevent_suppress(&sch->dev, 0); |
92 | kobject_uevent(&sch->dev.kobj, KOBJ_ADD); | 93 | kobject_uevent(&sch->dev.kobj, KOBJ_ADD); |
@@ -100,8 +101,8 @@ static int chsc_subchannel_remove(struct subchannel *sch) | |||
100 | struct chsc_private *private; | 101 | struct chsc_private *private; |
101 | 102 | ||
102 | cio_disable_subchannel(sch); | 103 | cio_disable_subchannel(sch); |
103 | private = sch->private; | 104 | private = dev_get_drvdata(&sch->dev); |
104 | sch->private = NULL; | 105 | dev_set_drvdata(&sch->dev, NULL); |
105 | if (private->request) { | 106 | if (private->request) { |
106 | complete(&private->request->completion); | 107 | complete(&private->request->completion); |
107 | put_device(&sch->dev); | 108 | put_device(&sch->dev); |
@@ -147,7 +148,10 @@ static struct css_device_id chsc_subchannel_ids[] = { | |||
147 | MODULE_DEVICE_TABLE(css, chsc_subchannel_ids); | 148 | MODULE_DEVICE_TABLE(css, chsc_subchannel_ids); |
148 | 149 | ||
149 | static struct css_driver chsc_subchannel_driver = { | 150 | static struct css_driver chsc_subchannel_driver = { |
150 | .owner = THIS_MODULE, | 151 | .drv = { |
152 | .owner = THIS_MODULE, | ||
153 | .name = "chsc_subchannel", | ||
154 | }, | ||
151 | .subchannel_type = chsc_subchannel_ids, | 155 | .subchannel_type = chsc_subchannel_ids, |
152 | .irq = chsc_subchannel_irq, | 156 | .irq = chsc_subchannel_irq, |
153 | .probe = chsc_subchannel_probe, | 157 | .probe = chsc_subchannel_probe, |
@@ -157,7 +161,6 @@ static struct css_driver chsc_subchannel_driver = { | |||
157 | .freeze = chsc_subchannel_freeze, | 161 | .freeze = chsc_subchannel_freeze, |
158 | .thaw = chsc_subchannel_restore, | 162 | .thaw = chsc_subchannel_restore, |
159 | .restore = chsc_subchannel_restore, | 163 | .restore = chsc_subchannel_restore, |
160 | .name = "chsc_subchannel", | ||
161 | }; | 164 | }; |
162 | 165 | ||
163 | static int __init chsc_init_dbfs(void) | 166 | static int __init chsc_init_dbfs(void) |
@@ -241,7 +244,7 @@ static int chsc_async(struct chsc_async_area *chsc_area, | |||
241 | chsc_area->header.key = PAGE_DEFAULT_KEY >> 4; | 244 | chsc_area->header.key = PAGE_DEFAULT_KEY >> 4; |
242 | while ((sch = chsc_get_next_subchannel(sch))) { | 245 | while ((sch = chsc_get_next_subchannel(sch))) { |
243 | spin_lock(sch->lock); | 246 | spin_lock(sch->lock); |
244 | private = sch->private; | 247 | private = dev_get_drvdata(&sch->dev); |
245 | if (private->request) { | 248 | if (private->request) { |
246 | spin_unlock(sch->lock); | 249 | spin_unlock(sch->lock); |
247 | ret = -EBUSY; | 250 | ret = -EBUSY; |
@@ -688,25 +691,31 @@ out_free: | |||
688 | 691 | ||
689 | static int chsc_ioctl_chpd(void __user *user_chpd) | 692 | static int chsc_ioctl_chpd(void __user *user_chpd) |
690 | { | 693 | { |
694 | struct chsc_scpd *scpd_area; | ||
691 | struct chsc_cpd_info *chpd; | 695 | struct chsc_cpd_info *chpd; |
692 | int ret; | 696 | int ret; |
693 | 697 | ||
694 | chpd = kzalloc(sizeof(*chpd), GFP_KERNEL); | 698 | chpd = kzalloc(sizeof(*chpd), GFP_KERNEL); |
695 | if (!chpd) | 699 | scpd_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA); |
696 | return -ENOMEM; | 700 | if (!scpd_area || !chpd) { |
701 | ret = -ENOMEM; | ||
702 | goto out_free; | ||
703 | } | ||
697 | if (copy_from_user(chpd, user_chpd, sizeof(*chpd))) { | 704 | if (copy_from_user(chpd, user_chpd, sizeof(*chpd))) { |
698 | ret = -EFAULT; | 705 | ret = -EFAULT; |
699 | goto out_free; | 706 | goto out_free; |
700 | } | 707 | } |
701 | ret = chsc_determine_channel_path_desc(chpd->chpid, chpd->fmt, | 708 | ret = chsc_determine_channel_path_desc(chpd->chpid, chpd->fmt, |
702 | chpd->rfmt, chpd->c, chpd->m, | 709 | chpd->rfmt, chpd->c, chpd->m, |
703 | &chpd->chpdb); | 710 | scpd_area); |
704 | if (ret) | 711 | if (ret) |
705 | goto out_free; | 712 | goto out_free; |
713 | memcpy(&chpd->chpdb, &scpd_area->response, scpd_area->response.length); | ||
706 | if (copy_to_user(user_chpd, chpd, sizeof(*chpd))) | 714 | if (copy_to_user(user_chpd, chpd, sizeof(*chpd))) |
707 | ret = -EFAULT; | 715 | ret = -EFAULT; |
708 | out_free: | 716 | out_free: |
709 | kfree(chpd); | 717 | kfree(chpd); |
718 | free_page((unsigned long)scpd_area); | ||
710 | return ret; | 719 | return ret; |
711 | } | 720 | } |
712 | 721 | ||
@@ -806,6 +815,7 @@ static const struct file_operations chsc_fops = { | |||
806 | .open = nonseekable_open, | 815 | .open = nonseekable_open, |
807 | .unlocked_ioctl = chsc_ioctl, | 816 | .unlocked_ioctl = chsc_ioctl, |
808 | .compat_ioctl = chsc_ioctl, | 817 | .compat_ioctl = chsc_ioctl, |
818 | .llseek = no_llseek, | ||
809 | }; | 819 | }; |
810 | 820 | ||
811 | static struct miscdevice chsc_misc_device = { | 821 | static struct miscdevice chsc_misc_device = { |