Home | History | Annotate | Download | only in VirtioScsiDxe
      1 /** @file
      2 
      3   This driver produces Extended SCSI Pass Thru Protocol instances for
      4   virtio-scsi devices.
      5 
      6   The implementation is basic:
      7 
      8   - No hotplug / hot-unplug.
      9 
     10   - Although EFI_EXT_SCSI_PASS_THRU_PROTOCOL.PassThru() could be a good match
     11     for multiple in-flight virtio-scsi requests, we stick to synchronous
     12     requests for now.
     13 
     14   - Timeouts are not supported for EFI_EXT_SCSI_PASS_THRU_PROTOCOL.PassThru().
     15 
     16   - Only one channel is supported. (At the time of this writing, host-side
     17     virtio-scsi supports a single channel too.)
     18 
     19   - Only one request queue is used (for the one synchronous request).
     20 
     21   - The ResetChannel() and ResetTargetLun() functions of
     22     EFI_EXT_SCSI_PASS_THRU_PROTOCOL are not supported (which is allowed by the
     23     UEFI 2.3.1 Errata C specification), although
     24     VIRTIO_SCSI_T_TMF_LOGICAL_UNIT_RESET could be a good match. That would
     25     however require client code for the control queue, which is deemed
     26     unreasonable for now.
     27 
     28   Copyright (C) 2012, Red Hat, Inc.
     29   Copyright (c) 2012 - 2014, Intel Corporation. All rights reserved.<BR>
     30 
     31   This program and the accompanying materials are licensed and made available
     32   under the terms and conditions of the BSD License which accompanies this
     33   distribution. The full text of the license may be found at
     34   http://opensource.org/licenses/bsd-license.php
     35 
     36   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT
     37   WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     38 
     39 **/
     40 
     41 #include <IndustryStandard/VirtioScsi.h>
     42 #include <Library/BaseMemoryLib.h>
     43 #include <Library/DebugLib.h>
     44 #include <Library/MemoryAllocationLib.h>
     45 #include <Library/UefiBootServicesTableLib.h>
     46 #include <Library/UefiLib.h>
     47 #include <Library/VirtioLib.h>
     48 
     49 #include "VirtioScsi.h"
     50 
     51 /**
     52 
     53   Convenience macros to read and write configuration elements of the
     54   virtio-scsi VirtIo device.
     55 
     56   The following macros make it possible to specify only the "core parameters"
     57   for such accesses and to derive the rest. By the time VIRTIO_CFG_WRITE()
     58   returns, the transaction will have been completed.
     59 
     60   @param[in] Dev       Pointer to the VSCSI_DEV structure.
     61 
     62   @param[in] Field     A field name from VSCSI_HDR, identifying the virtio-scsi
     63                        configuration item to access.
     64 
     65   @param[in] Value     (VIRTIO_CFG_WRITE() only.) The value to write to the
     66                        selected configuration item.
     67 
     68   @param[out] Pointer  (VIRTIO_CFG_READ() only.) The object to receive the
     69                        value read from the configuration item. Its type must be
     70                        one of UINT8, UINT16, UINT32, UINT64.
     71 
     72 
     73   @return  Status codes returned by Virtio->WriteDevice() / Virtio->ReadDevice().
     74 
     75 **/
     76 
     77 #define VIRTIO_CFG_WRITE(Dev, Field, Value)  ((Dev)->VirtIo->WriteDevice (  \
     78                                                 (Dev)->VirtIo,              \
     79                                                 OFFSET_OF_VSCSI (Field),    \
     80                                                 SIZE_OF_VSCSI (Field),      \
     81                                                 (Value)                     \
     82                                                 ))
     83 
     84 #define VIRTIO_CFG_READ(Dev, Field, Pointer) ((Dev)->VirtIo->ReadDevice (   \
     85                                                 (Dev)->VirtIo,              \
     86                                                 OFFSET_OF_VSCSI (Field),    \
     87                                                 SIZE_OF_VSCSI (Field),      \
     88                                                 sizeof *(Pointer),          \
     89                                                 (Pointer)                   \
     90                                                 ))
     91 
     92 
     93 //
     94 // UEFI Spec 2.3.1 + Errata C, 14.7 Extended SCSI Pass Thru Protocol specifies
     95 // the PassThru() interface. Beside returning a status code, the function must
     96 // set some fields in the EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET in/out
     97 // parameter on return. The following is a full list of those fields, for
     98 // easier validation of PopulateRequest(), ParseResponse(), and
     99 // VirtioScsiPassThru() below.
    100 //
    101 // - InTransferLength
    102 // - OutTransferLength
    103 // - HostAdapterStatus
    104 // - TargetStatus
    105 // - SenseDataLength
    106 // - SenseData
    107 //
    108 // On any return from the PassThru() interface, these fields must be set,
    109 // except if the returned status code is explicitly exempt. (Actually the
    110 // implementation here conservatively sets these fields even in case not all
    111 // of them would be required by the specification.)
    112 //
    113 
    114 /**
    115 
    116   Populate a virtio-scsi request from the Extended SCSI Pass Thru Protocol
    117   packet.
    118 
    119   The caller is responsible for pre-zeroing the virtio-scsi request. The
    120   Extended SCSI Pass Thru Protocol packet is modified, to be forwarded outwards
    121   by VirtioScsiPassThru(), if invalid or unsupported parameters are detected.
    122 
    123   @param[in] Dev          The virtio-scsi host device the packet targets.
    124 
    125   @param[in] Target       The SCSI target controlled by the virtio-scsi host
    126                           device.
    127 
    128   @param[in] Lun          The Logical Unit Number under the SCSI target.
    129 
    130   @param[in out] Packet   The Extended SCSI Pass Thru Protocol packet the
    131                           function translates to a virtio-scsi request. On
    132                           failure this parameter relays error contents.
    133 
    134   @param[out]    Request  The pre-zeroed virtio-scsi request to populate. This
    135                           parameter is volatile-qualified because we expect the
    136                           caller to append it to a virtio ring, thus
    137                           assignments to Request must be visible when the
    138                           function returns.
    139 
    140 
    141   @retval EFI_SUCCESS  The Extended SCSI Pass Thru Protocol packet was valid,
    142                        Request has been populated.
    143 
    144   @return              Otherwise, invalid or unsupported parameters were
    145                        detected. Status codes are meant for direct forwarding
    146                        by the EFI_EXT_SCSI_PASS_THRU_PROTOCOL.PassThru()
    147                        implementation.
    148 
    149 **/
    150 STATIC
    151 EFI_STATUS
    152 EFIAPI
    153 PopulateRequest (
    154   IN     CONST    VSCSI_DEV                                   *Dev,
    155   IN              UINT16                                      Target,
    156   IN              UINT64                                      Lun,
    157   IN OUT          EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET  *Packet,
    158   OUT    volatile VIRTIO_SCSI_REQ                             *Request
    159   )
    160 {
    161   UINTN Idx;
    162 
    163   if (
    164       //
    165       // bidirectional transfer was requested, but the host doesn't support it
    166       //
    167       (Packet->InTransferLength > 0 && Packet->OutTransferLength > 0 &&
    168        !Dev->InOutSupported) ||
    169 
    170       //
    171       // a target / LUN was addressed that's impossible to encode for the host
    172       //
    173       Target > 0xFF || Lun >= 0x4000 ||
    174 
    175       //
    176       // Command Descriptor Block bigger than VIRTIO_SCSI_CDB_SIZE
    177       //
    178       Packet->CdbLength > VIRTIO_SCSI_CDB_SIZE ||
    179 
    180       //
    181       // From virtio-0.9.5, 2.3.2 Descriptor Table:
    182       // "no descriptor chain may be more than 2^32 bytes long in total".
    183       //
    184       (UINT64) Packet->InTransferLength + Packet->OutTransferLength > SIZE_1GB
    185       ) {
    186 
    187     //
    188     // this error code doesn't require updates to the Packet output fields
    189     //
    190     return EFI_UNSUPPORTED;
    191   }
    192 
    193   if (
    194       //
    195       // addressed invalid device
    196       //
    197       Target > Dev->MaxTarget || Lun > Dev->MaxLun ||
    198 
    199       //
    200       // invalid direction (there doesn't seem to be a macro for the "no data
    201       // transferred" "direction", eg. for TEST UNIT READY)
    202       //
    203       Packet->DataDirection > EFI_EXT_SCSI_DATA_DIRECTION_BIDIRECTIONAL ||
    204 
    205       //
    206       // trying to receive, but destination pointer is NULL, or contradicting
    207       // transfer direction
    208       //
    209       (Packet->InTransferLength > 0 &&
    210        (Packet->InDataBuffer == NULL ||
    211         Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_WRITE
    212         )
    213        ) ||
    214 
    215       //
    216       // trying to send, but source pointer is NULL, or contradicting transfer
    217       // direction
    218       //
    219       (Packet->OutTransferLength > 0 &&
    220        (Packet->OutDataBuffer == NULL ||
    221         Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_READ
    222         )
    223        )
    224       ) {
    225 
    226     //
    227     // this error code doesn't require updates to the Packet output fields
    228     //
    229     return EFI_INVALID_PARAMETER;
    230   }
    231 
    232   //
    233   // Catch oversized requests eagerly. If this condition evaluates to false,
    234   // then the combined size of a bidirectional request will not exceed the
    235   // virtio-scsi device's transfer limit either.
    236   //
    237   if (ALIGN_VALUE (Packet->OutTransferLength, 512) / 512
    238         > Dev->MaxSectors / 2 ||
    239       ALIGN_VALUE (Packet->InTransferLength,  512) / 512
    240         > Dev->MaxSectors / 2) {
    241     Packet->InTransferLength  = (Dev->MaxSectors / 2) * 512;
    242     Packet->OutTransferLength = (Dev->MaxSectors / 2) * 512;
    243     Packet->HostAdapterStatus =
    244                         EFI_EXT_SCSI_STATUS_HOST_ADAPTER_DATA_OVERRUN_UNDERRUN;
    245     Packet->TargetStatus      = EFI_EXT_SCSI_STATUS_TARGET_GOOD;
    246     Packet->SenseDataLength   = 0;
    247     return EFI_BAD_BUFFER_SIZE;
    248   }
    249 
    250   //
    251   // target & LUN encoding: see virtio-0.9.5, Appendix I: SCSI Host Device,
    252   // Device Operation: request queues
    253   //
    254   Request->Lun[0] = 1;
    255   Request->Lun[1] = (UINT8) Target;
    256   Request->Lun[2] = (UINT8) (((UINT32)Lun >> 8) | 0x40);
    257   Request->Lun[3] = (UINT8) Lun;
    258 
    259   //
    260   // CopyMem() would cast away the "volatile" qualifier before access, which is
    261   // undefined behavior (ISO C99 6.7.3p5)
    262   //
    263   for (Idx = 0; Idx < Packet->CdbLength; ++Idx) {
    264     Request->Cdb[Idx] = ((UINT8 *) Packet->Cdb)[Idx];
    265   }
    266 
    267   return EFI_SUCCESS;
    268 }
    269 
    270 
    271 /**
    272 
    273   Parse the virtio-scsi device's response, translate it to an EFI status code,
    274   and update the Extended SCSI Pass Thru Protocol packet, to be returned by
    275   the EFI_EXT_SCSI_PASS_THRU_PROTOCOL.PassThru() implementation.
    276 
    277   @param[in out] Packet  The Extended SCSI Pass Thru Protocol packet that has
    278                          been translated to a virtio-scsi request with
    279                          PopulateRequest(), and processed by the host. On
    280                          output this parameter is updated with response or
    281                          error contents.
    282 
    283   @param[in] Response    The virtio-scsi response structure to parse. We expect
    284                          it to come from a virtio ring, thus it is qualified
    285                          volatile.
    286 
    287 
    288   @return  PassThru() status codes mandated by UEFI Spec 2.3.1 + Errata C, 14.7
    289            Extended SCSI Pass Thru Protocol.
    290 
    291 **/
    292 STATIC
    293 EFI_STATUS
    294 EFIAPI
    295 ParseResponse (
    296   IN OUT                EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet,
    297   IN     CONST volatile VIRTIO_SCSI_RESP                           *Response
    298   )
    299 {
    300   UINTN ResponseSenseLen;
    301   UINTN Idx;
    302 
    303   //
    304   // return sense data (length and contents) in all cases, truncated if needed
    305   //
    306   ResponseSenseLen = MIN (Response->SenseLen, VIRTIO_SCSI_SENSE_SIZE);
    307   if (Packet->SenseDataLength > ResponseSenseLen) {
    308     Packet->SenseDataLength = (UINT8) ResponseSenseLen;
    309   }
    310   for (Idx = 0; Idx < Packet->SenseDataLength; ++Idx) {
    311     ((UINT8 *) Packet->SenseData)[Idx] = Response->Sense[Idx];
    312   }
    313 
    314   //
    315   // Report actual transfer lengths. The logic below covers all three
    316   // DataDirections (read, write, bidirectional).
    317   //
    318   // -+- @ 0
    319   //  |
    320   //  | write                                       ^  @ Residual (unprocessed)
    321   //  |                                             |
    322   // -+- @ OutTransferLength                       -+- @ InTransferLength
    323   //  |                                             |
    324   //  | read                                        |
    325   //  |                                             |
    326   //  V  @ OutTransferLength + InTransferLength    -+- @ 0
    327   //
    328   if (Response->Residual <= Packet->InTransferLength) {
    329     Packet->InTransferLength  -= Response->Residual;
    330   }
    331   else {
    332     Packet->OutTransferLength -= Response->Residual - Packet->InTransferLength;
    333     Packet->InTransferLength   = 0;
    334   }
    335 
    336   //
    337   // report target status in all cases
    338   //
    339   Packet->TargetStatus = Response->Status;
    340 
    341   //
    342   // host adapter status and function return value depend on virtio-scsi
    343   // response code
    344   //
    345   switch (Response->Response) {
    346   case VIRTIO_SCSI_S_OK:
    347     Packet->HostAdapterStatus = EFI_EXT_SCSI_STATUS_HOST_ADAPTER_OK;
    348     return EFI_SUCCESS;
    349 
    350   case VIRTIO_SCSI_S_OVERRUN:
    351     Packet->HostAdapterStatus =
    352                         EFI_EXT_SCSI_STATUS_HOST_ADAPTER_DATA_OVERRUN_UNDERRUN;
    353     break;
    354 
    355   case VIRTIO_SCSI_S_BAD_TARGET:
    356     //
    357     // This is non-intuitive but explicitly required by the
    358     // EFI_EXT_SCSI_PASS_THRU_PROTOCOL.PassThru() specification for
    359     // disconnected (but otherwise valid) target / LUN addresses.
    360     //
    361     Packet->HostAdapterStatus =
    362                               EFI_EXT_SCSI_STATUS_HOST_ADAPTER_TIMEOUT_COMMAND;
    363     return EFI_TIMEOUT;
    364 
    365   case VIRTIO_SCSI_S_RESET:
    366     Packet->HostAdapterStatus = EFI_EXT_SCSI_STATUS_HOST_ADAPTER_BUS_RESET;
    367     break;
    368 
    369   case VIRTIO_SCSI_S_BUSY:
    370     Packet->HostAdapterStatus = EFI_EXT_SCSI_STATUS_HOST_ADAPTER_OK;
    371     return EFI_NOT_READY;
    372 
    373   //
    374   // Lump together the rest. The mapping for VIRTIO_SCSI_S_ABORTED is
    375   // intentional as well, not an oversight.
    376   //
    377   case VIRTIO_SCSI_S_ABORTED:
    378   case VIRTIO_SCSI_S_TRANSPORT_FAILURE:
    379   case VIRTIO_SCSI_S_TARGET_FAILURE:
    380   case VIRTIO_SCSI_S_NEXUS_FAILURE:
    381   case VIRTIO_SCSI_S_FAILURE:
    382   default:
    383     Packet->HostAdapterStatus = EFI_EXT_SCSI_STATUS_HOST_ADAPTER_OTHER;
    384   }
    385 
    386   return EFI_DEVICE_ERROR;
    387 }
    388 
    389 
    390 //
    391 // The next seven functions implement EFI_EXT_SCSI_PASS_THRU_PROTOCOL
    392 // for the virtio-scsi HBA. Refer to UEFI Spec 2.3.1 + Errata C, sections
    393 // - 14.1 SCSI Driver Model Overview,
    394 // - 14.7 Extended SCSI Pass Thru Protocol.
    395 //
    396 
    397 EFI_STATUS
    398 EFIAPI
    399 VirtioScsiPassThru (
    400   IN     EFI_EXT_SCSI_PASS_THRU_PROTOCOL            *This,
    401   IN     UINT8                                      *Target,
    402   IN     UINT64                                     Lun,
    403   IN OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet,
    404   IN     EFI_EVENT                                  Event   OPTIONAL
    405   )
    406 {
    407   VSCSI_DEV                 *Dev;
    408   UINT16                    TargetValue;
    409   EFI_STATUS                Status;
    410   volatile VIRTIO_SCSI_REQ  Request;
    411   volatile VIRTIO_SCSI_RESP Response;
    412   DESC_INDICES              Indices;
    413 
    414   ZeroMem ((VOID*) &Request, sizeof (Request));
    415   ZeroMem ((VOID*) &Response, sizeof (Response));
    416 
    417   Dev = VIRTIO_SCSI_FROM_PASS_THRU (This);
    418   CopyMem (&TargetValue, Target, sizeof TargetValue);
    419 
    420   Status = PopulateRequest (Dev, TargetValue, Lun, Packet, &Request);
    421   if (EFI_ERROR (Status)) {
    422     return Status;
    423   }
    424 
    425   VirtioPrepare (&Dev->Ring, &Indices);
    426 
    427   //
    428   // preset a host status for ourselves that we do not accept as success
    429   //
    430   Response.Response = VIRTIO_SCSI_S_FAILURE;
    431 
    432   //
    433   // ensured by VirtioScsiInit() -- this predicate, in combination with the
    434   // lock-step progress, ensures we don't have to track free descriptors.
    435   //
    436   ASSERT (Dev->Ring.QueueSize >= 4);
    437 
    438   //
    439   // enqueue Request
    440   //
    441   VirtioAppendDesc (&Dev->Ring, (UINTN) &Request, sizeof Request,
    442     VRING_DESC_F_NEXT, &Indices);
    443 
    444   //
    445   // enqueue "dataout" if any
    446   //
    447   if (Packet->OutTransferLength > 0) {
    448     VirtioAppendDesc (&Dev->Ring, (UINTN) Packet->OutDataBuffer,
    449       Packet->OutTransferLength, VRING_DESC_F_NEXT, &Indices);
    450   }
    451 
    452   //
    453   // enqueue Response, to be written by the host
    454   //
    455   VirtioAppendDesc (&Dev->Ring, (UINTN) &Response, sizeof Response,
    456     VRING_DESC_F_WRITE | (Packet->InTransferLength > 0 ?
    457                           VRING_DESC_F_NEXT : 0),
    458     &Indices);
    459 
    460   //
    461   // enqueue "datain" if any, to be written by the host
    462   //
    463   if (Packet->InTransferLength > 0) {
    464     VirtioAppendDesc (&Dev->Ring, (UINTN) Packet->InDataBuffer,
    465       Packet->InTransferLength, VRING_DESC_F_WRITE, &Indices);
    466   }
    467 
    468   // If kicking the host fails, we must fake a host adapter error.
    469   // EFI_NOT_READY would save us the effort, but it would also suggest that the
    470   // caller retry.
    471   //
    472   if (VirtioFlush (Dev->VirtIo, VIRTIO_SCSI_REQUEST_QUEUE, &Dev->Ring,
    473         &Indices, NULL) != EFI_SUCCESS) {
    474     Packet->InTransferLength  = 0;
    475     Packet->OutTransferLength = 0;
    476     Packet->HostAdapterStatus = EFI_EXT_SCSI_STATUS_HOST_ADAPTER_OTHER;
    477     Packet->TargetStatus      = EFI_EXT_SCSI_STATUS_TARGET_GOOD;
    478     Packet->SenseDataLength   = 0;
    479     return EFI_DEVICE_ERROR;
    480   }
    481 
    482   return ParseResponse (Packet, &Response);
    483 }
    484 
    485 
    486 EFI_STATUS
    487 EFIAPI
    488 VirtioScsiGetNextTargetLun (
    489   IN     EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,
    490   IN OUT UINT8                           **TargetPointer,
    491   IN OUT UINT64                          *Lun
    492   )
    493 {
    494   UINT8     *Target;
    495   UINTN     Idx;
    496   UINT16    LastTarget;
    497   VSCSI_DEV *Dev;
    498 
    499   //
    500   // the TargetPointer input parameter is unnecessarily a pointer-to-pointer
    501   //
    502   Target = *TargetPointer;
    503 
    504   //
    505   // Search for first non-0xFF byte. If not found, return first target & LUN.
    506   //
    507   for (Idx = 0; Idx < TARGET_MAX_BYTES && Target[Idx] == 0xFF; ++Idx)
    508     ;
    509   if (Idx == TARGET_MAX_BYTES) {
    510     SetMem (Target, TARGET_MAX_BYTES, 0x00);
    511     *Lun = 0;
    512     return EFI_SUCCESS;
    513   }
    514 
    515   //
    516   // see the TARGET_MAX_BYTES check in "VirtioScsi.h"
    517   //
    518   CopyMem (&LastTarget, Target, sizeof LastTarget);
    519 
    520   //
    521   // increment (target, LUN) pair if valid on input
    522   //
    523   Dev = VIRTIO_SCSI_FROM_PASS_THRU (This);
    524   if (LastTarget > Dev->MaxTarget || *Lun > Dev->MaxLun) {
    525     return EFI_INVALID_PARAMETER;
    526   }
    527 
    528   if (*Lun < Dev->MaxLun) {
    529     ++*Lun;
    530     return EFI_SUCCESS;
    531   }
    532 
    533   if (LastTarget < Dev->MaxTarget) {
    534     *Lun = 0;
    535     ++LastTarget;
    536     CopyMem (Target, &LastTarget, sizeof LastTarget);
    537     return EFI_SUCCESS;
    538   }
    539 
    540   return EFI_NOT_FOUND;
    541 }
    542 
    543 
    544 EFI_STATUS
    545 EFIAPI
    546 VirtioScsiBuildDevicePath (
    547   IN     EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,
    548   IN     UINT8                           *Target,
    549   IN     UINT64                          Lun,
    550   IN OUT EFI_DEVICE_PATH_PROTOCOL        **DevicePath
    551   )
    552 {
    553   UINT16           TargetValue;
    554   VSCSI_DEV        *Dev;
    555   SCSI_DEVICE_PATH *ScsiDevicePath;
    556 
    557   if (DevicePath == NULL) {
    558     return EFI_INVALID_PARAMETER;
    559   }
    560 
    561   CopyMem (&TargetValue, Target, sizeof TargetValue);
    562   Dev = VIRTIO_SCSI_FROM_PASS_THRU (This);
    563   if (TargetValue > Dev->MaxTarget || Lun > Dev->MaxLun || Lun > 0xFFFF) {
    564     return EFI_NOT_FOUND;
    565   }
    566 
    567   ScsiDevicePath = AllocatePool (sizeof *ScsiDevicePath);
    568   if (ScsiDevicePath == NULL) {
    569     return EFI_OUT_OF_RESOURCES;
    570   }
    571 
    572   ScsiDevicePath->Header.Type      = MESSAGING_DEVICE_PATH;
    573   ScsiDevicePath->Header.SubType   = MSG_SCSI_DP;
    574   ScsiDevicePath->Header.Length[0] = (UINT8)  sizeof *ScsiDevicePath;
    575   ScsiDevicePath->Header.Length[1] = (UINT8) (sizeof *ScsiDevicePath >> 8);
    576   ScsiDevicePath->Pun              = TargetValue;
    577   ScsiDevicePath->Lun              = (UINT16) Lun;
    578 
    579   *DevicePath = &ScsiDevicePath->Header;
    580   return EFI_SUCCESS;
    581 }
    582 
    583 
    584 EFI_STATUS
    585 EFIAPI
    586 VirtioScsiGetTargetLun (
    587   IN  EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,
    588   IN  EFI_DEVICE_PATH_PROTOCOL        *DevicePath,
    589   OUT UINT8                           **TargetPointer,
    590   OUT UINT64                          *Lun
    591   )
    592 {
    593   SCSI_DEVICE_PATH *ScsiDevicePath;
    594   VSCSI_DEV        *Dev;
    595   UINT8            *Target;
    596 
    597   if (DevicePath == NULL || TargetPointer == NULL || *TargetPointer == NULL ||
    598       Lun == NULL) {
    599     return EFI_INVALID_PARAMETER;
    600   }
    601 
    602   if (DevicePath->Type    != MESSAGING_DEVICE_PATH ||
    603       DevicePath->SubType != MSG_SCSI_DP) {
    604     return EFI_UNSUPPORTED;
    605   }
    606 
    607   ScsiDevicePath = (SCSI_DEVICE_PATH *) DevicePath;
    608   Dev = VIRTIO_SCSI_FROM_PASS_THRU (This);
    609   if (ScsiDevicePath->Pun > Dev->MaxTarget ||
    610       ScsiDevicePath->Lun > Dev->MaxLun) {
    611     return EFI_NOT_FOUND;
    612   }
    613 
    614   //
    615   // a) the TargetPointer input parameter is unnecessarily a pointer-to-pointer
    616   // b) see the TARGET_MAX_BYTES check in "VirtioScsi.h"
    617   // c) ScsiDevicePath->Pun is an UINT16
    618   //
    619   Target = *TargetPointer;
    620   CopyMem (Target, &ScsiDevicePath->Pun, 2);
    621   SetMem (Target + 2, TARGET_MAX_BYTES - 2, 0x00);
    622 
    623   *Lun = ScsiDevicePath->Lun;
    624   return EFI_SUCCESS;
    625 }
    626 
    627 
    628 EFI_STATUS
    629 EFIAPI
    630 VirtioScsiResetChannel (
    631   IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This
    632   )
    633 {
    634   return EFI_UNSUPPORTED;
    635 }
    636 
    637 
    638 EFI_STATUS
    639 EFIAPI
    640 VirtioScsiResetTargetLun (
    641   IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,
    642   IN UINT8                           *Target,
    643   IN UINT64                          Lun
    644   )
    645 {
    646   return EFI_UNSUPPORTED;
    647 }
    648 
    649 
    650 EFI_STATUS
    651 EFIAPI
    652 VirtioScsiGetNextTarget (
    653   IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,
    654   IN OUT UINT8                       **TargetPointer
    655   )
    656 {
    657   UINT8     *Target;
    658   UINTN     Idx;
    659   UINT16    LastTarget;
    660   VSCSI_DEV *Dev;
    661 
    662   //
    663   // the TargetPointer input parameter is unnecessarily a pointer-to-pointer
    664   //
    665   Target = *TargetPointer;
    666 
    667   //
    668   // Search for first non-0xFF byte. If not found, return first target.
    669   //
    670   for (Idx = 0; Idx < TARGET_MAX_BYTES && Target[Idx] == 0xFF; ++Idx)
    671     ;
    672   if (Idx == TARGET_MAX_BYTES) {
    673     SetMem (Target, TARGET_MAX_BYTES, 0x00);
    674     return EFI_SUCCESS;
    675   }
    676 
    677   //
    678   // see the TARGET_MAX_BYTES check in "VirtioScsi.h"
    679   //
    680   CopyMem (&LastTarget, Target, sizeof LastTarget);
    681 
    682   //
    683   // increment target if valid on input
    684   //
    685   Dev = VIRTIO_SCSI_FROM_PASS_THRU (This);
    686   if (LastTarget > Dev->MaxTarget) {
    687     return EFI_INVALID_PARAMETER;
    688   }
    689 
    690   if (LastTarget < Dev->MaxTarget) {
    691     ++LastTarget;
    692     CopyMem (Target, &LastTarget, sizeof LastTarget);
    693     return EFI_SUCCESS;
    694   }
    695 
    696   return EFI_NOT_FOUND;
    697 }
    698 
    699 
    700 STATIC
    701 EFI_STATUS
    702 EFIAPI
    703 VirtioScsiInit (
    704   IN OUT VSCSI_DEV *Dev
    705   )
    706 {
    707   UINT8      NextDevStat;
    708   EFI_STATUS Status;
    709 
    710   UINT64     Features;
    711   UINT16     MaxChannel; // for validation only
    712   UINT32     NumQueues;  // for validation only
    713   UINT16     QueueSize;
    714 
    715   //
    716   // Execute virtio-0.9.5, 2.2.1 Device Initialization Sequence.
    717   //
    718   NextDevStat = 0;             // step 1 -- reset device
    719   Status = Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, NextDevStat);
    720   if (EFI_ERROR (Status)) {
    721     goto Failed;
    722   }
    723 
    724   NextDevStat |= VSTAT_ACK;    // step 2 -- acknowledge device presence
    725   Status = Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, NextDevStat);
    726   if (EFI_ERROR (Status)) {
    727     goto Failed;
    728   }
    729 
    730   NextDevStat |= VSTAT_DRIVER; // step 3 -- we know how to drive it
    731   Status = Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, NextDevStat);
    732   if (EFI_ERROR (Status)) {
    733     goto Failed;
    734   }
    735 
    736   //
    737   // Set Page Size - MMIO VirtIo Specific
    738   //
    739   Status = Dev->VirtIo->SetPageSize (Dev->VirtIo, EFI_PAGE_SIZE);
    740   if (EFI_ERROR (Status)) {
    741     goto Failed;
    742   }
    743 
    744   //
    745   // step 4a -- retrieve and validate features
    746   //
    747   Status = Dev->VirtIo->GetDeviceFeatures (Dev->VirtIo, &Features);
    748   if (EFI_ERROR (Status)) {
    749     goto Failed;
    750   }
    751   Dev->InOutSupported = (BOOLEAN) ((Features & VIRTIO_SCSI_F_INOUT) != 0);
    752 
    753   Status = VIRTIO_CFG_READ (Dev, MaxChannel, &MaxChannel);
    754   if (EFI_ERROR (Status)) {
    755     goto Failed;
    756   }
    757   if (MaxChannel != 0) {
    758     //
    759     // this driver is for a single-channel virtio-scsi HBA
    760     //
    761     Status = EFI_UNSUPPORTED;
    762     goto Failed;
    763   }
    764 
    765   Status = VIRTIO_CFG_READ (Dev, NumQueues, &NumQueues);
    766   if (EFI_ERROR (Status)) {
    767     goto Failed;
    768   }
    769   if (NumQueues < 1) {
    770     Status = EFI_UNSUPPORTED;
    771     goto Failed;
    772   }
    773 
    774   Status = VIRTIO_CFG_READ (Dev, MaxTarget, &Dev->MaxTarget);
    775   if (EFI_ERROR (Status)) {
    776     goto Failed;
    777   }
    778   if (Dev->MaxTarget > PcdGet16 (PcdVirtioScsiMaxTargetLimit)) {
    779     Dev->MaxTarget = PcdGet16 (PcdVirtioScsiMaxTargetLimit);
    780   }
    781 
    782   Status = VIRTIO_CFG_READ (Dev, MaxLun, &Dev->MaxLun);
    783   if (EFI_ERROR (Status)) {
    784     goto Failed;
    785   }
    786   if (Dev->MaxLun > PcdGet32 (PcdVirtioScsiMaxLunLimit)) {
    787     Dev->MaxLun = PcdGet32 (PcdVirtioScsiMaxLunLimit);
    788   }
    789 
    790   Status = VIRTIO_CFG_READ (Dev, MaxSectors, &Dev->MaxSectors);
    791   if (EFI_ERROR (Status)) {
    792     goto Failed;
    793   }
    794   if (Dev->MaxSectors < 2) {
    795     //
    796     // We must be able to halve it for bidirectional transfers
    797     // (see EFI_BAD_BUFFER_SIZE in PopulateRequest()).
    798     //
    799     Status = EFI_UNSUPPORTED;
    800     goto Failed;
    801   }
    802 
    803   Features &= VIRTIO_SCSI_F_INOUT | VIRTIO_F_VERSION_1;
    804 
    805   //
    806   // In virtio-1.0, feature negotiation is expected to complete before queue
    807   // discovery, and the device can also reject the selected set of features.
    808   //
    809   if (Dev->VirtIo->Revision >= VIRTIO_SPEC_REVISION (1, 0, 0)) {
    810     Status = Virtio10WriteFeatures (Dev->VirtIo, Features, &NextDevStat);
    811     if (EFI_ERROR (Status)) {
    812       goto Failed;
    813     }
    814   }
    815 
    816   //
    817   // step 4b -- allocate request virtqueue
    818   //
    819   Status = Dev->VirtIo->SetQueueSel (Dev->VirtIo, VIRTIO_SCSI_REQUEST_QUEUE);
    820   if (EFI_ERROR (Status)) {
    821     goto Failed;
    822   }
    823   Status = Dev->VirtIo->GetQueueNumMax (Dev->VirtIo, &QueueSize);
    824   if (EFI_ERROR (Status)) {
    825     goto Failed;
    826   }
    827   //
    828   // VirtioScsiPassThru() uses at most four descriptors
    829   //
    830   if (QueueSize < 4) {
    831     Status = EFI_UNSUPPORTED;
    832     goto Failed;
    833   }
    834 
    835   Status = VirtioRingInit (QueueSize, &Dev->Ring);
    836   if (EFI_ERROR (Status)) {
    837     goto Failed;
    838   }
    839 
    840   //
    841   // Additional steps for MMIO: align the queue appropriately, and set the
    842   // size. If anything fails from here on, we must release the ring resources.
    843   //
    844   Status = Dev->VirtIo->SetQueueNum (Dev->VirtIo, QueueSize);
    845   if (EFI_ERROR (Status)) {
    846     goto ReleaseQueue;
    847   }
    848 
    849   Status = Dev->VirtIo->SetQueueAlign (Dev->VirtIo, EFI_PAGE_SIZE);
    850   if (EFI_ERROR (Status)) {
    851     goto ReleaseQueue;
    852   }
    853 
    854   //
    855   // step 4c -- Report GPFN (guest-physical frame number) of queue.
    856   //
    857   Status = Dev->VirtIo->SetQueueAddress (Dev->VirtIo, &Dev->Ring);
    858   if (EFI_ERROR (Status)) {
    859     goto ReleaseQueue;
    860   }
    861 
    862   //
    863   // step 5 -- Report understood features and guest-tuneables.
    864   //
    865   if (Dev->VirtIo->Revision < VIRTIO_SPEC_REVISION (1, 0, 0)) {
    866     Features &= ~(UINT64)VIRTIO_F_VERSION_1;
    867     Status = Dev->VirtIo->SetGuestFeatures (Dev->VirtIo, Features);
    868     if (EFI_ERROR (Status)) {
    869       goto ReleaseQueue;
    870     }
    871   }
    872 
    873   //
    874   // We expect these maximum sizes from the host. Since they are
    875   // guest-negotiable, ask for them rather than just checking them.
    876   //
    877   Status = VIRTIO_CFG_WRITE (Dev, CdbSize, VIRTIO_SCSI_CDB_SIZE);
    878   if (EFI_ERROR (Status)) {
    879     goto ReleaseQueue;
    880   }
    881   Status = VIRTIO_CFG_WRITE (Dev, SenseSize, VIRTIO_SCSI_SENSE_SIZE);
    882   if (EFI_ERROR (Status)) {
    883     goto ReleaseQueue;
    884   }
    885 
    886   //
    887   // step 6 -- initialization complete
    888   //
    889   NextDevStat |= VSTAT_DRIVER_OK;
    890   Status = Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, NextDevStat);
    891   if (EFI_ERROR (Status)) {
    892     goto ReleaseQueue;
    893   }
    894 
    895   //
    896   // populate the exported interface's attributes
    897   //
    898   Dev->PassThru.Mode             = &Dev->PassThruMode;
    899   Dev->PassThru.PassThru         = &VirtioScsiPassThru;
    900   Dev->PassThru.GetNextTargetLun = &VirtioScsiGetNextTargetLun;
    901   Dev->PassThru.BuildDevicePath  = &VirtioScsiBuildDevicePath;
    902   Dev->PassThru.GetTargetLun     = &VirtioScsiGetTargetLun;
    903   Dev->PassThru.ResetChannel     = &VirtioScsiResetChannel;
    904   Dev->PassThru.ResetTargetLun   = &VirtioScsiResetTargetLun;
    905   Dev->PassThru.GetNextTarget    = &VirtioScsiGetNextTarget;
    906 
    907   //
    908   // AdapterId is a target for which no handle will be created during bus scan.
    909   // Prevent any conflict with real devices.
    910   //
    911   Dev->PassThruMode.AdapterId = 0xFFFFFFFF;
    912 
    913   //
    914   // Set both physical and logical attributes for non-RAID SCSI channel. See
    915   // Driver Writer's Guide for UEFI 2.3.1 v1.01, 20.1.5 Implementing Extended
    916   // SCSI Pass Thru Protocol.
    917   //
    918   Dev->PassThruMode.Attributes = EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_PHYSICAL |
    919                                  EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL;
    920 
    921   //
    922   // no restriction on transfer buffer alignment
    923   //
    924   Dev->PassThruMode.IoAlign = 0;
    925 
    926   return EFI_SUCCESS;
    927 
    928 ReleaseQueue:
    929   VirtioRingUninit (&Dev->Ring);
    930 
    931 Failed:
    932   //
    933   // Notify the host about our failure to setup: virtio-0.9.5, 2.2.2.1 Device
    934   // Status. VirtIo access failure here should not mask the original error.
    935   //
    936   NextDevStat |= VSTAT_FAILED;
    937   Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, NextDevStat);
    938 
    939   Dev->InOutSupported = FALSE;
    940   Dev->MaxTarget      = 0;
    941   Dev->MaxLun         = 0;
    942   Dev->MaxSectors     = 0;
    943 
    944   return Status; // reached only via Failed above
    945 }
    946 
    947 
    948 STATIC
    949 VOID
    950 EFIAPI
    951 VirtioScsiUninit (
    952   IN OUT VSCSI_DEV *Dev
    953   )
    954 {
    955   //
    956   // Reset the virtual device -- see virtio-0.9.5, 2.2.2.1 Device Status. When
    957   // VIRTIO_CFG_WRITE() returns, the host will have learned to stay away from
    958   // the old comms area.
    959   //
    960   Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, 0);
    961 
    962   Dev->InOutSupported = FALSE;
    963   Dev->MaxTarget      = 0;
    964   Dev->MaxLun         = 0;
    965   Dev->MaxSectors     = 0;
    966 
    967   VirtioRingUninit (&Dev->Ring);
    968 
    969   SetMem (&Dev->PassThru,     sizeof Dev->PassThru,     0x00);
    970   SetMem (&Dev->PassThruMode, sizeof Dev->PassThruMode, 0x00);
    971 }
    972 
    973 
    974 //
    975 // Event notification function enqueued by ExitBootServices().
    976 //
    977 
    978 STATIC
    979 VOID
    980 EFIAPI
    981 VirtioScsiExitBoot (
    982   IN  EFI_EVENT Event,
    983   IN  VOID      *Context
    984   )
    985 {
    986   VSCSI_DEV *Dev;
    987 
    988   //
    989   // Reset the device. This causes the hypervisor to forget about the virtio
    990   // ring.
    991   //
    992   // We allocated said ring in EfiBootServicesData type memory, and code
    993   // executing after ExitBootServices() is permitted to overwrite it.
    994   //
    995   Dev = Context;
    996   Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, 0);
    997 }
    998 
    999 
   1000 //
   1001 // Probe, start and stop functions of this driver, called by the DXE core for
   1002 // specific devices.
   1003 //
   1004 // The following specifications document these interfaces:
   1005 // - Driver Writer's Guide for UEFI 2.3.1 v1.01, 9 Driver Binding Protocol
   1006 // - UEFI Spec 2.3.1 + Errata C, 10.1 EFI Driver Binding Protocol
   1007 //
   1008 // The implementation follows:
   1009 // - Driver Writer's Guide for UEFI 2.3.1 v1.01
   1010 //   - 5.1.3.4 OpenProtocol() and CloseProtocol()
   1011 // - UEFI Spec 2.3.1 + Errata C
   1012 //   -  6.3 Protocol Handler Services
   1013 //
   1014 
   1015 EFI_STATUS
   1016 EFIAPI
   1017 VirtioScsiDriverBindingSupported (
   1018   IN EFI_DRIVER_BINDING_PROTOCOL *This,
   1019   IN EFI_HANDLE                  DeviceHandle,
   1020   IN EFI_DEVICE_PATH_PROTOCOL    *RemainingDevicePath
   1021   )
   1022 {
   1023   EFI_STATUS             Status;
   1024   VIRTIO_DEVICE_PROTOCOL *VirtIo;
   1025 
   1026   //
   1027   // Attempt to open the device with the VirtIo set of interfaces. On success,
   1028   // the protocol is "instantiated" for the VirtIo device. Covers duplicate open
   1029   // attempts (EFI_ALREADY_STARTED).
   1030   //
   1031   Status = gBS->OpenProtocol (
   1032                   DeviceHandle,               // candidate device
   1033                   &gVirtioDeviceProtocolGuid, // for generic VirtIo access
   1034                   (VOID **)&VirtIo,           // handle to instantiate
   1035                   This->DriverBindingHandle,  // requestor driver identity
   1036                   DeviceHandle,               // ControllerHandle, according to
   1037                                               // the UEFI Driver Model
   1038                   EFI_OPEN_PROTOCOL_BY_DRIVER // get exclusive VirtIo access to
   1039                                               // the device; to be released
   1040                   );
   1041   if (EFI_ERROR (Status)) {
   1042     return Status;
   1043   }
   1044 
   1045   if (VirtIo->SubSystemDeviceId != VIRTIO_SUBSYSTEM_SCSI_HOST) {
   1046     Status = EFI_UNSUPPORTED;
   1047   }
   1048 
   1049   //
   1050   // We needed VirtIo access only transitorily, to see whether we support the
   1051   // device or not.
   1052   //
   1053   gBS->CloseProtocol (DeviceHandle, &gVirtioDeviceProtocolGuid,
   1054          This->DriverBindingHandle, DeviceHandle);
   1055   return Status;
   1056 }
   1057 
   1058 
   1059 EFI_STATUS
   1060 EFIAPI
   1061 VirtioScsiDriverBindingStart (
   1062   IN EFI_DRIVER_BINDING_PROTOCOL *This,
   1063   IN EFI_HANDLE                  DeviceHandle,
   1064   IN EFI_DEVICE_PATH_PROTOCOL    *RemainingDevicePath
   1065   )
   1066 {
   1067   VSCSI_DEV  *Dev;
   1068   EFI_STATUS Status;
   1069 
   1070   Dev = (VSCSI_DEV *) AllocateZeroPool (sizeof *Dev);
   1071   if (Dev == NULL) {
   1072     return EFI_OUT_OF_RESOURCES;
   1073   }
   1074 
   1075   Status = gBS->OpenProtocol (DeviceHandle, &gVirtioDeviceProtocolGuid,
   1076                   (VOID **)&Dev->VirtIo, This->DriverBindingHandle,
   1077                   DeviceHandle, EFI_OPEN_PROTOCOL_BY_DRIVER);
   1078   if (EFI_ERROR (Status)) {
   1079     goto FreeVirtioScsi;
   1080   }
   1081 
   1082   //
   1083   // VirtIo access granted, configure virtio-scsi device.
   1084   //
   1085   Status = VirtioScsiInit (Dev);
   1086   if (EFI_ERROR (Status)) {
   1087     goto CloseVirtIo;
   1088   }
   1089 
   1090   Status = gBS->CreateEvent (EVT_SIGNAL_EXIT_BOOT_SERVICES, TPL_CALLBACK,
   1091                   &VirtioScsiExitBoot, Dev, &Dev->ExitBoot);
   1092   if (EFI_ERROR (Status)) {
   1093     goto UninitDev;
   1094   }
   1095 
   1096   //
   1097   // Setup complete, attempt to export the driver instance's PassThru
   1098   // interface.
   1099   //
   1100   Dev->Signature = VSCSI_SIG;
   1101   Status = gBS->InstallProtocolInterface (&DeviceHandle,
   1102                   &gEfiExtScsiPassThruProtocolGuid, EFI_NATIVE_INTERFACE,
   1103                   &Dev->PassThru);
   1104   if (EFI_ERROR (Status)) {
   1105     goto CloseExitBoot;
   1106   }
   1107 
   1108   return EFI_SUCCESS;
   1109 
   1110 CloseExitBoot:
   1111   gBS->CloseEvent (Dev->ExitBoot);
   1112 
   1113 UninitDev:
   1114   VirtioScsiUninit (Dev);
   1115 
   1116 CloseVirtIo:
   1117   gBS->CloseProtocol (DeviceHandle, &gVirtioDeviceProtocolGuid,
   1118          This->DriverBindingHandle, DeviceHandle);
   1119 
   1120 FreeVirtioScsi:
   1121   FreePool (Dev);
   1122 
   1123   return Status;
   1124 }
   1125 
   1126 
   1127 EFI_STATUS
   1128 EFIAPI
   1129 VirtioScsiDriverBindingStop (
   1130   IN EFI_DRIVER_BINDING_PROTOCOL *This,
   1131   IN EFI_HANDLE                  DeviceHandle,
   1132   IN UINTN                       NumberOfChildren,
   1133   IN EFI_HANDLE                  *ChildHandleBuffer
   1134   )
   1135 {
   1136   EFI_STATUS                      Status;
   1137   EFI_EXT_SCSI_PASS_THRU_PROTOCOL *PassThru;
   1138   VSCSI_DEV                       *Dev;
   1139 
   1140   Status = gBS->OpenProtocol (
   1141                   DeviceHandle,                     // candidate device
   1142                   &gEfiExtScsiPassThruProtocolGuid, // retrieve the SCSI iface
   1143                   (VOID **)&PassThru,               // target pointer
   1144                   This->DriverBindingHandle,        // requestor driver ident.
   1145                   DeviceHandle,                     // lookup req. for dev.
   1146                   EFI_OPEN_PROTOCOL_GET_PROTOCOL    // lookup only, no new ref.
   1147                   );
   1148   if (EFI_ERROR (Status)) {
   1149     return Status;
   1150   }
   1151 
   1152   Dev = VIRTIO_SCSI_FROM_PASS_THRU (PassThru);
   1153 
   1154   //
   1155   // Handle Stop() requests for in-use driver instances gracefully.
   1156   //
   1157   Status = gBS->UninstallProtocolInterface (DeviceHandle,
   1158                   &gEfiExtScsiPassThruProtocolGuid, &Dev->PassThru);
   1159   if (EFI_ERROR (Status)) {
   1160     return Status;
   1161   }
   1162 
   1163   gBS->CloseEvent (Dev->ExitBoot);
   1164 
   1165   VirtioScsiUninit (Dev);
   1166 
   1167   gBS->CloseProtocol (DeviceHandle, &gVirtioDeviceProtocolGuid,
   1168          This->DriverBindingHandle, DeviceHandle);
   1169 
   1170   FreePool (Dev);
   1171 
   1172   return EFI_SUCCESS;
   1173 }
   1174 
   1175 
   1176 //
   1177 // The static object that groups the Supported() (ie. probe), Start() and
   1178 // Stop() functions of the driver together. Refer to UEFI Spec 2.3.1 + Errata
   1179 // C, 10.1 EFI Driver Binding Protocol.
   1180 //
   1181 STATIC EFI_DRIVER_BINDING_PROTOCOL gDriverBinding = {
   1182   &VirtioScsiDriverBindingSupported,
   1183   &VirtioScsiDriverBindingStart,
   1184   &VirtioScsiDriverBindingStop,
   1185   0x10, // Version, must be in [0x10 .. 0xFFFFFFEF] for IHV-developed drivers
   1186   NULL, // ImageHandle, to be overwritten by
   1187         // EfiLibInstallDriverBindingComponentName2() in VirtioScsiEntryPoint()
   1188   NULL  // DriverBindingHandle, ditto
   1189 };
   1190 
   1191 
   1192 //
   1193 // The purpose of the following scaffolding (EFI_COMPONENT_NAME_PROTOCOL and
   1194 // EFI_COMPONENT_NAME2_PROTOCOL implementation) is to format the driver's name
   1195 // in English, for display on standard console devices. This is recommended for
   1196 // UEFI drivers that follow the UEFI Driver Model. Refer to the Driver Writer's
   1197 // Guide for UEFI 2.3.1 v1.01, 11 UEFI Driver and Controller Names.
   1198 //
   1199 // Device type names ("Virtio SCSI Host Device") are not formatted because the
   1200 // driver supports only that device type. Therefore the driver name suffices
   1201 // for unambiguous identification.
   1202 //
   1203 
   1204 STATIC
   1205 EFI_UNICODE_STRING_TABLE mDriverNameTable[] = {
   1206   { "eng;en", L"Virtio SCSI Host Driver" },
   1207   { NULL,     NULL                   }
   1208 };
   1209 
   1210 STATIC
   1211 EFI_COMPONENT_NAME_PROTOCOL gComponentName;
   1212 
   1213 EFI_STATUS
   1214 EFIAPI
   1215 VirtioScsiGetDriverName (
   1216   IN  EFI_COMPONENT_NAME_PROTOCOL *This,
   1217   IN  CHAR8                       *Language,
   1218   OUT CHAR16                      **DriverName
   1219   )
   1220 {
   1221   return LookupUnicodeString2 (
   1222            Language,
   1223            This->SupportedLanguages,
   1224            mDriverNameTable,
   1225            DriverName,
   1226            (BOOLEAN)(This == &gComponentName) // Iso639Language
   1227            );
   1228 }
   1229 
   1230 EFI_STATUS
   1231 EFIAPI
   1232 VirtioScsiGetDeviceName (
   1233   IN  EFI_COMPONENT_NAME_PROTOCOL *This,
   1234   IN  EFI_HANDLE                  DeviceHandle,
   1235   IN  EFI_HANDLE                  ChildHandle,
   1236   IN  CHAR8                       *Language,
   1237   OUT CHAR16                      **ControllerName
   1238   )
   1239 {
   1240   return EFI_UNSUPPORTED;
   1241 }
   1242 
   1243 STATIC
   1244 EFI_COMPONENT_NAME_PROTOCOL gComponentName = {
   1245   &VirtioScsiGetDriverName,
   1246   &VirtioScsiGetDeviceName,
   1247   "eng" // SupportedLanguages, ISO 639-2 language codes
   1248 };
   1249 
   1250 STATIC
   1251 EFI_COMPONENT_NAME2_PROTOCOL gComponentName2 = {
   1252   (EFI_COMPONENT_NAME2_GET_DRIVER_NAME)     &VirtioScsiGetDriverName,
   1253   (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) &VirtioScsiGetDeviceName,
   1254   "en" // SupportedLanguages, RFC 4646 language codes
   1255 };
   1256 
   1257 
   1258 //
   1259 // Entry point of this driver.
   1260 //
   1261 EFI_STATUS
   1262 EFIAPI
   1263 VirtioScsiEntryPoint (
   1264   IN EFI_HANDLE       ImageHandle,
   1265   IN EFI_SYSTEM_TABLE *SystemTable
   1266   )
   1267 {
   1268   return EfiLibInstallDriverBindingComponentName2 (
   1269            ImageHandle,
   1270            SystemTable,
   1271            &gDriverBinding,
   1272            ImageHandle,
   1273            &gComponentName,
   1274            &gComponentName2
   1275            );
   1276 }
   1277