Commit | Line | Data |
---|---|---|
f6d0c1e6 | 1 | /* Copyright (C) 2010 - 2013 UNISYS CORPORATION |
e423812a KC |
2 | * All rights reserved. |
3 | * | |
4 | * This program is free software; you can redistribute it and/or modify | |
5 | * it under the terms of the GNU General Public License as published by | |
6 | * the Free Software Foundation; either version 2 of the License, or (at | |
7 | * your option) any later version. | |
8 | * | |
9 | * This program is distributed in the hope that it will be useful, but | |
10 | * WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 | * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or | |
12 | * NON INFRINGEMENT. See the GNU General Public License for more | |
13 | * details. | |
14 | */ | |
15 | ||
16 | #ifndef __CHANNEL_H__ | |
17 | #define __CHANNEL_H__ | |
18 | ||
1d2def98 BR |
19 | #include <linux/types.h> |
20 | #include <linux/io.h> | |
90addb02 BR |
21 | #include <linux/uuid.h> |
22 | ||
e423812a KC |
23 | /* |
24 | * Whenever this file is changed a corresponding change must be made in | |
25 | * the Console/ServicePart/visordiag_early/supervisor_channel.h file | |
26 | * which is needed for Linux kernel compiles. These two files must be | |
27 | * in sync. | |
28 | */ | |
29 | ||
30 | /* define the following to prevent include nesting in kernel header | |
fb90c609 | 31 | * files of similar abbreviated content |
e423812a KC |
32 | */ |
33 | #define __SUPERVISOR_CHANNEL_H__ | |
34 | ||
54bf4d45 | 35 | #define SIGNATURE_16(A, B) ((A) | (B << 8)) |
e423812a KC |
36 | #define SIGNATURE_32(A, B, C, D) \ |
37 | (SIGNATURE_16(A, B) | (SIGNATURE_16(C, D) << 16)) | |
38 | #define SIGNATURE_64(A, B, C, D, E, F, G, H) \ | |
5fc0229a | 39 | (SIGNATURE_32(A, B, C, D) | ((u64)(SIGNATURE_32(E, F, G, H)) << 32)) |
e423812a KC |
40 | |
41 | #ifndef lengthof | |
42 | #define lengthof(TYPE, MEMBER) (sizeof(((TYPE *)0)->MEMBER)) | |
43 | #endif | |
44 | #ifndef COVERQ | |
54bf4d45 | 45 | #define COVERQ(v, d) (((v) + (d) - 1) / (d)) |
e423812a KC |
46 | #endif |
47 | #ifndef COVER | |
54bf4d45 | 48 | #define COVER(v, d) ((d) * COVERQ(v, d)) |
e423812a KC |
49 | #endif |
50 | ||
e423812a KC |
51 | #define ULTRA_CHANNEL_PROTOCOL_SIGNATURE SIGNATURE_32('E', 'C', 'N', 'L') |
52 | ||
1e73f4b5 | 53 | enum channel_serverstate { |
e423812a KC |
54 | CHANNELSRV_UNINITIALIZED = 0, /* channel is in an undefined state */ |
55 | CHANNELSRV_READY = 1 /* channel has been initialized by server */ | |
1e73f4b5 | 56 | }; |
e423812a | 57 | |
9831a29a | 58 | enum channel_clientstate { |
e423812a KC |
59 | CHANNELCLI_DETACHED = 0, |
60 | CHANNELCLI_DISABLED = 1, /* client can see channel but is NOT | |
61 | * allowed to use it unless given TBD | |
62 | * explicit request (should actually be | |
180e2767 EA |
63 | * < DETACHED) |
64 | */ | |
e423812a | 65 | CHANNELCLI_ATTACHING = 2, /* legacy EFI client request |
180e2767 EA |
66 | * for EFI server to attach |
67 | */ | |
e423812a | 68 | CHANNELCLI_ATTACHED = 3, /* idle, but client may want |
180e2767 EA |
69 | * to use channel any time |
70 | */ | |
e423812a | 71 | CHANNELCLI_BUSY = 4, /* client either wants to use or is |
180e2767 EA |
72 | * using channel |
73 | */ | |
74 | CHANNELCLI_OWNED = 5 /* "no worries" state - client can */ | |
75 | /* access channel anytime */ | |
9831a29a | 76 | }; |
09a5073b | 77 | |
c242233e | 78 | static inline const u8 * |
85d83cd8 | 79 | ULTRA_CHANNELCLI_STRING(u32 state) |
e423812a | 80 | { |
85d83cd8 | 81 | switch (state) { |
e423812a | 82 | case CHANNELCLI_DETACHED: |
82d72bee | 83 | return (const u8 *)("DETACHED"); |
e423812a | 84 | case CHANNELCLI_DISABLED: |
82d72bee | 85 | return (const u8 *)("DISABLED"); |
e423812a | 86 | case CHANNELCLI_ATTACHING: |
82d72bee | 87 | return (const u8 *)("ATTACHING"); |
e423812a | 88 | case CHANNELCLI_ATTACHED: |
82d72bee | 89 | return (const u8 *)("ATTACHED"); |
e423812a | 90 | case CHANNELCLI_BUSY: |
82d72bee | 91 | return (const u8 *)("BUSY"); |
e423812a | 92 | case CHANNELCLI_OWNED: |
82d72bee | 93 | return (const u8 *)("OWNED"); |
e423812a KC |
94 | default: |
95 | break; | |
96 | } | |
82d72bee | 97 | return (const u8 *)("?"); |
e423812a KC |
98 | } |
99 | ||
10b133c7 BR |
100 | #define SPAR_CHANNEL_SERVER_READY(ch) \ |
101 | (readl(&(ch)->srv_state) == CHANNELSRV_READY) | |
e423812a KC |
102 | |
103 | #define ULTRA_VALID_CHANNELCLI_TRANSITION(o, n) \ | |
104 | (((((o) == CHANNELCLI_DETACHED) && ((n) == CHANNELCLI_DISABLED)) || \ | |
105 | (((o) == CHANNELCLI_ATTACHING) && ((n) == CHANNELCLI_DISABLED)) || \ | |
106 | (((o) == CHANNELCLI_ATTACHED) && ((n) == CHANNELCLI_DISABLED)) || \ | |
107 | (((o) == CHANNELCLI_ATTACHING) && ((n) == CHANNELCLI_DETACHED)) || \ | |
108 | (((o) == CHANNELCLI_ATTACHED) && ((n) == CHANNELCLI_DETACHED)) || \ | |
109 | (((o) == CHANNELCLI_DETACHED) && ((n) == CHANNELCLI_ATTACHING)) || \ | |
110 | (((o) == CHANNELCLI_ATTACHING) && ((n) == CHANNELCLI_ATTACHED)) || \ | |
111 | (((o) == CHANNELCLI_DETACHED) && ((n) == CHANNELCLI_ATTACHED)) || \ | |
112 | (((o) == CHANNELCLI_BUSY) && ((n) == CHANNELCLI_ATTACHED)) || \ | |
113 | (((o) == CHANNELCLI_ATTACHED) && ((n) == CHANNELCLI_BUSY)) || \ | |
114 | (((o) == CHANNELCLI_DETACHED) && ((n) == CHANNELCLI_OWNED)) || \ | |
115 | (((o) == CHANNELCLI_DISABLED) && ((n) == CHANNELCLI_OWNED)) || \ | |
116 | (((o) == CHANNELCLI_ATTACHING) && ((n) == CHANNELCLI_OWNED)) || \ | |
117 | (((o) == CHANNELCLI_ATTACHED) && ((n) == CHANNELCLI_OWNED)) || \ | |
118 | (((o) == CHANNELCLI_BUSY) && ((n) == CHANNELCLI_OWNED)) || (0)) \ | |
119 | ? (1) : (0)) | |
120 | ||
e423812a KC |
121 | /* Values for ULTRA_CHANNEL_PROTOCOL.CliErrorBoot: */ |
122 | /* throttling invalid boot channel statetransition error due to client | |
180e2767 EA |
123 | * disabled |
124 | */ | |
e423812a KC |
125 | #define ULTRA_CLIERRORBOOT_THROTTLEMSG_DISABLED 0x01 |
126 | ||
127 | /* throttling invalid boot channel statetransition error due to client | |
180e2767 EA |
128 | * not attached |
129 | */ | |
e423812a KC |
130 | #define ULTRA_CLIERRORBOOT_THROTTLEMSG_NOTATTACHED 0x02 |
131 | ||
132 | /* throttling invalid boot channel statetransition error due to busy channel */ | |
133 | #define ULTRA_CLIERRORBOOT_THROTTLEMSG_BUSY 0x04 | |
134 | ||
135 | /* Values for ULTRA_CHANNEL_PROTOCOL.CliErrorOS: */ | |
136 | /* throttling invalid guest OS channel statetransition error due to | |
180e2767 EA |
137 | * client disabled |
138 | */ | |
e423812a KC |
139 | #define ULTRA_CLIERROROS_THROTTLEMSG_DISABLED 0x01 |
140 | ||
141 | /* throttling invalid guest OS channel statetransition error due to | |
180e2767 EA |
142 | * client not attached |
143 | */ | |
e423812a KC |
144 | #define ULTRA_CLIERROROS_THROTTLEMSG_NOTATTACHED 0x02 |
145 | ||
146 | /* throttling invalid guest OS channel statetransition error due to | |
180e2767 EA |
147 | * busy channel |
148 | */ | |
e423812a KC |
149 | #define ULTRA_CLIERROROS_THROTTLEMSG_BUSY 0x04 |
150 | ||
151 | /* Values for ULTRA_CHANNEL_PROTOCOL.Features: This define exists so | |
180e2767 EA |
152 | * that windows guest can look at the FeatureFlags in the io channel, |
153 | * and configure the windows driver to use interrupts or not based on | |
154 | * this setting. This flag is set in uislib after the | |
155 | * ULTRA_VHBA_init_channel is called. All feature bits for all | |
156 | * channels should be defined here. The io channel feature bits are | |
157 | * defined right here | |
158 | */ | |
e423812a KC |
159 | #define ULTRA_IO_DRIVER_ENABLES_INTS (0x1ULL << 1) |
160 | #define ULTRA_IO_CHANNEL_IS_POLLING (0x1ULL << 3) | |
161 | #define ULTRA_IO_IOVM_IS_OK_WITH_DRIVER_DISABLING_INTS (0x1ULL << 4) | |
162 | #define ULTRA_IO_DRIVER_DISABLES_INTS (0x1ULL << 5) | |
163 | #define ULTRA_IO_DRIVER_SUPPORTS_ENHANCED_RCVBUF_CHECKING (0x1ULL << 6) | |
164 | ||
e423812a | 165 | /* Common Channel Header */ |
9fd1b95a | 166 | struct channel_header { |
a8a31f61 BR |
167 | u64 signature; /* Signature */ |
168 | u32 legacy_state; /* DEPRECATED - being replaced by */ | |
180e2767 | 169 | /* SrvState, CliStateBoot, and CliStateOS below */ |
a8a31f61 BR |
170 | u32 header_size; /* sizeof(struct channel_header) */ |
171 | u64 size; /* Total size of this channel in bytes */ | |
172 | u64 features; /* Flags to modify behavior */ | |
173 | uuid_le chtype; /* Channel type: data, bus, control, etc. */ | |
174 | u64 partition_handle; /* ID of guest partition */ | |
175 | u64 handle; /* Device number of this channel in client */ | |
176 | u64 ch_space_offset; /* Offset in bytes to channel specific area */ | |
177 | u32 version_id; /* struct channel_header Version ID */ | |
178 | u32 partition_index; /* Index of guest partition */ | |
179 | uuid_le zone_uuid; /* Guid of Channel's zone */ | |
180 | u32 cli_str_offset; /* offset from channel header to | |
e423812a | 181 | * nul-terminated ClientString (0 if |
180e2767 EA |
182 | * ClientString not present) |
183 | */ | |
a8a31f61 | 184 | u32 cli_state_boot; /* CHANNEL_CLIENTSTATE of pre-boot |
180e2767 EA |
185 | * EFI client of this channel |
186 | */ | |
a8a31f61 | 187 | u32 cmd_state_cli; /* CHANNEL_COMMANDSTATE (overloaded in |
e423812a | 188 | * Windows drivers, see ServerStateUp, |
180e2767 EA |
189 | * ServerStateDown, etc) |
190 | */ | |
a8a31f61 | 191 | u32 cli_state_os; /* CHANNEL_CLIENTSTATE of Guest OS |
180e2767 EA |
192 | * client of this channel |
193 | */ | |
a8a31f61 BR |
194 | u32 ch_characteristic; /* CHANNEL_CHARACTERISTIC_<xxx> */ |
195 | u32 cmd_state_srv; /* CHANNEL_COMMANDSTATE (overloaded in | |
e423812a | 196 | * Windows drivers, see ServerStateUp, |
180e2767 EA |
197 | * ServerStateDown, etc) |
198 | */ | |
a8a31f61 BR |
199 | u32 srv_state; /* CHANNEL_SERVERSTATE */ |
200 | u8 cli_error_boot; /* bits to indicate err states for | |
e423812a | 201 | * boot clients, so err messages can |
180e2767 EA |
202 | * be throttled |
203 | */ | |
a8a31f61 | 204 | u8 cli_error_os; /* bits to indicate err states for OS |
e423812a | 205 | * clients, so err messages can be |
180e2767 EA |
206 | * throttled |
207 | */ | |
a8a31f61 | 208 | u8 filler[1]; /* Pad out to 128 byte cacheline */ |
e423812a | 209 | /* Please add all new single-byte values below here */ |
a8a31f61 | 210 | u8 recover_channel; |
9f00be7f | 211 | } __packed; |
e423812a KC |
212 | |
213 | #define ULTRA_CHANNEL_ENABLE_INTS (0x1ULL << 0) | |
214 | ||
215 | /* Subheader for the Signal Type variation of the Common Channel */ | |
e0fed862 | 216 | struct signal_queue_header { |
e423812a | 217 | /* 1st cache line */ |
153cf710 BR |
218 | u32 version; /* SIGNAL_QUEUE_HEADER Version ID */ |
219 | u32 chtype; /* Queue type: storage, network */ | |
220 | u64 size; /* Total size of this queue in bytes */ | |
221 | u64 sig_base_offset; /* Offset to signal queue area */ | |
222 | u64 features; /* Flags to modify behavior */ | |
223 | u64 num_sent; /* Total # of signals placed in this queue */ | |
224 | u64 num_overflows; /* Total # of inserts failed due to | |
180e2767 EA |
225 | * full queue |
226 | */ | |
153cf710 BR |
227 | u32 signal_size; /* Total size of a signal for this queue */ |
228 | u32 max_slots; /* Max # of slots in queue, 1 slot is | |
180e2767 EA |
229 | * always empty |
230 | */ | |
153cf710 | 231 | u32 max_signals; /* Max # of signals in queue |
180e2767 EA |
232 | * (MaxSignalSlots-1) |
233 | */ | |
153cf710 | 234 | u32 head; /* Queue head signal # */ |
e423812a | 235 | /* 2nd cache line */ |
153cf710 | 236 | u64 num_received; /* Total # of signals removed from this queue */ |
180e2767 | 237 | u32 tail; /* Queue tail signal */ |
153cf710 BR |
238 | u32 reserved1; /* Reserved field */ |
239 | u64 reserved2; /* Reserved field */ | |
240 | u64 client_queue; | |
241 | u64 num_irq_received; /* Total # of Interrupts received. This | |
180e2767 EA |
242 | * is incremented by the ISR in the |
243 | * guest windows driver | |
244 | */ | |
153cf710 | 245 | u64 num_empty; /* Number of times that visor_signal_remove |
180e2767 EA |
246 | * is called and returned Empty Status. |
247 | */ | |
153cf710 | 248 | u32 errorflags; /* Error bits set during SignalReinit |
e423812a | 249 | * to denote trouble with client's |
180e2767 EA |
250 | * fields |
251 | */ | |
153cf710 | 252 | u8 filler[12]; /* Pad out to 64 byte cacheline */ |
9f00be7f | 253 | } __packed; |
e423812a | 254 | |
29fe22b3 | 255 | #define spar_signal_init(chan, QHDRFLD, QDATAFLD, QDATATYPE, ver, typ) \ |
e423812a | 256 | do { \ |
30de72db | 257 | memset(&chan->QHDRFLD, 0, sizeof(chan->QHDRFLD)); \ |
29fe22b3 BR |
258 | chan->QHDRFLD.version = ver; \ |
259 | chan->QHDRFLD.chtype = typ; \ | |
260 | chan->QHDRFLD.size = sizeof(chan->QDATAFLD); \ | |
261 | chan->QHDRFLD.signal_size = sizeof(QDATATYPE); \ | |
54bf4d45 | 262 | chan->QHDRFLD.sig_base_offset = (u64)(chan->QDATAFLD) - \ |
90f3b509 | 263 | (u64)(&chan->QHDRFLD); \ |
29fe22b3 | 264 | chan->QHDRFLD.max_slots = \ |
54bf4d45 DK |
265 | sizeof(chan->QDATAFLD) / sizeof(QDATATYPE); \ |
266 | chan->QHDRFLD.max_signals = chan->QHDRFLD.max_slots - 1;\ | |
e423812a KC |
267 | } while (0) |
268 | ||
269 | /* Generic function useful for validating any type of channel when it is | |
270 | * received by the client that will be accessing the channel. | |
271 | * Note that <logCtx> is only needed for callers in the EFI environment, and | |
272 | * is used to pass the EFI_DIAG_CAPTURE_PROTOCOL needed to log messages. | |
273 | */ | |
274 | static inline int | |
93a84565 BR |
275 | spar_check_channel_client(void __iomem *ch, |
276 | uuid_le expected_uuid, | |
277 | char *chname, | |
278 | u64 expected_min_bytes, | |
279 | u32 expected_version, | |
280 | u64 expected_signature) | |
e423812a | 281 | { |
93a84565 | 282 | if (uuid_le_cmp(expected_uuid, NULL_UUID_LE) != 0) { |
635ecc5f LH |
283 | uuid_le guid; |
284 | ||
35b8117b | 285 | memcpy_fromio(&guid, |
93a84565 BR |
286 | &((struct channel_header __iomem *)(ch))->chtype, |
287 | sizeof(guid)); | |
e423812a | 288 | /* caller wants us to verify type GUID */ |
93a84565 | 289 | if (uuid_le_cmp(guid, expected_uuid) != 0) { |
e2706697 | 290 | pr_err("Channel mismatch on channel=%s(%pUL) field=type expected=%pUL actual=%pUL\n", |
93a84565 BR |
291 | chname, &expected_uuid, |
292 | &expected_uuid, &guid); | |
e423812a KC |
293 | return 0; |
294 | } | |
635ecc5f | 295 | } |
180e2767 | 296 | if (expected_min_bytes > 0) { /* verify channel size */ |
9fd1b95a BR |
297 | unsigned long long bytes = |
298 | readq(&((struct channel_header __iomem *) | |
93a84565 BR |
299 | (ch))->size); |
300 | if (bytes < expected_min_bytes) { | |
e2706697 | 301 | pr_err("Channel mismatch on channel=%s(%pUL) field=size expected=0x%-8.8Lx actual=0x%-8.8Lx\n", |
93a84565 BR |
302 | chname, &expected_uuid, |
303 | (unsigned long long)expected_min_bytes, bytes); | |
e423812a KC |
304 | return 0; |
305 | } | |
e2706697 | 306 | } |
180e2767 | 307 | if (expected_version > 0) { /* verify channel version */ |
9fd1b95a | 308 | unsigned long ver = readl(&((struct channel_header __iomem *) |
93a84565 BR |
309 | (ch))->version_id); |
310 | if (ver != expected_version) { | |
e2706697 | 311 | pr_err("Channel mismatch on channel=%s(%pUL) field=version expected=0x%-8.8lx actual=0x%-8.8lx\n", |
93a84565 BR |
312 | chname, &expected_uuid, |
313 | (unsigned long)expected_version, ver); | |
e423812a KC |
314 | return 0; |
315 | } | |
e2706697 | 316 | } |
180e2767 | 317 | if (expected_signature > 0) { /* verify channel signature */ |
9fd1b95a BR |
318 | unsigned long long sig = |
319 | readq(&((struct channel_header __iomem *) | |
93a84565 BR |
320 | (ch))->signature); |
321 | if (sig != expected_signature) { | |
e2706697 | 322 | pr_err("Channel mismatch on channel=%s(%pUL) field=signature expected=0x%-8.8llx actual=0x%-8.8llx\n", |
93a84565 BR |
323 | chname, &expected_uuid, |
324 | expected_signature, sig); | |
e423812a KC |
325 | return 0; |
326 | } | |
e2706697 | 327 | } |
e423812a KC |
328 | return 1; |
329 | } | |
330 | ||
10c5ef69 BR |
331 | /* Generic function useful for validating any type of channel when it is about |
332 | * to be initialized by the server of the channel. | |
333 | * Note that <logCtx> is only needed for callers in the EFI environment, and | |
334 | * is used to pass the EFI_DIAG_CAPTURE_PROTOCOL needed to log messages. | |
335 | */ | |
336 | static inline int spar_check_channel_server(uuid_le typeuuid, char *name, | |
337 | u64 expected_min_bytes, | |
338 | u64 actual_bytes) | |
339 | { | |
180e2767 | 340 | if (expected_min_bytes > 0) /* verify channel size */ |
10c5ef69 BR |
341 | if (actual_bytes < expected_min_bytes) { |
342 | pr_err("Channel mismatch on channel=%s(%pUL) field=size expected=0x%-8.8llx actual=0x%-8.8llx\n", | |
343 | name, &typeuuid, expected_min_bytes, | |
344 | actual_bytes); | |
345 | return 0; | |
346 | } | |
347 | return 1; | |
348 | } | |
349 | ||
e423812a KC |
350 | /* Given a file pathname <s> (with '/' or '\' separating directory nodes), |
351 | * returns a pointer to the beginning of a node within that pathname such | |
352 | * that the number of nodes from that pointer to the end of the string is | |
353 | * NOT more than <n>. Note that if the pathname has less than <n> nodes | |
354 | * in it, the return pointer will be to the beginning of the string. | |
355 | */ | |
c242233e | 356 | static inline u8 * |
8800bfbc | 357 | pathname_last_n_nodes(u8 *s, unsigned int n) |
e423812a | 358 | { |
c242233e | 359 | u8 *p = s; |
e423812a | 360 | unsigned int node_count = 0; |
aff6de05 | 361 | |
e423812a KC |
362 | while (*p != '\0') { |
363 | if ((*p == '/') || (*p == '\\')) | |
364 | node_count++; | |
365 | p++; | |
366 | } | |
367 | if (node_count <= n) | |
368 | return s; | |
369 | while (n > 0) { | |
370 | p--; | |
371 | if (p == s) | |
372 | break; /* should never happen, unless someone | |
373 | * is changing the string while we are | |
180e2767 EA |
374 | * looking at it!! |
375 | */ | |
e423812a KC |
376 | if ((*p == '/') || (*p == '\\')) |
377 | n--; | |
378 | } | |
379 | return p + 1; | |
380 | } | |
381 | ||
382 | static inline int | |
9f16930e | 383 | spar_channel_client_acquire_os(void __iomem *ch, u8 *id) |
e423812a | 384 | { |
9f16930e | 385 | struct channel_header __iomem *hdr = ch; |
e423812a | 386 | |
9f16930e BR |
387 | if (readl(&hdr->cli_state_os) == CHANNELCLI_DISABLED) { |
388 | if ((readb(&hdr->cli_error_os) | |
a8d7f21d | 389 | & ULTRA_CLIERROROS_THROTTLEMSG_DISABLED) == 0) { |
e423812a | 390 | /* we are NOT throttling this message */ |
9f16930e | 391 | writeb(readb(&hdr->cli_error_os) | |
a8d7f21d | 392 | ULTRA_CLIERROROS_THROTTLEMSG_DISABLED, |
9f16930e | 393 | &hdr->cli_error_os); |
e423812a KC |
394 | /* throttle until acquire successful */ |
395 | ||
9f16930e BR |
396 | pr_info("%s Channel StateTransition INVALID! - acquire failed because OS client DISABLED\n", |
397 | id); | |
e423812a KC |
398 | } |
399 | return 0; | |
400 | } | |
bac9e37d BR |
401 | if ((readl(&hdr->cli_state_os) != CHANNELCLI_OWNED) && |
402 | (readl(&hdr->cli_state_boot) == CHANNELCLI_DISABLED)) { | |
e423812a | 403 | /* Our competitor is DISABLED, so we can transition to OWNED */ |
9f16930e BR |
404 | pr_info("%s Channel StateTransition (%s) %s(%d)-->%s(%d)\n", |
405 | id, "cli_state_os", | |
406 | ULTRA_CHANNELCLI_STRING(readl(&hdr->cli_state_os)), | |
407 | readl(&hdr->cli_state_os), | |
ddb38ae6 | 408 | ULTRA_CHANNELCLI_STRING(CHANNELCLI_OWNED), |
9f16930e BR |
409 | CHANNELCLI_OWNED); |
410 | writel(CHANNELCLI_OWNED, &hdr->cli_state_os); | |
e87cfde4 | 411 | mb(); /* required for channel synch */ |
e423812a | 412 | } |
9f16930e | 413 | if (readl(&hdr->cli_state_os) == CHANNELCLI_OWNED) { |
800aecc3 | 414 | if (readb(&hdr->cli_error_os)) { |
e423812a | 415 | /* we are in an error msg throttling state; |
180e2767 EA |
416 | * come out of it |
417 | */ | |
9f16930e BR |
418 | pr_info("%s Channel OS client acquire now successful\n", |
419 | id); | |
420 | writeb(0, &hdr->cli_error_os); | |
e423812a KC |
421 | } |
422 | return 1; | |
423 | } | |
424 | ||
425 | /* We have to do it the "hard way". We transition to BUSY, | |
180e2767 EA |
426 | * and can use the channel iff our competitor has not also |
427 | * transitioned to BUSY. | |
428 | */ | |
9f16930e BR |
429 | if (readl(&hdr->cli_state_os) != CHANNELCLI_ATTACHED) { |
430 | if ((readb(&hdr->cli_error_os) | |
a8d7f21d | 431 | & ULTRA_CLIERROROS_THROTTLEMSG_NOTATTACHED) == 0) { |
e423812a | 432 | /* we are NOT throttling this message */ |
9f16930e | 433 | writeb(readb(&hdr->cli_error_os) | |
a8d7f21d | 434 | ULTRA_CLIERROROS_THROTTLEMSG_NOTATTACHED, |
9f16930e | 435 | &hdr->cli_error_os); |
e423812a | 436 | /* throttle until acquire successful */ |
9f16930e BR |
437 | pr_info("%s Channel StateTransition INVALID! - acquire failed because OS client NOT ATTACHED (state=%s(%d))\n", |
438 | id, ULTRA_CHANNELCLI_STRING( | |
439 | readl(&hdr->cli_state_os)), | |
440 | readl(&hdr->cli_state_os)); | |
e423812a KC |
441 | } |
442 | return 0; | |
443 | } | |
9f16930e | 444 | writel(CHANNELCLI_BUSY, &hdr->cli_state_os); |
e87cfde4 | 445 | mb(); /* required for channel synch */ |
9f16930e BR |
446 | if (readl(&hdr->cli_state_boot) == CHANNELCLI_BUSY) { |
447 | if ((readb(&hdr->cli_error_os) | |
a8d7f21d | 448 | & ULTRA_CLIERROROS_THROTTLEMSG_BUSY) == 0) { |
e423812a | 449 | /* we are NOT throttling this message */ |
9f16930e | 450 | writeb(readb(&hdr->cli_error_os) | |
a8d7f21d | 451 | ULTRA_CLIERROROS_THROTTLEMSG_BUSY, |
9f16930e | 452 | &hdr->cli_error_os); |
e423812a | 453 | /* throttle until acquire successful */ |
9f16930e BR |
454 | pr_info("%s Channel StateTransition failed - host OS acquire failed because boot BUSY\n", |
455 | id); | |
e423812a | 456 | } |
a8d7f21d | 457 | /* reset busy */ |
9f16930e | 458 | writel(CHANNELCLI_ATTACHED, &hdr->cli_state_os); |
e87cfde4 | 459 | mb(); /* required for channel synch */ |
e423812a KC |
460 | return 0; |
461 | } | |
800aecc3 | 462 | if (readb(&hdr->cli_error_os)) { |
e423812a | 463 | /* we are in an error msg throttling state; come out of it */ |
9f16930e BR |
464 | pr_info("%s Channel OS client acquire now successful\n", id); |
465 | writeb(0, &hdr->cli_error_os); | |
e423812a KC |
466 | } |
467 | return 1; | |
468 | } | |
469 | ||
470 | static inline void | |
08598918 | 471 | spar_channel_client_release_os(void __iomem *ch, u8 *id) |
e423812a | 472 | { |
08598918 | 473 | struct channel_header __iomem *hdr = ch; |
aff6de05 | 474 | |
800aecc3 | 475 | if (readb(&hdr->cli_error_os)) { |
e423812a | 476 | /* we are in an error msg throttling state; come out of it */ |
08598918 BR |
477 | pr_info("%s Channel OS client error state cleared\n", id); |
478 | writeb(0, &hdr->cli_error_os); | |
e423812a | 479 | } |
08598918 | 480 | if (readl(&hdr->cli_state_os) == CHANNELCLI_OWNED) |
e423812a | 481 | return; |
08598918 BR |
482 | if (readl(&hdr->cli_state_os) != CHANNELCLI_BUSY) { |
483 | pr_info("%s Channel StateTransition INVALID! - release failed because OS client NOT BUSY (state=%s(%d))\n", | |
484 | id, ULTRA_CHANNELCLI_STRING( | |
485 | readl(&hdr->cli_state_os)), | |
486 | readl(&hdr->cli_state_os)); | |
e423812a KC |
487 | /* return; */ |
488 | } | |
08598918 | 489 | writel(CHANNELCLI_ATTACHED, &hdr->cli_state_os); /* release busy */ |
e423812a KC |
490 | } |
491 | ||
492 | /* | |
493 | * Routine Description: | |
494 | * Tries to insert the prebuilt signal pointed to by pSignal into the nth | |
495 | * Queue of the Channel pointed to by pChannel | |
496 | * | |
497 | * Parameters: | |
498 | * pChannel: (IN) points to the IO Channel | |
499 | * Queue: (IN) nth Queue of the IO Channel | |
500 | * pSignal: (IN) pointer to the signal | |
501 | * | |
502 | * Assumptions: | |
503 | * - pChannel, Queue and pSignal are valid. | |
504 | * - If insertion fails due to a full queue, the caller will determine the | |
505 | * retry policy (e.g. wait & try again, report an error, etc.). | |
506 | * | |
507 | * Return value: 1 if the insertion succeeds, 0 if the queue was | |
508 | * full. | |
509 | */ | |
510 | ||
93a84565 BR |
511 | unsigned char spar_signal_insert(struct channel_header __iomem *ch, u32 queue, |
512 | void *sig); | |
e423812a KC |
513 | |
514 | /* | |
515 | * Routine Description: | |
516 | * Removes one signal from Channel pChannel's nth Queue at the | |
517 | * time of the call and copies it into the memory pointed to by | |
518 | * pSignal. | |
519 | * | |
520 | * Parameters: | |
521 | * pChannel: (IN) points to the IO Channel | |
522 | * Queue: (IN) nth Queue of the IO Channel | |
523 | * pSignal: (IN) pointer to where the signals are to be copied | |
524 | * | |
525 | * Assumptions: | |
526 | * - pChannel and Queue are valid. | |
527 | * - pSignal points to a memory area large enough to hold queue's SignalSize | |
528 | * | |
529 | * Return value: 1 if the removal succeeds, 0 if the queue was | |
530 | * empty. | |
531 | */ | |
532 | ||
3f12c5f9 BR |
533 | unsigned char spar_signal_remove(struct channel_header __iomem *ch, u32 queue, |
534 | void *sig); | |
e423812a KC |
535 | |
536 | /* | |
537 | * Routine Description: | |
538 | * Removes all signals present in Channel pChannel's nth Queue at the | |
539 | * time of the call and copies them into the memory pointed to by | |
540 | * pSignal. Returns the # of signals copied as the value of the routine. | |
541 | * | |
542 | * Parameters: | |
543 | * pChannel: (IN) points to the IO Channel | |
544 | * Queue: (IN) nth Queue of the IO Channel | |
545 | * pSignal: (IN) pointer to where the signals are to be copied | |
546 | * | |
547 | * Assumptions: | |
548 | * - pChannel and Queue are valid. | |
549 | * - pSignal points to a memory area large enough to hold Queue's MaxSignals | |
550 | * # of signals, each of which is Queue's SignalSize. | |
551 | * | |
552 | * Return value: | |
553 | * # of signals copied. | |
554 | */ | |
c11cf5fd BR |
555 | unsigned int spar_signal_remove_all(struct channel_header *ch, u32 queue, |
556 | void *sig); | |
e423812a KC |
557 | |
558 | /* | |
559 | * Routine Description: | |
560 | * Determine whether a signal queue is empty. | |
561 | * | |
562 | * Parameters: | |
563 | * pChannel: (IN) points to the IO Channel | |
564 | * Queue: (IN) nth Queue of the IO Channel | |
565 | * | |
566 | * Return value: | |
567 | * 1 if the signal queue is empty, 0 otherwise. | |
568 | */ | |
a17f5b4a BR |
569 | unsigned char spar_signalqueue_empty(struct channel_header __iomem *ch, |
570 | u32 queue); | |
e423812a | 571 | |
d6d0c6f4 DB |
572 | /* |
573 | * CHANNEL Guids | |
574 | */ | |
575 | ||
576 | /* {414815ed-c58c-11da-95a9-00e08161165f} */ | |
577 | #define SPAR_VHBA_CHANNEL_PROTOCOL_UUID \ | |
578 | UUID_LE(0x414815ed, 0xc58c, 0x11da, \ | |
579 | 0x95, 0xa9, 0x0, 0xe0, 0x81, 0x61, 0x16, 0x5f) | |
580 | static const uuid_le spar_vhba_channel_protocol_uuid = | |
581 | SPAR_VHBA_CHANNEL_PROTOCOL_UUID; | |
582 | #define SPAR_VHBA_CHANNEL_PROTOCOL_UUID_STR \ | |
583 | "414815ed-c58c-11da-95a9-00e08161165f" | |
584 | ||
585 | /* {8cd5994d-c58e-11da-95a9-00e08161165f} */ | |
586 | #define SPAR_VNIC_CHANNEL_PROTOCOL_UUID \ | |
587 | UUID_LE(0x8cd5994d, 0xc58e, 0x11da, \ | |
588 | 0x95, 0xa9, 0x0, 0xe0, 0x81, 0x61, 0x16, 0x5f) | |
589 | static const uuid_le spar_vnic_channel_protocol_uuid = | |
590 | SPAR_VNIC_CHANNEL_PROTOCOL_UUID; | |
591 | #define SPAR_VNIC_CHANNEL_PROTOCOL_UUID_STR \ | |
592 | "8cd5994d-c58e-11da-95a9-00e08161165f" | |
593 | ||
594 | /* {72120008-4AAB-11DC-8530-444553544200} */ | |
595 | #define SPAR_SIOVM_UUID \ | |
596 | UUID_LE(0x72120008, 0x4AAB, 0x11DC, \ | |
597 | 0x85, 0x30, 0x44, 0x45, 0x53, 0x54, 0x42, 0x00) | |
598 | static const uuid_le spar_siovm_uuid = SPAR_SIOVM_UUID; | |
599 | ||
600 | /* {5b52c5ac-e5f5-4d42-8dff-429eaecd221f} */ | |
601 | #define SPAR_CONTROLDIRECTOR_CHANNEL_PROTOCOL_UUID \ | |
602 | UUID_LE(0x5b52c5ac, 0xe5f5, 0x4d42, \ | |
603 | 0x8d, 0xff, 0x42, 0x9e, 0xae, 0xcd, 0x22, 0x1f) | |
604 | ||
605 | static const uuid_le spar_controldirector_channel_protocol_uuid = | |
606 | SPAR_CONTROLDIRECTOR_CHANNEL_PROTOCOL_UUID; | |
607 | ||
608 | /* {b4e79625-aede-4eAA-9e11-D3eddcd4504c} */ | |
609 | #define SPAR_DIAG_POOL_CHANNEL_PROTOCOL_UUID \ | |
610 | UUID_LE(0xb4e79625, 0xaede, 0x4eaa, \ | |
611 | 0x9e, 0x11, 0xd3, 0xed, 0xdc, 0xd4, 0x50, 0x4c) | |
612 | ||
e423812a | 613 | #endif |