[S390] dasd: use idal for device characteristics
[safe/jmp/linux-2.6] / drivers / s390 / cio / chsc_sch.c
1 /*
2  * Driver for s390 chsc subchannels
3  *
4  * Copyright IBM Corp. 2008, 2009
5  *
6  * Author(s): Cornelia Huck <cornelia.huck@de.ibm.com>
7  *
8  */
9
10 #include <linux/device.h>
11 #include <linux/module.h>
12 #include <linux/uaccess.h>
13 #include <linux/miscdevice.h>
14
15 #include <asm/cio.h>
16 #include <asm/chsc.h>
17 #include <asm/isc.h>
18
19 #include "cio.h"
20 #include "cio_debug.h"
21 #include "css.h"
22 #include "chsc_sch.h"
23 #include "ioasm.h"
24
25 static debug_info_t *chsc_debug_msg_id;
26 static debug_info_t *chsc_debug_log_id;
27
28 #define CHSC_MSG(imp, args...) do {                                     \
29                 debug_sprintf_event(chsc_debug_msg_id, imp , ##args);   \
30         } while (0)
31
32 #define CHSC_LOG(imp, txt) do {                                 \
33                 debug_text_event(chsc_debug_log_id, imp , txt); \
34         } while (0)
35
36 static void CHSC_LOG_HEX(int level, void *data, int length)
37 {
38         while (length > 0) {
39                 debug_event(chsc_debug_log_id, level, data, length);
40                 length -= chsc_debug_log_id->buf_size;
41                 data += chsc_debug_log_id->buf_size;
42         }
43 }
44
45 MODULE_AUTHOR("IBM Corporation");
46 MODULE_DESCRIPTION("driver for s390 chsc subchannels");
47 MODULE_LICENSE("GPL");
48
49 static void chsc_subchannel_irq(struct subchannel *sch)
50 {
51         struct chsc_private *private = sch->private;
52         struct chsc_request *request = private->request;
53         struct irb *irb = (struct irb *)__LC_IRB;
54
55         CHSC_LOG(4, "irb");
56         CHSC_LOG_HEX(4, irb, sizeof(*irb));
57         /* Copy irb to provided request and set done. */
58         if (!request) {
59                 CHSC_MSG(0, "Interrupt on sch 0.%x.%04x with no request\n",
60                          sch->schid.ssid, sch->schid.sch_no);
61                 return;
62         }
63         private->request = NULL;
64         memcpy(&request->irb, irb, sizeof(*irb));
65         cio_update_schib(sch);
66         complete(&request->completion);
67         put_device(&sch->dev);
68 }
69
70 static int chsc_subchannel_probe(struct subchannel *sch)
71 {
72         struct chsc_private *private;
73         int ret;
74
75         CHSC_MSG(6, "Detected chsc subchannel 0.%x.%04x\n",
76                  sch->schid.ssid, sch->schid.sch_no);
77         sch->isc = CHSC_SCH_ISC;
78         private = kzalloc(sizeof(*private), GFP_KERNEL);
79         if (!private)
80                 return -ENOMEM;
81         ret = cio_enable_subchannel(sch, (u32)(unsigned long)sch);
82         if (ret) {
83                 CHSC_MSG(0, "Failed to enable 0.%x.%04x: %d\n",
84                          sch->schid.ssid, sch->schid.sch_no, ret);
85                 kfree(private);
86         } else {
87                 sch->private = private;
88                 if (dev_get_uevent_suppress(&sch->dev)) {
89                         dev_set_uevent_suppress(&sch->dev, 0);
90                         kobject_uevent(&sch->dev.kobj, KOBJ_ADD);
91                 }
92         }
93         return ret;
94 }
95
96 static int chsc_subchannel_remove(struct subchannel *sch)
97 {
98         struct chsc_private *private;
99
100         cio_disable_subchannel(sch);
101         private = sch->private;
102         sch->private = NULL;
103         if (private->request) {
104                 complete(&private->request->completion);
105                 put_device(&sch->dev);
106         }
107         kfree(private);
108         return 0;
109 }
110
111 static void chsc_subchannel_shutdown(struct subchannel *sch)
112 {
113         cio_disable_subchannel(sch);
114 }
115
116 static int chsc_subchannel_prepare(struct subchannel *sch)
117 {
118         int cc;
119         struct schib schib;
120         /*
121          * Don't allow suspend while the subchannel is not idle
122          * since we don't have a way to clear the subchannel and
123          * cannot disable it with a request running.
124          */
125         cc = stsch(sch->schid, &schib);
126         if (!cc && scsw_stctl(&schib.scsw))
127                 return -EAGAIN;
128         return 0;
129 }
130
131 static int chsc_subchannel_freeze(struct subchannel *sch)
132 {
133         return cio_disable_subchannel(sch);
134 }
135
136 static int chsc_subchannel_restore(struct subchannel *sch)
137 {
138         return cio_enable_subchannel(sch, (u32)(unsigned long)sch);
139 }
140
141 static struct css_device_id chsc_subchannel_ids[] = {
142         { .match_flags = 0x1, .type =SUBCHANNEL_TYPE_CHSC, },
143         { /* end of list */ },
144 };
145 MODULE_DEVICE_TABLE(css, chsc_subchannel_ids);
146
147 static struct css_driver chsc_subchannel_driver = {
148         .owner = THIS_MODULE,
149         .subchannel_type = chsc_subchannel_ids,
150         .irq = chsc_subchannel_irq,
151         .probe = chsc_subchannel_probe,
152         .remove = chsc_subchannel_remove,
153         .shutdown = chsc_subchannel_shutdown,
154         .prepare = chsc_subchannel_prepare,
155         .freeze = chsc_subchannel_freeze,
156         .thaw = chsc_subchannel_restore,
157         .restore = chsc_subchannel_restore,
158         .name = "chsc_subchannel",
159 };
160
161 static int __init chsc_init_dbfs(void)
162 {
163         chsc_debug_msg_id = debug_register("chsc_msg", 16, 1,
164                                            16 * sizeof(long));
165         if (!chsc_debug_msg_id)
166                 goto out;
167         debug_register_view(chsc_debug_msg_id, &debug_sprintf_view);
168         debug_set_level(chsc_debug_msg_id, 2);
169         chsc_debug_log_id = debug_register("chsc_log", 16, 1, 16);
170         if (!chsc_debug_log_id)
171                 goto out;
172         debug_register_view(chsc_debug_log_id, &debug_hex_ascii_view);
173         debug_set_level(chsc_debug_log_id, 2);
174         return 0;
175 out:
176         if (chsc_debug_msg_id)
177                 debug_unregister(chsc_debug_msg_id);
178         return -ENOMEM;
179 }
180
181 static void chsc_remove_dbfs(void)
182 {
183         debug_unregister(chsc_debug_log_id);
184         debug_unregister(chsc_debug_msg_id);
185 }
186
187 static int __init chsc_init_sch_driver(void)
188 {
189         return css_driver_register(&chsc_subchannel_driver);
190 }
191
192 static void chsc_cleanup_sch_driver(void)
193 {
194         css_driver_unregister(&chsc_subchannel_driver);
195 }
196
197 static DEFINE_SPINLOCK(chsc_lock);
198
199 static int chsc_subchannel_match_next_free(struct device *dev, void *data)
200 {
201         struct subchannel *sch = to_subchannel(dev);
202
203         return sch->schib.pmcw.ena && !scsw_fctl(&sch->schib.scsw);
204 }
205
206 static struct subchannel *chsc_get_next_subchannel(struct subchannel *sch)
207 {
208         struct device *dev;
209
210         dev = driver_find_device(&chsc_subchannel_driver.drv,
211                                  sch ? &sch->dev : NULL, NULL,
212                                  chsc_subchannel_match_next_free);
213         return dev ? to_subchannel(dev) : NULL;
214 }
215
216 /**
217  * chsc_async() - try to start a chsc request asynchronously
218  * @chsc_area: request to be started
219  * @request: request structure to associate
220  *
221  * Tries to start a chsc request on one of the existing chsc subchannels.
222  * Returns:
223  *  %0 if the request was performed synchronously
224  *  %-EINPROGRESS if the request was successfully started
225  *  %-EBUSY if all chsc subchannels are busy
226  *  %-ENODEV if no chsc subchannels are available
227  * Context:
228  *  interrupts disabled, chsc_lock held
229  */
230 static int chsc_async(struct chsc_async_area *chsc_area,
231                       struct chsc_request *request)
232 {
233         int cc;
234         struct chsc_private *private;
235         struct subchannel *sch = NULL;
236         int ret = -ENODEV;
237         char dbf[10];
238
239         chsc_area->header.key = PAGE_DEFAULT_KEY;
240         while ((sch = chsc_get_next_subchannel(sch))) {
241                 spin_lock(sch->lock);
242                 private = sch->private;
243                 if (private->request) {
244                         spin_unlock(sch->lock);
245                         ret = -EBUSY;
246                         continue;
247                 }
248                 chsc_area->header.sid = sch->schid;
249                 CHSC_LOG(2, "schid");
250                 CHSC_LOG_HEX(2, &sch->schid, sizeof(sch->schid));
251                 cc = chsc(chsc_area);
252                 sprintf(dbf, "cc:%d", cc);
253                 CHSC_LOG(2, dbf);
254                 switch (cc) {
255                 case 0:
256                         ret = 0;
257                         break;
258                 case 1:
259                         sch->schib.scsw.cmd.fctl |= SCSW_FCTL_START_FUNC;
260                         ret = -EINPROGRESS;
261                         private->request = request;
262                         break;
263                 case 2:
264                         ret = -EBUSY;
265                         break;
266                 default:
267                         ret = -ENODEV;
268                 }
269                 spin_unlock(sch->lock);
270                 CHSC_MSG(2, "chsc on 0.%x.%04x returned cc=%d\n",
271                          sch->schid.ssid, sch->schid.sch_no, cc);
272                 if (ret == -EINPROGRESS)
273                         return -EINPROGRESS;
274                 put_device(&sch->dev);
275                 if (ret == 0)
276                         return 0;
277         }
278         return ret;
279 }
280
281 static void chsc_log_command(struct chsc_async_area *chsc_area)
282 {
283         char dbf[10];
284
285         sprintf(dbf, "CHSC:%x", chsc_area->header.code);
286         CHSC_LOG(0, dbf);
287         CHSC_LOG_HEX(0, chsc_area, 32);
288 }
289
290 static int chsc_examine_irb(struct chsc_request *request)
291 {
292         int backed_up;
293
294         if (!(scsw_stctl(&request->irb.scsw) & SCSW_STCTL_STATUS_PEND))
295                 return -EIO;
296         backed_up = scsw_cstat(&request->irb.scsw) & SCHN_STAT_CHAIN_CHECK;
297         request->irb.scsw.cmd.cstat &= ~SCHN_STAT_CHAIN_CHECK;
298         if (scsw_cstat(&request->irb.scsw) == 0)
299                 return 0;
300         if (!backed_up)
301                 return 0;
302         if (scsw_cstat(&request->irb.scsw) & SCHN_STAT_PROG_CHECK)
303                 return -EIO;
304         if (scsw_cstat(&request->irb.scsw) & SCHN_STAT_PROT_CHECK)
305                 return -EPERM;
306         if (scsw_cstat(&request->irb.scsw) & SCHN_STAT_CHN_DATA_CHK)
307                 return -EAGAIN;
308         if (scsw_cstat(&request->irb.scsw) & SCHN_STAT_CHN_CTRL_CHK)
309                 return -EAGAIN;
310         return -EIO;
311 }
312
313 static int chsc_ioctl_start(void __user *user_area)
314 {
315         struct chsc_request *request;
316         struct chsc_async_area *chsc_area;
317         int ret;
318         char dbf[10];
319
320         if (!css_general_characteristics.dynio)
321                 /* It makes no sense to try. */
322                 return -EOPNOTSUPP;
323         chsc_area = (void *)get_zeroed_page(GFP_DMA | GFP_KERNEL);
324         if (!chsc_area)
325                 return -ENOMEM;
326         request = kzalloc(sizeof(*request), GFP_KERNEL);
327         if (!request) {
328                 ret = -ENOMEM;
329                 goto out_free;
330         }
331         init_completion(&request->completion);
332         if (copy_from_user(chsc_area, user_area, PAGE_SIZE)) {
333                 ret = -EFAULT;
334                 goto out_free;
335         }
336         chsc_log_command(chsc_area);
337         spin_lock_irq(&chsc_lock);
338         ret = chsc_async(chsc_area, request);
339         spin_unlock_irq(&chsc_lock);
340         if (ret == -EINPROGRESS) {
341                 wait_for_completion(&request->completion);
342                 ret = chsc_examine_irb(request);
343         }
344         /* copy area back to user */
345         if (!ret)
346                 if (copy_to_user(user_area, chsc_area, PAGE_SIZE))
347                         ret = -EFAULT;
348 out_free:
349         sprintf(dbf, "ret:%d", ret);
350         CHSC_LOG(0, dbf);
351         kfree(request);
352         free_page((unsigned long)chsc_area);
353         return ret;
354 }
355
356 static int chsc_ioctl_info_channel_path(void __user *user_cd)
357 {
358         struct chsc_chp_cd *cd;
359         int ret, ccode;
360         struct {
361                 struct chsc_header request;
362                 u32 : 2;
363                 u32 m : 1;
364                 u32 : 1;
365                 u32 fmt1 : 4;
366                 u32 cssid : 8;
367                 u32 : 8;
368                 u32 first_chpid : 8;
369                 u32 : 24;
370                 u32 last_chpid : 8;
371                 u32 : 32;
372                 struct chsc_header response;
373                 u8 data[PAGE_SIZE - 20];
374         } __attribute__ ((packed)) *scpcd_area;
375
376         scpcd_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
377         if (!scpcd_area)
378                 return -ENOMEM;
379         cd = kzalloc(sizeof(*cd), GFP_KERNEL);
380         if (!cd) {
381                 ret = -ENOMEM;
382                 goto out_free;
383         }
384         if (copy_from_user(cd, user_cd, sizeof(*cd))) {
385                 ret = -EFAULT;
386                 goto out_free;
387         }
388         scpcd_area->request.length = 0x0010;
389         scpcd_area->request.code = 0x0028;
390         scpcd_area->m = cd->m;
391         scpcd_area->fmt1 = cd->fmt;
392         scpcd_area->cssid = cd->chpid.cssid;
393         scpcd_area->first_chpid = cd->chpid.id;
394         scpcd_area->last_chpid = cd->chpid.id;
395
396         ccode = chsc(scpcd_area);
397         if (ccode != 0) {
398                 ret = -EIO;
399                 goto out_free;
400         }
401         if (scpcd_area->response.code != 0x0001) {
402                 ret = -EIO;
403                 CHSC_MSG(0, "scpcd: response code=%x\n",
404                          scpcd_area->response.code);
405                 goto out_free;
406         }
407         memcpy(&cd->cpcb, &scpcd_area->response, scpcd_area->response.length);
408         if (copy_to_user(user_cd, cd, sizeof(*cd)))
409                 ret = -EFAULT;
410         else
411                 ret = 0;
412 out_free:
413         kfree(cd);
414         free_page((unsigned long)scpcd_area);
415         return ret;
416 }
417
418 static int chsc_ioctl_info_cu(void __user *user_cd)
419 {
420         struct chsc_cu_cd *cd;
421         int ret, ccode;
422         struct {
423                 struct chsc_header request;
424                 u32 : 2;
425                 u32 m : 1;
426                 u32 : 1;
427                 u32 fmt1 : 4;
428                 u32 cssid : 8;
429                 u32 : 8;
430                 u32 first_cun : 8;
431                 u32 : 24;
432                 u32 last_cun : 8;
433                 u32 : 32;
434                 struct chsc_header response;
435                 u8 data[PAGE_SIZE - 20];
436         } __attribute__ ((packed)) *scucd_area;
437
438         scucd_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
439         if (!scucd_area)
440                 return -ENOMEM;
441         cd = kzalloc(sizeof(*cd), GFP_KERNEL);
442         if (!cd) {
443                 ret = -ENOMEM;
444                 goto out_free;
445         }
446         if (copy_from_user(cd, user_cd, sizeof(*cd))) {
447                 ret = -EFAULT;
448                 goto out_free;
449         }
450         scucd_area->request.length = 0x0010;
451         scucd_area->request.code = 0x0028;
452         scucd_area->m = cd->m;
453         scucd_area->fmt1 = cd->fmt;
454         scucd_area->cssid = cd->cssid;
455         scucd_area->first_cun = cd->cun;
456         scucd_area->last_cun = cd->cun;
457
458         ccode = chsc(scucd_area);
459         if (ccode != 0) {
460                 ret = -EIO;
461                 goto out_free;
462         }
463         if (scucd_area->response.code != 0x0001) {
464                 ret = -EIO;
465                 CHSC_MSG(0, "scucd: response code=%x\n",
466                          scucd_area->response.code);
467                 goto out_free;
468         }
469         memcpy(&cd->cucb, &scucd_area->response, scucd_area->response.length);
470         if (copy_to_user(user_cd, cd, sizeof(*cd)))
471                 ret = -EFAULT;
472         else
473                 ret = 0;
474 out_free:
475         kfree(cd);
476         free_page((unsigned long)scucd_area);
477         return ret;
478 }
479
480 static int chsc_ioctl_info_sch_cu(void __user *user_cud)
481 {
482         struct chsc_sch_cud *cud;
483         int ret, ccode;
484         struct {
485                 struct chsc_header request;
486                 u32 : 2;
487                 u32 m : 1;
488                 u32 : 5;
489                 u32 fmt1 : 4;
490                 u32 : 2;
491                 u32 ssid : 2;
492                 u32 first_sch : 16;
493                 u32 : 8;
494                 u32 cssid : 8;
495                 u32 last_sch : 16;
496                 u32 : 32;
497                 struct chsc_header response;
498                 u8 data[PAGE_SIZE - 20];
499         } __attribute__ ((packed)) *sscud_area;
500
501         sscud_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
502         if (!sscud_area)
503                 return -ENOMEM;
504         cud = kzalloc(sizeof(*cud), GFP_KERNEL);
505         if (!cud) {
506                 ret = -ENOMEM;
507                 goto out_free;
508         }
509         if (copy_from_user(cud, user_cud, sizeof(*cud))) {
510                 ret = -EFAULT;
511                 goto out_free;
512         }
513         sscud_area->request.length = 0x0010;
514         sscud_area->request.code = 0x0006;
515         sscud_area->m = cud->schid.m;
516         sscud_area->fmt1 = cud->fmt;
517         sscud_area->ssid = cud->schid.ssid;
518         sscud_area->first_sch = cud->schid.sch_no;
519         sscud_area->cssid = cud->schid.cssid;
520         sscud_area->last_sch = cud->schid.sch_no;
521
522         ccode = chsc(sscud_area);
523         if (ccode != 0) {
524                 ret = -EIO;
525                 goto out_free;
526         }
527         if (sscud_area->response.code != 0x0001) {
528                 ret = -EIO;
529                 CHSC_MSG(0, "sscud: response code=%x\n",
530                          sscud_area->response.code);
531                 goto out_free;
532         }
533         memcpy(&cud->scub, &sscud_area->response, sscud_area->response.length);
534         if (copy_to_user(user_cud, cud, sizeof(*cud)))
535                 ret = -EFAULT;
536         else
537                 ret = 0;
538 out_free:
539         kfree(cud);
540         free_page((unsigned long)sscud_area);
541         return ret;
542 }
543
544 static int chsc_ioctl_conf_info(void __user *user_ci)
545 {
546         struct chsc_conf_info *ci;
547         int ret, ccode;
548         struct {
549                 struct chsc_header request;
550                 u32 : 2;
551                 u32 m : 1;
552                 u32 : 1;
553                 u32 fmt1 : 4;
554                 u32 cssid : 8;
555                 u32 : 6;
556                 u32 ssid : 2;
557                 u32 : 8;
558                 u64 : 64;
559                 struct chsc_header response;
560                 u8 data[PAGE_SIZE - 20];
561         } __attribute__ ((packed)) *sci_area;
562
563         sci_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
564         if (!sci_area)
565                 return -ENOMEM;
566         ci = kzalloc(sizeof(*ci), GFP_KERNEL);
567         if (!ci) {
568                 ret = -ENOMEM;
569                 goto out_free;
570         }
571         if (copy_from_user(ci, user_ci, sizeof(*ci))) {
572                 ret = -EFAULT;
573                 goto out_free;
574         }
575         sci_area->request.length = 0x0010;
576         sci_area->request.code = 0x0012;
577         sci_area->m = ci->id.m;
578         sci_area->fmt1 = ci->fmt;
579         sci_area->cssid = ci->id.cssid;
580         sci_area->ssid = ci->id.ssid;
581
582         ccode = chsc(sci_area);
583         if (ccode != 0) {
584                 ret = -EIO;
585                 goto out_free;
586         }
587         if (sci_area->response.code != 0x0001) {
588                 ret = -EIO;
589                 CHSC_MSG(0, "sci: response code=%x\n",
590                          sci_area->response.code);
591                 goto out_free;
592         }
593         memcpy(&ci->scid, &sci_area->response, sci_area->response.length);
594         if (copy_to_user(user_ci, ci, sizeof(*ci)))
595                 ret = -EFAULT;
596         else
597                 ret = 0;
598 out_free:
599         kfree(ci);
600         free_page((unsigned long)sci_area);
601         return ret;
602 }
603
604 static int chsc_ioctl_conf_comp_list(void __user *user_ccl)
605 {
606         struct chsc_comp_list *ccl;
607         int ret, ccode;
608         struct {
609                 struct chsc_header request;
610                 u32 ctype : 8;
611                 u32 : 4;
612                 u32 fmt : 4;
613                 u32 : 16;
614                 u64 : 64;
615                 u32 list_parm[2];
616                 u64 : 64;
617                 struct chsc_header response;
618                 u8 data[PAGE_SIZE - 36];
619         } __attribute__ ((packed)) *sccl_area;
620         struct {
621                 u32 m : 1;
622                 u32 : 31;
623                 u32 cssid : 8;
624                 u32 : 16;
625                 u32 chpid : 8;
626         } __attribute__ ((packed)) *chpid_parm;
627         struct {
628                 u32 f_cssid : 8;
629                 u32 l_cssid : 8;
630                 u32 : 16;
631                 u32 res;
632         } __attribute__ ((packed)) *cssids_parm;
633
634         sccl_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
635         if (!sccl_area)
636                 return -ENOMEM;
637         ccl = kzalloc(sizeof(*ccl), GFP_KERNEL);
638         if (!ccl) {
639                 ret = -ENOMEM;
640                 goto out_free;
641         }
642         if (copy_from_user(ccl, user_ccl, sizeof(*ccl))) {
643                 ret = -EFAULT;
644                 goto out_free;
645         }
646         sccl_area->request.length = 0x0020;
647         sccl_area->request.code = 0x0030;
648         sccl_area->fmt = ccl->req.fmt;
649         sccl_area->ctype = ccl->req.ctype;
650         switch (sccl_area->ctype) {
651         case CCL_CU_ON_CHP:
652         case CCL_IOP_CHP:
653                 chpid_parm = (void *)&sccl_area->list_parm;
654                 chpid_parm->m = ccl->req.chpid.m;
655                 chpid_parm->cssid = ccl->req.chpid.chp.cssid;
656                 chpid_parm->chpid = ccl->req.chpid.chp.id;
657                 break;
658         case CCL_CSS_IMG:
659         case CCL_CSS_IMG_CONF_CHAR:
660                 cssids_parm = (void *)&sccl_area->list_parm;
661                 cssids_parm->f_cssid = ccl->req.cssids.f_cssid;
662                 cssids_parm->l_cssid = ccl->req.cssids.l_cssid;
663                 break;
664         }
665         ccode = chsc(sccl_area);
666         if (ccode != 0) {
667                 ret = -EIO;
668                 goto out_free;
669         }
670         if (sccl_area->response.code != 0x0001) {
671                 ret = -EIO;
672                 CHSC_MSG(0, "sccl: response code=%x\n",
673                          sccl_area->response.code);
674                 goto out_free;
675         }
676         memcpy(&ccl->sccl, &sccl_area->response, sccl_area->response.length);
677         if (copy_to_user(user_ccl, ccl, sizeof(*ccl)))
678                 ret = -EFAULT;
679         else
680                 ret = 0;
681 out_free:
682         kfree(ccl);
683         free_page((unsigned long)sccl_area);
684         return ret;
685 }
686
687 static int chsc_ioctl_chpd(void __user *user_chpd)
688 {
689         struct chsc_cpd_info *chpd;
690         int ret;
691
692         chpd = kzalloc(sizeof(*chpd), GFP_KERNEL);
693         if (!chpd)
694                 return -ENOMEM;
695         if (copy_from_user(chpd, user_chpd, sizeof(*chpd))) {
696                 ret = -EFAULT;
697                 goto out_free;
698         }
699         ret = chsc_determine_channel_path_desc(chpd->chpid, chpd->fmt,
700                                                chpd->rfmt, chpd->c, chpd->m,
701                                                &chpd->chpdb);
702         if (ret)
703                 goto out_free;
704         if (copy_to_user(user_chpd, chpd, sizeof(*chpd)))
705                 ret = -EFAULT;
706 out_free:
707         kfree(chpd);
708         return ret;
709 }
710
711 static int chsc_ioctl_dcal(void __user *user_dcal)
712 {
713         struct chsc_dcal *dcal;
714         int ret, ccode;
715         struct {
716                 struct chsc_header request;
717                 u32 atype : 8;
718                 u32 : 4;
719                 u32 fmt : 4;
720                 u32 : 16;
721                 u32 res0[2];
722                 u32 list_parm[2];
723                 u32 res1[2];
724                 struct chsc_header response;
725                 u8 data[PAGE_SIZE - 36];
726         } __attribute__ ((packed)) *sdcal_area;
727
728         sdcal_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
729         if (!sdcal_area)
730                 return -ENOMEM;
731         dcal = kzalloc(sizeof(*dcal), GFP_KERNEL);
732         if (!dcal) {
733                 ret = -ENOMEM;
734                 goto out_free;
735         }
736         if (copy_from_user(dcal, user_dcal, sizeof(*dcal))) {
737                 ret = -EFAULT;
738                 goto out_free;
739         }
740         sdcal_area->request.length = 0x0020;
741         sdcal_area->request.code = 0x0034;
742         sdcal_area->atype = dcal->req.atype;
743         sdcal_area->fmt = dcal->req.fmt;
744         memcpy(&sdcal_area->list_parm, &dcal->req.list_parm,
745                sizeof(sdcal_area->list_parm));
746
747         ccode = chsc(sdcal_area);
748         if (ccode != 0) {
749                 ret = -EIO;
750                 goto out_free;
751         }
752         if (sdcal_area->response.code != 0x0001) {
753                 ret = -EIO;
754                 CHSC_MSG(0, "sdcal: response code=%x\n",
755                          sdcal_area->response.code);
756                 goto out_free;
757         }
758         memcpy(&dcal->sdcal, &sdcal_area->response,
759                sdcal_area->response.length);
760         if (copy_to_user(user_dcal, dcal, sizeof(*dcal)))
761                 ret = -EFAULT;
762         else
763                 ret = 0;
764 out_free:
765         kfree(dcal);
766         free_page((unsigned long)sdcal_area);
767         return ret;
768 }
769
770 static long chsc_ioctl(struct file *filp, unsigned int cmd,
771                        unsigned long arg)
772 {
773         CHSC_MSG(2, "chsc_ioctl called, cmd=%x\n", cmd);
774         switch (cmd) {
775         case CHSC_START:
776                 return chsc_ioctl_start((void __user *)arg);
777         case CHSC_INFO_CHANNEL_PATH:
778                 return chsc_ioctl_info_channel_path((void __user *)arg);
779         case CHSC_INFO_CU:
780                 return chsc_ioctl_info_cu((void __user *)arg);
781         case CHSC_INFO_SCH_CU:
782                 return chsc_ioctl_info_sch_cu((void __user *)arg);
783         case CHSC_INFO_CI:
784                 return chsc_ioctl_conf_info((void __user *)arg);
785         case CHSC_INFO_CCL:
786                 return chsc_ioctl_conf_comp_list((void __user *)arg);
787         case CHSC_INFO_CPD:
788                 return chsc_ioctl_chpd((void __user *)arg);
789         case CHSC_INFO_DCAL:
790                 return chsc_ioctl_dcal((void __user *)arg);
791         default: /* unknown ioctl number */
792                 return -ENOIOCTLCMD;
793         }
794 }
795
796 static const struct file_operations chsc_fops = {
797         .owner = THIS_MODULE,
798         .unlocked_ioctl = chsc_ioctl,
799         .compat_ioctl = chsc_ioctl,
800 };
801
802 static struct miscdevice chsc_misc_device = {
803         .minor = MISC_DYNAMIC_MINOR,
804         .name = "chsc",
805         .fops = &chsc_fops,
806 };
807
808 static int __init chsc_misc_init(void)
809 {
810         return misc_register(&chsc_misc_device);
811 }
812
813 static void chsc_misc_cleanup(void)
814 {
815         misc_deregister(&chsc_misc_device);
816 }
817
818 static int __init chsc_sch_init(void)
819 {
820         int ret;
821
822         ret = chsc_init_dbfs();
823         if (ret)
824                 return ret;
825         isc_register(CHSC_SCH_ISC);
826         ret = chsc_init_sch_driver();
827         if (ret)
828                 goto out_dbf;
829         ret = chsc_misc_init();
830         if (ret)
831                 goto out_driver;
832         return ret;
833 out_driver:
834         chsc_cleanup_sch_driver();
835 out_dbf:
836         isc_unregister(CHSC_SCH_ISC);
837         chsc_remove_dbfs();
838         return ret;
839 }
840
841 static void __exit chsc_sch_exit(void)
842 {
843         chsc_misc_cleanup();
844         chsc_cleanup_sch_driver();
845         isc_unregister(CHSC_SCH_ISC);
846         chsc_remove_dbfs();
847 }
848
849 module_init(chsc_sch_init);
850 module_exit(chsc_sch_exit);