File Index
Files and directories
Sign in
FILE

sclp_cmd.c

File preview with syntax highlighting.

linux-6.19.14/drivers/s390/char/sclp_cmd.c C
  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
 30struct cpu_configure_sccb {
 31	struct sccb_header header;
 32} __packed __aligned(8);
 33
 34struct chp_cfg_sccb {
 35	struct sccb_header header;
 36	u8 ccm;
 37	u8 reserved[6];
 38	u8 cssid;
 39} __packed;
 40
 41struct 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
 51static void sclp_sync_callback(struct sclp_req *req, void *data)
 52{
 53	struct completion *completion = data;
 54
 55	complete(completion);
 56}
 57
 58int sclp_sync_request(sclp_cmdw_t cmd, void *sccb)
 59{
 60	return sclp_sync_request_timeout(cmd, sccb, 0);
 61}
 62
 63int 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	}
 91out:
 92	kfree(request);
 93	return rc;
 94}
 95
 96int _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);
121out:
122	free_pages((unsigned long)sccb, get_order(length));
123	return rc;
124}
125
126static 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	}
154out:
155	kfree(sccb);
156	return rc;
157}
158
159int sclp_core_configure(u8 core)
160{
161	return do_core_configure(SCLP_CMDW_CONFIGURE_CPU | core << 8);
162}
163
164int sclp_core_deconfigure(u8 core)
165{
166	return do_core_configure(SCLP_CMDW_DECONFIGURE_CPU | core << 8);
167}
168
169static 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	}
195out:
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 */
207int 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 */
219int 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 */
232int 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);
255out:
256	free_page((unsigned long)sccb);
257	return rc;
258}
~/ Read-only file preview.