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