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