sclp_cpi.c revision 6ab3d5624e172c553004ecc862bfeac16d9d68b7
1/* 2 * Author: Martin Peschke <mpeschke@de.ibm.com> 3 * Copyright (C) 2001 IBM Entwicklung GmbH, IBM Corporation 4 * 5 * SCLP Control-Program Identification. 6 */ 7 8#include <linux/version.h> 9#include <linux/kmod.h> 10#include <linux/module.h> 11#include <linux/moduleparam.h> 12#include <linux/init.h> 13#include <linux/timer.h> 14#include <linux/string.h> 15#include <linux/err.h> 16#include <linux/slab.h> 17#include <asm/ebcdic.h> 18#include <asm/semaphore.h> 19 20#include "sclp.h" 21#include "sclp_rw.h" 22 23#define CPI_LENGTH_SYSTEM_TYPE 8 24#define CPI_LENGTH_SYSTEM_NAME 8 25#define CPI_LENGTH_SYSPLEX_NAME 8 26 27struct cpi_evbuf { 28 struct evbuf_header header; 29 u8 id_format; 30 u8 reserved0; 31 u8 system_type[CPI_LENGTH_SYSTEM_TYPE]; 32 u64 reserved1; 33 u8 system_name[CPI_LENGTH_SYSTEM_NAME]; 34 u64 reserved2; 35 u64 system_level; 36 u64 reserved3; 37 u8 sysplex_name[CPI_LENGTH_SYSPLEX_NAME]; 38 u8 reserved4[16]; 39} __attribute__((packed)); 40 41struct cpi_sccb { 42 struct sccb_header header; 43 struct cpi_evbuf cpi_evbuf; 44} __attribute__((packed)); 45 46/* Event type structure for write message and write priority message */ 47static struct sclp_register sclp_cpi_event = 48{ 49 .send_mask = EvTyp_CtlProgIdent_Mask 50}; 51 52MODULE_AUTHOR( 53 "Martin Peschke, IBM Deutschland Entwicklung GmbH " 54 "<mpeschke@de.ibm.com>"); 55 56MODULE_DESCRIPTION( 57 "identify this operating system instance to the S/390 " 58 "or zSeries hardware"); 59 60static char *system_name = NULL; 61module_param(system_name, charp, 0); 62MODULE_PARM_DESC(system_name, "e.g. hostname - max. 8 characters"); 63 64static char *sysplex_name = NULL; 65#ifdef ALLOW_SYSPLEX_NAME 66module_param(sysplex_name, charp, 0); 67MODULE_PARM_DESC(sysplex_name, "if applicable - max. 8 characters"); 68#endif 69 70/* use default value for this field (as well as for system level) */ 71static char *system_type = "LINUX"; 72 73static int 74cpi_check_parms(void) 75{ 76 /* reject if no system type specified */ 77 if (!system_type) { 78 printk("cpi: bug: no system type specified\n"); 79 return -EINVAL; 80 } 81 82 /* reject if system type larger than 8 characters */ 83 if (strlen(system_type) > CPI_LENGTH_SYSTEM_NAME) { 84 printk("cpi: bug: system type has length of %li characters - " 85 "only %i characters supported\n", 86 strlen(system_type), CPI_LENGTH_SYSTEM_TYPE); 87 return -EINVAL; 88 } 89 90 /* reject if no system name specified */ 91 if (!system_name) { 92 printk("cpi: no system name specified\n"); 93 return -EINVAL; 94 } 95 96 /* reject if system name larger than 8 characters */ 97 if (strlen(system_name) > CPI_LENGTH_SYSTEM_NAME) { 98 printk("cpi: system name has length of %li characters - " 99 "only %i characters supported\n", 100 strlen(system_name), CPI_LENGTH_SYSTEM_NAME); 101 return -EINVAL; 102 } 103 104 /* reject if specified sysplex name larger than 8 characters */ 105 if (sysplex_name && strlen(sysplex_name) > CPI_LENGTH_SYSPLEX_NAME) { 106 printk("cpi: sysplex name has length of %li characters" 107 " - only %i characters supported\n", 108 strlen(sysplex_name), CPI_LENGTH_SYSPLEX_NAME); 109 return -EINVAL; 110 } 111 return 0; 112} 113 114static void 115cpi_callback(struct sclp_req *req, void *data) 116{ 117 struct semaphore *sem; 118 119 sem = (struct semaphore *) data; 120 up(sem); 121} 122 123static struct sclp_req * 124cpi_prepare_req(void) 125{ 126 struct sclp_req *req; 127 struct cpi_sccb *sccb; 128 struct cpi_evbuf *evb; 129 130 req = (struct sclp_req *) kmalloc(sizeof(struct sclp_req), GFP_KERNEL); 131 if (req == NULL) 132 return ERR_PTR(-ENOMEM); 133 sccb = (struct cpi_sccb *) __get_free_page(GFP_KERNEL | GFP_DMA); 134 if (sccb == NULL) { 135 kfree(req); 136 return ERR_PTR(-ENOMEM); 137 } 138 memset(sccb, 0, sizeof(struct cpi_sccb)); 139 140 /* setup SCCB for Control-Program Identification */ 141 sccb->header.length = sizeof(struct cpi_sccb); 142 sccb->cpi_evbuf.header.length = sizeof(struct cpi_evbuf); 143 sccb->cpi_evbuf.header.type = 0x0B; 144 evb = &sccb->cpi_evbuf; 145 146 /* set system type */ 147 memset(evb->system_type, ' ', CPI_LENGTH_SYSTEM_TYPE); 148 memcpy(evb->system_type, system_type, strlen(system_type)); 149 sclp_ascebc_str(evb->system_type, CPI_LENGTH_SYSTEM_TYPE); 150 EBC_TOUPPER(evb->system_type, CPI_LENGTH_SYSTEM_TYPE); 151 152 /* set system name */ 153 memset(evb->system_name, ' ', CPI_LENGTH_SYSTEM_NAME); 154 memcpy(evb->system_name, system_name, strlen(system_name)); 155 sclp_ascebc_str(evb->system_name, CPI_LENGTH_SYSTEM_NAME); 156 EBC_TOUPPER(evb->system_name, CPI_LENGTH_SYSTEM_NAME); 157 158 /* set sytem level */ 159 evb->system_level = LINUX_VERSION_CODE; 160 161 /* set sysplex name */ 162 if (sysplex_name) { 163 memset(evb->sysplex_name, ' ', CPI_LENGTH_SYSPLEX_NAME); 164 memcpy(evb->sysplex_name, sysplex_name, strlen(sysplex_name)); 165 sclp_ascebc_str(evb->sysplex_name, CPI_LENGTH_SYSPLEX_NAME); 166 EBC_TOUPPER(evb->sysplex_name, CPI_LENGTH_SYSPLEX_NAME); 167 } 168 169 /* prepare request data structure presented to SCLP driver */ 170 req->command = SCLP_CMDW_WRITEDATA; 171 req->sccb = sccb; 172 req->status = SCLP_REQ_FILLED; 173 req->callback = cpi_callback; 174 return req; 175} 176 177static void 178cpi_free_req(struct sclp_req *req) 179{ 180 free_page((unsigned long) req->sccb); 181 kfree(req); 182} 183 184static int __init 185cpi_module_init(void) 186{ 187 struct semaphore sem; 188 struct sclp_req *req; 189 int rc; 190 191 rc = cpi_check_parms(); 192 if (rc) 193 return rc; 194 195 rc = sclp_register(&sclp_cpi_event); 196 if (rc) { 197 /* could not register sclp event. Die. */ 198 printk(KERN_WARNING "cpi: could not register to hardware " 199 "console.\n"); 200 return -EINVAL; 201 } 202 if (!(sclp_cpi_event.sclp_send_mask & EvTyp_CtlProgIdent_Mask)) { 203 printk(KERN_WARNING "cpi: no control program identification " 204 "support\n"); 205 sclp_unregister(&sclp_cpi_event); 206 return -EOPNOTSUPP; 207 } 208 209 req = cpi_prepare_req(); 210 if (IS_ERR(req)) { 211 printk(KERN_WARNING "cpi: couldn't allocate request\n"); 212 sclp_unregister(&sclp_cpi_event); 213 return PTR_ERR(req); 214 } 215 216 /* Prepare semaphore */ 217 sema_init(&sem, 0); 218 req->callback_data = &sem; 219 /* Add request to sclp queue */ 220 rc = sclp_add_request(req); 221 if (rc) { 222 printk(KERN_WARNING "cpi: could not start request\n"); 223 cpi_free_req(req); 224 sclp_unregister(&sclp_cpi_event); 225 return rc; 226 } 227 /* make "insmod" sleep until callback arrives */ 228 down(&sem); 229 230 rc = ((struct cpi_sccb *) req->sccb)->header.response_code; 231 if (rc != 0x0020) { 232 printk(KERN_WARNING "cpi: failed with response code 0x%x\n", 233 rc); 234 rc = -ECOMM; 235 } else 236 rc = 0; 237 238 cpi_free_req(req); 239 sclp_unregister(&sclp_cpi_event); 240 241 return rc; 242} 243 244 245static void __exit cpi_module_exit(void) 246{ 247} 248 249 250/* declare driver module init/cleanup functions */ 251module_init(cpi_module_init); 252module_exit(cpi_module_exit); 253 254