VirtualBox

source: vbox/trunk/src/VBox/Devices/EFI/Firmware/OvmfPkg/VirtioScsiDxe/VirtioScsi.c@ 80924

Last change on this file since 80924 was 80721, checked in by vboxsync, 5 years ago

Devices/EFI/FirmwareNew: Start upgrade process to edk2-stable201908 (compiles on Windows and works to some extent), bugref:4643

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

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette