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