123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224 |
- /** @file
- This driver produces Extended SCSI Pass Thru Protocol instances for
- LSI Fusion MPT SCSI devices.
- Copyright (C) 2020, Oracle and/or its affiliates.
- SPDX-License-Identifier: BSD-2-Clause-Patent
- **/
- #include <IndustryStandard/FusionMptScsi.h>
- #include <IndustryStandard/Pci.h>
- #include <Library/BaseLib.h>
- #include <Library/BaseMemoryLib.h>
- #include <Library/DebugLib.h>
- #include <Library/MemoryAllocationLib.h>
- #include <Library/PcdLib.h>
- #include <Library/UefiBootServicesTableLib.h>
- #include <Library/UefiLib.h>
- #include <Protocol/PciIo.h>
- #include <Protocol/PciRootBridgeIo.h>
- #include <Protocol/ScsiPassThruExt.h>
- #include <Uefi/UefiSpec.h>
- //
- // Higher versions will be used before lower, 0x10-0xffffffef is the version
- // range for IVH (Indie Hardware Vendors)
- //
- #define MPT_SCSI_BINDING_VERSION 0x10
- //
- // Runtime Structures
- //
- typedef struct {
- MPT_SCSI_REQUEST_ALIGNED IoRequest;
- MPT_SCSI_IO_REPLY_ALIGNED IoReply;
- //
- // As EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET.SenseDataLength is defined
- // as UINT8, defining here SenseData size to MAX_UINT8 will guarantee it
- // cannot overflow when passed to device.
- //
- UINT8 Sense[MAX_UINT8];
- //
- // This size of the data is arbitrarily chosen.
- // It seems to be sufficient for all I/O requests sent through
- // EFI_SCSI_PASS_THRU_PROTOCOL.PassThru() for common boot scenarios.
- //
- UINT8 Data[0x2000];
- } MPT_SCSI_DMA_BUFFER;
- #define MPT_SCSI_DEV_SIGNATURE SIGNATURE_32 ('M','P','T','S')
- typedef struct {
- UINT32 Signature;
- EFI_EXT_SCSI_PASS_THRU_PROTOCOL PassThru;
- EFI_EXT_SCSI_PASS_THRU_MODE PassThruMode;
- UINT8 MaxTarget;
- UINT32 StallPerPollUsec;
- EFI_PCI_IO_PROTOCOL *PciIo;
- UINT64 OriginalPciAttributes;
- EFI_EVENT ExitBoot;
- MPT_SCSI_DMA_BUFFER *Dma;
- EFI_PHYSICAL_ADDRESS DmaPhysical;
- VOID *DmaMapping;
- BOOLEAN IoReplyEnqueued;
- } MPT_SCSI_DEV;
- #define MPT_SCSI_FROM_PASS_THRU(PassThruPtr) \
- CR (PassThruPtr, MPT_SCSI_DEV, PassThru, MPT_SCSI_DEV_SIGNATURE)
- #define MPT_SCSI_DMA_ADDR(Dev, MemberName) \
- (Dev->DmaPhysical + OFFSET_OF (MPT_SCSI_DMA_BUFFER, MemberName))
- #define MPT_SCSI_DMA_ADDR_HIGH(Dev, MemberName) \
- ((UINT32)RShiftU64 (MPT_SCSI_DMA_ADDR (Dev, MemberName), 32))
- #define MPT_SCSI_DMA_ADDR_LOW(Dev, MemberName) \
- ((UINT32)MPT_SCSI_DMA_ADDR (Dev, MemberName))
- //
- // Hardware functions
- //
- STATIC
- EFI_STATUS
- Out32 (
- IN MPT_SCSI_DEV *Dev,
- IN UINT32 Addr,
- IN UINT32 Data
- )
- {
- return Dev->PciIo->Io.Write (
- Dev->PciIo,
- EfiPciIoWidthUint32,
- PCI_BAR_IDX0,
- Addr,
- 1,
- &Data
- );
- }
- STATIC
- EFI_STATUS
- In32 (
- IN MPT_SCSI_DEV *Dev,
- IN UINT32 Addr,
- OUT UINT32 *Data
- )
- {
- return Dev->PciIo->Io.Read (
- Dev->PciIo,
- EfiPciIoWidthUint32,
- PCI_BAR_IDX0,
- Addr,
- 1,
- Data
- );
- }
- STATIC
- EFI_STATUS
- MptDoorbell (
- IN MPT_SCSI_DEV *Dev,
- IN UINT8 DoorbellFunc,
- IN UINT8 DoorbellArg
- )
- {
- return Out32 (
- Dev,
- MPT_REG_DOORBELL,
- (((UINT32)DoorbellFunc) << 24) | (DoorbellArg << 16)
- );
- }
- STATIC
- EFI_STATUS
- MptScsiReset (
- IN MPT_SCSI_DEV *Dev
- )
- {
- EFI_STATUS Status;
- //
- // Reset hardware
- //
- Status = MptDoorbell (Dev, MPT_DOORBELL_RESET, 0);
- if (EFI_ERROR (Status)) {
- return Status;
- }
- //
- // Mask interrupts
- //
- Status = Out32 (Dev, MPT_REG_IMASK, MPT_IMASK_DOORBELL | MPT_IMASK_REPLY);
- if (EFI_ERROR (Status)) {
- return Status;
- }
- //
- // Clear interrupt status
- //
- Status = Out32 (Dev, MPT_REG_ISTATUS, 0);
- if (EFI_ERROR (Status)) {
- return Status;
- }
- return EFI_SUCCESS;
- }
- STATIC
- EFI_STATUS
- MptScsiInit (
- IN MPT_SCSI_DEV *Dev
- )
- {
- EFI_STATUS Status;
- union {
- MPT_IO_CONTROLLER_INIT_REQUEST Data;
- UINT32 Uint32;
- } AlignedReq;
- MPT_IO_CONTROLLER_INIT_REQUEST *Req;
- MPT_IO_CONTROLLER_INIT_REPLY Reply;
- UINT8 *ReplyBytes;
- UINT32 ReplyWord;
- Req = &AlignedReq.Data;
- Status = MptScsiReset (Dev);
- if (EFI_ERROR (Status)) {
- return Status;
- }
- ZeroMem (Req, sizeof (*Req));
- ZeroMem (&Reply, sizeof (Reply));
- Req->WhoInit = MPT_IOC_WHOINIT_ROM_BIOS;
- Req->Function = MPT_MESSAGE_HDR_FUNCTION_IOC_INIT;
- STATIC_ASSERT (
- FixedPcdGet8 (PcdMptScsiMaxTargetLimit) < 255,
- "Req supports 255 targets only (max target is 254)"
- );
- Req->MaxDevices = Dev->MaxTarget + 1;
- Req->MaxBuses = 1;
- Req->ReplyFrameSize = sizeof Dev->Dma->IoReply.Data;
- Req->HostMfaHighAddr = MPT_SCSI_DMA_ADDR_HIGH (Dev, IoRequest);
- Req->SenseBufferHighAddr = MPT_SCSI_DMA_ADDR_HIGH (Dev, Sense);
- //
- // Send controller init through doorbell
- //
- STATIC_ASSERT (
- sizeof (*Req) % sizeof (UINT32) == 0,
- "Req must be multiple of UINT32"
- );
- STATIC_ASSERT (
- sizeof (*Req) / sizeof (UINT32) <= MAX_UINT8,
- "Req must fit in MAX_UINT8 Dwords"
- );
- Status = MptDoorbell (
- Dev,
- MPT_DOORBELL_HANDSHAKE,
- (UINT8)(sizeof (*Req) / sizeof (UINT32))
- );
- if (EFI_ERROR (Status)) {
- return Status;
- }
- Status = Dev->PciIo->Io.Write (
- Dev->PciIo,
- EfiPciIoWidthFifoUint32,
- PCI_BAR_IDX0,
- MPT_REG_DOORBELL,
- sizeof (*Req) / sizeof (UINT32),
- Req
- );
- if (EFI_ERROR (Status)) {
- return Status;
- }
- //
- // Read reply through doorbell
- // Each 32bit (Dword) read produces 16bit (Word) of data
- //
- // The reply is read back to complete the doorbell function but it
- // isn't useful because it doesn't contain relevant data or status
- // codes.
- //
- STATIC_ASSERT (
- sizeof (Reply) % sizeof (UINT16) == 0,
- "Reply must be multiple of UINT16"
- );
- ReplyBytes = (UINT8 *)&Reply;
- while (ReplyBytes != (UINT8 *)(&Reply + 1)) {
- Status = In32 (Dev, MPT_REG_DOORBELL, &ReplyWord);
- if (EFI_ERROR (Status)) {
- return Status;
- }
- CopyMem (ReplyBytes, &ReplyWord, sizeof (UINT16));
- ReplyBytes += sizeof (UINT16);
- }
- //
- // Clear interrupts generated by doorbell reply
- //
- Status = Out32 (Dev, MPT_REG_ISTATUS, 0);
- if (EFI_ERROR (Status)) {
- return Status;
- }
- return EFI_SUCCESS;
- }
- STATIC
- EFI_STATUS
- ReportHostAdapterError (
- OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet
- )
- {
- DEBUG ((DEBUG_ERROR, "%a: fatal error in scsi request\n", __FUNCTION__));
- Packet->InTransferLength = 0;
- Packet->OutTransferLength = 0;
- Packet->SenseDataLength = 0;
- Packet->HostAdapterStatus = EFI_EXT_SCSI_STATUS_HOST_ADAPTER_OTHER;
- Packet->TargetStatus = EFI_EXT_SCSI_STATUS_TARGET_TASK_ABORTED;
- return EFI_DEVICE_ERROR;
- }
- STATIC
- EFI_STATUS
- ReportHostAdapterOverrunError (
- OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet
- )
- {
- Packet->SenseDataLength = 0;
- Packet->HostAdapterStatus =
- EFI_EXT_SCSI_STATUS_HOST_ADAPTER_DATA_OVERRUN_UNDERRUN;
- Packet->TargetStatus = EFI_EXT_SCSI_STATUS_TARGET_GOOD;
- return EFI_BAD_BUFFER_SIZE;
- }
- STATIC
- EFI_STATUS
- MptScsiPopulateRequest (
- IN MPT_SCSI_DEV *Dev,
- IN UINT8 Target,
- IN UINT64 Lun,
- IN OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet
- )
- {
- MPT_SCSI_REQUEST_WITH_SG *Request;
- Request = &Dev->Dma->IoRequest.Data;
- if ((Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_BIDIRECTIONAL) ||
- ((Packet->InTransferLength > 0) && (Packet->OutTransferLength > 0)) ||
- (Packet->CdbLength > sizeof (Request->Header.Cdb)))
- {
- return EFI_UNSUPPORTED;
- }
- if ((Target > Dev->MaxTarget) || (Lun > 0) ||
- (Packet->DataDirection > EFI_EXT_SCSI_DATA_DIRECTION_BIDIRECTIONAL) ||
- //
- // Trying to receive, but destination pointer is NULL, or contradicting
- // transfer direction
- //
- ((Packet->InTransferLength > 0) &&
- ((Packet->InDataBuffer == NULL) ||
- (Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_WRITE)
- )
- ) ||
- //
- // Trying to send, but source pointer is NULL, or contradicting transfer
- // direction
- //
- ((Packet->OutTransferLength > 0) &&
- ((Packet->OutDataBuffer == NULL) ||
- (Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_READ)
- )
- )
- )
- {
- return EFI_INVALID_PARAMETER;
- }
- if (Packet->InTransferLength > sizeof (Dev->Dma->Data)) {
- Packet->InTransferLength = sizeof (Dev->Dma->Data);
- return ReportHostAdapterOverrunError (Packet);
- }
- if (Packet->OutTransferLength > sizeof (Dev->Dma->Data)) {
- Packet->OutTransferLength = sizeof (Dev->Dma->Data);
- return ReportHostAdapterOverrunError (Packet);
- }
- ZeroMem (Request, sizeof (*Request));
- Request->Header.TargetId = Target;
- //
- // Only LUN 0 is currently supported, hence the cast is safe
- //
- Request->Header.Lun[1] = (UINT8)Lun;
- Request->Header.Function = MPT_MESSAGE_HDR_FUNCTION_SCSI_IO_REQUEST;
- Request->Header.MessageContext = 1; // We handle one request at a time
- Request->Header.CdbLength = Packet->CdbLength;
- CopyMem (Request->Header.Cdb, Packet->Cdb, Packet->CdbLength);
- //
- // SenseDataLength is UINT8, Sense[] is MAX_UINT8, so we can't overflow
- //
- ZeroMem (Dev->Dma->Sense, Packet->SenseDataLength);
- Request->Header.SenseBufferLength = Packet->SenseDataLength;
- Request->Header.SenseBufferLowAddress = MPT_SCSI_DMA_ADDR_LOW (Dev, Sense);
- Request->Sg.EndOfList = 1;
- Request->Sg.EndOfBuffer = 1;
- Request->Sg.LastElement = 1;
- Request->Sg.ElementType = MPT_SG_ENTRY_TYPE_SIMPLE;
- Request->Sg.Is64BitAddress = 1;
- Request->Sg.DataBufferAddress = MPT_SCSI_DMA_ADDR (Dev, Data);
- //
- // "MPT_SG_ENTRY_SIMPLE.Length" is a 24-bit quantity.
- //
- STATIC_ASSERT (
- sizeof (Dev->Dma->Data) < SIZE_16MB,
- "MPT_SCSI_DMA_BUFFER.Data must be smaller than 16MB"
- );
- if (Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_READ) {
- Request->Header.DataLength = Packet->InTransferLength;
- Request->Sg.Length = Packet->InTransferLength;
- Request->Header.Control = MPT_SCSIIO_REQUEST_CONTROL_TXDIR_READ;
- } else {
- Request->Header.DataLength = Packet->OutTransferLength;
- Request->Sg.Length = Packet->OutTransferLength;
- Request->Header.Control = MPT_SCSIIO_REQUEST_CONTROL_TXDIR_WRITE;
- CopyMem (Dev->Dma->Data, Packet->OutDataBuffer, Packet->OutTransferLength);
- Request->Sg.BufferContainsData = 1;
- }
- if (Request->Header.DataLength == 0) {
- Request->Header.Control = MPT_SCSIIO_REQUEST_CONTROL_TXDIR_NONE;
- }
- return EFI_SUCCESS;
- }
- STATIC
- EFI_STATUS
- MptScsiSendRequest (
- IN MPT_SCSI_DEV *Dev,
- IN OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet
- )
- {
- EFI_STATUS Status;
- if (!Dev->IoReplyEnqueued) {
- //
- // Put one free reply frame on the reply queue, the hardware may use it to
- // report an error to us.
- //
- Status = Out32 (Dev, MPT_REG_REP_Q, MPT_SCSI_DMA_ADDR_LOW (Dev, IoReply));
- if (EFI_ERROR (Status)) {
- return EFI_DEVICE_ERROR;
- }
- Dev->IoReplyEnqueued = TRUE;
- }
- Status = Out32 (Dev, MPT_REG_REQ_Q, MPT_SCSI_DMA_ADDR_LOW (Dev, IoRequest));
- if (EFI_ERROR (Status)) {
- return EFI_DEVICE_ERROR;
- }
- return EFI_SUCCESS;
- }
- STATIC
- EFI_STATUS
- MptScsiGetReply (
- IN MPT_SCSI_DEV *Dev,
- OUT UINT32 *Reply
- )
- {
- EFI_STATUS Status;
- UINT32 Istatus;
- UINT32 EmptyReply;
- //
- // Timeouts are not supported for
- // EFI_EXT_SCSI_PASS_THRU_PROTOCOL.PassThru() in this implementation.
- //
- for ( ; ;) {
- Status = In32 (Dev, MPT_REG_ISTATUS, &Istatus);
- if (EFI_ERROR (Status)) {
- return Status;
- }
- //
- // Interrupt raised
- //
- if (Istatus & MPT_IMASK_REPLY) {
- break;
- }
- gBS->Stall (Dev->StallPerPollUsec);
- }
- Status = In32 (Dev, MPT_REG_REP_Q, Reply);
- if (EFI_ERROR (Status)) {
- return Status;
- }
- //
- // The driver is supposed to fetch replies until 0xffffffff is returned, which
- // will reset the interrupt status. We put only one request, so we expect the
- // next read reply to be the last.
- //
- Status = In32 (Dev, MPT_REG_REP_Q, &EmptyReply);
- if (EFI_ERROR (Status) || (EmptyReply != MAX_UINT32)) {
- return EFI_DEVICE_ERROR;
- }
- return EFI_SUCCESS;
- }
- STATIC
- EFI_STATUS
- MptScsiHandleReply (
- IN MPT_SCSI_DEV *Dev,
- IN UINT32 Reply,
- OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet
- )
- {
- if (Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_READ) {
- CopyMem (Packet->InDataBuffer, Dev->Dma->Data, Packet->InTransferLength);
- }
- if (Reply == Dev->Dma->IoRequest.Data.Header.MessageContext) {
- //
- // This is a turbo reply, everything is good
- //
- Packet->SenseDataLength = 0;
- Packet->HostAdapterStatus = EFI_EXT_SCSI_STATUS_HOST_ADAPTER_OK;
- Packet->TargetStatus = EFI_EXT_SCSI_STATUS_TARGET_GOOD;
- } else if ((Reply & BIT31) != 0) {
- DEBUG ((DEBUG_INFO, "%a: Full reply returned\n", __FUNCTION__));
- //
- // When reply MSB is set, we got a full reply. Since we submitted only one
- // reply frame, we know it's IoReply.
- //
- Dev->IoReplyEnqueued = FALSE;
- Packet->TargetStatus = Dev->Dma->IoReply.Data.ScsiStatus;
- //
- // Make sure device only lowers SenseDataLength before copying sense
- //
- ASSERT (Dev->Dma->IoReply.Data.SenseCount <= Packet->SenseDataLength);
- Packet->SenseDataLength =
- (UINT8)MIN (Dev->Dma->IoReply.Data.SenseCount, Packet->SenseDataLength);
- CopyMem (Packet->SenseData, Dev->Dma->Sense, Packet->SenseDataLength);
- if (Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_READ) {
- Packet->InTransferLength = Dev->Dma->IoReply.Data.TransferCount;
- } else {
- Packet->OutTransferLength = Dev->Dma->IoReply.Data.TransferCount;
- }
- switch (Dev->Dma->IoReply.Data.IocStatus) {
- case MPT_SCSI_IOCSTATUS_SUCCESS:
- Packet->HostAdapterStatus = EFI_EXT_SCSI_STATUS_HOST_ADAPTER_OK;
- break;
- case MPT_SCSI_IOCSTATUS_DEVICE_NOT_THERE:
- Packet->HostAdapterStatus =
- EFI_EXT_SCSI_STATUS_HOST_ADAPTER_SELECTION_TIMEOUT;
- return EFI_TIMEOUT;
- case MPT_SCSI_IOCSTATUS_DATA_UNDERRUN:
- case MPT_SCSI_IOCSTATUS_DATA_OVERRUN:
- Packet->HostAdapterStatus =
- EFI_EXT_SCSI_STATUS_HOST_ADAPTER_DATA_OVERRUN_UNDERRUN;
- break;
- default:
- Packet->HostAdapterStatus = EFI_EXT_SCSI_STATUS_HOST_ADAPTER_OTHER;
- return EFI_DEVICE_ERROR;
- }
- } else {
- DEBUG ((DEBUG_ERROR, "%a: unexpected reply (%x)\n", __FUNCTION__, Reply));
- return ReportHostAdapterError (Packet);
- }
- return EFI_SUCCESS;
- }
- //
- // Ext SCSI Pass Thru
- //
- STATIC
- EFI_STATUS
- EFIAPI
- MptScsiPassThru (
- IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,
- IN UINT8 *Target,
- IN UINT64 Lun,
- IN OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet,
- IN EFI_EVENT Event OPTIONAL
- )
- {
- EFI_STATUS Status;
- MPT_SCSI_DEV *Dev;
- UINT32 Reply;
- Dev = MPT_SCSI_FROM_PASS_THRU (This);
- //
- // We only use first byte of target identifer
- //
- Status = MptScsiPopulateRequest (Dev, *Target, Lun, Packet);
- if (EFI_ERROR (Status)) {
- //
- // MptScsiPopulateRequest modified packet according to the error
- //
- return Status;
- }
- Status = MptScsiSendRequest (Dev, Packet);
- if (EFI_ERROR (Status)) {
- return ReportHostAdapterError (Packet);
- }
- Status = MptScsiGetReply (Dev, &Reply);
- if (EFI_ERROR (Status)) {
- return ReportHostAdapterError (Packet);
- }
- return MptScsiHandleReply (Dev, Reply, Packet);
- }
- STATIC
- BOOLEAN
- IsTargetInitialized (
- IN UINT8 *Target
- )
- {
- UINTN Idx;
- for (Idx = 0; Idx < TARGET_MAX_BYTES; ++Idx) {
- if (Target[Idx] != 0xFF) {
- return TRUE;
- }
- }
- return FALSE;
- }
- STATIC
- EFI_STATUS
- EFIAPI
- MptScsiGetNextTargetLun (
- IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,
- IN OUT UINT8 **Target,
- IN OUT UINT64 *Lun
- )
- {
- MPT_SCSI_DEV *Dev;
- Dev = MPT_SCSI_FROM_PASS_THRU (This);
- //
- // Currently support only LUN 0, so hardcode it
- //
- if (!IsTargetInitialized (*Target)) {
- ZeroMem (*Target, TARGET_MAX_BYTES);
- *Lun = 0;
- } else if ((**Target > Dev->MaxTarget) || (*Lun > 0)) {
- return EFI_INVALID_PARAMETER;
- } else if (**Target < Dev->MaxTarget) {
- //
- // This device interface support 256 targets only, so it's enough to
- // increment the LSB of Target, as it will never overflow.
- //
- **Target += 1;
- } else {
- return EFI_NOT_FOUND;
- }
- return EFI_SUCCESS;
- }
- STATIC
- EFI_STATUS
- EFIAPI
- MptScsiGetNextTarget (
- IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,
- IN OUT UINT8 **Target
- )
- {
- MPT_SCSI_DEV *Dev;
- Dev = MPT_SCSI_FROM_PASS_THRU (This);
- if (!IsTargetInitialized (*Target)) {
- ZeroMem (*Target, TARGET_MAX_BYTES);
- } else if (**Target > Dev->MaxTarget) {
- return EFI_INVALID_PARAMETER;
- } else if (**Target < Dev->MaxTarget) {
- //
- // This device interface support 256 targets only, so it's enough to
- // increment the LSB of Target, as it will never overflow.
- //
- **Target += 1;
- } else {
- return EFI_NOT_FOUND;
- }
- return EFI_SUCCESS;
- }
- STATIC
- EFI_STATUS
- EFIAPI
- MptScsiBuildDevicePath (
- IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,
- IN UINT8 *Target,
- IN UINT64 Lun,
- IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath
- )
- {
- MPT_SCSI_DEV *Dev;
- SCSI_DEVICE_PATH *ScsiDevicePath;
- if (DevicePath == NULL) {
- return EFI_INVALID_PARAMETER;
- }
- //
- // This device support 256 targets only, so it's enough to dereference
- // the LSB of Target.
- //
- Dev = MPT_SCSI_FROM_PASS_THRU (This);
- if ((*Target > Dev->MaxTarget) || (Lun > 0)) {
- return EFI_NOT_FOUND;
- }
- ScsiDevicePath = AllocateZeroPool (sizeof (*ScsiDevicePath));
- if (ScsiDevicePath == NULL) {
- return EFI_OUT_OF_RESOURCES;
- }
- ScsiDevicePath->Header.Type = MESSAGING_DEVICE_PATH;
- ScsiDevicePath->Header.SubType = MSG_SCSI_DP;
- ScsiDevicePath->Header.Length[0] = (UINT8)sizeof (*ScsiDevicePath);
- ScsiDevicePath->Header.Length[1] = (UINT8)(sizeof (*ScsiDevicePath) >> 8);
- ScsiDevicePath->Pun = *Target;
- ScsiDevicePath->Lun = (UINT16)Lun;
- *DevicePath = &ScsiDevicePath->Header;
- return EFI_SUCCESS;
- }
- STATIC
- EFI_STATUS
- EFIAPI
- MptScsiGetTargetLun (
- IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,
- IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
- OUT UINT8 **Target,
- OUT UINT64 *Lun
- )
- {
- MPT_SCSI_DEV *Dev;
- SCSI_DEVICE_PATH *ScsiDevicePath;
- if ((DevicePath == NULL) ||
- (Target == NULL) || (*Target == NULL) || (Lun == NULL))
- {
- return EFI_INVALID_PARAMETER;
- }
- if ((DevicePath->Type != MESSAGING_DEVICE_PATH) ||
- (DevicePath->SubType != MSG_SCSI_DP))
- {
- return EFI_UNSUPPORTED;
- }
- Dev = MPT_SCSI_FROM_PASS_THRU (This);
- ScsiDevicePath = (SCSI_DEVICE_PATH *)DevicePath;
- if ((ScsiDevicePath->Pun > Dev->MaxTarget) ||
- (ScsiDevicePath->Lun > 0))
- {
- return EFI_NOT_FOUND;
- }
- ZeroMem (*Target, TARGET_MAX_BYTES);
- //
- // This device support 256 targets only, so it's enough to set the LSB
- // of Target.
- //
- **Target = (UINT8)ScsiDevicePath->Pun;
- *Lun = ScsiDevicePath->Lun;
- return EFI_SUCCESS;
- }
- STATIC
- EFI_STATUS
- EFIAPI
- MptScsiResetChannel (
- IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This
- )
- {
- return EFI_UNSUPPORTED;
- }
- STATIC
- VOID
- EFIAPI
- MptScsiExitBoot (
- IN EFI_EVENT Event,
- IN VOID *Context
- )
- {
- MPT_SCSI_DEV *Dev;
- Dev = Context;
- DEBUG ((DEBUG_VERBOSE, "%a: Context=0x%p\n", __FUNCTION__, Context));
- MptScsiReset (Dev);
- }
- STATIC
- EFI_STATUS
- EFIAPI
- MptScsiResetTargetLun (
- IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,
- IN UINT8 *Target,
- IN UINT64 Lun
- )
- {
- return EFI_UNSUPPORTED;
- }
- //
- // Driver Binding
- //
- STATIC
- EFI_STATUS
- EFIAPI
- MptScsiControllerSupported (
- IN EFI_DRIVER_BINDING_PROTOCOL *This,
- IN EFI_HANDLE ControllerHandle,
- IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
- )
- {
- EFI_STATUS Status;
- EFI_PCI_IO_PROTOCOL *PciIo;
- PCI_TYPE00 Pci;
- Status = gBS->OpenProtocol (
- ControllerHandle,
- &gEfiPciIoProtocolGuid,
- (VOID **)&PciIo,
- This->DriverBindingHandle,
- ControllerHandle,
- EFI_OPEN_PROTOCOL_BY_DRIVER
- );
- if (EFI_ERROR (Status)) {
- return Status;
- }
- Status = PciIo->Pci.Read (
- PciIo,
- EfiPciIoWidthUint32,
- 0,
- sizeof (Pci) / sizeof (UINT32),
- &Pci
- );
- if (EFI_ERROR (Status)) {
- goto Done;
- }
- if ((Pci.Hdr.VendorId == LSI_LOGIC_PCI_VENDOR_ID) &&
- ((Pci.Hdr.DeviceId == LSI_53C1030_PCI_DEVICE_ID) ||
- (Pci.Hdr.DeviceId == LSI_SAS1068_PCI_DEVICE_ID) ||
- (Pci.Hdr.DeviceId == LSI_SAS1068E_PCI_DEVICE_ID)))
- {
- Status = EFI_SUCCESS;
- } else {
- Status = EFI_UNSUPPORTED;
- }
- Done:
- gBS->CloseProtocol (
- ControllerHandle,
- &gEfiPciIoProtocolGuid,
- This->DriverBindingHandle,
- ControllerHandle
- );
- return Status;
- }
- STATIC
- EFI_STATUS
- EFIAPI
- MptScsiControllerStart (
- IN EFI_DRIVER_BINDING_PROTOCOL *This,
- IN EFI_HANDLE ControllerHandle,
- IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
- )
- {
- EFI_STATUS Status;
- MPT_SCSI_DEV *Dev;
- UINTN Pages;
- UINTN BytesMapped;
- Dev = AllocateZeroPool (sizeof (*Dev));
- if (Dev == NULL) {
- return EFI_OUT_OF_RESOURCES;
- }
- Dev->Signature = MPT_SCSI_DEV_SIGNATURE;
- Dev->MaxTarget = PcdGet8 (PcdMptScsiMaxTargetLimit);
- Dev->StallPerPollUsec = PcdGet32 (PcdMptScsiStallPerPollUsec);
- Status = gBS->OpenProtocol (
- ControllerHandle,
- &gEfiPciIoProtocolGuid,
- (VOID **)&Dev->PciIo,
- This->DriverBindingHandle,
- ControllerHandle,
- EFI_OPEN_PROTOCOL_BY_DRIVER
- );
- if (EFI_ERROR (Status)) {
- goto FreePool;
- }
- Status = Dev->PciIo->Attributes (
- Dev->PciIo,
- EfiPciIoAttributeOperationGet,
- 0,
- &Dev->OriginalPciAttributes
- );
- if (EFI_ERROR (Status)) {
- goto CloseProtocol;
- }
- //
- // Enable I/O Space & Bus-Mastering
- //
- Status = Dev->PciIo->Attributes (
- Dev->PciIo,
- EfiPciIoAttributeOperationEnable,
- (EFI_PCI_IO_ATTRIBUTE_IO |
- EFI_PCI_IO_ATTRIBUTE_BUS_MASTER),
- NULL
- );
- if (EFI_ERROR (Status)) {
- goto CloseProtocol;
- }
- //
- // Signal device supports 64-bit DMA addresses
- //
- Status = Dev->PciIo->Attributes (
- Dev->PciIo,
- EfiPciIoAttributeOperationEnable,
- EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE,
- NULL
- );
- if (EFI_ERROR (Status)) {
- //
- // Warn user that device will only be using 32-bit DMA addresses.
- //
- // Note that this does not prevent the device/driver from working
- // and therefore we only warn and continue as usual.
- //
- DEBUG ((
- DEBUG_WARN,
- "%a: failed to enable 64-bit DMA addresses\n",
- __FUNCTION__
- ));
- }
- //
- // Create buffers for data transfer
- //
- Pages = EFI_SIZE_TO_PAGES (sizeof (*Dev->Dma));
- Status = Dev->PciIo->AllocateBuffer (
- Dev->PciIo,
- AllocateAnyPages,
- EfiBootServicesData,
- Pages,
- (VOID **)&Dev->Dma,
- EFI_PCI_ATTRIBUTE_MEMORY_CACHED
- );
- if (EFI_ERROR (Status)) {
- goto RestoreAttributes;
- }
- BytesMapped = EFI_PAGES_TO_SIZE (Pages);
- Status = Dev->PciIo->Map (
- Dev->PciIo,
- EfiPciIoOperationBusMasterCommonBuffer,
- Dev->Dma,
- &BytesMapped,
- &Dev->DmaPhysical,
- &Dev->DmaMapping
- );
- if (EFI_ERROR (Status)) {
- goto FreeBuffer;
- }
- if (BytesMapped != EFI_PAGES_TO_SIZE (Pages)) {
- Status = EFI_OUT_OF_RESOURCES;
- goto Unmap;
- }
- Status = MptScsiInit (Dev);
- if (EFI_ERROR (Status)) {
- goto Unmap;
- }
- Status = gBS->CreateEvent (
- EVT_SIGNAL_EXIT_BOOT_SERVICES,
- TPL_CALLBACK,
- &MptScsiExitBoot,
- Dev,
- &Dev->ExitBoot
- );
- if (EFI_ERROR (Status)) {
- goto UninitDev;
- }
- //
- // Host adapter channel, doesn't exist
- //
- Dev->PassThruMode.AdapterId = MAX_UINT32;
- Dev->PassThruMode.Attributes =
- EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_PHYSICAL |
- EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL;
- Dev->PassThru.Mode = &Dev->PassThruMode;
- Dev->PassThru.PassThru = &MptScsiPassThru;
- Dev->PassThru.GetNextTargetLun = &MptScsiGetNextTargetLun;
- Dev->PassThru.BuildDevicePath = &MptScsiBuildDevicePath;
- Dev->PassThru.GetTargetLun = &MptScsiGetTargetLun;
- Dev->PassThru.ResetChannel = &MptScsiResetChannel;
- Dev->PassThru.ResetTargetLun = &MptScsiResetTargetLun;
- Dev->PassThru.GetNextTarget = &MptScsiGetNextTarget;
- Status = gBS->InstallProtocolInterface (
- &ControllerHandle,
- &gEfiExtScsiPassThruProtocolGuid,
- EFI_NATIVE_INTERFACE,
- &Dev->PassThru
- );
- if (EFI_ERROR (Status)) {
- goto CloseExitBoot;
- }
- return EFI_SUCCESS;
- CloseExitBoot:
- gBS->CloseEvent (Dev->ExitBoot);
- UninitDev:
- MptScsiReset (Dev);
- Unmap:
- Dev->PciIo->Unmap (
- Dev->PciIo,
- Dev->DmaMapping
- );
- FreeBuffer:
- Dev->PciIo->FreeBuffer (
- Dev->PciIo,
- Pages,
- Dev->Dma
- );
- RestoreAttributes:
- Dev->PciIo->Attributes (
- Dev->PciIo,
- EfiPciIoAttributeOperationSet,
- Dev->OriginalPciAttributes,
- NULL
- );
- CloseProtocol:
- gBS->CloseProtocol (
- ControllerHandle,
- &gEfiPciIoProtocolGuid,
- This->DriverBindingHandle,
- ControllerHandle
- );
- FreePool:
- FreePool (Dev);
- return Status;
- }
- STATIC
- EFI_STATUS
- EFIAPI
- MptScsiControllerStop (
- IN EFI_DRIVER_BINDING_PROTOCOL *This,
- IN EFI_HANDLE ControllerHandle,
- IN UINTN NumberOfChildren,
- IN EFI_HANDLE *ChildHandleBuffer
- )
- {
- EFI_STATUS Status;
- EFI_EXT_SCSI_PASS_THRU_PROTOCOL *PassThru;
- MPT_SCSI_DEV *Dev;
- Status = gBS->OpenProtocol (
- ControllerHandle,
- &gEfiExtScsiPassThruProtocolGuid,
- (VOID **)&PassThru,
- This->DriverBindingHandle,
- ControllerHandle,
- EFI_OPEN_PROTOCOL_GET_PROTOCOL // Lookup only
- );
- if (EFI_ERROR (Status)) {
- return Status;
- }
- Dev = MPT_SCSI_FROM_PASS_THRU (PassThru);
- Status = gBS->UninstallProtocolInterface (
- ControllerHandle,
- &gEfiExtScsiPassThruProtocolGuid,
- &Dev->PassThru
- );
- if (EFI_ERROR (Status)) {
- return Status;
- }
- gBS->CloseEvent (Dev->ExitBoot);
- MptScsiReset (Dev);
- Dev->PciIo->Unmap (
- Dev->PciIo,
- Dev->DmaMapping
- );
- Dev->PciIo->FreeBuffer (
- Dev->PciIo,
- EFI_SIZE_TO_PAGES (sizeof (*Dev->Dma)),
- Dev->Dma
- );
- Dev->PciIo->Attributes (
- Dev->PciIo,
- EfiPciIoAttributeOperationSet,
- Dev->OriginalPciAttributes,
- NULL
- );
- gBS->CloseProtocol (
- ControllerHandle,
- &gEfiPciIoProtocolGuid,
- This->DriverBindingHandle,
- ControllerHandle
- );
- FreePool (Dev);
- return Status;
- }
- STATIC
- EFI_DRIVER_BINDING_PROTOCOL mMptScsiDriverBinding = {
- &MptScsiControllerSupported,
- &MptScsiControllerStart,
- &MptScsiControllerStop,
- MPT_SCSI_BINDING_VERSION,
- NULL, // ImageHandle, filled by EfiLibInstallDriverBindingComponentName2
- NULL, // DriverBindingHandle, filled as well
- };
- //
- // Component Name
- //
- STATIC
- EFI_UNICODE_STRING_TABLE mDriverNameTable[] = {
- { "eng;en", L"LSI Fusion MPT SCSI Driver" },
- { NULL, NULL }
- };
- STATIC
- EFI_COMPONENT_NAME_PROTOCOL mComponentName;
- EFI_STATUS
- EFIAPI
- MptScsiGetDriverName (
- IN EFI_COMPONENT_NAME_PROTOCOL *This,
- IN CHAR8 *Language,
- OUT CHAR16 **DriverName
- )
- {
- return LookupUnicodeString2 (
- Language,
- This->SupportedLanguages,
- mDriverNameTable,
- DriverName,
- (BOOLEAN)(This == &mComponentName) // Iso639Language
- );
- }
- EFI_STATUS
- EFIAPI
- MptScsiGetDeviceName (
- IN EFI_COMPONENT_NAME_PROTOCOL *This,
- IN EFI_HANDLE DeviceHandle,
- IN EFI_HANDLE ChildHandle,
- IN CHAR8 *Language,
- OUT CHAR16 **ControllerName
- )
- {
- return EFI_UNSUPPORTED;
- }
- STATIC
- EFI_COMPONENT_NAME_PROTOCOL mComponentName = {
- &MptScsiGetDriverName,
- &MptScsiGetDeviceName,
- "eng" // SupportedLanguages, ISO 639-2 language codes
- };
- STATIC
- EFI_COMPONENT_NAME2_PROTOCOL mComponentName2 = {
- (EFI_COMPONENT_NAME2_GET_DRIVER_NAME)&MptScsiGetDriverName,
- (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME)&MptScsiGetDeviceName,
- "en" // SupportedLanguages, RFC 4646 language codes
- };
- //
- // Entry Point
- //
- EFI_STATUS
- EFIAPI
- MptScsiEntryPoint (
- IN EFI_HANDLE ImageHandle,
- IN EFI_SYSTEM_TABLE *SystemTable
- )
- {
- return EfiLibInstallDriverBindingComponentName2 (
- ImageHandle,
- SystemTable,
- &mMptScsiDriverBinding,
- ImageHandle, // The handle to install onto
- &mComponentName,
- &mComponentName2
- );
- }
|