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