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 **/
145 STATIC
146 EFI_STATUS
147 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)148 PopulateRequest (
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 **/
287 STATIC
288 EFI_STATUS
289 EFIAPI
ParseResponse(IN OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET * Packet,IN CONST volatile VIRTIO_SCSI_RESP * Response)290 ParseResponse (
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 **/
401 STATIC
402 EFI_STATUS
ReportHostAdapterError(OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET * Packet)403 ReportHostAdapterError (
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
423 EFI_STATUS
424 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)425 VirtioScsiPassThru (
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 VOID *RequestMapping;
441 VOID *ResponseMapping;
442 VOID *InDataMapping;
443 VOID *OutDataMapping;
444 EFI_PHYSICAL_ADDRESS RequestDeviceAddress;
445 EFI_PHYSICAL_ADDRESS ResponseDeviceAddress;
446 EFI_PHYSICAL_ADDRESS InDataDeviceAddress;
447 EFI_PHYSICAL_ADDRESS OutDataDeviceAddress;
448 VOID *InDataBuffer;
449 UINTN InDataNumPages;
450 BOOLEAN OutDataBufferIsMapped;
451
452 //
453 // Set InDataMapping,OutDataMapping,InDataDeviceAddress and OutDataDeviceAddress to
454 // suppress incorrect compiler/analyzer warnings.
455 //
456 InDataMapping = NULL;
457 OutDataMapping = NULL;
458 InDataDeviceAddress = 0;
459 OutDataDeviceAddress = 0;
460
461 ZeroMem ((VOID*) &Request, sizeof (Request));
462
463 Dev = VIRTIO_SCSI_FROM_PASS_THRU (This);
464 CopyMem (&TargetValue, Target, sizeof TargetValue);
465
466 InDataBuffer = NULL;
467 OutDataBufferIsMapped = FALSE;
468 InDataNumPages = 0;
469
470 Status = PopulateRequest (Dev, TargetValue, Lun, Packet, &Request);
471 if (EFI_ERROR (Status)) {
472 return Status;
473 }
474
475 //
476 // Map the virtio-scsi Request header buffer
477 //
478 Status = VirtioMapAllBytesInSharedBuffer (
479 Dev->VirtIo,
480 VirtioOperationBusMasterRead,
481 (VOID *) &Request,
482 sizeof Request,
483 &RequestDeviceAddress,
484 &RequestMapping);
485 if (EFI_ERROR (Status)) {
486 return ReportHostAdapterError (Packet);
487 }
488
489 //
490 // Map the input buffer
491 //
492 if (Packet->InTransferLength > 0) {
493 //
494 // Allocate a intermediate input buffer. This is mainly to handle the
495 // following case:
496 // * caller submits a bi-directional request
497 // * we perform the request fine
498 // * but we fail to unmap the "InDataMapping"
499 //
500 // In that case simply returing the EFI_DEVICE_ERROR is not sufficient. In
501 // addition to the error code we also need to update Packet fields
502 // accordingly so that we report the full loss of the incoming transfer.
503 //
504 // We allocate a temporary buffer and map it with BusMasterCommonBuffer. If
505 // the Virtio request is successful then we copy the data from temporary
506 // buffer into Packet->InDataBuffer.
507 //
508 InDataNumPages = EFI_SIZE_TO_PAGES ((UINTN)Packet->InTransferLength);
509 Status = Dev->VirtIo->AllocateSharedPages (
510 Dev->VirtIo,
511 InDataNumPages,
512 &InDataBuffer
513 );
514 if (EFI_ERROR (Status)) {
515 Status = ReportHostAdapterError (Packet);
516 goto UnmapRequestBuffer;
517 }
518
519 ZeroMem (InDataBuffer, Packet->InTransferLength);
520
521 Status = VirtioMapAllBytesInSharedBuffer (
522 Dev->VirtIo,
523 VirtioOperationBusMasterCommonBuffer,
524 InDataBuffer,
525 Packet->InTransferLength,
526 &InDataDeviceAddress,
527 &InDataMapping
528 );
529 if (EFI_ERROR (Status)) {
530 Status = ReportHostAdapterError (Packet);
531 goto FreeInDataBuffer;
532 }
533 }
534
535 //
536 // Map the output buffer
537 //
538 if (Packet->OutTransferLength > 0) {
539 Status = VirtioMapAllBytesInSharedBuffer (
540 Dev->VirtIo,
541 VirtioOperationBusMasterRead,
542 Packet->OutDataBuffer,
543 Packet->OutTransferLength,
544 &OutDataDeviceAddress,
545 &OutDataMapping
546 );
547 if (EFI_ERROR (Status)) {
548 Status = ReportHostAdapterError (Packet);
549 goto UnmapInDataBuffer;
550 }
551
552 OutDataBufferIsMapped = TRUE;
553 }
554
555 //
556 // Response header is bi-direction (we preset with host status and expect
557 // the device to update it). Allocate a response buffer which can be mapped
558 // to access equally by both processor and device.
559 //
560 Status = Dev->VirtIo->AllocateSharedPages (
561 Dev->VirtIo,
562 EFI_SIZE_TO_PAGES (sizeof *Response),
563 &ResponseBuffer
564 );
565 if (EFI_ERROR (Status)) {
566 Status = ReportHostAdapterError (Packet);
567 goto UnmapOutDataBuffer;
568 }
569
570 Response = ResponseBuffer;
571
572 ZeroMem ((VOID *)Response, sizeof (*Response));
573
574 //
575 // preset a host status for ourselves that we do not accept as success
576 //
577 Response->Response = VIRTIO_SCSI_S_FAILURE;
578
579 //
580 // Map the response buffer with BusMasterCommonBuffer so that response
581 // buffer can be accessed by both host and device.
582 //
583 Status = VirtioMapAllBytesInSharedBuffer (
584 Dev->VirtIo,
585 VirtioOperationBusMasterCommonBuffer,
586 ResponseBuffer,
587 sizeof (*Response),
588 &ResponseDeviceAddress,
589 &ResponseMapping
590 );
591 if (EFI_ERROR (Status)) {
592 Status = ReportHostAdapterError (Packet);
593 goto FreeResponseBuffer;
594 }
595
596 VirtioPrepare (&Dev->Ring, &Indices);
597
598 //
599 // ensured by VirtioScsiInit() -- this predicate, in combination with the
600 // lock-step progress, ensures we don't have to track free descriptors.
601 //
602 ASSERT (Dev->Ring.QueueSize >= 4);
603
604 //
605 // enqueue Request
606 //
607 VirtioAppendDesc (
608 &Dev->Ring,
609 RequestDeviceAddress,
610 sizeof Request,
611 VRING_DESC_F_NEXT,
612 &Indices
613 );
614
615 //
616 // enqueue "dataout" if any
617 //
618 if (Packet->OutTransferLength > 0) {
619 VirtioAppendDesc (
620 &Dev->Ring,
621 OutDataDeviceAddress,
622 Packet->OutTransferLength,
623 VRING_DESC_F_NEXT,
624 &Indices
625 );
626 }
627
628 //
629 // enqueue Response, to be written by the host
630 //
631 VirtioAppendDesc (
632 &Dev->Ring,
633 ResponseDeviceAddress,
634 sizeof *Response,
635 VRING_DESC_F_WRITE | (Packet->InTransferLength > 0 ? VRING_DESC_F_NEXT : 0),
636 &Indices
637 );
638
639 //
640 // enqueue "datain" if any, to be written by the host
641 //
642 if (Packet->InTransferLength > 0) {
643 VirtioAppendDesc (
644 &Dev->Ring,
645 InDataDeviceAddress,
646 Packet->InTransferLength,
647 VRING_DESC_F_WRITE,
648 &Indices
649 );
650 }
651
652 // If kicking the host fails, we must fake a host adapter error.
653 // EFI_NOT_READY would save us the effort, but it would also suggest that the
654 // caller retry.
655 //
656 if (VirtioFlush (Dev->VirtIo, VIRTIO_SCSI_REQUEST_QUEUE, &Dev->Ring,
657 &Indices, NULL) != EFI_SUCCESS) {
658 Status = ReportHostAdapterError (Packet);
659 goto UnmapResponseBuffer;
660 }
661
662 Status = ParseResponse (Packet, Response);
663
664 //
665 // If virtio request was successful and it was a CPU read request then we
666 // have used an intermediate buffer. Copy the data from intermediate buffer
667 // to the final buffer.
668 //
669 if (InDataBuffer != NULL) {
670 CopyMem (Packet->InDataBuffer, InDataBuffer, Packet->InTransferLength);
671 }
672
673 UnmapResponseBuffer:
674 Dev->VirtIo->UnmapSharedBuffer (Dev->VirtIo, ResponseMapping);
675
676 FreeResponseBuffer:
677 Dev->VirtIo->FreeSharedPages (
678 Dev->VirtIo,
679 EFI_SIZE_TO_PAGES (sizeof *Response),
680 ResponseBuffer
681 );
682
683 UnmapOutDataBuffer:
684 if (OutDataBufferIsMapped) {
685 Dev->VirtIo->UnmapSharedBuffer (Dev->VirtIo, OutDataMapping);
686 }
687
688 UnmapInDataBuffer:
689 if (InDataBuffer != NULL) {
690 Dev->VirtIo->UnmapSharedBuffer (Dev->VirtIo, InDataMapping);
691 }
692
693 FreeInDataBuffer:
694 if (InDataBuffer != NULL) {
695 Dev->VirtIo->FreeSharedPages (Dev->VirtIo, InDataNumPages, InDataBuffer);
696 }
697
698 UnmapRequestBuffer:
699 Dev->VirtIo->UnmapSharedBuffer (Dev->VirtIo, RequestMapping);
700
701 return Status;
702 }
703
704
705 EFI_STATUS
706 EFIAPI
VirtioScsiGetNextTargetLun(IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL * This,IN OUT UINT8 ** TargetPointer,IN OUT UINT64 * Lun)707 VirtioScsiGetNextTargetLun (
708 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,
709 IN OUT UINT8 **TargetPointer,
710 IN OUT UINT64 *Lun
711 )
712 {
713 UINT8 *Target;
714 UINTN Idx;
715 UINT16 LastTarget;
716 VSCSI_DEV *Dev;
717
718 //
719 // the TargetPointer input parameter is unnecessarily a pointer-to-pointer
720 //
721 Target = *TargetPointer;
722
723 //
724 // Search for first non-0xFF byte. If not found, return first target & LUN.
725 //
726 for (Idx = 0; Idx < TARGET_MAX_BYTES && Target[Idx] == 0xFF; ++Idx)
727 ;
728 if (Idx == TARGET_MAX_BYTES) {
729 SetMem (Target, TARGET_MAX_BYTES, 0x00);
730 *Lun = 0;
731 return EFI_SUCCESS;
732 }
733
734 //
735 // see the TARGET_MAX_BYTES check in "VirtioScsi.h"
736 //
737 CopyMem (&LastTarget, Target, sizeof LastTarget);
738
739 //
740 // increment (target, LUN) pair if valid on input
741 //
742 Dev = VIRTIO_SCSI_FROM_PASS_THRU (This);
743 if (LastTarget > Dev->MaxTarget || *Lun > Dev->MaxLun) {
744 return EFI_INVALID_PARAMETER;
745 }
746
747 if (*Lun < Dev->MaxLun) {
748 ++*Lun;
749 return EFI_SUCCESS;
750 }
751
752 if (LastTarget < Dev->MaxTarget) {
753 *Lun = 0;
754 ++LastTarget;
755 CopyMem (Target, &LastTarget, sizeof LastTarget);
756 return EFI_SUCCESS;
757 }
758
759 return EFI_NOT_FOUND;
760 }
761
762
763 EFI_STATUS
764 EFIAPI
VirtioScsiBuildDevicePath(IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL * This,IN UINT8 * Target,IN UINT64 Lun,IN OUT EFI_DEVICE_PATH_PROTOCOL ** DevicePath)765 VirtioScsiBuildDevicePath (
766 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,
767 IN UINT8 *Target,
768 IN UINT64 Lun,
769 IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath
770 )
771 {
772 UINT16 TargetValue;
773 VSCSI_DEV *Dev;
774 SCSI_DEVICE_PATH *ScsiDevicePath;
775
776 if (DevicePath == NULL) {
777 return EFI_INVALID_PARAMETER;
778 }
779
780 CopyMem (&TargetValue, Target, sizeof TargetValue);
781 Dev = VIRTIO_SCSI_FROM_PASS_THRU (This);
782 if (TargetValue > Dev->MaxTarget || Lun > Dev->MaxLun || Lun > 0xFFFF) {
783 return EFI_NOT_FOUND;
784 }
785
786 ScsiDevicePath = AllocatePool (sizeof *ScsiDevicePath);
787 if (ScsiDevicePath == NULL) {
788 return EFI_OUT_OF_RESOURCES;
789 }
790
791 ScsiDevicePath->Header.Type = MESSAGING_DEVICE_PATH;
792 ScsiDevicePath->Header.SubType = MSG_SCSI_DP;
793 ScsiDevicePath->Header.Length[0] = (UINT8) sizeof *ScsiDevicePath;
794 ScsiDevicePath->Header.Length[1] = (UINT8) (sizeof *ScsiDevicePath >> 8);
795 ScsiDevicePath->Pun = TargetValue;
796 ScsiDevicePath->Lun = (UINT16) Lun;
797
798 *DevicePath = &ScsiDevicePath->Header;
799 return EFI_SUCCESS;
800 }
801
802
803 EFI_STATUS
804 EFIAPI
VirtioScsiGetTargetLun(IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL * This,IN EFI_DEVICE_PATH_PROTOCOL * DevicePath,OUT UINT8 ** TargetPointer,OUT UINT64 * Lun)805 VirtioScsiGetTargetLun (
806 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,
807 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
808 OUT UINT8 **TargetPointer,
809 OUT UINT64 *Lun
810 )
811 {
812 SCSI_DEVICE_PATH *ScsiDevicePath;
813 VSCSI_DEV *Dev;
814 UINT8 *Target;
815
816 if (DevicePath == NULL || TargetPointer == NULL || *TargetPointer == NULL ||
817 Lun == NULL) {
818 return EFI_INVALID_PARAMETER;
819 }
820
821 if (DevicePath->Type != MESSAGING_DEVICE_PATH ||
822 DevicePath->SubType != MSG_SCSI_DP) {
823 return EFI_UNSUPPORTED;
824 }
825
826 ScsiDevicePath = (SCSI_DEVICE_PATH *) DevicePath;
827 Dev = VIRTIO_SCSI_FROM_PASS_THRU (This);
828 if (ScsiDevicePath->Pun > Dev->MaxTarget ||
829 ScsiDevicePath->Lun > Dev->MaxLun) {
830 return EFI_NOT_FOUND;
831 }
832
833 //
834 // a) the TargetPointer input parameter is unnecessarily a pointer-to-pointer
835 // b) see the TARGET_MAX_BYTES check in "VirtioScsi.h"
836 // c) ScsiDevicePath->Pun is an UINT16
837 //
838 Target = *TargetPointer;
839 CopyMem (Target, &ScsiDevicePath->Pun, 2);
840 SetMem (Target + 2, TARGET_MAX_BYTES - 2, 0x00);
841
842 *Lun = ScsiDevicePath->Lun;
843 return EFI_SUCCESS;
844 }
845
846
847 EFI_STATUS
848 EFIAPI
VirtioScsiResetChannel(IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL * This)849 VirtioScsiResetChannel (
850 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This
851 )
852 {
853 return EFI_UNSUPPORTED;
854 }
855
856
857 EFI_STATUS
858 EFIAPI
VirtioScsiResetTargetLun(IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL * This,IN UINT8 * Target,IN UINT64 Lun)859 VirtioScsiResetTargetLun (
860 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,
861 IN UINT8 *Target,
862 IN UINT64 Lun
863 )
864 {
865 return EFI_UNSUPPORTED;
866 }
867
868
869 EFI_STATUS
870 EFIAPI
VirtioScsiGetNextTarget(IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL * This,IN OUT UINT8 ** TargetPointer)871 VirtioScsiGetNextTarget (
872 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,
873 IN OUT UINT8 **TargetPointer
874 )
875 {
876 UINT8 *Target;
877 UINTN Idx;
878 UINT16 LastTarget;
879 VSCSI_DEV *Dev;
880
881 //
882 // the TargetPointer input parameter is unnecessarily a pointer-to-pointer
883 //
884 Target = *TargetPointer;
885
886 //
887 // Search for first non-0xFF byte. If not found, return first target.
888 //
889 for (Idx = 0; Idx < TARGET_MAX_BYTES && Target[Idx] == 0xFF; ++Idx)
890 ;
891 if (Idx == TARGET_MAX_BYTES) {
892 SetMem (Target, TARGET_MAX_BYTES, 0x00);
893 return EFI_SUCCESS;
894 }
895
896 //
897 // see the TARGET_MAX_BYTES check in "VirtioScsi.h"
898 //
899 CopyMem (&LastTarget, Target, sizeof LastTarget);
900
901 //
902 // increment target if valid on input
903 //
904 Dev = VIRTIO_SCSI_FROM_PASS_THRU (This);
905 if (LastTarget > Dev->MaxTarget) {
906 return EFI_INVALID_PARAMETER;
907 }
908
909 if (LastTarget < Dev->MaxTarget) {
910 ++LastTarget;
911 CopyMem (Target, &LastTarget, sizeof LastTarget);
912 return EFI_SUCCESS;
913 }
914
915 return EFI_NOT_FOUND;
916 }
917
918
919 STATIC
920 EFI_STATUS
921 EFIAPI
VirtioScsiInit(IN OUT VSCSI_DEV * Dev)922 VirtioScsiInit (
923 IN OUT VSCSI_DEV *Dev
924 )
925 {
926 UINT8 NextDevStat;
927 EFI_STATUS Status;
928 UINT64 RingBaseShift;
929 UINT64 Features;
930 UINT16 MaxChannel; // for validation only
931 UINT32 NumQueues; // for validation only
932 UINT16 QueueSize;
933
934 //
935 // Execute virtio-0.9.5, 2.2.1 Device Initialization Sequence.
936 //
937 NextDevStat = 0; // step 1 -- reset device
938 Status = Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, NextDevStat);
939 if (EFI_ERROR (Status)) {
940 goto Failed;
941 }
942
943 NextDevStat |= VSTAT_ACK; // step 2 -- acknowledge device presence
944 Status = Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, NextDevStat);
945 if (EFI_ERROR (Status)) {
946 goto Failed;
947 }
948
949 NextDevStat |= VSTAT_DRIVER; // step 3 -- we know how to drive it
950 Status = Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, NextDevStat);
951 if (EFI_ERROR (Status)) {
952 goto Failed;
953 }
954
955 //
956 // Set Page Size - MMIO VirtIo Specific
957 //
958 Status = Dev->VirtIo->SetPageSize (Dev->VirtIo, EFI_PAGE_SIZE);
959 if (EFI_ERROR (Status)) {
960 goto Failed;
961 }
962
963 //
964 // step 4a -- retrieve and validate features
965 //
966 Status = Dev->VirtIo->GetDeviceFeatures (Dev->VirtIo, &Features);
967 if (EFI_ERROR (Status)) {
968 goto Failed;
969 }
970 Dev->InOutSupported = (BOOLEAN) ((Features & VIRTIO_SCSI_F_INOUT) != 0);
971
972 Status = VIRTIO_CFG_READ (Dev, MaxChannel, &MaxChannel);
973 if (EFI_ERROR (Status)) {
974 goto Failed;
975 }
976 if (MaxChannel != 0) {
977 //
978 // this driver is for a single-channel virtio-scsi HBA
979 //
980 Status = EFI_UNSUPPORTED;
981 goto Failed;
982 }
983
984 Status = VIRTIO_CFG_READ (Dev, NumQueues, &NumQueues);
985 if (EFI_ERROR (Status)) {
986 goto Failed;
987 }
988 if (NumQueues < 1) {
989 Status = EFI_UNSUPPORTED;
990 goto Failed;
991 }
992
993 Status = VIRTIO_CFG_READ (Dev, MaxTarget, &Dev->MaxTarget);
994 if (EFI_ERROR (Status)) {
995 goto Failed;
996 }
997 if (Dev->MaxTarget > PcdGet16 (PcdVirtioScsiMaxTargetLimit)) {
998 Dev->MaxTarget = PcdGet16 (PcdVirtioScsiMaxTargetLimit);
999 }
1000
1001 Status = VIRTIO_CFG_READ (Dev, MaxLun, &Dev->MaxLun);
1002 if (EFI_ERROR (Status)) {
1003 goto Failed;
1004 }
1005 if (Dev->MaxLun > PcdGet32 (PcdVirtioScsiMaxLunLimit)) {
1006 Dev->MaxLun = PcdGet32 (PcdVirtioScsiMaxLunLimit);
1007 }
1008
1009 Status = VIRTIO_CFG_READ (Dev, MaxSectors, &Dev->MaxSectors);
1010 if (EFI_ERROR (Status)) {
1011 goto Failed;
1012 }
1013 if (Dev->MaxSectors < 2) {
1014 //
1015 // We must be able to halve it for bidirectional transfers
1016 // (see EFI_BAD_BUFFER_SIZE in PopulateRequest()).
1017 //
1018 Status = EFI_UNSUPPORTED;
1019 goto Failed;
1020 }
1021
1022 Features &= VIRTIO_SCSI_F_INOUT | VIRTIO_F_VERSION_1 |
1023 VIRTIO_F_IOMMU_PLATFORM;
1024
1025 //
1026 // In virtio-1.0, feature negotiation is expected to complete before queue
1027 // discovery, and the device can also reject the selected set of features.
1028 //
1029 if (Dev->VirtIo->Revision >= VIRTIO_SPEC_REVISION (1, 0, 0)) {
1030 Status = Virtio10WriteFeatures (Dev->VirtIo, Features, &NextDevStat);
1031 if (EFI_ERROR (Status)) {
1032 goto Failed;
1033 }
1034 }
1035
1036 //
1037 // step 4b -- allocate request virtqueue
1038 //
1039 Status = Dev->VirtIo->SetQueueSel (Dev->VirtIo, VIRTIO_SCSI_REQUEST_QUEUE);
1040 if (EFI_ERROR (Status)) {
1041 goto Failed;
1042 }
1043 Status = Dev->VirtIo->GetQueueNumMax (Dev->VirtIo, &QueueSize);
1044 if (EFI_ERROR (Status)) {
1045 goto Failed;
1046 }
1047 //
1048 // VirtioScsiPassThru() uses at most four descriptors
1049 //
1050 if (QueueSize < 4) {
1051 Status = EFI_UNSUPPORTED;
1052 goto Failed;
1053 }
1054
1055 Status = VirtioRingInit (Dev->VirtIo, QueueSize, &Dev->Ring);
1056 if (EFI_ERROR (Status)) {
1057 goto Failed;
1058 }
1059
1060 //
1061 // If anything fails from here on, we must release the ring resources
1062 //
1063 Status = VirtioRingMap (
1064 Dev->VirtIo,
1065 &Dev->Ring,
1066 &RingBaseShift,
1067 &Dev->RingMap
1068 );
1069 if (EFI_ERROR (Status)) {
1070 goto ReleaseQueue;
1071 }
1072
1073 //
1074 // Additional steps for MMIO: align the queue appropriately, and set the
1075 // size. If anything fails from here on, we must unmap the ring resources.
1076 //
1077 Status = Dev->VirtIo->SetQueueNum (Dev->VirtIo, QueueSize);
1078 if (EFI_ERROR (Status)) {
1079 goto UnmapQueue;
1080 }
1081
1082 Status = Dev->VirtIo->SetQueueAlign (Dev->VirtIo, EFI_PAGE_SIZE);
1083 if (EFI_ERROR (Status)) {
1084 goto UnmapQueue;
1085 }
1086
1087 //
1088 // step 4c -- Report GPFN (guest-physical frame number) of queue.
1089 //
1090 Status = Dev->VirtIo->SetQueueAddress (
1091 Dev->VirtIo,
1092 &Dev->Ring,
1093 RingBaseShift
1094 );
1095 if (EFI_ERROR (Status)) {
1096 goto UnmapQueue;
1097 }
1098
1099 //
1100 // step 5 -- Report understood features and guest-tuneables.
1101 //
1102 if (Dev->VirtIo->Revision < VIRTIO_SPEC_REVISION (1, 0, 0)) {
1103 Features &= ~(UINT64)(VIRTIO_F_VERSION_1 | VIRTIO_F_IOMMU_PLATFORM);
1104 Status = Dev->VirtIo->SetGuestFeatures (Dev->VirtIo, Features);
1105 if (EFI_ERROR (Status)) {
1106 goto UnmapQueue;
1107 }
1108 }
1109
1110 //
1111 // We expect these maximum sizes from the host. Since they are
1112 // guest-negotiable, ask for them rather than just checking them.
1113 //
1114 Status = VIRTIO_CFG_WRITE (Dev, CdbSize, VIRTIO_SCSI_CDB_SIZE);
1115 if (EFI_ERROR (Status)) {
1116 goto UnmapQueue;
1117 }
1118 Status = VIRTIO_CFG_WRITE (Dev, SenseSize, VIRTIO_SCSI_SENSE_SIZE);
1119 if (EFI_ERROR (Status)) {
1120 goto UnmapQueue;
1121 }
1122
1123 //
1124 // step 6 -- initialization complete
1125 //
1126 NextDevStat |= VSTAT_DRIVER_OK;
1127 Status = Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, NextDevStat);
1128 if (EFI_ERROR (Status)) {
1129 goto UnmapQueue;
1130 }
1131
1132 //
1133 // populate the exported interface's attributes
1134 //
1135 Dev->PassThru.Mode = &Dev->PassThruMode;
1136 Dev->PassThru.PassThru = &VirtioScsiPassThru;
1137 Dev->PassThru.GetNextTargetLun = &VirtioScsiGetNextTargetLun;
1138 Dev->PassThru.BuildDevicePath = &VirtioScsiBuildDevicePath;
1139 Dev->PassThru.GetTargetLun = &VirtioScsiGetTargetLun;
1140 Dev->PassThru.ResetChannel = &VirtioScsiResetChannel;
1141 Dev->PassThru.ResetTargetLun = &VirtioScsiResetTargetLun;
1142 Dev->PassThru.GetNextTarget = &VirtioScsiGetNextTarget;
1143
1144 //
1145 // AdapterId is a target for which no handle will be created during bus scan.
1146 // Prevent any conflict with real devices.
1147 //
1148 Dev->PassThruMode.AdapterId = 0xFFFFFFFF;
1149
1150 //
1151 // Set both physical and logical attributes for non-RAID SCSI channel. See
1152 // Driver Writer's Guide for UEFI 2.3.1 v1.01, 20.1.5 Implementing Extended
1153 // SCSI Pass Thru Protocol.
1154 //
1155 Dev->PassThruMode.Attributes = EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_PHYSICAL |
1156 EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL;
1157
1158 //
1159 // no restriction on transfer buffer alignment
1160 //
1161 Dev->PassThruMode.IoAlign = 0;
1162
1163 return EFI_SUCCESS;
1164
1165 UnmapQueue:
1166 Dev->VirtIo->UnmapSharedBuffer (Dev->VirtIo, Dev->RingMap);
1167
1168 ReleaseQueue:
1169 VirtioRingUninit (Dev->VirtIo, &Dev->Ring);
1170
1171 Failed:
1172 //
1173 // Notify the host about our failure to setup: virtio-0.9.5, 2.2.2.1 Device
1174 // Status. VirtIo access failure here should not mask the original error.
1175 //
1176 NextDevStat |= VSTAT_FAILED;
1177 Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, NextDevStat);
1178
1179 Dev->InOutSupported = FALSE;
1180 Dev->MaxTarget = 0;
1181 Dev->MaxLun = 0;
1182 Dev->MaxSectors = 0;
1183
1184 return Status; // reached only via Failed above
1185 }
1186
1187
1188 STATIC
1189 VOID
1190 EFIAPI
VirtioScsiUninit(IN OUT VSCSI_DEV * Dev)1191 VirtioScsiUninit (
1192 IN OUT VSCSI_DEV *Dev
1193 )
1194 {
1195 //
1196 // Reset the virtual device -- see virtio-0.9.5, 2.2.2.1 Device Status. When
1197 // VIRTIO_CFG_WRITE() returns, the host will have learned to stay away from
1198 // the old comms area.
1199 //
1200 Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, 0);
1201
1202 Dev->InOutSupported = FALSE;
1203 Dev->MaxTarget = 0;
1204 Dev->MaxLun = 0;
1205 Dev->MaxSectors = 0;
1206
1207 Dev->VirtIo->UnmapSharedBuffer (Dev->VirtIo, Dev->RingMap);
1208 VirtioRingUninit (Dev->VirtIo, &Dev->Ring);
1209
1210 SetMem (&Dev->PassThru, sizeof Dev->PassThru, 0x00);
1211 SetMem (&Dev->PassThruMode, sizeof Dev->PassThruMode, 0x00);
1212 }
1213
1214
1215 //
1216 // Event notification function enqueued by ExitBootServices().
1217 //
1218
1219 STATIC
1220 VOID
1221 EFIAPI
VirtioScsiExitBoot(IN EFI_EVENT Event,IN VOID * Context)1222 VirtioScsiExitBoot (
1223 IN EFI_EVENT Event,
1224 IN VOID *Context
1225 )
1226 {
1227 VSCSI_DEV *Dev;
1228
1229 DEBUG ((DEBUG_VERBOSE, "%a: Context=0x%p\n", __FUNCTION__, Context));
1230 //
1231 // Reset the device. This causes the hypervisor to forget about the virtio
1232 // ring.
1233 //
1234 // We allocated said ring in EfiBootServicesData type memory, and code
1235 // executing after ExitBootServices() is permitted to overwrite it.
1236 //
1237 Dev = Context;
1238 Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, 0);
1239 }
1240
1241
1242 //
1243 // Probe, start and stop functions of this driver, called by the DXE core for
1244 // specific devices.
1245 //
1246 // The following specifications document these interfaces:
1247 // - Driver Writer's Guide for UEFI 2.3.1 v1.01, 9 Driver Binding Protocol
1248 // - UEFI Spec 2.3.1 + Errata C, 10.1 EFI Driver Binding Protocol
1249 //
1250 // The implementation follows:
1251 // - Driver Writer's Guide for UEFI 2.3.1 v1.01
1252 // - 5.1.3.4 OpenProtocol() and CloseProtocol()
1253 // - UEFI Spec 2.3.1 + Errata C
1254 // - 6.3 Protocol Handler Services
1255 //
1256
1257 EFI_STATUS
1258 EFIAPI
VirtioScsiDriverBindingSupported(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE DeviceHandle,IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath)1259 VirtioScsiDriverBindingSupported (
1260 IN EFI_DRIVER_BINDING_PROTOCOL *This,
1261 IN EFI_HANDLE DeviceHandle,
1262 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
1263 )
1264 {
1265 EFI_STATUS Status;
1266 VIRTIO_DEVICE_PROTOCOL *VirtIo;
1267
1268 //
1269 // Attempt to open the device with the VirtIo set of interfaces. On success,
1270 // the protocol is "instantiated" for the VirtIo device. Covers duplicate open
1271 // attempts (EFI_ALREADY_STARTED).
1272 //
1273 Status = gBS->OpenProtocol (
1274 DeviceHandle, // candidate device
1275 &gVirtioDeviceProtocolGuid, // for generic VirtIo access
1276 (VOID **)&VirtIo, // handle to instantiate
1277 This->DriverBindingHandle, // requestor driver identity
1278 DeviceHandle, // ControllerHandle, according to
1279 // the UEFI Driver Model
1280 EFI_OPEN_PROTOCOL_BY_DRIVER // get exclusive VirtIo access to
1281 // the device; to be released
1282 );
1283 if (EFI_ERROR (Status)) {
1284 return Status;
1285 }
1286
1287 if (VirtIo->SubSystemDeviceId != VIRTIO_SUBSYSTEM_SCSI_HOST) {
1288 Status = EFI_UNSUPPORTED;
1289 }
1290
1291 //
1292 // We needed VirtIo access only transitorily, to see whether we support the
1293 // device or not.
1294 //
1295 gBS->CloseProtocol (DeviceHandle, &gVirtioDeviceProtocolGuid,
1296 This->DriverBindingHandle, DeviceHandle);
1297 return Status;
1298 }
1299
1300
1301 EFI_STATUS
1302 EFIAPI
VirtioScsiDriverBindingStart(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE DeviceHandle,IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath)1303 VirtioScsiDriverBindingStart (
1304 IN EFI_DRIVER_BINDING_PROTOCOL *This,
1305 IN EFI_HANDLE DeviceHandle,
1306 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
1307 )
1308 {
1309 VSCSI_DEV *Dev;
1310 EFI_STATUS Status;
1311
1312 Dev = (VSCSI_DEV *) AllocateZeroPool (sizeof *Dev);
1313 if (Dev == NULL) {
1314 return EFI_OUT_OF_RESOURCES;
1315 }
1316
1317 Status = gBS->OpenProtocol (DeviceHandle, &gVirtioDeviceProtocolGuid,
1318 (VOID **)&Dev->VirtIo, This->DriverBindingHandle,
1319 DeviceHandle, EFI_OPEN_PROTOCOL_BY_DRIVER);
1320 if (EFI_ERROR (Status)) {
1321 goto FreeVirtioScsi;
1322 }
1323
1324 //
1325 // VirtIo access granted, configure virtio-scsi device.
1326 //
1327 Status = VirtioScsiInit (Dev);
1328 if (EFI_ERROR (Status)) {
1329 goto CloseVirtIo;
1330 }
1331
1332 Status = gBS->CreateEvent (EVT_SIGNAL_EXIT_BOOT_SERVICES, TPL_CALLBACK,
1333 &VirtioScsiExitBoot, Dev, &Dev->ExitBoot);
1334 if (EFI_ERROR (Status)) {
1335 goto UninitDev;
1336 }
1337
1338 //
1339 // Setup complete, attempt to export the driver instance's PassThru
1340 // interface.
1341 //
1342 Dev->Signature = VSCSI_SIG;
1343 Status = gBS->InstallProtocolInterface (&DeviceHandle,
1344 &gEfiExtScsiPassThruProtocolGuid, EFI_NATIVE_INTERFACE,
1345 &Dev->PassThru);
1346 if (EFI_ERROR (Status)) {
1347 goto CloseExitBoot;
1348 }
1349
1350 return EFI_SUCCESS;
1351
1352 CloseExitBoot:
1353 gBS->CloseEvent (Dev->ExitBoot);
1354
1355 UninitDev:
1356 VirtioScsiUninit (Dev);
1357
1358 CloseVirtIo:
1359 gBS->CloseProtocol (DeviceHandle, &gVirtioDeviceProtocolGuid,
1360 This->DriverBindingHandle, DeviceHandle);
1361
1362 FreeVirtioScsi:
1363 FreePool (Dev);
1364
1365 return Status;
1366 }
1367
1368
1369 EFI_STATUS
1370 EFIAPI
VirtioScsiDriverBindingStop(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE DeviceHandle,IN UINTN NumberOfChildren,IN EFI_HANDLE * ChildHandleBuffer)1371 VirtioScsiDriverBindingStop (
1372 IN EFI_DRIVER_BINDING_PROTOCOL *This,
1373 IN EFI_HANDLE DeviceHandle,
1374 IN UINTN NumberOfChildren,
1375 IN EFI_HANDLE *ChildHandleBuffer
1376 )
1377 {
1378 EFI_STATUS Status;
1379 EFI_EXT_SCSI_PASS_THRU_PROTOCOL *PassThru;
1380 VSCSI_DEV *Dev;
1381
1382 Status = gBS->OpenProtocol (
1383 DeviceHandle, // candidate device
1384 &gEfiExtScsiPassThruProtocolGuid, // retrieve the SCSI iface
1385 (VOID **)&PassThru, // target pointer
1386 This->DriverBindingHandle, // requestor driver ident.
1387 DeviceHandle, // lookup req. for dev.
1388 EFI_OPEN_PROTOCOL_GET_PROTOCOL // lookup only, no new ref.
1389 );
1390 if (EFI_ERROR (Status)) {
1391 return Status;
1392 }
1393
1394 Dev = VIRTIO_SCSI_FROM_PASS_THRU (PassThru);
1395
1396 //
1397 // Handle Stop() requests for in-use driver instances gracefully.
1398 //
1399 Status = gBS->UninstallProtocolInterface (DeviceHandle,
1400 &gEfiExtScsiPassThruProtocolGuid, &Dev->PassThru);
1401 if (EFI_ERROR (Status)) {
1402 return Status;
1403 }
1404
1405 gBS->CloseEvent (Dev->ExitBoot);
1406
1407 VirtioScsiUninit (Dev);
1408
1409 gBS->CloseProtocol (DeviceHandle, &gVirtioDeviceProtocolGuid,
1410 This->DriverBindingHandle, DeviceHandle);
1411
1412 FreePool (Dev);
1413
1414 return EFI_SUCCESS;
1415 }
1416
1417
1418 //
1419 // The static object that groups the Supported() (ie. probe), Start() and
1420 // Stop() functions of the driver together. Refer to UEFI Spec 2.3.1 + Errata
1421 // C, 10.1 EFI Driver Binding Protocol.
1422 //
1423 STATIC EFI_DRIVER_BINDING_PROTOCOL gDriverBinding = {
1424 &VirtioScsiDriverBindingSupported,
1425 &VirtioScsiDriverBindingStart,
1426 &VirtioScsiDriverBindingStop,
1427 0x10, // Version, must be in [0x10 .. 0xFFFFFFEF] for IHV-developed drivers
1428 NULL, // ImageHandle, to be overwritten by
1429 // EfiLibInstallDriverBindingComponentName2() in VirtioScsiEntryPoint()
1430 NULL // DriverBindingHandle, ditto
1431 };
1432
1433
1434 //
1435 // The purpose of the following scaffolding (EFI_COMPONENT_NAME_PROTOCOL and
1436 // EFI_COMPONENT_NAME2_PROTOCOL implementation) is to format the driver's name
1437 // in English, for display on standard console devices. This is recommended for
1438 // UEFI drivers that follow the UEFI Driver Model. Refer to the Driver Writer's
1439 // Guide for UEFI 2.3.1 v1.01, 11 UEFI Driver and Controller Names.
1440 //
1441 // Device type names ("Virtio SCSI Host Device") are not formatted because the
1442 // driver supports only that device type. Therefore the driver name suffices
1443 // for unambiguous identification.
1444 //
1445
1446 STATIC
1447 EFI_UNICODE_STRING_TABLE mDriverNameTable[] = {
1448 { "eng;en", L"Virtio SCSI Host Driver" },
1449 { NULL, NULL }
1450 };
1451
1452 STATIC
1453 EFI_COMPONENT_NAME_PROTOCOL gComponentName;
1454
1455 EFI_STATUS
1456 EFIAPI
VirtioScsiGetDriverName(IN EFI_COMPONENT_NAME_PROTOCOL * This,IN CHAR8 * Language,OUT CHAR16 ** DriverName)1457 VirtioScsiGetDriverName (
1458 IN EFI_COMPONENT_NAME_PROTOCOL *This,
1459 IN CHAR8 *Language,
1460 OUT CHAR16 **DriverName
1461 )
1462 {
1463 return LookupUnicodeString2 (
1464 Language,
1465 This->SupportedLanguages,
1466 mDriverNameTable,
1467 DriverName,
1468 (BOOLEAN)(This == &gComponentName) // Iso639Language
1469 );
1470 }
1471
1472 EFI_STATUS
1473 EFIAPI
VirtioScsiGetDeviceName(IN EFI_COMPONENT_NAME_PROTOCOL * This,IN EFI_HANDLE DeviceHandle,IN EFI_HANDLE ChildHandle,IN CHAR8 * Language,OUT CHAR16 ** ControllerName)1474 VirtioScsiGetDeviceName (
1475 IN EFI_COMPONENT_NAME_PROTOCOL *This,
1476 IN EFI_HANDLE DeviceHandle,
1477 IN EFI_HANDLE ChildHandle,
1478 IN CHAR8 *Language,
1479 OUT CHAR16 **ControllerName
1480 )
1481 {
1482 return EFI_UNSUPPORTED;
1483 }
1484
1485 STATIC
1486 EFI_COMPONENT_NAME_PROTOCOL gComponentName = {
1487 &VirtioScsiGetDriverName,
1488 &VirtioScsiGetDeviceName,
1489 "eng" // SupportedLanguages, ISO 639-2 language codes
1490 };
1491
1492 STATIC
1493 EFI_COMPONENT_NAME2_PROTOCOL gComponentName2 = {
1494 (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) &VirtioScsiGetDriverName,
1495 (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) &VirtioScsiGetDeviceName,
1496 "en" // SupportedLanguages, RFC 4646 language codes
1497 };
1498
1499
1500 //
1501 // Entry point of this driver.
1502 //
1503 EFI_STATUS
1504 EFIAPI
VirtioScsiEntryPoint(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)1505 VirtioScsiEntryPoint (
1506 IN EFI_HANDLE ImageHandle,
1507 IN EFI_SYSTEM_TABLE *SystemTable
1508 )
1509 {
1510 return EfiLibInstallDriverBindingComponentName2 (
1511 ImageHandle,
1512 SystemTable,
1513 &gDriverBinding,
1514 ImageHandle,
1515 &gComponentName,
1516 &gComponentName2
1517 );
1518 }
1519