[S390] permanent subchannel busy conditions may cause I/O stall
[linux-2.6] / drivers / s390 / sysinfo.c
1 /*
2  *  drivers/s390/sysinfo.c
3  *
4  *    Copyright (C) 2001 IBM Deutschland Entwicklung GmbH, IBM Corporation
5  *    Author(s): Ulrich Weigand (Ulrich.Weigand@de.ibm.com)
6  */
7
8 #include <linux/kernel.h>
9 #include <linux/mm.h>
10 #include <linux/proc_fs.h>
11 #include <linux/init.h>
12 #include <asm/ebcdic.h>
13
14 struct sysinfo_1_1_1
15 {
16         char reserved_0[32];
17         char manufacturer[16];
18         char type[4];
19         char reserved_1[12];
20         char model[16];
21         char sequence[16];
22         char plant[4];
23 };
24
25 struct sysinfo_1_2_1
26 {
27         char reserved_0[80];
28         char sequence[16];
29         char plant[4];
30         char reserved_1[2];
31         unsigned short cpu_address;
32 };
33
34 struct sysinfo_1_2_2
35 {
36         char reserved_0[32];
37         unsigned int capability;
38         unsigned short cpus_total;
39         unsigned short cpus_configured;
40         unsigned short cpus_standby;
41         unsigned short cpus_reserved;
42         unsigned short adjustment[0];
43 };
44
45 struct sysinfo_2_2_1
46 {
47         char reserved_0[80];
48         char sequence[16];
49         char plant[4];
50         unsigned short cpu_id;
51         unsigned short cpu_address;
52 };
53
54 struct sysinfo_2_2_2
55 {
56         char reserved_0[32];
57         unsigned short lpar_number;
58         char reserved_1;
59         unsigned char characteristics;
60         #define LPAR_CHAR_DEDICATED     (1 << 7)
61         #define LPAR_CHAR_SHARED        (1 << 6)
62         #define LPAR_CHAR_LIMITED       (1 << 5)
63         unsigned short cpus_total;
64         unsigned short cpus_configured;
65         unsigned short cpus_standby;
66         unsigned short cpus_reserved;
67         char name[8];
68         unsigned int caf;
69         char reserved_2[16];
70         unsigned short cpus_dedicated;
71         unsigned short cpus_shared;
72 };
73
74 struct sysinfo_3_2_2
75 {
76         char reserved_0[31];
77         unsigned char count;
78         struct
79         {
80                 char reserved_0[4];
81                 unsigned short cpus_total;
82                 unsigned short cpus_configured;
83                 unsigned short cpus_standby;
84                 unsigned short cpus_reserved;
85                 char name[8];
86                 unsigned int caf;
87                 char cpi[16];
88                 char reserved_1[24];
89
90         } vm[8];
91 };
92
93 union s390_sysinfo
94 {
95         struct sysinfo_1_1_1 sysinfo_1_1_1;
96         struct sysinfo_1_2_1 sysinfo_1_2_1;
97         struct sysinfo_1_2_2 sysinfo_1_2_2;
98         struct sysinfo_2_2_1 sysinfo_2_2_1;
99         struct sysinfo_2_2_2 sysinfo_2_2_2;
100         struct sysinfo_3_2_2 sysinfo_3_2_2;
101 };
102
103 static inline int stsi (void *sysinfo, 
104                         int fc, int sel1, int sel2)
105 {
106         int cc, retv;
107
108 #ifndef CONFIG_64BIT
109         __asm__ __volatile__ (  "lr\t0,%2\n"
110                                 "\tlr\t1,%3\n"
111                                 "\tstsi\t0(%4)\n"
112                                 "0:\tipm\t%0\n"
113                                 "\tsrl\t%0,28\n"
114                                 "1:lr\t%1,0\n"
115                                 ".section .fixup,\"ax\"\n"
116                                 "2:\tlhi\t%0,3\n"
117                                 "\tbras\t1,3f\n"
118                                 "\t.long 1b\n"
119                                 "3:\tl\t1,0(1)\n"
120                                 "\tbr\t1\n"
121                                 ".previous\n"
122                                 ".section __ex_table,\"a\"\n"
123                                 "\t.align 4\n"
124                                 "\t.long 0b,2b\n"
125                                 ".previous\n"
126                                 : "=d" (cc), "=d" (retv)
127                                 : "d" ((fc << 28) | sel1), "d" (sel2), "a" (sysinfo) 
128                                 : "cc", "memory", "0", "1" );
129 #else
130         __asm__ __volatile__ (  "lr\t0,%2\n"
131                                 "lr\t1,%3\n"
132                                 "\tstsi\t0(%4)\n"
133                                 "0:\tipm\t%0\n"
134                                 "\tsrl\t%0,28\n"
135                                 "1:lr\t%1,0\n"
136                                 ".section .fixup,\"ax\"\n"
137                                 "2:\tlhi\t%0,3\n"
138                                 "\tjg\t1b\n"
139                                 ".previous\n"
140                                 ".section __ex_table,\"a\"\n"
141                                 "\t.align 8\n"
142                                 "\t.quad 0b,2b\n"
143                                 ".previous\n"
144                                 : "=d" (cc), "=d" (retv)
145                                 : "d" ((fc << 28) | sel1), "d" (sel2), "a" (sysinfo) 
146                                 : "cc", "memory", "0", "1" );
147 #endif
148
149         return cc? -1 : retv;
150 }
151
152 static inline int stsi_0 (void)
153 {
154         int rc = stsi (NULL, 0, 0, 0);
155         return rc == -1 ? rc : (((unsigned int)rc) >> 28);
156 }
157
158 static inline int stsi_1_1_1 (struct sysinfo_1_1_1 *info)
159 {
160         int rc = stsi (info, 1, 1, 1);
161         if (rc != -1)
162         {
163                 EBCASC (info->manufacturer, sizeof(info->manufacturer));
164                 EBCASC (info->type, sizeof(info->type));
165                 EBCASC (info->model, sizeof(info->model));
166                 EBCASC (info->sequence, sizeof(info->sequence));
167                 EBCASC (info->plant, sizeof(info->plant));
168         }
169         return rc == -1 ? rc : 0;
170 }
171
172 static inline int stsi_1_2_1 (struct sysinfo_1_2_1 *info)
173 {
174         int rc = stsi (info, 1, 2, 1);
175         if (rc != -1)
176         {
177                 EBCASC (info->sequence, sizeof(info->sequence));
178                 EBCASC (info->plant, sizeof(info->plant));
179         }
180         return rc == -1 ? rc : 0;
181 }
182
183 static inline int stsi_1_2_2 (struct sysinfo_1_2_2 *info)
184 {
185         int rc = stsi (info, 1, 2, 2);
186         return rc == -1 ? rc : 0;
187 }
188
189 static inline int stsi_2_2_1 (struct sysinfo_2_2_1 *info)
190 {
191         int rc = stsi (info, 2, 2, 1);
192         if (rc != -1)
193         {
194                 EBCASC (info->sequence, sizeof(info->sequence));
195                 EBCASC (info->plant, sizeof(info->plant));
196         }
197         return rc == -1 ? rc : 0;
198 }
199
200 static inline int stsi_2_2_2 (struct sysinfo_2_2_2 *info)
201 {
202         int rc = stsi (info, 2, 2, 2);
203         if (rc != -1)
204         {
205                 EBCASC (info->name, sizeof(info->name));
206         }
207         return rc == -1 ? rc : 0;
208 }
209
210 static inline int stsi_3_2_2 (struct sysinfo_3_2_2 *info)
211 {
212         int rc = stsi (info, 3, 2, 2);
213         if (rc != -1)
214         {
215                 int i;
216                 for (i = 0; i < info->count; i++)
217                 {
218                         EBCASC (info->vm[i].name, sizeof(info->vm[i].name));
219                         EBCASC (info->vm[i].cpi, sizeof(info->vm[i].cpi));
220                 }
221         }
222         return rc == -1 ? rc : 0;
223 }
224
225
226 static int proc_read_sysinfo(char *page, char **start,
227                              off_t off, int count,
228                              int *eof, void *data)
229 {
230         unsigned long info_page = get_zeroed_page (GFP_KERNEL); 
231         union s390_sysinfo *info = (union s390_sysinfo *) info_page;
232         int len = 0;
233         int level;
234         int i;
235         
236         if (!info)
237                 return 0;
238
239         level = stsi_0 ();
240
241         if (level >= 1 && stsi_1_1_1 (&info->sysinfo_1_1_1) == 0)
242         {
243                 len += sprintf (page+len, "Manufacturer:         %-16.16s\n",
244                                 info->sysinfo_1_1_1.manufacturer);
245                 len += sprintf (page+len, "Type:                 %-4.4s\n",
246                                 info->sysinfo_1_1_1.type);
247                 len += sprintf (page+len, "Model:                %-16.16s\n",
248                                 info->sysinfo_1_1_1.model);
249                 len += sprintf (page+len, "Sequence Code:        %-16.16s\n",
250                                 info->sysinfo_1_1_1.sequence);
251                 len += sprintf (page+len, "Plant:                %-4.4s\n",
252                                 info->sysinfo_1_1_1.plant);
253         }
254
255         if (level >= 1 && stsi_1_2_2 (&info->sysinfo_1_2_2) == 0)
256         {
257                 len += sprintf (page+len, "\n");
258                 len += sprintf (page+len, "CPUs Total:           %d\n",
259                                 info->sysinfo_1_2_2.cpus_total);
260                 len += sprintf (page+len, "CPUs Configured:      %d\n",
261                                 info->sysinfo_1_2_2.cpus_configured);
262                 len += sprintf (page+len, "CPUs Standby:         %d\n",
263                                 info->sysinfo_1_2_2.cpus_standby);
264                 len += sprintf (page+len, "CPUs Reserved:        %d\n",
265                                 info->sysinfo_1_2_2.cpus_reserved);
266         
267                 len += sprintf (page+len, "Capability:           %d\n",
268                                 info->sysinfo_1_2_2.capability);
269
270                 for (i = 2; i <= info->sysinfo_1_2_2.cpus_total; i++)
271                         len += sprintf (page+len, "Adjustment %02d-way:    %d\n",
272                                         i, info->sysinfo_1_2_2.adjustment[i-2]);
273         }
274
275         if (level >= 2 && stsi_2_2_2 (&info->sysinfo_2_2_2) == 0)
276         {
277                 len += sprintf (page+len, "\n");
278                 len += sprintf (page+len, "LPAR Number:          %d\n",
279                                 info->sysinfo_2_2_2.lpar_number);
280
281                 len += sprintf (page+len, "LPAR Characteristics: ");
282                 if (info->sysinfo_2_2_2.characteristics & LPAR_CHAR_DEDICATED)
283                         len += sprintf (page+len, "Dedicated ");
284                 if (info->sysinfo_2_2_2.characteristics & LPAR_CHAR_SHARED)
285                         len += sprintf (page+len, "Shared ");
286                 if (info->sysinfo_2_2_2.characteristics & LPAR_CHAR_LIMITED)
287                         len += sprintf (page+len, "Limited ");
288                 len += sprintf (page+len, "\n");
289         
290                 len += sprintf (page+len, "LPAR Name:            %-8.8s\n",
291                                 info->sysinfo_2_2_2.name);
292         
293                 len += sprintf (page+len, "LPAR Adjustment:      %d\n",
294                                 info->sysinfo_2_2_2.caf);
295         
296                 len += sprintf (page+len, "LPAR CPUs Total:      %d\n",
297                                 info->sysinfo_2_2_2.cpus_total);
298                 len += sprintf (page+len, "LPAR CPUs Configured: %d\n",
299                                 info->sysinfo_2_2_2.cpus_configured);
300                 len += sprintf (page+len, "LPAR CPUs Standby:    %d\n",
301                                 info->sysinfo_2_2_2.cpus_standby);
302                 len += sprintf (page+len, "LPAR CPUs Reserved:   %d\n",
303                                 info->sysinfo_2_2_2.cpus_reserved);
304                 len += sprintf (page+len, "LPAR CPUs Dedicated:  %d\n",
305                                 info->sysinfo_2_2_2.cpus_dedicated);
306                 len += sprintf (page+len, "LPAR CPUs Shared:     %d\n",
307                                 info->sysinfo_2_2_2.cpus_shared);
308         }
309
310         if (level >= 3 && stsi_3_2_2 (&info->sysinfo_3_2_2) == 0)
311         {
312                 for (i = 0; i < info->sysinfo_3_2_2.count; i++)
313                 {
314                         len += sprintf (page+len, "\n");
315                         len += sprintf (page+len, "VM%02d Name:            %-8.8s\n",
316                                         i, info->sysinfo_3_2_2.vm[i].name);
317                         len += sprintf (page+len, "VM%02d Control Program: %-16.16s\n",
318                                         i, info->sysinfo_3_2_2.vm[i].cpi);
319         
320                         len += sprintf (page+len, "VM%02d Adjustment:      %d\n",
321                                         i, info->sysinfo_3_2_2.vm[i].caf);
322         
323                         len += sprintf (page+len, "VM%02d CPUs Total:      %d\n",
324                                         i, info->sysinfo_3_2_2.vm[i].cpus_total);
325                         len += sprintf (page+len, "VM%02d CPUs Configured: %d\n",
326                                         i, info->sysinfo_3_2_2.vm[i].cpus_configured);
327                         len += sprintf (page+len, "VM%02d CPUs Standby:    %d\n",
328                                         i, info->sysinfo_3_2_2.vm[i].cpus_standby);
329                         len += sprintf (page+len, "VM%02d CPUs Reserved:   %d\n",
330                                         i, info->sysinfo_3_2_2.vm[i].cpus_reserved);
331                 }
332         }
333
334         free_page (info_page);
335         return len;
336 }
337
338 static __init int create_proc_sysinfo(void)
339 {
340         create_proc_read_entry ("sysinfo", 0444, NULL, 
341                                 proc_read_sysinfo, NULL);
342         return 0;
343 }
344
345 __initcall(create_proc_sysinfo);
346