File: /usr/src/linux/drivers/s390/char/hwc_cpi.c
1
2 /*
3 * Author: Martin Peschke <mpeschke@de.ibm.com>
4 * Copyright (C) 2001 IBM Entwicklung GmbH, IBM Corporation
5 */
6
7 #include <linux/string.h>
8 #include <linux/ctype.h>
9 #include <linux/module.h>
10 #include <linux/init.h>
11 #include <linux/errno.h>
12 #include <linux/malloc.h>
13 #include <linux/version.h>
14 #include <asm/semaphore.h>
15 #include <asm/ebcdic.h>
16 #include "hwc_rw.h"
17 #include "hwc.h"
18
19 #define CPI_LENGTH_SYSTEM_TYPE 8
20 #define CPI_LENGTH_SYSTEM_NAME 8
21 #define CPI_LENGTH_SYSPLEX_NAME 8
22
23 typedef struct {
24 _EBUF_HEADER
25 u8 id_format;
26 u8 reserved0;
27 u8 system_type[CPI_LENGTH_SYSTEM_TYPE];
28 u64 reserved1;
29 u8 system_name[CPI_LENGTH_SYSTEM_NAME];
30 u64 reserved2;
31 u64 system_level;
32 u64 reserved3;
33 u8 sysplex_name[CPI_LENGTH_SYSPLEX_NAME];
34 u8 reserved4[16];
35 } __attribute__ ((packed))
36
37 cpi_evbuf_t;
38
39 typedef struct _cpi_hwcb_t {
40 _HWCB_HEADER
41 cpi_evbuf_t cpi_evbuf;
42 } __attribute__ ((packed))
43
44 cpi_hwcb_t;
45
46 cpi_hwcb_t *cpi_hwcb;
47
48 static int __init cpi_module_init (void);
49 static void __exit cpi_module_exit (void);
50
51 module_init (cpi_module_init);
52 module_exit (cpi_module_exit);
53
54 MODULE_AUTHOR (
55 "Martin Peschke, IBM Deutschland Entwicklung GmbH "
56 "<mpeschke@de.ibm.com>");
57
58 MODULE_DESCRIPTION (
59 "identify this operating system instance to the S/390 or zSeries hardware");
60
61 static char *system_name = NULL;
62 MODULE_PARM (system_name, "s");
63 MODULE_PARM_DESC (system_name, "e.g. hostname - max. 8 characters");
64
65 static char *sysplex_name = NULL;
66 #ifdef ALLOW_SYSPLEX_NAME
67 MODULE_PARM (sysplex_name, "s");
68 MODULE_PARM_DESC (sysplex_name, "if applicable - max. 8 characters");
69 #endif
70
71 static char *system_type = "LINUX";
72
73 hwc_request_t cpi_request =
74 {};
75
76 hwc_callback_t cpi_callback;
77
78 static DECLARE_MUTEX_LOCKED (sem);
79
80 static int __init
81 cpi_module_init (void)
82 {
83 int retval;
84 int system_type_length;
85 int system_name_length;
86 int sysplex_name_length = 0;
87
88 if (!MACHINE_HAS_HWC) {
89 printk ("cpi: bug: hardware console not present\n");
90 retval = -EINVAL;
91 goto out;
92 }
93 if (!system_type) {
94 printk ("cpi: bug: no system type specified\n");
95 retval = -EINVAL;
96 goto out;
97 }
98 system_type_length = strlen (system_type);
99 if (system_type_length > CPI_LENGTH_SYSTEM_NAME) {
100 printk ("cpi: bug: system type has length of %i characters - "
101 "only %i characters supported\n",
102 system_type_length,
103 CPI_LENGTH_SYSTEM_TYPE);
104 retval = -EINVAL;
105 goto out;
106 }
107 if (!system_name) {
108 printk ("cpi: no system name specified\n");
109 retval = -EINVAL;
110 goto out;
111 }
112 system_name_length = strlen (system_name);
113 if (system_name_length > CPI_LENGTH_SYSTEM_NAME) {
114 printk ("cpi: system name has length of %i characters - "
115 "only %i characters supported\n",
116 system_name_length,
117 CPI_LENGTH_SYSTEM_NAME);
118 retval = -EINVAL;
119 goto out;
120 }
121 if (sysplex_name) {
122 sysplex_name_length = strlen (sysplex_name);
123 if (sysplex_name_length > CPI_LENGTH_SYSPLEX_NAME) {
124 printk ("cpi: sysplex name has length of %i characters - "
125 "only %i characters supported\n",
126 sysplex_name_length,
127 CPI_LENGTH_SYSPLEX_NAME);
128 retval = -EINVAL;
129 goto out;
130 }
131 }
132 cpi_hwcb = kmalloc (sizeof (cpi_hwcb_t), GFP_KERNEL);
133 if (!cpi_hwcb) {
134 printk ("cpi: no storage to fulfill request\n");
135 retval = -ENOMEM;
136 goto out;
137 }
138 memset (cpi_hwcb, 0, sizeof (cpi_hwcb_t));
139
140 cpi_hwcb->length = sizeof (cpi_hwcb_t);
141 cpi_hwcb->cpi_evbuf.length = sizeof (cpi_evbuf_t);
142 cpi_hwcb->cpi_evbuf.type = 0x0B;
143
144 memset (cpi_hwcb->cpi_evbuf.system_type, ' ', CPI_LENGTH_SYSTEM_TYPE);
145 memcpy (cpi_hwcb->cpi_evbuf.system_type, system_type, system_type_length);
146 HWC_ASCEBC_STR (cpi_hwcb->cpi_evbuf.system_type, CPI_LENGTH_SYSTEM_TYPE);
147 EBC_TOUPPER (cpi_hwcb->cpi_evbuf.system_type, CPI_LENGTH_SYSTEM_TYPE);
148
149 memset (cpi_hwcb->cpi_evbuf.system_name, ' ', CPI_LENGTH_SYSTEM_NAME);
150 memcpy (cpi_hwcb->cpi_evbuf.system_name, system_name, system_name_length);
151 HWC_ASCEBC_STR (cpi_hwcb->cpi_evbuf.system_name, CPI_LENGTH_SYSTEM_NAME);
152 EBC_TOUPPER (cpi_hwcb->cpi_evbuf.system_name, CPI_LENGTH_SYSTEM_NAME);
153
154 cpi_hwcb->cpi_evbuf.system_level = LINUX_VERSION_CODE;
155
156 if (sysplex_name) {
157 memset (cpi_hwcb->cpi_evbuf.sysplex_name, ' ', CPI_LENGTH_SYSPLEX_NAME);
158 memcpy (cpi_hwcb->cpi_evbuf.sysplex_name, sysplex_name, sysplex_name_length);
159 HWC_ASCEBC_STR (cpi_hwcb->cpi_evbuf.sysplex_name, CPI_LENGTH_SYSPLEX_NAME);
160 EBC_TOUPPER (cpi_hwcb->cpi_evbuf.sysplex_name, CPI_LENGTH_SYSPLEX_NAME);
161 }
162 cpi_request.block = cpi_hwcb;
163 cpi_request.word = HWC_CMDW_WRITEDATA;
164 cpi_request.callback = cpi_callback;
165
166 retval = hwc_send (&cpi_request);
167 if (retval) {
168 printk ("cpi: failed (%i)\n", retval);
169 goto free;
170 }
171 down (&sem);
172
173 switch (cpi_hwcb->response_code) {
174 case 0x0020:
175 printk ("cpi: succeeded\n");
176 break;
177 default:
178 printk ("cpi: failed with response code 0x%x\n",
179 cpi_hwcb->response_code);
180 }
181
182 free:
183 kfree (cpi_hwcb);
184
185 out:
186 return retval;
187 }
188
189 static void __exit
190 cpi_module_exit (void)
191 {
192 printk ("cpi: exit\n");
193 }
194
195 void
196 cpi_callback (hwc_request_t * req)
197 {
198 up (&sem);
199 }
200