]>
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 | |
48 | .Vendor.Header.Type = HARDWARE_DEVICE_PATH,\r | |
49 | .Vendor.Header.SubType = HW_VENDOR_DP,\r | |
50 | .Vendor.Header.Length[0] = (UINT8) sizeof (XENBUS_DEVICE_PATH),\r | |
51 | .Vendor.Header.Length[1] = (UINT8) (sizeof (XENBUS_DEVICE_PATH) >> 8),\r | |
52 | .Vendor.Guid = XENBUS_PROTOCOL_GUID,\r | |
53 | .Type = 0,\r | |
54 | .DeviceId = 0\r | |
55 | };\r | |
56 | \r | |
57 | \r | |
58 | /**\r | |
59 | Search our internal record of configured devices (not the XenStore) to\r | |
60 | determine if the XenBus device indicated by Node is known to the system.\r | |
61 | \r | |
62 | @param Dev The XENBUS_DEVICE instance to search for device children.\r | |
63 | @param Node The XenStore node path for the device to find.\r | |
64 | \r | |
65 | @return The XENBUS_PRIVATE_DATA of the found device if any, or NULL.\r | |
66 | */\r | |
67 | STATIC\r | |
68 | XENBUS_PRIVATE_DATA *\r | |
69 | XenBusDeviceInitialized (\r | |
70 | IN XENBUS_DEVICE *Dev,\r | |
71 | IN CONST CHAR8 *Node\r | |
72 | )\r | |
73 | {\r | |
74 | LIST_ENTRY *Entry;\r | |
75 | XENBUS_PRIVATE_DATA *Child;\r | |
76 | XENBUS_PRIVATE_DATA *Result;\r | |
77 | \r | |
78 | if (IsListEmpty (&Dev->ChildList)) {\r | |
79 | return NULL;\r | |
80 | }\r | |
81 | \r | |
82 | Result = NULL;\r | |
83 | for (Entry = GetFirstNode (&Dev->ChildList);\r | |
84 | !IsNodeAtEnd (&Dev->ChildList, Entry);\r | |
85 | Entry = GetNextNode (&Dev->ChildList, Entry)) {\r | |
86 | Child = XENBUS_PRIVATE_DATA_FROM_LINK (Entry);\r | |
87 | if (!AsciiStrCmp (Child->XenBusIo.Node, Node)) {\r | |
88 | Result = Child;\r | |
89 | break;\r | |
90 | }\r | |
91 | }\r | |
92 | \r | |
93 | return (Result);\r | |
94 | }\r | |
95 | \r | |
96 | STATIC\r | |
97 | XenbusState\r | |
98 | XenBusReadDriverState (\r | |
99 | IN CONST CHAR8 *Path\r | |
100 | )\r | |
101 | {\r | |
102 | XenbusState State;\r | |
103 | CHAR8 *Ptr = NULL;\r | |
104 | XENSTORE_STATUS Status;\r | |
105 | \r | |
106 | Status = XenStoreRead (XST_NIL, Path, "state", NULL, (VOID **)&Ptr);\r | |
107 | if (Status != XENSTORE_STATUS_SUCCESS) {\r | |
108 | State = XenbusStateClosed;\r | |
109 | } else {\r | |
110 | State = AsciiStrDecimalToUintn (Ptr);\r | |
111 | }\r | |
112 | \r | |
113 | if (Ptr != NULL) {\r | |
114 | FreePool (Ptr);\r | |
115 | }\r | |
116 | \r | |
117 | return State;\r | |
118 | }\r | |
119 | \r | |
120 | //\r | |
121 | // Callers should ensure that they are only one calling XenBusAddDevice.\r | |
122 | //\r | |
123 | STATIC\r | |
124 | EFI_STATUS\r | |
125 | XenBusAddDevice (\r | |
126 | XENBUS_DEVICE *Dev,\r | |
127 | CONST CHAR8 *Type,\r | |
128 | CONST CHAR8 *Id)\r | |
129 | {\r | |
130 | CHAR8 DevicePath[XENSTORE_ABS_PATH_MAX];\r | |
131 | XENSTORE_STATUS StatusXenStore;\r | |
132 | XENBUS_PRIVATE_DATA *Private;\r | |
133 | EFI_STATUS Status;\r | |
134 | XENBUS_DEVICE_PATH *TempXenBusPath;\r | |
135 | VOID *ChildPciIo;\r | |
136 | \r | |
137 | AsciiSPrint (DevicePath, sizeof (DevicePath),\r | |
138 | "device/%a/%a", Type, Id);\r | |
139 | \r | |
140 | if (XenStorePathExists (XST_NIL, DevicePath, "")) {\r | |
141 | XENBUS_PRIVATE_DATA *Child;\r | |
142 | enum xenbus_state State;\r | |
143 | CHAR8 *BackendPath;\r | |
144 | \r | |
145 | Child = XenBusDeviceInitialized (Dev, DevicePath);\r | |
146 | if (Child != NULL) {\r | |
147 | /*\r | |
148 | * We are already tracking this node\r | |
149 | */\r | |
150 | Status = EFI_SUCCESS;\r | |
151 | goto out;\r | |
152 | }\r | |
153 | \r | |
154 | State = XenBusReadDriverState (DevicePath);\r | |
155 | if (State != XenbusStateInitialising) {\r | |
156 | /*\r | |
157 | * Device is not new, so ignore it. This can\r | |
158 | * happen if a device is going away after\r | |
159 | * switching to Closed.\r | |
160 | */\r | |
161 | DEBUG ((EFI_D_INFO, "XenBus: Device %a ignored. "\r | |
162 | "State %d\n", DevicePath, State));\r | |
163 | Status = EFI_SUCCESS;\r | |
164 | goto out;\r | |
165 | }\r | |
166 | \r | |
167 | StatusXenStore = XenStoreRead (XST_NIL, DevicePath, "backend",\r | |
168 | NULL, (VOID **) &BackendPath);\r | |
169 | if (StatusXenStore != XENSTORE_STATUS_SUCCESS) {\r | |
170 | DEBUG ((EFI_D_ERROR, "xenbus: %a no backend path.\n", DevicePath));\r | |
171 | Status = EFI_NOT_FOUND;\r | |
172 | goto out;\r | |
173 | }\r | |
174 | \r | |
175 | Private = AllocateCopyPool (sizeof (*Private), &gXenBusPrivateData);\r | |
176 | Private->XenBusIo.Type = AsciiStrDup (Type);\r | |
177 | Private->XenBusIo.Node = AsciiStrDup (DevicePath);\r | |
178 | Private->XenBusIo.Backend = BackendPath;\r | |
179 | Private->XenBusIo.DeviceId = AsciiStrDecimalToUintn (Id);\r | |
180 | Private->Dev = Dev;\r | |
181 | \r | |
182 | TempXenBusPath = AllocateCopyPool (sizeof (XENBUS_DEVICE_PATH),\r | |
183 | &gXenBusDevicePathTemplate);\r | |
184 | if (!AsciiStrCmp (Private->XenBusIo.Type, "vbd")) {\r | |
185 | TempXenBusPath->Type = XENBUS_DEVICE_PATH_TYPE_VBD;\r | |
186 | }\r | |
187 | TempXenBusPath->DeviceId = Private->XenBusIo.DeviceId;\r | |
188 | Private->DevicePath = (XENBUS_DEVICE_PATH *)AppendDevicePathNode (\r | |
189 | Dev->DevicePath,\r | |
190 | &TempXenBusPath->Vendor.Header);\r | |
191 | FreePool (TempXenBusPath);\r | |
192 | \r | |
193 | InsertTailList (&Dev->ChildList, &Private->Link);\r | |
194 | \r | |
195 | Status = gBS->InstallMultipleProtocolInterfaces (\r | |
196 | &Private->Handle,\r | |
197 | &gEfiDevicePathProtocolGuid, Private->DevicePath,\r | |
198 | &gXenBusProtocolGuid, &Private->XenBusIo,\r | |
199 | NULL);\r | |
200 | if (EFI_ERROR (Status)) {\r | |
201 | goto ErrorInstallProtocol;\r | |
202 | }\r | |
203 | \r | |
204 | Status = gBS->OpenProtocol (Dev->ControllerHandle,\r | |
205 | &gEfiPciIoProtocolGuid,\r | |
206 | &ChildPciIo, Dev->This->DriverBindingHandle,\r | |
207 | Private->Handle,\r | |
208 | EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER);\r | |
209 | if (EFI_ERROR (Status)) {\r | |
210 | DEBUG ((EFI_D_ERROR, "open by child controller fail (%r)\n",\r | |
211 | Status));\r | |
212 | goto ErrorOpenProtocolByChild;\r | |
213 | }\r | |
214 | } else {\r | |
215 | DEBUG ((EFI_D_ERROR, "XenBus: does not exist: %a\n", DevicePath));\r | |
216 | Status = EFI_NOT_FOUND;\r | |
217 | }\r | |
218 | \r | |
219 | return Status;\r | |
220 | \r | |
221 | ErrorOpenProtocolByChild:\r | |
222 | gBS->UninstallMultipleProtocolInterfaces (\r | |
223 | &Private->Handle,\r | |
224 | &gEfiDevicePathProtocolGuid, Private->DevicePath,\r | |
225 | &gXenBusProtocolGuid, &Private->XenBusIo,\r | |
226 | NULL);\r | |
227 | ErrorInstallProtocol:\r | |
228 | RemoveEntryList (&Private->Link);\r | |
229 | FreePool (Private->DevicePath);\r | |
230 | FreePool ((VOID *) Private->XenBusIo.Backend);\r | |
231 | FreePool ((VOID *) Private->XenBusIo.Node);\r | |
232 | FreePool ((VOID *) Private->XenBusIo.Type);\r | |
233 | FreePool (Private);\r | |
234 | out:\r | |
235 | return Status;\r | |
236 | }\r | |
237 | \r | |
238 | /**\r | |
239 | Enumerate all devices of the given type on this bus.\r | |
240 | \r | |
241 | @param Dev A XENBUS_DEVICE instance.\r | |
242 | @param Type String indicating the device sub-tree (e.g. "vfb", "vif")\r | |
243 | to enumerate.\r | |
244 | \r | |
245 | Devices that are found are been initialize via XenBusAddDevice ().\r | |
246 | XenBusAddDevice () ignores duplicate detects and ignores duplicate devices,\r | |
247 | so it can be called unconditionally for any device found in the XenStore.\r | |
248 | */\r | |
249 | STATIC\r | |
250 | VOID\r | |
251 | XenBusEnumerateDeviceType (\r | |
252 | XENBUS_DEVICE *Dev,\r | |
253 | CONST CHAR8 *Type\r | |
254 | )\r | |
255 | {\r | |
256 | CONST CHAR8 **Directory;\r | |
257 | UINTN Index;\r | |
258 | UINT32 Count;\r | |
259 | XENSTORE_STATUS Status;\r | |
260 | \r | |
261 | Status = XenStoreListDirectory (XST_NIL,\r | |
262 | "device", Type,\r | |
263 | &Count, &Directory);\r | |
264 | if (Status != XENSTORE_STATUS_SUCCESS) {\r | |
265 | return;\r | |
266 | }\r | |
267 | for (Index = 0; Index < Count; Index++) {\r | |
268 | XenBusAddDevice (Dev, Type, Directory[Index]);\r | |
269 | }\r | |
270 | \r | |
271 | FreePool (Directory);\r | |
272 | }\r | |
273 | \r | |
274 | \r | |
275 | /**\r | |
276 | Enumerate the devices on a XenBus bus and install a XenBus Protocol instance.\r | |
277 | \r | |
278 | Caller should ensure that it is the only one to call this function. This\r | |
279 | function cannot be called concurrently.\r | |
280 | \r | |
281 | @param Dev A XENBUS_DEVICE instance.\r | |
282 | \r | |
283 | @return On success, XENSTORE_STATUS_SUCCESS. Otherwise an errno value\r | |
284 | indicating the type of failure.\r | |
285 | */\r | |
286 | XENSTORE_STATUS\r | |
287 | XenBusEnumerateBus (\r | |
288 | XENBUS_DEVICE *Dev\r | |
289 | )\r | |
290 | {\r | |
291 | CONST CHAR8 **Types;\r | |
292 | UINTN Index;\r | |
293 | UINT32 Count;\r | |
294 | XENSTORE_STATUS Status;\r | |
295 | \r | |
296 | Status = XenStoreListDirectory (XST_NIL,\r | |
297 | "device", "",\r | |
298 | &Count, &Types);\r | |
299 | if (Status != XENSTORE_STATUS_SUCCESS) {\r | |
300 | return Status;\r | |
301 | }\r | |
302 | \r | |
303 | for (Index = 0; Index < Count; Index++) {\r | |
304 | XenBusEnumerateDeviceType (Dev, Types[Index]);\r | |
305 | }\r | |
306 | \r | |
307 | FreePool (Types);\r | |
308 | \r | |
309 | return XENSTORE_STATUS_SUCCESS;\r | |
310 | }\r | |
311 | \r | |
312 | STATIC\r | |
313 | XENSTORE_STATUS\r | |
314 | EFIAPI\r | |
315 | XenBusSetState (\r | |
316 | IN XENBUS_PROTOCOL *This,\r | |
e26a83cd | 317 | IN CONST XENSTORE_TRANSACTION *Transaction,\r |
86d968e0 AP |
318 | IN enum xenbus_state NewState\r |
319 | )\r | |
320 | {\r | |
321 | enum xenbus_state CurrentState;\r | |
322 | XENSTORE_STATUS Status;\r | |
323 | CHAR8 *Temp;\r | |
324 | \r | |
325 | DEBUG ((EFI_D_INFO, "XenBus: Set state to %d\n", NewState));\r | |
326 | \r | |
327 | Status = XenStoreRead (Transaction, This->Node, "state", NULL, (VOID **)&Temp);\r | |
328 | if (Status != XENSTORE_STATUS_SUCCESS) {\r | |
329 | goto Out;\r | |
330 | }\r | |
331 | CurrentState = AsciiStrDecimalToUintn (Temp);\r | |
332 | FreePool (Temp);\r | |
333 | if (CurrentState == NewState) {\r | |
334 | goto Out;\r | |
335 | }\r | |
336 | \r | |
337 | do {\r | |
338 | Status = XenStoreSPrint (Transaction, This->Node, "state", "%d", NewState);\r | |
339 | } while (Status == XENSTORE_STATUS_EAGAIN);\r | |
340 | if (Status != XENSTORE_STATUS_SUCCESS) {\r | |
341 | DEBUG ((EFI_D_ERROR, "XenBus: failed to write new state\n"));\r | |
342 | goto Out;\r | |
343 | }\r | |
344 | DEBUG ((EFI_D_INFO, "XenBus: Set state to %d, done\n", NewState));\r | |
345 | \r | |
346 | Out:\r | |
347 | return Status;\r | |
348 | }\r | |
349 | \r | |
350 | STATIC XENBUS_PRIVATE_DATA gXenBusPrivateData = {\r | |
351 | .Signature = XENBUS_PRIVATE_DATA_SIGNATURE,\r | |
352 | \r | |
353 | .XenBusIo.XsRead = XenBusXenStoreRead,\r | |
354 | .XenBusIo.XsBackendRead = XenBusXenStoreBackendRead,\r | |
355 | .XenBusIo.XsPrintf = XenBusXenStoreSPrint,\r | |
356 | .XenBusIo.XsRemove = XenBusXenStoreRemove,\r | |
357 | .XenBusIo.XsTransactionStart = XenBusXenStoreTransactionStart,\r | |
358 | .XenBusIo.XsTransactionEnd = XenBusXenStoreTransactionEnd,\r | |
359 | .XenBusIo.SetState = XenBusSetState,\r | |
360 | .XenBusIo.GrantAccess = XenBusGrantAccess,\r | |
361 | .XenBusIo.GrantEndAccess = XenBusGrantEndAccess,\r | |
e86895d9 AP |
362 | .XenBusIo.EventChannelAllocate = XenBusEventChannelAllocate,\r |
363 | .XenBusIo.EventChannelNotify = XenBusEventChannelNotify,\r | |
364 | .XenBusIo.EventChannelClose = XenBusEventChannelClose,\r | |
86d968e0 AP |
365 | .XenBusIo.RegisterWatch = XenBusRegisterWatch,\r |
366 | .XenBusIo.RegisterWatchBackend = XenBusRegisterWatchBackend,\r | |
367 | .XenBusIo.UnregisterWatch = XenBusUnregisterWatch,\r | |
368 | .XenBusIo.WaitForWatch = XenBusWaitForWatch,\r | |
369 | \r | |
370 | .XenBusIo.Type = NULL,\r | |
371 | .XenBusIo.Node = NULL,\r | |
372 | .XenBusIo.Backend = NULL,\r | |
373 | \r | |
374 | .Dev = NULL\r | |
375 | };\r |