]>
Commit | Line | Data |
---|---|---|
86d968e0 AP |
1 | /** @file\r |
2 | XenBus Bus driver implemtation.\r | |
3 | \r | |
4 | This file implement the necessary to discover and enumerate Xen PV devices\r | |
5 | through XenStore.\r | |
6 | \r | |
7 | Copyright (C) 2010 Spectra Logic Corporation\r | |
8 | Copyright (C) 2008 Doug Rabson\r | |
9 | Copyright (C) 2005 Rusty Russell, IBM Corporation\r | |
10 | Copyright (C) 2005 Mike Wray, Hewlett-Packard\r | |
11 | Copyright (C) 2005 XenSource Ltd\r | |
12 | Copyright (C) 2014, Citrix Ltd.\r | |
13 | \r | |
14 | This file may be distributed separately from the Linux kernel, or\r | |
15 | incorporated into other software packages, subject to the following license:\r | |
16 | \r | |
17 | Permission is hereby granted, free of charge, to any person obtaining a copy\r | |
18 | of this source file (the "Software"), to deal in the Software without\r | |
19 | restriction, including without limitation the rights to use, copy, modify,\r | |
20 | merge, publish, distribute, sublicense, and/or sell copies of the Software,\r | |
21 | and to permit persons to whom the Software is furnished to do so, subject to\r | |
22 | the following conditions:\r | |
23 | \r | |
24 | The above copyright notice and this permission notice shall be included in\r | |
25 | all copies or substantial portions of the Software.\r | |
26 | \r | |
27 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r | |
28 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r | |
29 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r | |
30 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r | |
31 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\r | |
32 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\r | |
33 | IN THE SOFTWARE.\r | |
34 | **/\r | |
35 | \r | |
36 | #include <Library/PrintLib.h>\r | |
37 | \r | |
38 | #include "XenBus.h"\r | |
39 | #include "GrantTable.h"\r | |
40 | #include "XenStore.h"\r | |
41 | #include "EventChannel.h"\r | |
42 | \r | |
43 | #include <IndustryStandard/Xen/io/xenbus.h>\r | |
44 | \r | |
45 | STATIC XENBUS_PRIVATE_DATA gXenBusPrivateData;\r | |
46 | \r | |
47 | STATIC XENBUS_DEVICE_PATH gXenBusDevicePathTemplate = {\r | |
489c5c67 AP |
48 | { // Vendor\r |
49 | { // Vendor.Header\r | |
50 | HARDWARE_DEVICE_PATH, // Vendor.Header.Type\r | |
51 | HW_VENDOR_DP, // Vendor.Header.SubType\r | |
52 | {\r | |
53 | (UINT8) (sizeof (XENBUS_DEVICE_PATH)), // Vendor.Header.Length[0]\r | |
54 | (UINT8) (sizeof (XENBUS_DEVICE_PATH) >> 8), // Vendor.Header.Length[1]\r | |
55 | }\r | |
56 | },\r | |
57 | XENBUS_PROTOCOL_GUID, // Vendor.Guid\r | |
58 | },\r | |
59 | 0, // Type\r | |
60 | 0 // DeviceId\r | |
86d968e0 AP |
61 | };\r |
62 | \r | |
63 | \r | |
64 | /**\r | |
65 | Search our internal record of configured devices (not the XenStore) to\r | |
66 | determine if the XenBus device indicated by Node is known to the system.\r | |
67 | \r | |
68 | @param Dev The XENBUS_DEVICE instance to search for device children.\r | |
69 | @param Node The XenStore node path for the device to find.\r | |
70 | \r | |
71 | @return The XENBUS_PRIVATE_DATA of the found device if any, or NULL.\r | |
72 | */\r | |
73 | STATIC\r | |
74 | XENBUS_PRIVATE_DATA *\r | |
75 | XenBusDeviceInitialized (\r | |
76 | IN XENBUS_DEVICE *Dev,\r | |
77 | IN CONST CHAR8 *Node\r | |
78 | )\r | |
79 | {\r | |
80 | LIST_ENTRY *Entry;\r | |
81 | XENBUS_PRIVATE_DATA *Child;\r | |
82 | XENBUS_PRIVATE_DATA *Result;\r | |
83 | \r | |
84 | if (IsListEmpty (&Dev->ChildList)) {\r | |
85 | return NULL;\r | |
86 | }\r | |
87 | \r | |
88 | Result = NULL;\r | |
89 | for (Entry = GetFirstNode (&Dev->ChildList);\r | |
90 | !IsNodeAtEnd (&Dev->ChildList, Entry);\r | |
91 | Entry = GetNextNode (&Dev->ChildList, Entry)) {\r | |
92 | Child = XENBUS_PRIVATE_DATA_FROM_LINK (Entry);\r | |
93 | if (!AsciiStrCmp (Child->XenBusIo.Node, Node)) {\r | |
94 | Result = Child;\r | |
95 | break;\r | |
96 | }\r | |
97 | }\r | |
98 | \r | |
99 | return (Result);\r | |
100 | }\r | |
101 | \r | |
102 | STATIC\r | |
103 | XenbusState\r | |
104 | XenBusReadDriverState (\r | |
105 | IN CONST CHAR8 *Path\r | |
106 | )\r | |
107 | {\r | |
108 | XenbusState State;\r | |
109 | CHAR8 *Ptr = NULL;\r | |
110 | XENSTORE_STATUS Status;\r | |
111 | \r | |
112 | Status = XenStoreRead (XST_NIL, Path, "state", NULL, (VOID **)&Ptr);\r | |
113 | if (Status != XENSTORE_STATUS_SUCCESS) {\r | |
114 | State = XenbusStateClosed;\r | |
115 | } else {\r | |
116 | State = AsciiStrDecimalToUintn (Ptr);\r | |
117 | }\r | |
118 | \r | |
119 | if (Ptr != NULL) {\r | |
120 | FreePool (Ptr);\r | |
121 | }\r | |
122 | \r | |
123 | return State;\r | |
124 | }\r | |
125 | \r | |
126 | //\r | |
127 | // Callers should ensure that they are only one calling XenBusAddDevice.\r | |
128 | //\r | |
129 | STATIC\r | |
130 | EFI_STATUS\r | |
131 | XenBusAddDevice (\r | |
132 | XENBUS_DEVICE *Dev,\r | |
133 | CONST CHAR8 *Type,\r | |
134 | CONST CHAR8 *Id)\r | |
135 | {\r | |
136 | CHAR8 DevicePath[XENSTORE_ABS_PATH_MAX];\r | |
137 | XENSTORE_STATUS StatusXenStore;\r | |
138 | XENBUS_PRIVATE_DATA *Private;\r | |
139 | EFI_STATUS Status;\r | |
140 | XENBUS_DEVICE_PATH *TempXenBusPath;\r | |
d9fdfd85 | 141 | VOID *ChildXenIo;\r |
86d968e0 AP |
142 | \r |
143 | AsciiSPrint (DevicePath, sizeof (DevicePath),\r | |
144 | "device/%a/%a", Type, Id);\r | |
145 | \r | |
146 | if (XenStorePathExists (XST_NIL, DevicePath, "")) {\r | |
147 | XENBUS_PRIVATE_DATA *Child;\r | |
148 | enum xenbus_state State;\r | |
149 | CHAR8 *BackendPath;\r | |
150 | \r | |
151 | Child = XenBusDeviceInitialized (Dev, DevicePath);\r | |
152 | if (Child != NULL) {\r | |
153 | /*\r | |
154 | * We are already tracking this node\r | |
155 | */\r | |
156 | Status = EFI_SUCCESS;\r | |
157 | goto out;\r | |
158 | }\r | |
159 | \r | |
160 | State = XenBusReadDriverState (DevicePath);\r | |
161 | if (State != XenbusStateInitialising) {\r | |
162 | /*\r | |
163 | * Device is not new, so ignore it. This can\r | |
164 | * happen if a device is going away after\r | |
165 | * switching to Closed.\r | |
166 | */\r | |
167 | DEBUG ((EFI_D_INFO, "XenBus: Device %a ignored. "\r | |
168 | "State %d\n", DevicePath, State));\r | |
169 | Status = EFI_SUCCESS;\r | |
170 | goto out;\r | |
171 | }\r | |
172 | \r | |
173 | StatusXenStore = XenStoreRead (XST_NIL, DevicePath, "backend",\r | |
174 | NULL, (VOID **) &BackendPath);\r | |
175 | if (StatusXenStore != XENSTORE_STATUS_SUCCESS) {\r | |
176 | DEBUG ((EFI_D_ERROR, "xenbus: %a no backend path.\n", DevicePath));\r | |
177 | Status = EFI_NOT_FOUND;\r | |
178 | goto out;\r | |
179 | }\r | |
180 | \r | |
181 | Private = AllocateCopyPool (sizeof (*Private), &gXenBusPrivateData);\r | |
182 | Private->XenBusIo.Type = AsciiStrDup (Type);\r | |
183 | Private->XenBusIo.Node = AsciiStrDup (DevicePath);\r | |
184 | Private->XenBusIo.Backend = BackendPath;\r | |
017a4866 | 185 | Private->XenBusIo.DeviceId = (UINT16)AsciiStrDecimalToUintn (Id);\r |
86d968e0 AP |
186 | Private->Dev = Dev;\r |
187 | \r | |
188 | TempXenBusPath = AllocateCopyPool (sizeof (XENBUS_DEVICE_PATH),\r | |
189 | &gXenBusDevicePathTemplate);\r | |
190 | if (!AsciiStrCmp (Private->XenBusIo.Type, "vbd")) {\r | |
191 | TempXenBusPath->Type = XENBUS_DEVICE_PATH_TYPE_VBD;\r | |
192 | }\r | |
193 | TempXenBusPath->DeviceId = Private->XenBusIo.DeviceId;\r | |
194 | Private->DevicePath = (XENBUS_DEVICE_PATH *)AppendDevicePathNode (\r | |
195 | Dev->DevicePath,\r | |
196 | &TempXenBusPath->Vendor.Header);\r | |
197 | FreePool (TempXenBusPath);\r | |
198 | \r | |
199 | InsertTailList (&Dev->ChildList, &Private->Link);\r | |
200 | \r | |
201 | Status = gBS->InstallMultipleProtocolInterfaces (\r | |
202 | &Private->Handle,\r | |
203 | &gEfiDevicePathProtocolGuid, Private->DevicePath,\r | |
204 | &gXenBusProtocolGuid, &Private->XenBusIo,\r | |
205 | NULL);\r | |
206 | if (EFI_ERROR (Status)) {\r | |
207 | goto ErrorInstallProtocol;\r | |
208 | }\r | |
209 | \r | |
210 | Status = gBS->OpenProtocol (Dev->ControllerHandle,\r | |
d9fdfd85 AB |
211 | &gXenIoProtocolGuid,\r |
212 | &ChildXenIo, Dev->This->DriverBindingHandle,\r | |
86d968e0 AP |
213 | Private->Handle,\r |
214 | EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER);\r | |
215 | if (EFI_ERROR (Status)) {\r | |
216 | DEBUG ((EFI_D_ERROR, "open by child controller fail (%r)\n",\r | |
217 | Status));\r | |
218 | goto ErrorOpenProtocolByChild;\r | |
219 | }\r | |
220 | } else {\r | |
221 | DEBUG ((EFI_D_ERROR, "XenBus: does not exist: %a\n", DevicePath));\r | |
222 | Status = EFI_NOT_FOUND;\r | |
223 | }\r | |
224 | \r | |
225 | return Status;\r | |
226 | \r | |
227 | ErrorOpenProtocolByChild:\r | |
228 | gBS->UninstallMultipleProtocolInterfaces (\r | |
229 | &Private->Handle,\r | |
230 | &gEfiDevicePathProtocolGuid, Private->DevicePath,\r | |
231 | &gXenBusProtocolGuid, &Private->XenBusIo,\r | |
232 | NULL);\r | |
233 | ErrorInstallProtocol:\r | |
234 | RemoveEntryList (&Private->Link);\r | |
235 | FreePool (Private->DevicePath);\r | |
236 | FreePool ((VOID *) Private->XenBusIo.Backend);\r | |
237 | FreePool ((VOID *) Private->XenBusIo.Node);\r | |
238 | FreePool ((VOID *) Private->XenBusIo.Type);\r | |
239 | FreePool (Private);\r | |
240 | out:\r | |
241 | return Status;\r | |
242 | }\r | |
243 | \r | |
244 | /**\r | |
245 | Enumerate all devices of the given type on this bus.\r | |
246 | \r | |
247 | @param Dev A XENBUS_DEVICE instance.\r | |
248 | @param Type String indicating the device sub-tree (e.g. "vfb", "vif")\r | |
249 | to enumerate.\r | |
250 | \r | |
251 | Devices that are found are been initialize via XenBusAddDevice ().\r | |
252 | XenBusAddDevice () ignores duplicate detects and ignores duplicate devices,\r | |
253 | so it can be called unconditionally for any device found in the XenStore.\r | |
254 | */\r | |
255 | STATIC\r | |
256 | VOID\r | |
257 | XenBusEnumerateDeviceType (\r | |
258 | XENBUS_DEVICE *Dev,\r | |
259 | CONST CHAR8 *Type\r | |
260 | )\r | |
261 | {\r | |
262 | CONST CHAR8 **Directory;\r | |
263 | UINTN Index;\r | |
264 | UINT32 Count;\r | |
265 | XENSTORE_STATUS Status;\r | |
266 | \r | |
267 | Status = XenStoreListDirectory (XST_NIL,\r | |
268 | "device", Type,\r | |
269 | &Count, &Directory);\r | |
270 | if (Status != XENSTORE_STATUS_SUCCESS) {\r | |
271 | return;\r | |
272 | }\r | |
273 | for (Index = 0; Index < Count; Index++) {\r | |
274 | XenBusAddDevice (Dev, Type, Directory[Index]);\r | |
275 | }\r | |
276 | \r | |
017a4866 | 277 | FreePool ((VOID*)Directory);\r |
86d968e0 AP |
278 | }\r |
279 | \r | |
280 | \r | |
281 | /**\r | |
282 | Enumerate the devices on a XenBus bus and install a XenBus Protocol instance.\r | |
283 | \r | |
284 | Caller should ensure that it is the only one to call this function. This\r | |
285 | function cannot be called concurrently.\r | |
286 | \r | |
287 | @param Dev A XENBUS_DEVICE instance.\r | |
288 | \r | |
289 | @return On success, XENSTORE_STATUS_SUCCESS. Otherwise an errno value\r | |
290 | indicating the type of failure.\r | |
291 | */\r | |
292 | XENSTORE_STATUS\r | |
293 | XenBusEnumerateBus (\r | |
294 | XENBUS_DEVICE *Dev\r | |
295 | )\r | |
296 | {\r | |
297 | CONST CHAR8 **Types;\r | |
298 | UINTN Index;\r | |
299 | UINT32 Count;\r | |
300 | XENSTORE_STATUS Status;\r | |
301 | \r | |
302 | Status = XenStoreListDirectory (XST_NIL,\r | |
303 | "device", "",\r | |
304 | &Count, &Types);\r | |
305 | if (Status != XENSTORE_STATUS_SUCCESS) {\r | |
306 | return Status;\r | |
307 | }\r | |
308 | \r | |
309 | for (Index = 0; Index < Count; Index++) {\r | |
310 | XenBusEnumerateDeviceType (Dev, Types[Index]);\r | |
311 | }\r | |
312 | \r | |
017a4866 | 313 | FreePool ((VOID*)Types);\r |
86d968e0 AP |
314 | \r |
315 | return XENSTORE_STATUS_SUCCESS;\r | |
316 | }\r | |
317 | \r | |
318 | STATIC\r | |
319 | XENSTORE_STATUS\r | |
320 | EFIAPI\r | |
321 | XenBusSetState (\r | |
322 | IN XENBUS_PROTOCOL *This,\r | |
e26a83cd | 323 | IN CONST XENSTORE_TRANSACTION *Transaction,\r |
86d968e0 AP |
324 | IN enum xenbus_state NewState\r |
325 | )\r | |
326 | {\r | |
327 | enum xenbus_state CurrentState;\r | |
328 | XENSTORE_STATUS Status;\r | |
329 | CHAR8 *Temp;\r | |
330 | \r | |
331 | DEBUG ((EFI_D_INFO, "XenBus: Set state to %d\n", NewState));\r | |
332 | \r | |
333 | Status = XenStoreRead (Transaction, This->Node, "state", NULL, (VOID **)&Temp);\r | |
334 | if (Status != XENSTORE_STATUS_SUCCESS) {\r | |
335 | goto Out;\r | |
336 | }\r | |
337 | CurrentState = AsciiStrDecimalToUintn (Temp);\r | |
338 | FreePool (Temp);\r | |
339 | if (CurrentState == NewState) {\r | |
340 | goto Out;\r | |
341 | }\r | |
342 | \r | |
343 | do {\r | |
344 | Status = XenStoreSPrint (Transaction, This->Node, "state", "%d", NewState);\r | |
345 | } while (Status == XENSTORE_STATUS_EAGAIN);\r | |
346 | if (Status != XENSTORE_STATUS_SUCCESS) {\r | |
347 | DEBUG ((EFI_D_ERROR, "XenBus: failed to write new state\n"));\r | |
348 | goto Out;\r | |
349 | }\r | |
350 | DEBUG ((EFI_D_INFO, "XenBus: Set state to %d, done\n", NewState));\r | |
351 | \r | |
352 | Out:\r | |
353 | return Status;\r | |
354 | }\r | |
355 | \r | |
356 | STATIC XENBUS_PRIVATE_DATA gXenBusPrivateData = {\r | |
43be9f4c AP |
357 | XENBUS_PRIVATE_DATA_SIGNATURE, // Signature\r |
358 | { NULL, NULL }, // Link\r | |
359 | NULL, // Handle\r | |
360 | { // XenBusIo\r | |
361 | XenBusXenStoreRead, // XenBusIo.XsRead\r | |
362 | XenBusXenStoreBackendRead, // XenBusIo.XsBackendRead\r | |
363 | XenBusXenStoreSPrint, // XenBusIo.XsPrintf\r | |
364 | XenBusXenStoreRemove, // XenBusIo.XsRemove\r | |
365 | XenBusXenStoreTransactionStart, // XenBusIo.XsTransactionStart\r | |
366 | XenBusXenStoreTransactionEnd, // XenBusIo.XsTransactionEnd\r | |
367 | XenBusSetState, // XenBusIo.SetState\r | |
368 | XenBusGrantAccess, // XenBusIo.GrantAccess\r | |
369 | XenBusGrantEndAccess, // XenBusIo.GrantEndAccess\r | |
370 | XenBusEventChannelAllocate, // XenBusIo.EventChannelAllocate\r | |
371 | XenBusEventChannelNotify, // XenBusIo.EventChannelNotify\r | |
372 | XenBusEventChannelClose, // XenBusIo.EventChannelClose\r | |
373 | XenBusRegisterWatch, // XenBusIo.RegisterWatch\r | |
374 | XenBusRegisterWatchBackend, // XenBusIo.RegisterWatchBackend\r | |
375 | XenBusUnregisterWatch, // XenBusIo.UnregisterWatch\r | |
376 | XenBusWaitForWatch, // XenBusIo.WaitForWatch\r | |
377 | \r | |
378 | NULL, // XenBusIo.Type\r | |
379 | 0, // XenBusIo.DeviceId\r | |
380 | NULL, // XenBusIo.Node\r | |
381 | NULL, // XenBusIo.Backend\r | |
382 | },\r | |
383 | \r | |
384 | NULL, // Dev\r | |
385 | NULL // DevicePath\r | |
86d968e0 | 386 | };\r |