]> git.proxmox.com Git - mirror_edk2.git/blame - OvmfPkg/PvScsiDxe/PvScsi.c
OvmfPkg/PvScsiDxe: Setup requests and completions rings
[mirror_edk2.git] / OvmfPkg / PvScsiDxe / PvScsi.c
CommitLineData
478c07d4
LA
1/** @file\r
2\r
3 This driver produces Extended SCSI Pass Thru Protocol instances for\r
4 pvscsi devices.\r
5\r
6 Copyright (C) 2020, Oracle and/or its affiliates.\r
7\r
8 SPDX-License-Identifier: BSD-2-Clause-Patent\r
9\r
10**/\r
11\r
a9f9d5cf
LA
12#include <IndustryStandard/Pci.h>\r
13#include <IndustryStandard/PvScsi.h>\r
b654edec 14#include <Library/BaseLib.h>\r
7efce2e5 15#include <Library/BaseMemoryLib.h>\r
e497432c 16#include <Library/MemoryAllocationLib.h>\r
a9f9d5cf 17#include <Library/UefiBootServicesTableLib.h>\r
ed08c571 18#include <Library/UefiLib.h>\r
a9f9d5cf 19#include <Protocol/PciIo.h>\r
b654edec 20#include <Protocol/PciRootBridgeIo.h>\r
478c07d4
LA
21#include <Uefi/UefiSpec.h>\r
22\r
e497432c
LA
23#include "PvScsi.h"\r
24\r
ed08c571
LA
25//\r
26// Higher versions will be used before lower, 0x10-0xffffffef is the version\r
27// range for IHV (Indie Hardware Vendors)\r
28//\r
29#define PVSCSI_BINDING_VERSION 0x10\r
30\r
7efce2e5
LA
31//\r
32// Ext SCSI Pass Thru utilities\r
33//\r
34\r
5269c26e
LA
35/**\r
36 Writes a 32-bit value into BAR0 using MMIO\r
37**/\r
38STATIC\r
39EFI_STATUS\r
40PvScsiMmioWrite32 (\r
41 IN CONST PVSCSI_DEV *Dev,\r
42 IN UINT64 Offset,\r
43 IN UINT32 Value\r
44 )\r
45{\r
46 return Dev->PciIo->Mem.Write (\r
47 Dev->PciIo,\r
48 EfiPciIoWidthUint32,\r
49 PCI_BAR_IDX0,\r
50 Offset,\r
51 1, // Count\r
52 &Value\r
53 );\r
54}\r
55\r
56/**\r
57 Writes multiple words of data into BAR0 using MMIO\r
58**/\r
59STATIC\r
60EFI_STATUS\r
61PvScsiMmioWrite32Multiple (\r
62 IN CONST PVSCSI_DEV *Dev,\r
63 IN UINT64 Offset,\r
64 IN UINTN Count,\r
65 IN UINT32 *Words\r
66 )\r
67{\r
68 return Dev->PciIo->Mem.Write (\r
69 Dev->PciIo,\r
70 EfiPciIoWidthFifoUint32,\r
71 PCI_BAR_IDX0,\r
72 Offset,\r
73 Count,\r
74 Words\r
75 );\r
76}\r
77\r
78/**\r
79 Send a PVSCSI command to device.\r
80\r
81 @param[in] Dev The pvscsi host device.\r
82 @param[in] Cmd The command to send to device.\r
83 @param[in] OPTIONAL DescWords An optional command descriptor (If command\r
84 have a descriptor). The descriptor is\r
85 provided as an array of UINT32 words and\r
86 is must be 32-bit aligned.\r
87 @param[in] DescWordsCount The number of words in command descriptor.\r
88 Caller must specify here 0 if DescWords\r
89 is not supplied (It is optional). In that\r
90 case, DescWords is ignored.\r
91\r
92 @return Status codes returned by Dev->PciIo->Mem.Write().\r
93\r
94**/\r
95STATIC\r
96EFI_STATUS\r
97PvScsiWriteCmdDesc (\r
98 IN CONST PVSCSI_DEV *Dev,\r
99 IN UINT32 Cmd,\r
100 IN UINT32 *DescWords OPTIONAL,\r
101 IN UINTN DescWordsCount\r
102 )\r
103{\r
104 EFI_STATUS Status;\r
105\r
106 if (DescWordsCount > PVSCSI_MAX_CMD_DATA_WORDS) {\r
107 return EFI_INVALID_PARAMETER;\r
108 }\r
109\r
110 Status = PvScsiMmioWrite32 (Dev, PvScsiRegOffsetCommand, Cmd);\r
111 if (EFI_ERROR (Status)) {\r
112 return Status;\r
113 }\r
114\r
115 if (DescWordsCount > 0) {\r
116 return PvScsiMmioWrite32Multiple (\r
117 Dev,\r
118 PvScsiRegOffsetCommandData,\r
119 DescWordsCount,\r
120 DescWords\r
121 );\r
122 }\r
123\r
124 return EFI_SUCCESS;\r
125}\r
126\r
127STATIC\r
128EFI_STATUS\r
129PvScsiResetAdapter (\r
130 IN CONST PVSCSI_DEV *Dev\r
131 )\r
132{\r
133 return PvScsiWriteCmdDesc (Dev, PvScsiCmdAdapterReset, NULL, 0);\r
134}\r
135\r
7efce2e5
LA
136/**\r
137 Check if Target argument to EXT_SCSI_PASS_THRU.GetNextTarget() and\r
138 EXT_SCSI_PASS_THRU.GetNextTargetLun() is initialized\r
139**/\r
140STATIC\r
141BOOLEAN\r
142IsTargetInitialized (\r
143 IN UINT8 *Target\r
144 )\r
145{\r
146 UINTN Idx;\r
147\r
148 for (Idx = 0; Idx < TARGET_MAX_BYTES; ++Idx) {\r
149 if (Target[Idx] != 0xFF) {\r
150 return TRUE;\r
151 }\r
152 }\r
153 return FALSE;\r
154}\r
155\r
e497432c
LA
156//\r
157// Ext SCSI Pass Thru\r
158//\r
159\r
160STATIC\r
161EFI_STATUS\r
162EFIAPI\r
163PvScsiPassThru (\r
164 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,\r
165 IN UINT8 *Target,\r
166 IN UINT64 Lun,\r
167 IN OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet,\r
168 IN EFI_EVENT Event OPTIONAL\r
169 )\r
170{\r
171 return EFI_UNSUPPORTED;\r
172}\r
173\r
174STATIC\r
175EFI_STATUS\r
176EFIAPI\r
177PvScsiGetNextTargetLun (\r
178 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,\r
179 IN OUT UINT8 **Target,\r
180 IN OUT UINT64 *Lun\r
181 )\r
182{\r
7efce2e5
LA
183 UINT8 *TargetPtr;\r
184 UINT8 LastTarget;\r
185 PVSCSI_DEV *Dev;\r
186\r
187 if (Target == NULL) {\r
188 return EFI_INVALID_PARAMETER;\r
189 }\r
190\r
191 //\r
192 // The Target input parameter is unnecessarily a pointer-to-pointer\r
193 //\r
194 TargetPtr = *Target;\r
195\r
196 //\r
197 // If target not initialized, return first target & LUN\r
198 //\r
199 if (!IsTargetInitialized (TargetPtr)) {\r
200 ZeroMem (TargetPtr, TARGET_MAX_BYTES);\r
201 *Lun = 0;\r
202 return EFI_SUCCESS;\r
203 }\r
204\r
205 //\r
206 // We only use first byte of target identifer\r
207 //\r
208 LastTarget = *TargetPtr;\r
209\r
210 //\r
211 // Increment (target, LUN) pair if valid on input\r
212 //\r
213 Dev = PVSCSI_FROM_PASS_THRU (This);\r
214 if (LastTarget > Dev->MaxTarget || *Lun > Dev->MaxLun) {\r
215 return EFI_INVALID_PARAMETER;\r
216 }\r
217\r
218 if (*Lun < Dev->MaxLun) {\r
219 ++*Lun;\r
220 return EFI_SUCCESS;\r
221 }\r
222\r
223 if (LastTarget < Dev->MaxTarget) {\r
224 *Lun = 0;\r
225 ++LastTarget;\r
226 *TargetPtr = LastTarget;\r
227 return EFI_SUCCESS;\r
228 }\r
229\r
230 return EFI_NOT_FOUND;\r
e497432c
LA
231}\r
232\r
233STATIC\r
234EFI_STATUS\r
235EFIAPI\r
236PvScsiBuildDevicePath (\r
237 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,\r
238 IN UINT8 *Target,\r
239 IN UINT64 Lun,\r
240 IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath\r
241 )\r
242{\r
9c2d8281
LA
243 UINT8 TargetValue;\r
244 PVSCSI_DEV *Dev;\r
245 SCSI_DEVICE_PATH *ScsiDevicePath;\r
246\r
247 if (DevicePath == NULL) {\r
248 return EFI_INVALID_PARAMETER;\r
249 }\r
250\r
251 //\r
252 // We only use first byte of target identifer\r
253 //\r
254 TargetValue = *Target;\r
255\r
256 Dev = PVSCSI_FROM_PASS_THRU (This);\r
257 if (TargetValue > Dev->MaxTarget || Lun > Dev->MaxLun) {\r
258 return EFI_NOT_FOUND;\r
259 }\r
260\r
261 ScsiDevicePath = AllocatePool (sizeof (*ScsiDevicePath));\r
262 if (ScsiDevicePath == NULL) {\r
263 return EFI_OUT_OF_RESOURCES;\r
264 }\r
265\r
266 ScsiDevicePath->Header.Type = MESSAGING_DEVICE_PATH;\r
267 ScsiDevicePath->Header.SubType = MSG_SCSI_DP;\r
268 ScsiDevicePath->Header.Length[0] = (UINT8)sizeof (*ScsiDevicePath);\r
269 ScsiDevicePath->Header.Length[1] = (UINT8)(sizeof (*ScsiDevicePath) >> 8);\r
270 ScsiDevicePath->Pun = TargetValue;\r
271 ScsiDevicePath->Lun = (UINT16)Lun;\r
272\r
273 *DevicePath = &ScsiDevicePath->Header;\r
274 return EFI_SUCCESS;\r
e497432c
LA
275}\r
276\r
277STATIC\r
278EFI_STATUS\r
279EFIAPI\r
280PvScsiGetTargetLun (\r
281 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,\r
282 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,\r
283 OUT UINT8 **Target,\r
284 OUT UINT64 *Lun\r
285 )\r
286{\r
9c2d8281
LA
287 SCSI_DEVICE_PATH *ScsiDevicePath;\r
288 PVSCSI_DEV *Dev;\r
289\r
290 if (DevicePath == NULL || Target == NULL || *Target == NULL || Lun == NULL) {\r
291 return EFI_INVALID_PARAMETER;\r
292 }\r
293\r
294 if (DevicePath->Type != MESSAGING_DEVICE_PATH ||\r
295 DevicePath->SubType != MSG_SCSI_DP) {\r
296 return EFI_UNSUPPORTED;\r
297 }\r
298\r
299 ScsiDevicePath = (SCSI_DEVICE_PATH *)DevicePath;\r
300 Dev = PVSCSI_FROM_PASS_THRU (This);\r
301 if (ScsiDevicePath->Pun > Dev->MaxTarget ||\r
302 ScsiDevicePath->Lun > Dev->MaxLun) {\r
303 return EFI_NOT_FOUND;\r
304 }\r
305\r
306 //\r
307 // We only use first byte of target identifer\r
308 //\r
309 **Target = (UINT8)ScsiDevicePath->Pun;\r
310 ZeroMem (*Target + 1, TARGET_MAX_BYTES - 1);\r
311 *Lun = ScsiDevicePath->Lun;\r
312\r
313 return EFI_SUCCESS;\r
e497432c
LA
314}\r
315\r
316STATIC\r
317EFI_STATUS\r
318EFIAPI\r
319PvScsiResetChannel (\r
320 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This\r
321 )\r
322{\r
323 return EFI_UNSUPPORTED;\r
324}\r
325\r
326STATIC\r
327EFI_STATUS\r
328EFIAPI\r
329PvScsiResetTargetLun (\r
330 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,\r
331 IN UINT8 *Target,\r
332 IN UINT64 Lun\r
333 )\r
334{\r
335 return EFI_UNSUPPORTED;\r
336}\r
337\r
338STATIC\r
339EFI_STATUS\r
340EFIAPI\r
341PvScsiGetNextTarget (\r
342 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,\r
343 IN OUT UINT8 **Target\r
344 )\r
345{\r
7efce2e5
LA
346 UINT8 *TargetPtr;\r
347 UINT8 LastTarget;\r
348 PVSCSI_DEV *Dev;\r
349\r
350 if (Target == NULL) {\r
351 return EFI_INVALID_PARAMETER;\r
352 }\r
353\r
354 //\r
355 // The Target input parameter is unnecessarily a pointer-to-pointer\r
356 //\r
357 TargetPtr = *Target;\r
358\r
359 //\r
360 // If target not initialized, return first target\r
361 //\r
362 if (!IsTargetInitialized (TargetPtr)) {\r
363 ZeroMem (TargetPtr, TARGET_MAX_BYTES);\r
364 return EFI_SUCCESS;\r
365 }\r
366\r
367 //\r
368 // We only use first byte of target identifer\r
369 //\r
370 LastTarget = *TargetPtr;\r
371\r
372 //\r
373 // Increment target if valid on input\r
374 //\r
375 Dev = PVSCSI_FROM_PASS_THRU (This);\r
376 if (LastTarget > Dev->MaxTarget) {\r
377 return EFI_INVALID_PARAMETER;\r
378 }\r
379\r
380 if (LastTarget < Dev->MaxTarget) {\r
381 ++LastTarget;\r
382 *TargetPtr = LastTarget;\r
383 return EFI_SUCCESS;\r
384 }\r
385\r
386 return EFI_NOT_FOUND;\r
e497432c
LA
387}\r
388\r
45098e8a
LA
389STATIC\r
390EFI_STATUS\r
391PvScsiSetPciAttributes (\r
392 IN OUT PVSCSI_DEV *Dev\r
393 )\r
394{\r
395 EFI_STATUS Status;\r
396\r
397 //\r
398 // Backup original PCI Attributes\r
399 //\r
400 Status = Dev->PciIo->Attributes (\r
401 Dev->PciIo,\r
402 EfiPciIoAttributeOperationGet,\r
403 0,\r
404 &Dev->OriginalPciAttributes\r
405 );\r
406 if (EFI_ERROR (Status)) {\r
407 return Status;\r
408 }\r
409\r
410 //\r
6672b3cf 411 // Enable MMIO-Space & Bus-Mastering\r
45098e8a 412 //\r
6672b3cf
LA
413 Status = Dev->PciIo->Attributes (\r
414 Dev->PciIo,\r
415 EfiPciIoAttributeOperationEnable,\r
416 (EFI_PCI_IO_ATTRIBUTE_MEMORY |\r
417 EFI_PCI_IO_ATTRIBUTE_BUS_MASTER),\r
418 NULL\r
419 );\r
420 if (EFI_ERROR (Status)) {\r
421 return Status;\r
422 }\r
45098e8a
LA
423\r
424 return EFI_SUCCESS;\r
425}\r
426\r
427STATIC\r
428VOID\r
429PvScsiRestorePciAttributes (\r
430 IN PVSCSI_DEV *Dev\r
431 )\r
432{\r
433 Dev->PciIo->Attributes (\r
434 Dev->PciIo,\r
435 EfiPciIoAttributeOperationSet,\r
436 Dev->OriginalPciAttributes,\r
437 NULL\r
438 );\r
439}\r
440\r
b654edec
LA
441STATIC\r
442EFI_STATUS\r
443PvScsiAllocateSharedPages (\r
444 IN PVSCSI_DEV *Dev,\r
445 IN UINTN Pages,\r
446 OUT VOID **HostAddress,\r
447 OUT PVSCSI_DMA_DESC *DmaDesc\r
448 )\r
449{\r
450 EFI_STATUS Status;\r
451 UINTN NumberOfBytes;\r
452\r
453 Status = Dev->PciIo->AllocateBuffer (\r
454 Dev->PciIo,\r
455 AllocateAnyPages,\r
456 EfiBootServicesData,\r
457 Pages,\r
458 HostAddress,\r
459 EFI_PCI_ATTRIBUTE_MEMORY_CACHED\r
460 );\r
461 if (EFI_ERROR (Status)) {\r
462 return Status;\r
463 }\r
464\r
465 NumberOfBytes = EFI_PAGES_TO_SIZE (Pages);\r
466 Status = Dev->PciIo->Map (\r
467 Dev->PciIo,\r
468 EfiPciIoOperationBusMasterCommonBuffer,\r
469 *HostAddress,\r
470 &NumberOfBytes,\r
471 &DmaDesc->DeviceAddress,\r
472 &DmaDesc->Mapping\r
473 );\r
474 if (EFI_ERROR (Status)) {\r
475 goto FreeBuffer;\r
476 }\r
477\r
478 if (NumberOfBytes != EFI_PAGES_TO_SIZE (Pages)) {\r
479 Status = EFI_OUT_OF_RESOURCES;\r
480 goto Unmap;\r
481 }\r
482\r
483 return EFI_SUCCESS;\r
484\r
485Unmap:\r
486 Dev->PciIo->Unmap (Dev->PciIo, DmaDesc->Mapping);\r
487\r
488FreeBuffer:\r
489 Dev->PciIo->FreeBuffer (Dev->PciIo, Pages, *HostAddress);\r
490\r
491 return Status;\r
492}\r
493\r
494STATIC\r
495VOID\r
496PvScsiFreeSharedPages (\r
497 IN PVSCSI_DEV *Dev,\r
498 IN UINTN Pages,\r
499 IN VOID *HostAddress,\r
500 IN PVSCSI_DMA_DESC *DmaDesc\r
501 )\r
502{\r
503 Dev->PciIo->Unmap (Dev->PciIo, DmaDesc->Mapping);\r
504 Dev->PciIo->FreeBuffer (Dev->PciIo, Pages, HostAddress);\r
505}\r
506\r
507STATIC\r
508EFI_STATUS\r
509PvScsiInitRings (\r
510 IN OUT PVSCSI_DEV *Dev\r
511 )\r
512{\r
513 EFI_STATUS Status;\r
514 union {\r
515 PVSCSI_CMD_DESC_SETUP_RINGS Cmd;\r
516 UINT32 Uint32;\r
517 } AlignedCmd;\r
518 PVSCSI_CMD_DESC_SETUP_RINGS *Cmd;\r
519\r
520 Cmd = &AlignedCmd.Cmd;\r
521\r
522 Status = PvScsiAllocateSharedPages (\r
523 Dev,\r
524 1,\r
525 (VOID **)&Dev->RingDesc.RingState,\r
526 &Dev->RingDesc.RingStateDmaDesc\r
527 );\r
528 if (EFI_ERROR (Status)) {\r
529 return Status;\r
530 }\r
531 ZeroMem (Dev->RingDesc.RingState, EFI_PAGE_SIZE);\r
532\r
533 Status = PvScsiAllocateSharedPages (\r
534 Dev,\r
535 1,\r
536 (VOID **)&Dev->RingDesc.RingReqs,\r
537 &Dev->RingDesc.RingReqsDmaDesc\r
538 );\r
539 if (EFI_ERROR (Status)) {\r
540 goto FreeRingState;\r
541 }\r
542 ZeroMem (Dev->RingDesc.RingReqs, EFI_PAGE_SIZE);\r
543\r
544 Status = PvScsiAllocateSharedPages (\r
545 Dev,\r
546 1,\r
547 (VOID **)&Dev->RingDesc.RingCmps,\r
548 &Dev->RingDesc.RingCmpsDmaDesc\r
549 );\r
550 if (EFI_ERROR (Status)) {\r
551 goto FreeRingReqs;\r
552 }\r
553 ZeroMem (Dev->RingDesc.RingCmps, EFI_PAGE_SIZE);\r
554\r
555 ZeroMem (Cmd, sizeof (*Cmd));\r
556 Cmd->ReqRingNumPages = 1;\r
557 Cmd->CmpRingNumPages = 1;\r
558 Cmd->RingsStatePPN = RShiftU64 (\r
559 Dev->RingDesc.RingStateDmaDesc.DeviceAddress,\r
560 EFI_PAGE_SHIFT\r
561 );\r
562 Cmd->ReqRingPPNs[0] = RShiftU64 (\r
563 Dev->RingDesc.RingReqsDmaDesc.DeviceAddress,\r
564 EFI_PAGE_SHIFT\r
565 );\r
566 Cmd->CmpRingPPNs[0] = RShiftU64 (\r
567 Dev->RingDesc.RingCmpsDmaDesc.DeviceAddress,\r
568 EFI_PAGE_SHIFT\r
569 );\r
570\r
571 STATIC_ASSERT (\r
572 sizeof (*Cmd) % sizeof (UINT32) == 0,\r
573 "Cmd must be multiple of 32-bit words"\r
574 );\r
575 Status = PvScsiWriteCmdDesc (\r
576 Dev,\r
577 PvScsiCmdSetupRings,\r
578 (UINT32 *)Cmd,\r
579 sizeof (*Cmd) / sizeof (UINT32)\r
580 );\r
581 if (EFI_ERROR (Status)) {\r
582 goto FreeRingCmps;\r
583 }\r
584\r
585 return EFI_SUCCESS;\r
586\r
587FreeRingCmps:\r
588 PvScsiFreeSharedPages (\r
589 Dev,\r
590 1,\r
591 Dev->RingDesc.RingCmps,\r
592 &Dev->RingDesc.RingCmpsDmaDesc\r
593 );\r
594\r
595FreeRingReqs:\r
596 PvScsiFreeSharedPages (\r
597 Dev,\r
598 1,\r
599 Dev->RingDesc.RingReqs,\r
600 &Dev->RingDesc.RingReqsDmaDesc\r
601 );\r
602\r
603FreeRingState:\r
604 PvScsiFreeSharedPages (\r
605 Dev,\r
606 1,\r
607 Dev->RingDesc.RingState,\r
608 &Dev->RingDesc.RingStateDmaDesc\r
609 );\r
610\r
611 return Status;\r
612}\r
613\r
614STATIC\r
615VOID\r
616PvScsiFreeRings (\r
617 IN OUT PVSCSI_DEV *Dev\r
618 )\r
619{\r
620 PvScsiFreeSharedPages (\r
621 Dev,\r
622 1,\r
623 Dev->RingDesc.RingCmps,\r
624 &Dev->RingDesc.RingCmpsDmaDesc\r
625 );\r
626\r
627 PvScsiFreeSharedPages (\r
628 Dev,\r
629 1,\r
630 Dev->RingDesc.RingReqs,\r
631 &Dev->RingDesc.RingReqsDmaDesc\r
632 );\r
633\r
634 PvScsiFreeSharedPages (\r
635 Dev,\r
636 1,\r
637 Dev->RingDesc.RingState,\r
638 &Dev->RingDesc.RingStateDmaDesc\r
639 );\r
640}\r
641\r
e497432c
LA
642STATIC\r
643EFI_STATUS\r
644PvScsiInit (\r
645 IN OUT PVSCSI_DEV *Dev\r
646 )\r
647{\r
45098e8a
LA
648 EFI_STATUS Status;\r
649\r
7efce2e5
LA
650 //\r
651 // Init configuration\r
652 //\r
653 Dev->MaxTarget = PcdGet8 (PcdPvScsiMaxTargetLimit);\r
654 Dev->MaxLun = PcdGet8 (PcdPvScsiMaxLunLimit);\r
655\r
45098e8a
LA
656 //\r
657 // Set PCI Attributes\r
658 //\r
659 Status = PvScsiSetPciAttributes (Dev);\r
660 if (EFI_ERROR (Status)) {\r
661 return Status;\r
662 }\r
663\r
5269c26e
LA
664 //\r
665 // Reset adapter\r
666 //\r
667 Status = PvScsiResetAdapter (Dev);\r
668 if (EFI_ERROR (Status)) {\r
669 goto RestorePciAttributes;\r
670 }\r
671\r
b654edec
LA
672 //\r
673 // Init PVSCSI rings\r
674 //\r
675 Status = PvScsiInitRings (Dev);\r
676 if (EFI_ERROR (Status)) {\r
677 goto RestorePciAttributes;\r
678 }\r
679\r
e497432c
LA
680 //\r
681 // Populate the exported interface's attributes\r
682 //\r
683 Dev->PassThru.Mode = &Dev->PassThruMode;\r
684 Dev->PassThru.PassThru = &PvScsiPassThru;\r
685 Dev->PassThru.GetNextTargetLun = &PvScsiGetNextTargetLun;\r
686 Dev->PassThru.BuildDevicePath = &PvScsiBuildDevicePath;\r
687 Dev->PassThru.GetTargetLun = &PvScsiGetTargetLun;\r
688 Dev->PassThru.ResetChannel = &PvScsiResetChannel;\r
689 Dev->PassThru.ResetTargetLun = &PvScsiResetTargetLun;\r
690 Dev->PassThru.GetNextTarget = &PvScsiGetNextTarget;\r
691\r
692 //\r
693 // AdapterId is a target for which no handle will be created during bus scan.\r
694 // Prevent any conflict with real devices.\r
695 //\r
696 Dev->PassThruMode.AdapterId = MAX_UINT32;\r
697\r
698 //\r
699 // Set both physical and logical attributes for non-RAID SCSI channel\r
700 //\r
701 Dev->PassThruMode.Attributes = EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_PHYSICAL |\r
702 EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL;\r
703\r
704 //\r
705 // No restriction on transfer buffer alignment\r
706 //\r
707 Dev->PassThruMode.IoAlign = 0;\r
708\r
709 return EFI_SUCCESS;\r
5269c26e
LA
710\r
711RestorePciAttributes:\r
712 PvScsiRestorePciAttributes (Dev);\r
713\r
714 return Status;\r
e497432c
LA
715}\r
716\r
717STATIC\r
718VOID\r
719PvScsiUninit (\r
720 IN OUT PVSCSI_DEV *Dev\r
721 )\r
722{\r
b654edec
LA
723 //\r
724 // Reset device to stop device usage of the rings.\r
725 // This is required to safely free the rings.\r
726 //\r
727 PvScsiResetAdapter (Dev);\r
728\r
729 PvScsiFreeRings (Dev);\r
730\r
45098e8a 731 PvScsiRestorePciAttributes (Dev);\r
e497432c
LA
732}\r
733\r
ed08c571
LA
734//\r
735// Driver Binding\r
736//\r
737\r
738STATIC\r
739EFI_STATUS\r
740EFIAPI\r
741PvScsiDriverBindingSupported (\r
742 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
743 IN EFI_HANDLE ControllerHandle,\r
744 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL\r
745 )\r
746{\r
a9f9d5cf
LA
747 EFI_STATUS Status;\r
748 EFI_PCI_IO_PROTOCOL *PciIo;\r
749 PCI_TYPE00 Pci;\r
750\r
751 Status = gBS->OpenProtocol (\r
752 ControllerHandle,\r
753 &gEfiPciIoProtocolGuid,\r
754 (VOID **)&PciIo,\r
755 This->DriverBindingHandle,\r
756 ControllerHandle,\r
757 EFI_OPEN_PROTOCOL_BY_DRIVER\r
758 );\r
759 if (EFI_ERROR (Status)) {\r
760 return Status;\r
761 }\r
762\r
763 Status = PciIo->Pci.Read (\r
764 PciIo,\r
765 EfiPciIoWidthUint32,\r
766 0,\r
767 sizeof (Pci) / sizeof (UINT32),\r
768 &Pci\r
769 );\r
770 if (EFI_ERROR (Status)) {\r
771 goto Done;\r
772 }\r
773\r
774 if ((Pci.Hdr.VendorId != PCI_VENDOR_ID_VMWARE) ||\r
775 (Pci.Hdr.DeviceId != PCI_DEVICE_ID_VMWARE_PVSCSI)) {\r
776 Status = EFI_UNSUPPORTED;\r
777 goto Done;\r
778 }\r
779\r
780 Status = EFI_SUCCESS;\r
781\r
782Done:\r
783 gBS->CloseProtocol (\r
784 ControllerHandle,\r
785 &gEfiPciIoProtocolGuid,\r
786 This->DriverBindingHandle,\r
787 ControllerHandle\r
788 );\r
789\r
790 return Status;\r
ed08c571
LA
791}\r
792\r
793STATIC\r
794EFI_STATUS\r
795EFIAPI\r
796PvScsiDriverBindingStart (\r
797 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
798 IN EFI_HANDLE ControllerHandle,\r
799 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL\r
800 )\r
801{\r
e497432c
LA
802 PVSCSI_DEV *Dev;\r
803 EFI_STATUS Status;\r
804\r
805 Dev = (PVSCSI_DEV *) AllocateZeroPool (sizeof (*Dev));\r
806 if (Dev == NULL) {\r
807 return EFI_OUT_OF_RESOURCES;\r
808 }\r
809\r
c08eaaaf
LA
810 Status = gBS->OpenProtocol (\r
811 ControllerHandle,\r
812 &gEfiPciIoProtocolGuid,\r
813 (VOID **)&Dev->PciIo,\r
814 This->DriverBindingHandle,\r
815 ControllerHandle,\r
816 EFI_OPEN_PROTOCOL_BY_DRIVER\r
817 );\r
e497432c
LA
818 if (EFI_ERROR (Status)) {\r
819 goto FreePvScsi;\r
820 }\r
821\r
c08eaaaf
LA
822 Status = PvScsiInit (Dev);\r
823 if (EFI_ERROR (Status)) {\r
824 goto ClosePciIo;\r
825 }\r
826\r
e497432c
LA
827 //\r
828 // Setup complete, attempt to export the driver instance's PassThru interface\r
829 //\r
830 Dev->Signature = PVSCSI_SIG;\r
831 Status = gBS->InstallProtocolInterface (\r
832 &ControllerHandle,\r
833 &gEfiExtScsiPassThruProtocolGuid,\r
834 EFI_NATIVE_INTERFACE,\r
835 &Dev->PassThru\r
836 );\r
837 if (EFI_ERROR (Status)) {\r
838 goto UninitDev;\r
839 }\r
840\r
841 return EFI_SUCCESS;\r
842\r
843UninitDev:\r
844 PvScsiUninit (Dev);\r
845\r
c08eaaaf
LA
846ClosePciIo:\r
847 gBS->CloseProtocol (\r
848 ControllerHandle,\r
849 &gEfiPciIoProtocolGuid,\r
850 This->DriverBindingHandle,\r
851 ControllerHandle\r
852 );\r
853\r
e497432c
LA
854FreePvScsi:\r
855 FreePool (Dev);\r
856\r
857 return Status;\r
ed08c571
LA
858}\r
859\r
860STATIC\r
861EFI_STATUS\r
862EFIAPI\r
863PvScsiDriverBindingStop (\r
864 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
865 IN EFI_HANDLE ControllerHandle,\r
866 IN UINTN NumberOfChildren,\r
867 IN EFI_HANDLE *ChildHandleBuffer\r
868 )\r
869{\r
e497432c
LA
870 EFI_STATUS Status;\r
871 EFI_EXT_SCSI_PASS_THRU_PROTOCOL *PassThru;\r
872 PVSCSI_DEV *Dev;\r
873\r
874 Status = gBS->OpenProtocol (\r
875 ControllerHandle,\r
876 &gEfiExtScsiPassThruProtocolGuid,\r
877 (VOID **)&PassThru,\r
878 This->DriverBindingHandle,\r
879 ControllerHandle,\r
880 EFI_OPEN_PROTOCOL_GET_PROTOCOL // Lookup only\r
881 );\r
882 if (EFI_ERROR (Status)) {\r
883 return Status;\r
884 }\r
885\r
886 Dev = PVSCSI_FROM_PASS_THRU (PassThru);\r
887\r
888 Status = gBS->UninstallProtocolInterface (\r
889 ControllerHandle,\r
890 &gEfiExtScsiPassThruProtocolGuid,\r
891 &Dev->PassThru\r
892 );\r
893 if (EFI_ERROR (Status)) {\r
894 return Status;\r
895 }\r
896\r
897 PvScsiUninit (Dev);\r
898\r
c08eaaaf
LA
899 gBS->CloseProtocol (\r
900 ControllerHandle,\r
901 &gEfiPciIoProtocolGuid,\r
902 This->DriverBindingHandle,\r
903 ControllerHandle\r
904 );\r
905\r
e497432c
LA
906 FreePool (Dev);\r
907\r
908 return EFI_SUCCESS;\r
ed08c571
LA
909}\r
910\r
911STATIC EFI_DRIVER_BINDING_PROTOCOL mPvScsiDriverBinding = {\r
912 &PvScsiDriverBindingSupported,\r
913 &PvScsiDriverBindingStart,\r
914 &PvScsiDriverBindingStop,\r
915 PVSCSI_BINDING_VERSION,\r
916 NULL, // ImageHandle, filled by EfiLibInstallDriverBindingComponentName2()\r
917 NULL // DriverBindingHandle, filled as well\r
918};\r
919\r
419b30d6
LA
920//\r
921// Component Name\r
922//\r
923\r
924STATIC EFI_UNICODE_STRING_TABLE mDriverNameTable[] = {\r
925 { "eng;en", L"PVSCSI Host Driver" },\r
926 { NULL, NULL }\r
927};\r
928\r
929STATIC EFI_COMPONENT_NAME_PROTOCOL mComponentName;\r
930\r
931STATIC\r
932EFI_STATUS\r
933EFIAPI\r
934PvScsiGetDriverName (\r
935 IN EFI_COMPONENT_NAME_PROTOCOL *This,\r
936 IN CHAR8 *Language,\r
937 OUT CHAR16 **DriverName\r
938 )\r
939{\r
940 return LookupUnicodeString2 (\r
941 Language,\r
942 This->SupportedLanguages,\r
943 mDriverNameTable,\r
944 DriverName,\r
945 (BOOLEAN)(This == &mComponentName) // Iso639Language\r
946 );\r
947}\r
948\r
949STATIC\r
950EFI_STATUS\r
951EFIAPI\r
952PvScsiGetDeviceName (\r
953 IN EFI_COMPONENT_NAME_PROTOCOL *This,\r
954 IN EFI_HANDLE DeviceHandle,\r
955 IN EFI_HANDLE ChildHandle,\r
956 IN CHAR8 *Language,\r
957 OUT CHAR16 **ControllerName\r
958 )\r
959{\r
960 return EFI_UNSUPPORTED;\r
961}\r
962\r
963STATIC EFI_COMPONENT_NAME_PROTOCOL mComponentName = {\r
964 &PvScsiGetDriverName,\r
965 &PvScsiGetDeviceName,\r
966 "eng" // SupportedLanguages, ISO 639-2 language codes\r
967};\r
968\r
969STATIC EFI_COMPONENT_NAME2_PROTOCOL mComponentName2 = {\r
970 (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) &PvScsiGetDriverName,\r
971 (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) &PvScsiGetDeviceName,\r
972 "en" // SupportedLanguages, RFC 4646 language codes\r
973};\r
974\r
478c07d4
LA
975//\r
976// Entry Point\r
977//\r
978\r
979EFI_STATUS\r
980EFIAPI\r
981PvScsiEntryPoint (\r
982 IN EFI_HANDLE ImageHandle,\r
983 IN EFI_SYSTEM_TABLE *SystemTable\r
984 )\r
985{\r
ed08c571
LA
986 return EfiLibInstallDriverBindingComponentName2 (\r
987 ImageHandle,\r
988 SystemTable,\r
989 &mPvScsiDriverBinding,\r
990 ImageHandle,\r
419b30d6
LA
991 &mComponentName,\r
992 &mComponentName2\r
ed08c571 993 );\r
478c07d4 994}\r