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