VirtualBox

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

最後變更 在這個檔案從63524是 58464,由 vboxsync 提交於 9 年 前

EFI/Firmware: Export new files and directories.

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

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