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