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