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