xref: /linux/drivers/s390/char/sclp_cmd.c (revision 7fc2cd2e4b398c57c9cf961cfea05eadbf34c05c)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright IBM Corp. 2007,2012
4  *
5  * Author(s): Peter Oberparleiter <peter.oberparleiter@de.ibm.com>
6  */
7 
8 #define pr_fmt(fmt) "sclp_cmd: " fmt
9 
10 #include <linux/completion.h>
11 #include <linux/err.h>
12 #include <linux/errno.h>
13 #include <linux/init.h>
14 #include <linux/slab.h>
15 #include <linux/string.h>
16 #include <asm/chpid.h>
17 #include <asm/ctlreg.h>
18 #include <asm/sclp.h>
19 
20 #include "sclp.h"
21 
22 /* CPU configuration related functions */
23 #define SCLP_CMDW_CONFIGURE_CPU			0x00110001
24 #define SCLP_CMDW_DECONFIGURE_CPU		0x00100001
25 /* Channel path configuration related functions */
26 #define SCLP_CMDW_CONFIGURE_CHPATH		0x000f0001
27 #define SCLP_CMDW_DECONFIGURE_CHPATH		0x000e0001
28 #define SCLP_CMDW_READ_CHPATH_INFORMATION	0x00030001
29 
30 struct cpu_configure_sccb {
31 	struct sccb_header header;
32 } __packed __aligned(8);
33 
34 struct chp_cfg_sccb {
35 	struct sccb_header header;
36 	u8 ccm;
37 	u8 reserved[6];
38 	u8 cssid;
39 } __packed;
40 
41 struct chp_info_sccb {
42 	struct sccb_header header;
43 	u8 recognized[SCLP_CHP_INFO_MASK_SIZE];
44 	u8 standby[SCLP_CHP_INFO_MASK_SIZE];
45 	u8 configured[SCLP_CHP_INFO_MASK_SIZE];
46 	u8 ccm;
47 	u8 reserved[6];
48 	u8 cssid;
49 } __packed;
50 
51 static void sclp_sync_callback(struct sclp_req *req, void *data)
52 {
53 	struct completion *completion = data;
54 
55 	complete(completion);
56 }
57 
58 int sclp_sync_request(sclp_cmdw_t cmd, void *sccb)
59 {
60 	return sclp_sync_request_timeout(cmd, sccb, 0);
61 }
62 
63 int sclp_sync_request_timeout(sclp_cmdw_t cmd, void *sccb, int timeout)
64 {
65 	struct completion completion;
66 	struct sclp_req *request;
67 	int rc;
68 
69 	request = kzalloc(sizeof(*request), GFP_KERNEL);
70 	if (!request)
71 		return -ENOMEM;
72 	if (timeout)
73 		request->queue_timeout = timeout;
74 	request->command = cmd;
75 	request->sccb = sccb;
76 	request->status = SCLP_REQ_FILLED;
77 	request->callback = sclp_sync_callback;
78 	request->callback_data = &completion;
79 	init_completion(&completion);
80 
81 	rc = sclp_add_request(request);
82 	if (rc)
83 		goto out;
84 	wait_for_completion(&completion);
85 
86 	if (request->status != SCLP_REQ_DONE) {
87 		pr_warn("sync request failed (cmd=0x%08x, status=0x%02x)\n",
88 			cmd, request->status);
89 		rc = -EIO;
90 	}
91 out:
92 	kfree(request);
93 	return rc;
94 }
95 
96 int _sclp_get_core_info(struct sclp_core_info *info)
97 {
98 	struct read_cpu_info_sccb *sccb;
99 	int rc, length;
100 
101 	if (!SCLP_HAS_CPU_INFO)
102 		return -EOPNOTSUPP;
103 
104 	length = test_facility(140) ? EXT_SCCB_READ_CPU : PAGE_SIZE;
105 	sccb = (void *)__get_free_pages(GFP_KERNEL | GFP_DMA | __GFP_ZERO, get_order(length));
106 	if (!sccb)
107 		return -ENOMEM;
108 	sccb->header.length = length;
109 	sccb->header.control_mask[2] = 0x80;
110 	rc = sclp_sync_request_timeout(SCLP_CMDW_READ_CPU_INFO, sccb,
111 				       SCLP_QUEUE_INTERVAL);
112 	if (rc)
113 		goto out;
114 	if (sccb->header.response_code != 0x0010) {
115 		pr_warn("readcpuinfo failed (response=0x%04x)\n",
116 			sccb->header.response_code);
117 		rc = -EIO;
118 		goto out;
119 	}
120 	sclp_fill_core_info(info, sccb);
121 out:
122 	free_pages((unsigned long)sccb, get_order(length));
123 	return rc;
124 }
125 
126 static int do_core_configure(sclp_cmdw_t cmd)
127 {
128 	struct cpu_configure_sccb *sccb;
129 	int rc;
130 
131 	if (!SCLP_HAS_CPU_RECONFIG)
132 		return -EOPNOTSUPP;
133 	/*
134 	 * Use kmalloc to have a minimum alignment of 8 bytes and ensure sccb
135 	 * is not going to cross a page boundary.
136 	 */
137 	sccb = kzalloc(sizeof(*sccb), GFP_KERNEL | GFP_DMA);
138 	if (!sccb)
139 		return -ENOMEM;
140 	sccb->header.length = sizeof(*sccb);
141 	rc = sclp_sync_request_timeout(cmd, sccb, SCLP_QUEUE_INTERVAL);
142 	if (rc)
143 		goto out;
144 	switch (sccb->header.response_code) {
145 	case 0x0020:
146 	case 0x0120:
147 		break;
148 	default:
149 		pr_warn("configure cpu failed (cmd=0x%08x, response=0x%04x)\n",
150 			cmd, sccb->header.response_code);
151 		rc = -EIO;
152 		break;
153 	}
154 out:
155 	kfree(sccb);
156 	return rc;
157 }
158 
159 int sclp_core_configure(u8 core)
160 {
161 	return do_core_configure(SCLP_CMDW_CONFIGURE_CPU | core << 8);
162 }
163 
164 int sclp_core_deconfigure(u8 core)
165 {
166 	return do_core_configure(SCLP_CMDW_DECONFIGURE_CPU | core << 8);
167 }
168 
169 static int do_chp_configure(sclp_cmdw_t cmd)
170 {
171 	struct chp_cfg_sccb *sccb;
172 	int rc;
173 
174 	if (!SCLP_HAS_CHP_RECONFIG)
175 		return -EOPNOTSUPP;
176 	sccb = (struct chp_cfg_sccb *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
177 	if (!sccb)
178 		return -ENOMEM;
179 	sccb->header.length = sizeof(*sccb);
180 	rc = sclp_sync_request(cmd, sccb);
181 	if (rc)
182 		goto out;
183 	switch (sccb->header.response_code) {
184 	case 0x0020:
185 	case 0x0120:
186 	case 0x0440:
187 	case 0x0450:
188 		break;
189 	default:
190 		pr_warn("configure channel-path failed (cmd=0x%08x, response=0x%04x)\n",
191 			cmd, sccb->header.response_code);
192 		rc = -EIO;
193 		break;
194 	}
195 out:
196 	free_page((unsigned long)sccb);
197 	return rc;
198 }
199 
200 /**
201  * sclp_chp_configure - perform configure channel-path sclp command
202  * @chpid: channel-path ID
203  *
204  * Perform configure channel-path command sclp command for specified chpid.
205  * Return 0 after command successfully finished, non-zero otherwise.
206  */
207 int sclp_chp_configure(struct chp_id chpid)
208 {
209 	return do_chp_configure(SCLP_CMDW_CONFIGURE_CHPATH | chpid.id << 8);
210 }
211 
212 /**
213  * sclp_chp_deconfigure - perform deconfigure channel-path sclp command
214  * @chpid: channel-path ID
215  *
216  * Perform deconfigure channel-path command sclp command for specified chpid
217  * and wait for completion. On success return 0. Return non-zero otherwise.
218  */
219 int sclp_chp_deconfigure(struct chp_id chpid)
220 {
221 	return do_chp_configure(SCLP_CMDW_DECONFIGURE_CHPATH | chpid.id << 8);
222 }
223 
224 /**
225  * sclp_chp_read_info - perform read channel-path information sclp command
226  * @info: resulting channel-path information data
227  *
228  * Perform read channel-path information sclp command and wait for completion.
229  * On success, store channel-path information in @info and return 0. Return
230  * non-zero otherwise.
231  */
232 int sclp_chp_read_info(struct sclp_chp_info *info)
233 {
234 	struct chp_info_sccb *sccb;
235 	int rc;
236 
237 	if (!SCLP_HAS_CHP_INFO)
238 		return -EOPNOTSUPP;
239 	sccb = (struct chp_info_sccb *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
240 	if (!sccb)
241 		return -ENOMEM;
242 	sccb->header.length = sizeof(*sccb);
243 	rc = sclp_sync_request(SCLP_CMDW_READ_CHPATH_INFORMATION, sccb);
244 	if (rc)
245 		goto out;
246 	if (sccb->header.response_code != 0x0010) {
247 		pr_warn("read channel-path info failed (response=0x%04x)\n",
248 			sccb->header.response_code);
249 		rc = -EIO;
250 		goto out;
251 	}
252 	memcpy(info->recognized, sccb->recognized, SCLP_CHP_INFO_MASK_SIZE);
253 	memcpy(info->standby, sccb->standby, SCLP_CHP_INFO_MASK_SIZE);
254 	memcpy(info->configured, sccb->configured, SCLP_CHP_INFO_MASK_SIZE);
255 out:
256 	free_page((unsigned long)sccb);
257 	return rc;
258 }
259