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 45 STATIC XENBUS_PRIVATE_DATA gXenBusPrivateData; 46 47 STATIC 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 */ 73 STATIC 74 XENBUS_PRIVATE_DATA * 75 XenBusDeviceInitialized ( 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 102 STATIC 103 XenbusState 104 XenBusReadDriverState ( 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 // 129 STATIC 130 EFI_STATUS 131 XenBusAddDevice ( 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 227 ErrorOpenProtocolByChild: 228 gBS->UninstallMultipleProtocolInterfaces ( 229 &Private->Handle, 230 &gEfiDevicePathProtocolGuid, Private->DevicePath, 231 &gXenBusProtocolGuid, &Private->XenBusIo, 232 NULL); 233 ErrorInstallProtocol: 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); 240 out: 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 */ 255 STATIC 256 VOID 257 XenBusEnumerateDeviceType ( 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 */ 292 XENSTORE_STATUS 293 XenBusEnumerateBus ( 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 318 STATIC 319 XENSTORE_STATUS 320 EFIAPI 321 XenBusSetState ( 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 352 Out: 353 return Status; 354 } 355 356 STATIC 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