]> git.proxmox.com Git - mirror_edk2.git/blobdiff - OvmfPkg/LsiScsiDxe/LsiScsi.c
OvmfPkg/LsiScsiDxe: Report Targets and LUNs
[mirror_edk2.git] / OvmfPkg / LsiScsiDxe / LsiScsi.c
index 62daa3ab99bf2cfdd2eb495b9423dc2dd28525a2..1727792406368973f3f7aca599c3738e6beddc1d 100644 (file)
 \r
 **/\r
 \r
+#include <IndustryStandard/LsiScsi.h>\r
+#include <IndustryStandard/Pci.h>\r
+#include <Library/BaseLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+#include <Library/PcdLib.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
 #include <Library/UefiLib.h>\r
+#include <Protocol/PciIo.h>\r
+#include <Protocol/PciRootBridgeIo.h>\r
+#include <Protocol/ScsiPassThruExt.h>\r
 #include <Uefi/UefiSpec.h>\r
 \r
 #include "LsiScsi.h"\r
 \r
+//\r
+// The next seven functions implement EFI_EXT_SCSI_PASS_THRU_PROTOCOL\r
+// for the LSI 53C895A SCSI Controller. Refer to UEFI Spec 2.3.1 + Errata C,\r
+// sections\r
+// - 14.1 SCSI Driver Model Overview,\r
+// - 14.7 Extended SCSI Pass Thru Protocol.\r
+//\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+LsiScsiPassThru (\r
+  IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL                *This,\r
+  IN UINT8                                          *Target,\r
+  IN UINT64                                         Lun,\r
+  IN OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet,\r
+  IN EFI_EVENT                                      Event     OPTIONAL\r
+  )\r
+{\r
+  return EFI_UNSUPPORTED;\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+LsiScsiGetNextTargetLun (\r
+  IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,\r
+  IN OUT UINT8                       **TargetPointer,\r
+  IN OUT UINT64                      *Lun\r
+  )\r
+{\r
+  LSI_SCSI_DEV *Dev;\r
+  UINTN        Idx;\r
+  UINT8        *Target;\r
+  UINT16       LastTarget;\r
+\r
+  //\r
+  // the TargetPointer input parameter is unnecessarily a pointer-to-pointer\r
+  //\r
+  Target = *TargetPointer;\r
+\r
+  //\r
+  // Search for first non-0xFF byte. If not found, return first target & LUN.\r
+  //\r
+  for (Idx = 0; Idx < TARGET_MAX_BYTES && Target[Idx] == 0xFF; ++Idx)\r
+    ;\r
+  if (Idx == TARGET_MAX_BYTES) {\r
+    SetMem (Target, TARGET_MAX_BYTES, 0x00);\r
+    *Lun = 0;\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  CopyMem (&LastTarget, Target, sizeof LastTarget);\r
+\r
+  //\r
+  // increment (target, LUN) pair if valid on input\r
+  //\r
+  Dev = LSI_SCSI_FROM_PASS_THRU (This);\r
+  if (LastTarget > Dev->MaxTarget || *Lun > Dev->MaxLun) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (*Lun < Dev->MaxLun) {\r
+    ++*Lun;\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  if (LastTarget < Dev->MaxTarget) {\r
+    *Lun = 0;\r
+    ++LastTarget;\r
+    CopyMem (Target, &LastTarget, sizeof LastTarget);\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  return EFI_NOT_FOUND;\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+LsiScsiBuildDevicePath (\r
+  IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,\r
+  IN UINT8                           *Target,\r
+  IN UINT64                          Lun,\r
+  IN OUT EFI_DEVICE_PATH_PROTOCOL    **DevicePath\r
+  )\r
+{\r
+  UINT16           TargetValue;\r
+  LSI_SCSI_DEV     *Dev;\r
+  SCSI_DEVICE_PATH *ScsiDevicePath;\r
+\r
+  if (DevicePath == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  CopyMem (&TargetValue, Target, sizeof TargetValue);\r
+  Dev = LSI_SCSI_FROM_PASS_THRU (This);\r
+  if (TargetValue > Dev->MaxTarget || Lun > Dev->MaxLun || Lun > 0xFFFF) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  ScsiDevicePath = AllocatePool (sizeof *ScsiDevicePath);\r
+  if (ScsiDevicePath == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  ScsiDevicePath->Header.Type      = MESSAGING_DEVICE_PATH;\r
+  ScsiDevicePath->Header.SubType   = MSG_SCSI_DP;\r
+  ScsiDevicePath->Header.Length[0] = (UINT8)  sizeof *ScsiDevicePath;\r
+  ScsiDevicePath->Header.Length[1] = (UINT8) (sizeof *ScsiDevicePath >> 8);\r
+  ScsiDevicePath->Pun              = TargetValue;\r
+  ScsiDevicePath->Lun              = (UINT16) Lun;\r
+\r
+  *DevicePath = &ScsiDevicePath->Header;\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+LsiScsiGetTargetLun (\r
+  IN  EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,\r
+  IN  EFI_DEVICE_PATH_PROTOCOL        *DevicePath,\r
+  OUT UINT8                           **TargetPointer,\r
+  OUT UINT64                          *Lun\r
+  )\r
+{\r
+  SCSI_DEVICE_PATH *ScsiDevicePath;\r
+  LSI_SCSI_DEV     *Dev;\r
+  UINT8            *Target;\r
+\r
+  if (DevicePath == NULL || TargetPointer == NULL || *TargetPointer == NULL ||\r
+      Lun == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (DevicePath->Type    != MESSAGING_DEVICE_PATH ||\r
+      DevicePath->SubType != MSG_SCSI_DP) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  ScsiDevicePath = (SCSI_DEVICE_PATH *) DevicePath;\r
+  Dev = LSI_SCSI_FROM_PASS_THRU (This);\r
+  if (ScsiDevicePath->Pun > Dev->MaxTarget ||\r
+      ScsiDevicePath->Lun > Dev->MaxLun) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  Target = *TargetPointer;\r
+  ZeroMem (Target, TARGET_MAX_BYTES);\r
+  CopyMem (Target, &ScsiDevicePath->Pun, sizeof ScsiDevicePath->Pun);\r
+  *Lun = ScsiDevicePath->Lun;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+LsiScsiResetChannel (\r
+  IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This\r
+  )\r
+{\r
+  return EFI_UNSUPPORTED;\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+LsiScsiResetTargetLun (\r
+  IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,\r
+  IN UINT8                           *Target,\r
+  IN UINT64                          Lun\r
+  )\r
+{\r
+  return EFI_UNSUPPORTED;\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+LsiScsiGetNextTarget (\r
+  IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,\r
+  IN OUT UINT8                       **TargetPointer\r
+  )\r
+{\r
+  LSI_SCSI_DEV *Dev;\r
+  UINTN        Idx;\r
+  UINT8        *Target;\r
+  UINT16       LastTarget;\r
+\r
+  //\r
+  // the TargetPointer input parameter is unnecessarily a pointer-to-pointer\r
+  //\r
+  Target = *TargetPointer;\r
+\r
+  //\r
+  // Search for first non-0xFF byte. If not found, return first target.\r
+  //\r
+  for (Idx = 0; Idx < TARGET_MAX_BYTES && Target[Idx] == 0xFF; ++Idx)\r
+    ;\r
+  if (Idx == TARGET_MAX_BYTES) {\r
+    SetMem (Target, TARGET_MAX_BYTES, 0x00);\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  CopyMem (&LastTarget, Target, sizeof LastTarget);\r
+\r
+  //\r
+  // increment target if valid on input\r
+  //\r
+  Dev = LSI_SCSI_FROM_PASS_THRU (This);\r
+  if (LastTarget > Dev->MaxTarget) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (LastTarget < Dev->MaxTarget) {\r
+    ++LastTarget;\r
+    CopyMem (Target, &LastTarget, sizeof LastTarget);\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  return EFI_NOT_FOUND;\r
+}\r
+\r
 //\r
 // Probe, start and stop functions of this driver, called by the DXE core for\r
 // specific devices.\r
@@ -31,7 +260,48 @@ LsiScsiControllerSupported (
   IN EFI_DEVICE_PATH_PROTOCOL    *RemainingDevicePath OPTIONAL\r
   )\r
 {\r
-  return EFI_UNSUPPORTED;\r
+  EFI_STATUS          Status;\r
+  EFI_PCI_IO_PROTOCOL *PciIo;\r
+  PCI_TYPE00          Pci;\r
+\r
+  Status = gBS->OpenProtocol (\r
+                  ControllerHandle,\r
+                  &gEfiPciIoProtocolGuid,\r
+                  (VOID **)&PciIo,\r
+                  This->DriverBindingHandle,\r
+                  ControllerHandle,\r
+                  EFI_OPEN_PROTOCOL_BY_DRIVER\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  Status = PciIo->Pci.Read (\r
+                        PciIo,\r
+                        EfiPciIoWidthUint32,\r
+                        0,\r
+                        sizeof (Pci) / sizeof (UINT32),\r
+                        &Pci\r
+                        );\r
+  if (EFI_ERROR (Status)) {\r
+    goto Done;\r
+  }\r
+\r
+  if (Pci.Hdr.VendorId == LSI_LOGIC_PCI_VENDOR_ID &&\r
+      Pci.Hdr.DeviceId == LSI_53C895A_PCI_DEVICE_ID) {\r
+    Status = EFI_SUCCESS;\r
+  } else {\r
+    Status = EFI_UNSUPPORTED;\r
+  }\r
+\r
+Done:\r
+  gBS->CloseProtocol (\r
+         ControllerHandle,\r
+         &gEfiPciIoProtocolGuid,\r
+         This->DriverBindingHandle,\r
+         ControllerHandle\r
+         );\r
+  return Status;\r
 }\r
 \r
 EFI_STATUS\r
@@ -42,7 +312,60 @@ LsiScsiControllerStart (
   IN EFI_DEVICE_PATH_PROTOCOL    *RemainingDevicePath OPTIONAL\r
   )\r
 {\r
+  EFI_STATUS           Status;\r
+  LSI_SCSI_DEV         *Dev;\r
+\r
+  Dev = AllocateZeroPool (sizeof (*Dev));\r
+  if (Dev == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  Dev->Signature = LSI_SCSI_DEV_SIGNATURE;\r
+\r
+  STATIC_ASSERT (\r
+    FixedPcdGet8 (PcdLsiScsiMaxTargetLimit) < 8,\r
+    "LSI 53C895A supports targets [0..7]"\r
+    );\r
+  STATIC_ASSERT (\r
+    FixedPcdGet8 (PcdLsiScsiMaxLunLimit) < 128,\r
+    "LSI 53C895A supports LUNs [0..127]"\r
+    );\r
+  Dev->MaxTarget = PcdGet8 (PcdLsiScsiMaxTargetLimit);\r
+  Dev->MaxLun = PcdGet8 (PcdLsiScsiMaxLunLimit);\r
+\r
+  //\r
+  // Host adapter channel, doesn't exist\r
+  //\r
+  Dev->PassThruMode.AdapterId = MAX_UINT32;\r
+  Dev->PassThruMode.Attributes =\r
+    EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_PHYSICAL |\r
+    EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL;\r
+\r
+  Dev->PassThru.Mode = &Dev->PassThruMode;\r
+  Dev->PassThru.PassThru = &LsiScsiPassThru;\r
+  Dev->PassThru.GetNextTargetLun = &LsiScsiGetNextTargetLun;\r
+  Dev->PassThru.BuildDevicePath = &LsiScsiBuildDevicePath;\r
+  Dev->PassThru.GetTargetLun = &LsiScsiGetTargetLun;\r
+  Dev->PassThru.ResetChannel = &LsiScsiResetChannel;\r
+  Dev->PassThru.ResetTargetLun = &LsiScsiResetTargetLun;\r
+  Dev->PassThru.GetNextTarget = &LsiScsiGetNextTarget;\r
+\r
+  Status = gBS->InstallProtocolInterface (\r
+                  &ControllerHandle,\r
+                  &gEfiExtScsiPassThruProtocolGuid,\r
+                  EFI_NATIVE_INTERFACE,\r
+                  &Dev->PassThru\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    goto FreePool;\r
+  }\r
+\r
   return EFI_SUCCESS;\r
+\r
+FreePool:\r
+  FreePool (Dev);\r
+\r
+  return Status;\r
 }\r
 \r
 EFI_STATUS\r
@@ -54,7 +377,36 @@ LsiScsiControllerStop (
   IN EFI_HANDLE                  *ChildHandleBuffer\r
   )\r
 {\r
-  return EFI_SUCCESS;\r
+  EFI_STATUS                      Status;\r
+  EFI_EXT_SCSI_PASS_THRU_PROTOCOL *PassThru;\r
+  LSI_SCSI_DEV                    *Dev;\r
+\r
+  Status = gBS->OpenProtocol (\r
+                  ControllerHandle,\r
+                  &gEfiExtScsiPassThruProtocolGuid,\r
+                  (VOID **)&PassThru,\r
+                  This->DriverBindingHandle,\r
+                  ControllerHandle,\r
+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL // Lookup only\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  Dev = LSI_SCSI_FROM_PASS_THRU (PassThru);\r
+\r
+  Status = gBS->UninstallProtocolInterface (\r
+                  ControllerHandle,\r
+                  &gEfiExtScsiPassThruProtocolGuid,\r
+                  &Dev->PassThru\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  FreePool (Dev);\r
+\r
+  return Status;\r
 }\r
 \r
 //\r