• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
PopulateRequest(IN CONST VSCSI_DEV * Dev,IN UINT16 Target,IN UINT64 Lun,IN OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET * Packet,OUT volatile VIRTIO_SCSI_REQ * Request)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
ParseResponse(IN OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET * Packet,IN CONST volatile VIRTIO_SCSI_RESP * Response)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
VirtioScsiPassThru(IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL * This,IN UINT8 * Target,IN UINT64 Lun,IN OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET * Packet,IN EFI_EVENT Event OPTIONAL)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) != 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
VirtioScsiGetNextTargetLun(IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL * This,IN OUT UINT8 ** TargetPointer,IN OUT UINT64 * Lun)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
VirtioScsiBuildDevicePath(IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL * This,IN UINT8 * Target,IN UINT64 Lun,IN OUT EFI_DEVICE_PATH_PROTOCOL ** DevicePath)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
VirtioScsiGetTargetLun(IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL * This,IN EFI_DEVICE_PATH_PROTOCOL * DevicePath,OUT UINT8 ** TargetPointer,OUT UINT64 * Lun)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
VirtioScsiResetChannel(IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL * This)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
VirtioScsiResetTargetLun(IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL * This,IN UINT8 * Target,IN UINT64 Lun)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
VirtioScsiGetNextTarget(IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL * This,IN OUT UINT8 ** TargetPointer)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
VirtioScsiInit(IN OUT VSCSI_DEV * Dev)703 VirtioScsiInit (
704   IN OUT VSCSI_DEV *Dev
705   )
706 {
707   UINT8      NextDevStat;
708   EFI_STATUS Status;
709 
710   UINT32     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   //
804   // step 4b -- allocate request virtqueue
805   //
806   Status = Dev->VirtIo->SetQueueSel (Dev->VirtIo, VIRTIO_SCSI_REQUEST_QUEUE);
807   if (EFI_ERROR (Status)) {
808     goto Failed;
809   }
810   Status = Dev->VirtIo->GetQueueNumMax (Dev->VirtIo, &QueueSize);
811   if (EFI_ERROR (Status)) {
812     goto Failed;
813   }
814   //
815   // VirtioScsiPassThru() uses at most four descriptors
816   //
817   if (QueueSize < 4) {
818     Status = EFI_UNSUPPORTED;
819     goto Failed;
820   }
821 
822   Status = VirtioRingInit (QueueSize, &Dev->Ring);
823   if (EFI_ERROR (Status)) {
824     goto Failed;
825   }
826 
827   //
828   // Additional steps for MMIO: align the queue appropriately, and set the
829   // size. If anything fails from here on, we must release the ring resources.
830   //
831   Status = Dev->VirtIo->SetQueueNum (Dev->VirtIo, QueueSize);
832   if (EFI_ERROR (Status)) {
833     goto ReleaseQueue;
834   }
835 
836   Status = Dev->VirtIo->SetQueueAlign (Dev->VirtIo, EFI_PAGE_SIZE);
837   if (EFI_ERROR (Status)) {
838     goto ReleaseQueue;
839   }
840 
841   //
842   // step 4c -- Report GPFN (guest-physical frame number) of queue.
843   //
844   Status = Dev->VirtIo->SetQueueAddress (Dev->VirtIo,
845       (UINT32) ((UINTN) Dev->Ring.Base >> EFI_PAGE_SHIFT));
846   if (EFI_ERROR (Status)) {
847     goto ReleaseQueue;
848   }
849 
850   //
851   // step 5 -- Report understood features and guest-tuneables. We want none of
852   // the known (or unknown) VIRTIO_SCSI_F_* or VIRTIO_F_* capabilities (see
853   // virtio-0.9.5, Appendices B and I), except bidirectional transfers.
854   //
855   Status = Dev->VirtIo->SetGuestFeatures (Dev->VirtIo,
856       Features & VIRTIO_SCSI_F_INOUT);
857   if (EFI_ERROR (Status)) {
858     goto ReleaseQueue;
859   }
860 
861   //
862   // We expect these maximum sizes from the host. Since they are
863   // guest-negotiable, ask for them rather than just checking them.
864   //
865   Status = VIRTIO_CFG_WRITE (Dev, CdbSize, VIRTIO_SCSI_CDB_SIZE);
866   if (EFI_ERROR (Status)) {
867     goto ReleaseQueue;
868   }
869   Status = VIRTIO_CFG_WRITE (Dev, SenseSize, VIRTIO_SCSI_SENSE_SIZE);
870   if (EFI_ERROR (Status)) {
871     goto ReleaseQueue;
872   }
873 
874   //
875   // step 6 -- initialization complete
876   //
877   NextDevStat |= VSTAT_DRIVER_OK;
878   Status = Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, NextDevStat);
879   if (EFI_ERROR (Status)) {
880     goto ReleaseQueue;
881   }
882 
883   //
884   // populate the exported interface's attributes
885   //
886   Dev->PassThru.Mode             = &Dev->PassThruMode;
887   Dev->PassThru.PassThru         = &VirtioScsiPassThru;
888   Dev->PassThru.GetNextTargetLun = &VirtioScsiGetNextTargetLun;
889   Dev->PassThru.BuildDevicePath  = &VirtioScsiBuildDevicePath;
890   Dev->PassThru.GetTargetLun     = &VirtioScsiGetTargetLun;
891   Dev->PassThru.ResetChannel     = &VirtioScsiResetChannel;
892   Dev->PassThru.ResetTargetLun   = &VirtioScsiResetTargetLun;
893   Dev->PassThru.GetNextTarget    = &VirtioScsiGetNextTarget;
894 
895   //
896   // AdapterId is a target for which no handle will be created during bus scan.
897   // Prevent any conflict with real devices.
898   //
899   Dev->PassThruMode.AdapterId = 0xFFFFFFFF;
900 
901   //
902   // Set both physical and logical attributes for non-RAID SCSI channel. See
903   // Driver Writer's Guide for UEFI 2.3.1 v1.01, 20.1.5 Implementing Extended
904   // SCSI Pass Thru Protocol.
905   //
906   Dev->PassThruMode.Attributes = EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_PHYSICAL |
907                                  EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL;
908 
909   //
910   // no restriction on transfer buffer alignment
911   //
912   Dev->PassThruMode.IoAlign = 0;
913 
914   return EFI_SUCCESS;
915 
916 ReleaseQueue:
917   VirtioRingUninit (&Dev->Ring);
918 
919 Failed:
920   //
921   // Notify the host about our failure to setup: virtio-0.9.5, 2.2.2.1 Device
922   // Status. VirtIo access failure here should not mask the original error.
923   //
924   NextDevStat |= VSTAT_FAILED;
925   Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, NextDevStat);
926 
927   Dev->InOutSupported = FALSE;
928   Dev->MaxTarget      = 0;
929   Dev->MaxLun         = 0;
930   Dev->MaxSectors     = 0;
931 
932   return Status; // reached only via Failed above
933 }
934 
935 
936 STATIC
937 VOID
938 EFIAPI
VirtioScsiUninit(IN OUT VSCSI_DEV * Dev)939 VirtioScsiUninit (
940   IN OUT VSCSI_DEV *Dev
941   )
942 {
943   //
944   // Reset the virtual device -- see virtio-0.9.5, 2.2.2.1 Device Status. When
945   // VIRTIO_CFG_WRITE() returns, the host will have learned to stay away from
946   // the old comms area.
947   //
948   Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, 0);
949 
950   Dev->InOutSupported = FALSE;
951   Dev->MaxTarget      = 0;
952   Dev->MaxLun         = 0;
953   Dev->MaxSectors     = 0;
954 
955   VirtioRingUninit (&Dev->Ring);
956 
957   SetMem (&Dev->PassThru,     sizeof Dev->PassThru,     0x00);
958   SetMem (&Dev->PassThruMode, sizeof Dev->PassThruMode, 0x00);
959 }
960 
961 
962 //
963 // Event notification function enqueued by ExitBootServices().
964 //
965 
966 STATIC
967 VOID
968 EFIAPI
VirtioScsiExitBoot(IN EFI_EVENT Event,IN VOID * Context)969 VirtioScsiExitBoot (
970   IN  EFI_EVENT Event,
971   IN  VOID      *Context
972   )
973 {
974   VSCSI_DEV *Dev;
975 
976   //
977   // Reset the device. This causes the hypervisor to forget about the virtio
978   // ring.
979   //
980   // We allocated said ring in EfiBootServicesData type memory, and code
981   // executing after ExitBootServices() is permitted to overwrite it.
982   //
983   Dev = Context;
984   Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, 0);
985 }
986 
987 
988 //
989 // Probe, start and stop functions of this driver, called by the DXE core for
990 // specific devices.
991 //
992 // The following specifications document these interfaces:
993 // - Driver Writer's Guide for UEFI 2.3.1 v1.01, 9 Driver Binding Protocol
994 // - UEFI Spec 2.3.1 + Errata C, 10.1 EFI Driver Binding Protocol
995 //
996 // The implementation follows:
997 // - Driver Writer's Guide for UEFI 2.3.1 v1.01
998 //   - 5.1.3.4 OpenProtocol() and CloseProtocol()
999 // - UEFI Spec 2.3.1 + Errata C
1000 //   -  6.3 Protocol Handler Services
1001 //
1002 
1003 EFI_STATUS
1004 EFIAPI
VirtioScsiDriverBindingSupported(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE DeviceHandle,IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath)1005 VirtioScsiDriverBindingSupported (
1006   IN EFI_DRIVER_BINDING_PROTOCOL *This,
1007   IN EFI_HANDLE                  DeviceHandle,
1008   IN EFI_DEVICE_PATH_PROTOCOL    *RemainingDevicePath
1009   )
1010 {
1011   EFI_STATUS             Status;
1012   VIRTIO_DEVICE_PROTOCOL *VirtIo;
1013 
1014   //
1015   // Attempt to open the device with the VirtIo set of interfaces. On success,
1016   // the protocol is "instantiated" for the VirtIo device. Covers duplicate open
1017   // attempts (EFI_ALREADY_STARTED).
1018   //
1019   Status = gBS->OpenProtocol (
1020                   DeviceHandle,               // candidate device
1021                   &gVirtioDeviceProtocolGuid, // for generic VirtIo access
1022                   (VOID **)&VirtIo,           // handle to instantiate
1023                   This->DriverBindingHandle,  // requestor driver identity
1024                   DeviceHandle,               // ControllerHandle, according to
1025                                               // the UEFI Driver Model
1026                   EFI_OPEN_PROTOCOL_BY_DRIVER // get exclusive VirtIo access to
1027                                               // the device; to be released
1028                   );
1029   if (EFI_ERROR (Status)) {
1030     return Status;
1031   }
1032 
1033   if (VirtIo->SubSystemDeviceId != VIRTIO_SUBSYSTEM_SCSI_HOST) {
1034     Status = EFI_UNSUPPORTED;
1035   }
1036 
1037   //
1038   // We needed VirtIo access only transitorily, to see whether we support the
1039   // device or not.
1040   //
1041   gBS->CloseProtocol (DeviceHandle, &gVirtioDeviceProtocolGuid,
1042          This->DriverBindingHandle, DeviceHandle);
1043   return Status;
1044 }
1045 
1046 
1047 EFI_STATUS
1048 EFIAPI
VirtioScsiDriverBindingStart(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE DeviceHandle,IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath)1049 VirtioScsiDriverBindingStart (
1050   IN EFI_DRIVER_BINDING_PROTOCOL *This,
1051   IN EFI_HANDLE                  DeviceHandle,
1052   IN EFI_DEVICE_PATH_PROTOCOL    *RemainingDevicePath
1053   )
1054 {
1055   VSCSI_DEV  *Dev;
1056   EFI_STATUS Status;
1057 
1058   Dev = (VSCSI_DEV *) AllocateZeroPool (sizeof *Dev);
1059   if (Dev == NULL) {
1060     return EFI_OUT_OF_RESOURCES;
1061   }
1062 
1063   Status = gBS->OpenProtocol (DeviceHandle, &gVirtioDeviceProtocolGuid,
1064                   (VOID **)&Dev->VirtIo, This->DriverBindingHandle,
1065                   DeviceHandle, EFI_OPEN_PROTOCOL_BY_DRIVER);
1066   if (EFI_ERROR (Status)) {
1067     goto FreeVirtioScsi;
1068   }
1069 
1070   //
1071   // VirtIo access granted, configure virtio-scsi device.
1072   //
1073   Status = VirtioScsiInit (Dev);
1074   if (EFI_ERROR (Status)) {
1075     goto CloseVirtIo;
1076   }
1077 
1078   Status = gBS->CreateEvent (EVT_SIGNAL_EXIT_BOOT_SERVICES, TPL_CALLBACK,
1079                   &VirtioScsiExitBoot, Dev, &Dev->ExitBoot);
1080   if (EFI_ERROR (Status)) {
1081     goto UninitDev;
1082   }
1083 
1084   //
1085   // Setup complete, attempt to export the driver instance's PassThru
1086   // interface.
1087   //
1088   Dev->Signature = VSCSI_SIG;
1089   Status = gBS->InstallProtocolInterface (&DeviceHandle,
1090                   &gEfiExtScsiPassThruProtocolGuid, EFI_NATIVE_INTERFACE,
1091                   &Dev->PassThru);
1092   if (EFI_ERROR (Status)) {
1093     goto CloseExitBoot;
1094   }
1095 
1096   return EFI_SUCCESS;
1097 
1098 CloseExitBoot:
1099   gBS->CloseEvent (Dev->ExitBoot);
1100 
1101 UninitDev:
1102   VirtioScsiUninit (Dev);
1103 
1104 CloseVirtIo:
1105   gBS->CloseProtocol (DeviceHandle, &gVirtioDeviceProtocolGuid,
1106          This->DriverBindingHandle, DeviceHandle);
1107 
1108 FreeVirtioScsi:
1109   FreePool (Dev);
1110 
1111   return Status;
1112 }
1113 
1114 
1115 EFI_STATUS
1116 EFIAPI
VirtioScsiDriverBindingStop(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE DeviceHandle,IN UINTN NumberOfChildren,IN EFI_HANDLE * ChildHandleBuffer)1117 VirtioScsiDriverBindingStop (
1118   IN EFI_DRIVER_BINDING_PROTOCOL *This,
1119   IN EFI_HANDLE                  DeviceHandle,
1120   IN UINTN                       NumberOfChildren,
1121   IN EFI_HANDLE                  *ChildHandleBuffer
1122   )
1123 {
1124   EFI_STATUS                      Status;
1125   EFI_EXT_SCSI_PASS_THRU_PROTOCOL *PassThru;
1126   VSCSI_DEV                       *Dev;
1127 
1128   Status = gBS->OpenProtocol (
1129                   DeviceHandle,                     // candidate device
1130                   &gEfiExtScsiPassThruProtocolGuid, // retrieve the SCSI iface
1131                   (VOID **)&PassThru,               // target pointer
1132                   This->DriverBindingHandle,        // requestor driver ident.
1133                   DeviceHandle,                     // lookup req. for dev.
1134                   EFI_OPEN_PROTOCOL_GET_PROTOCOL    // lookup only, no new ref.
1135                   );
1136   if (EFI_ERROR (Status)) {
1137     return Status;
1138   }
1139 
1140   Dev = VIRTIO_SCSI_FROM_PASS_THRU (PassThru);
1141 
1142   //
1143   // Handle Stop() requests for in-use driver instances gracefully.
1144   //
1145   Status = gBS->UninstallProtocolInterface (DeviceHandle,
1146                   &gEfiExtScsiPassThruProtocolGuid, &Dev->PassThru);
1147   if (EFI_ERROR (Status)) {
1148     return Status;
1149   }
1150 
1151   gBS->CloseEvent (Dev->ExitBoot);
1152 
1153   VirtioScsiUninit (Dev);
1154 
1155   gBS->CloseProtocol (DeviceHandle, &gVirtioDeviceProtocolGuid,
1156          This->DriverBindingHandle, DeviceHandle);
1157 
1158   FreePool (Dev);
1159 
1160   return EFI_SUCCESS;
1161 }
1162 
1163 
1164 //
1165 // The static object that groups the Supported() (ie. probe), Start() and
1166 // Stop() functions of the driver together. Refer to UEFI Spec 2.3.1 + Errata
1167 // C, 10.1 EFI Driver Binding Protocol.
1168 //
1169 STATIC EFI_DRIVER_BINDING_PROTOCOL gDriverBinding = {
1170   &VirtioScsiDriverBindingSupported,
1171   &VirtioScsiDriverBindingStart,
1172   &VirtioScsiDriverBindingStop,
1173   0x10, // Version, must be in [0x10 .. 0xFFFFFFEF] for IHV-developed drivers
1174   NULL, // ImageHandle, to be overwritten by
1175         // EfiLibInstallDriverBindingComponentName2() in VirtioScsiEntryPoint()
1176   NULL  // DriverBindingHandle, ditto
1177 };
1178 
1179 
1180 //
1181 // The purpose of the following scaffolding (EFI_COMPONENT_NAME_PROTOCOL and
1182 // EFI_COMPONENT_NAME2_PROTOCOL implementation) is to format the driver's name
1183 // in English, for display on standard console devices. This is recommended for
1184 // UEFI drivers that follow the UEFI Driver Model. Refer to the Driver Writer's
1185 // Guide for UEFI 2.3.1 v1.01, 11 UEFI Driver and Controller Names.
1186 //
1187 // Device type names ("Virtio SCSI Host Device") are not formatted because the
1188 // driver supports only that device type. Therefore the driver name suffices
1189 // for unambiguous identification.
1190 //
1191 
1192 STATIC
1193 EFI_UNICODE_STRING_TABLE mDriverNameTable[] = {
1194   { "eng;en", L"Virtio SCSI Host Driver" },
1195   { NULL,     NULL                   }
1196 };
1197 
1198 STATIC
1199 EFI_COMPONENT_NAME_PROTOCOL gComponentName;
1200 
1201 EFI_STATUS
1202 EFIAPI
VirtioScsiGetDriverName(IN EFI_COMPONENT_NAME_PROTOCOL * This,IN CHAR8 * Language,OUT CHAR16 ** DriverName)1203 VirtioScsiGetDriverName (
1204   IN  EFI_COMPONENT_NAME_PROTOCOL *This,
1205   IN  CHAR8                       *Language,
1206   OUT CHAR16                      **DriverName
1207   )
1208 {
1209   return LookupUnicodeString2 (
1210            Language,
1211            This->SupportedLanguages,
1212            mDriverNameTable,
1213            DriverName,
1214            (BOOLEAN)(This == &gComponentName) // Iso639Language
1215            );
1216 }
1217 
1218 EFI_STATUS
1219 EFIAPI
VirtioScsiGetDeviceName(IN EFI_COMPONENT_NAME_PROTOCOL * This,IN EFI_HANDLE DeviceHandle,IN EFI_HANDLE ChildHandle,IN CHAR8 * Language,OUT CHAR16 ** ControllerName)1220 VirtioScsiGetDeviceName (
1221   IN  EFI_COMPONENT_NAME_PROTOCOL *This,
1222   IN  EFI_HANDLE                  DeviceHandle,
1223   IN  EFI_HANDLE                  ChildHandle,
1224   IN  CHAR8                       *Language,
1225   OUT CHAR16                      **ControllerName
1226   )
1227 {
1228   return EFI_UNSUPPORTED;
1229 }
1230 
1231 STATIC
1232 EFI_COMPONENT_NAME_PROTOCOL gComponentName = {
1233   &VirtioScsiGetDriverName,
1234   &VirtioScsiGetDeviceName,
1235   "eng" // SupportedLanguages, ISO 639-2 language codes
1236 };
1237 
1238 STATIC
1239 EFI_COMPONENT_NAME2_PROTOCOL gComponentName2 = {
1240   (EFI_COMPONENT_NAME2_GET_DRIVER_NAME)     &VirtioScsiGetDriverName,
1241   (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) &VirtioScsiGetDeviceName,
1242   "en" // SupportedLanguages, RFC 4646 language codes
1243 };
1244 
1245 
1246 //
1247 // Entry point of this driver.
1248 //
1249 EFI_STATUS
1250 EFIAPI
VirtioScsiEntryPoint(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)1251 VirtioScsiEntryPoint (
1252   IN EFI_HANDLE       ImageHandle,
1253   IN EFI_SYSTEM_TABLE *SystemTable
1254   )
1255 {
1256   return EfiLibInstallDriverBindingComponentName2 (
1257            ImageHandle,
1258            SystemTable,
1259            &gDriverBinding,
1260            ImageHandle,
1261            &gComponentName,
1262            &gComponentName2
1263            );
1264 }
1265