TianoCore EDK2 master
Loading...
Searching...
No Matches
MptScsi.c
Go to the documentation of this file.
1
14#include <Library/BaseLib.h>
16#include <Library/DebugLib.h>
18#include <Library/PcdLib.h>
20#include <Library/UefiLib.h>
21#include <Protocol/PciIo.h>
24#include <Uefi/UefiSpec.h>
25
26//
27// Higher versions will be used before lower, 0x10-0xffffffef is the version
28// range for IVH (Indie Hardware Vendors)
29//
30#define MPT_SCSI_BINDING_VERSION 0x10
31
32//
33// Runtime Structures
34//
35
36typedef struct {
39 //
40 // As EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET.SenseDataLength is defined
41 // as UINT8, defining here SenseData size to MAX_UINT8 will guarantee it
42 // cannot overflow when passed to device.
43 //
44 UINT8 Sense[MAX_UINT8];
45 //
46 // This size of the data is arbitrarily chosen.
47 // It seems to be sufficient for all I/O requests sent through
48 // EFI_SCSI_PASS_THRU_PROTOCOL.PassThru() for common boot scenarios.
49 //
50 UINT8 Data[0x2000];
52
53#define MPT_SCSI_DEV_SIGNATURE SIGNATURE_32 ('M','P','T','S')
54typedef struct {
55 UINT32 Signature;
57 EFI_EXT_SCSI_PASS_THRU_MODE PassThruMode;
58 UINT8 MaxTarget;
59 UINT32 StallPerPollUsec;
61 UINT64 OriginalPciAttributes;
62 EFI_EVENT ExitBoot;
64 EFI_PHYSICAL_ADDRESS DmaPhysical;
65 VOID *DmaMapping;
66 BOOLEAN IoReplyEnqueued;
68
69#define MPT_SCSI_FROM_PASS_THRU(PassThruPtr) \
70 CR (PassThruPtr, MPT_SCSI_DEV, PassThru, MPT_SCSI_DEV_SIGNATURE)
71
72#define MPT_SCSI_DMA_ADDR(Dev, MemberName) \
73 (Dev->DmaPhysical + OFFSET_OF (MPT_SCSI_DMA_BUFFER, MemberName))
74
75#define MPT_SCSI_DMA_ADDR_HIGH(Dev, MemberName) \
76 ((UINT32)RShiftU64 (MPT_SCSI_DMA_ADDR (Dev, MemberName), 32))
77
78#define MPT_SCSI_DMA_ADDR_LOW(Dev, MemberName) \
79 ((UINT32)MPT_SCSI_DMA_ADDR (Dev, MemberName))
80
81//
82// Hardware functions
83//
84
87Out32 (
88 IN MPT_SCSI_DEV *Dev,
89 IN UINT32 Addr,
90 IN UINT32 Data
91 )
92{
93 return Dev->PciIo->Io.Write (
94 Dev->PciIo,
95 EfiPciIoWidthUint32,
96 PCI_BAR_IDX0,
97 Addr,
98 1,
99 &Data
100 );
101}
102
103STATIC
105In32 (
106 IN MPT_SCSI_DEV *Dev,
107 IN UINT32 Addr,
108 OUT UINT32 *Data
109 )
110{
111 return Dev->PciIo->Io.Read (
112 Dev->PciIo,
113 EfiPciIoWidthUint32,
114 PCI_BAR_IDX0,
115 Addr,
116 1,
117 Data
118 );
119}
120
121STATIC
123MptDoorbell (
124 IN MPT_SCSI_DEV *Dev,
125 IN UINT8 DoorbellFunc,
126 IN UINT8 DoorbellArg
127 )
128{
129 return Out32 (
130 Dev,
131 MPT_REG_DOORBELL,
132 (((UINT32)DoorbellFunc) << 24) | (DoorbellArg << 16)
133 );
134}
135
136STATIC
138MptScsiReset (
139 IN MPT_SCSI_DEV *Dev
140 )
141{
142 EFI_STATUS Status;
143
144 //
145 // Reset hardware
146 //
147 Status = MptDoorbell (Dev, MPT_DOORBELL_RESET, 0);
148 if (EFI_ERROR (Status)) {
149 return Status;
150 }
151
152 //
153 // Mask interrupts
154 //
155 Status = Out32 (Dev, MPT_REG_IMASK, MPT_IMASK_DOORBELL | MPT_IMASK_REPLY);
156 if (EFI_ERROR (Status)) {
157 return Status;
158 }
159
160 //
161 // Clear interrupt status
162 //
163 Status = Out32 (Dev, MPT_REG_ISTATUS, 0);
164 if (EFI_ERROR (Status)) {
165 return Status;
166 }
167
168 return EFI_SUCCESS;
169}
170
171STATIC
173MptScsiInit (
174 IN MPT_SCSI_DEV *Dev
175 )
176{
177 EFI_STATUS Status;
178
179 union {
181 UINT32 Uint32;
182 } AlignedReq;
185 UINT8 *ReplyBytes;
186 UINT32 ReplyWord;
187
188 Req = &AlignedReq.Data;
189
190 Status = MptScsiReset (Dev);
191 if (EFI_ERROR (Status)) {
192 return Status;
193 }
194
195 ZeroMem (Req, sizeof (*Req));
196 ZeroMem (&Reply, sizeof (Reply));
197 Req->WhoInit = MPT_IOC_WHOINIT_ROM_BIOS;
198 Req->Function = MPT_MESSAGE_HDR_FUNCTION_IOC_INIT;
200 FixedPcdGet8 (PcdMptScsiMaxTargetLimit) < 255,
201 "Req supports 255 targets only (max target is 254)"
202 );
203 Req->MaxDevices = Dev->MaxTarget + 1;
204 Req->MaxBuses = 1;
205 Req->ReplyFrameSize = sizeof Dev->Dma->IoReply.Data;
206 Req->HostMfaHighAddr = MPT_SCSI_DMA_ADDR_HIGH (Dev, IoRequest);
207 Req->SenseBufferHighAddr = MPT_SCSI_DMA_ADDR_HIGH (Dev, Sense);
208
209 //
210 // Send controller init through doorbell
211 //
213 sizeof (*Req) % sizeof (UINT32) == 0,
214 "Req must be multiple of UINT32"
215 );
217 sizeof (*Req) / sizeof (UINT32) <= MAX_UINT8,
218 "Req must fit in MAX_UINT8 Dwords"
219 );
220 Status = MptDoorbell (
221 Dev,
222 MPT_DOORBELL_HANDSHAKE,
223 (UINT8)(sizeof (*Req) / sizeof (UINT32))
224 );
225 if (EFI_ERROR (Status)) {
226 return Status;
227 }
228
229 Status = Dev->PciIo->Io.Write (
230 Dev->PciIo,
231 EfiPciIoWidthFifoUint32,
232 PCI_BAR_IDX0,
233 MPT_REG_DOORBELL,
234 sizeof (*Req) / sizeof (UINT32),
235 Req
236 );
237 if (EFI_ERROR (Status)) {
238 return Status;
239 }
240
241 //
242 // Read reply through doorbell
243 // Each 32bit (Dword) read produces 16bit (Word) of data
244 //
245 // The reply is read back to complete the doorbell function but it
246 // isn't useful because it doesn't contain relevant data or status
247 // codes.
248 //
250 sizeof (Reply) % sizeof (UINT16) == 0,
251 "Reply must be multiple of UINT16"
252 );
253 ReplyBytes = (UINT8 *)&Reply;
254 while (ReplyBytes != (UINT8 *)(&Reply + 1)) {
255 Status = In32 (Dev, MPT_REG_DOORBELL, &ReplyWord);
256 if (EFI_ERROR (Status)) {
257 return Status;
258 }
259
260 CopyMem (ReplyBytes, &ReplyWord, sizeof (UINT16));
261 ReplyBytes += sizeof (UINT16);
262 }
263
264 //
265 // Clear interrupts generated by doorbell reply
266 //
267 Status = Out32 (Dev, MPT_REG_ISTATUS, 0);
268 if (EFI_ERROR (Status)) {
269 return Status;
270 }
271
272 return EFI_SUCCESS;
273}
274
275STATIC
277ReportHostAdapterError (
279 )
280{
281 DEBUG ((DEBUG_ERROR, "%a: fatal error in scsi request\n", __func__));
282 Packet->InTransferLength = 0;
283 Packet->OutTransferLength = 0;
284 Packet->SenseDataLength = 0;
285 Packet->HostAdapterStatus = EFI_EXT_SCSI_STATUS_HOST_ADAPTER_OTHER;
286 Packet->TargetStatus = EFI_EXT_SCSI_STATUS_TARGET_TASK_ABORTED;
287 return EFI_DEVICE_ERROR;
288}
289
290STATIC
292ReportHostAdapterOverrunError (
294 )
295{
296 Packet->SenseDataLength = 0;
297 Packet->HostAdapterStatus =
298 EFI_EXT_SCSI_STATUS_HOST_ADAPTER_DATA_OVERRUN_UNDERRUN;
299 Packet->TargetStatus = EFI_EXT_SCSI_STATUS_TARGET_GOOD;
300 return EFI_BAD_BUFFER_SIZE;
301}
302
303STATIC
305MptScsiPopulateRequest (
306 IN MPT_SCSI_DEV *Dev,
307 IN UINT8 Target,
308 IN UINT64 Lun,
310 )
311{
313
314 Request = &Dev->Dma->IoRequest.Data;
315
316 if ((Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_BIDIRECTIONAL) ||
317 ((Packet->InTransferLength > 0) && (Packet->OutTransferLength > 0)) ||
318 (Packet->CdbLength > sizeof (Request->Header.Cdb)))
319 {
320 return EFI_UNSUPPORTED;
321 }
322
323 if ((Target > Dev->MaxTarget) || (Lun > 0) ||
324 (Packet->DataDirection > EFI_EXT_SCSI_DATA_DIRECTION_BIDIRECTIONAL) ||
325 //
326 // Trying to receive, but destination pointer is NULL, or contradicting
327 // transfer direction
328 //
329 ((Packet->InTransferLength > 0) &&
330 ((Packet->InDataBuffer == NULL) ||
331 (Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_WRITE)
332 )
333 ) ||
334
335 //
336 // Trying to send, but source pointer is NULL, or contradicting transfer
337 // direction
338 //
339 ((Packet->OutTransferLength > 0) &&
340 ((Packet->OutDataBuffer == NULL) ||
341 (Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_READ)
342 )
343 )
344 )
345 {
346 return EFI_INVALID_PARAMETER;
347 }
348
349 if (Packet->InTransferLength > sizeof (Dev->Dma->Data)) {
350 Packet->InTransferLength = sizeof (Dev->Dma->Data);
351 return ReportHostAdapterOverrunError (Packet);
352 }
353
354 if (Packet->OutTransferLength > sizeof (Dev->Dma->Data)) {
355 Packet->OutTransferLength = sizeof (Dev->Dma->Data);
356 return ReportHostAdapterOverrunError (Packet);
357 }
358
359 ZeroMem (Request, sizeof (*Request));
360 Request->Header.TargetId = Target;
361 //
362 // Only LUN 0 is currently supported, hence the cast is safe
363 //
364 Request->Header.Lun[1] = (UINT8)Lun;
365 Request->Header.Function = MPT_MESSAGE_HDR_FUNCTION_SCSI_IO_REQUEST;
366 Request->Header.MessageContext = 1; // We handle one request at a time
367
368 Request->Header.CdbLength = Packet->CdbLength;
369 CopyMem (Request->Header.Cdb, Packet->Cdb, Packet->CdbLength);
370
371 //
372 // SenseDataLength is UINT8, Sense[] is MAX_UINT8, so we can't overflow
373 //
374 ZeroMem (Dev->Dma->Sense, Packet->SenseDataLength);
375 Request->Header.SenseBufferLength = Packet->SenseDataLength;
376 Request->Header.SenseBufferLowAddress = MPT_SCSI_DMA_ADDR_LOW (Dev, Sense);
377
378 Request->Sg.EndOfList = 1;
379 Request->Sg.EndOfBuffer = 1;
380 Request->Sg.LastElement = 1;
381 Request->Sg.ElementType = MPT_SG_ENTRY_TYPE_SIMPLE;
382 Request->Sg.Is64BitAddress = 1;
383 Request->Sg.DataBufferAddress = MPT_SCSI_DMA_ADDR (Dev, Data);
384
385 //
386 // "MPT_SG_ENTRY_SIMPLE.Length" is a 24-bit quantity.
387 //
389 sizeof (Dev->Dma->Data) < SIZE_16MB,
390 "MPT_SCSI_DMA_BUFFER.Data must be smaller than 16MB"
391 );
392
393 if (Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_READ) {
394 Request->Header.DataLength = Packet->InTransferLength;
395 Request->Sg.Length = Packet->InTransferLength;
396 Request->Header.Control = MPT_SCSIIO_REQUEST_CONTROL_TXDIR_READ;
397 } else {
398 Request->Header.DataLength = Packet->OutTransferLength;
399 Request->Sg.Length = Packet->OutTransferLength;
400 Request->Header.Control = MPT_SCSIIO_REQUEST_CONTROL_TXDIR_WRITE;
401
402 CopyMem (Dev->Dma->Data, Packet->OutDataBuffer, Packet->OutTransferLength);
403 Request->Sg.BufferContainsData = 1;
404 }
405
406 if (Request->Header.DataLength == 0) {
407 Request->Header.Control = MPT_SCSIIO_REQUEST_CONTROL_TXDIR_NONE;
408 }
409
410 return EFI_SUCCESS;
411}
412
413STATIC
415MptScsiSendRequest (
416 IN MPT_SCSI_DEV *Dev,
418 )
419{
420 EFI_STATUS Status;
421
422 if (!Dev->IoReplyEnqueued) {
423 //
424 // Put one free reply frame on the reply queue, the hardware may use it to
425 // report an error to us.
426 //
427 Status = Out32 (Dev, MPT_REG_REP_Q, MPT_SCSI_DMA_ADDR_LOW (Dev, IoReply));
428 if (EFI_ERROR (Status)) {
429 return EFI_DEVICE_ERROR;
430 }
431
432 Dev->IoReplyEnqueued = TRUE;
433 }
434
435 Status = Out32 (Dev, MPT_REG_REQ_Q, MPT_SCSI_DMA_ADDR_LOW (Dev, IoRequest));
436 if (EFI_ERROR (Status)) {
437 return EFI_DEVICE_ERROR;
438 }
439
440 return EFI_SUCCESS;
441}
442
443STATIC
445MptScsiGetReply (
446 IN MPT_SCSI_DEV *Dev,
447 OUT UINT32 *Reply
448 )
449{
450 EFI_STATUS Status;
451 UINT32 Istatus;
452 UINT32 EmptyReply;
453
454 //
455 // Timeouts are not supported for
456 // EFI_EXT_SCSI_PASS_THRU_PROTOCOL.PassThru() in this implementation.
457 //
458 for ( ; ;) {
459 Status = In32 (Dev, MPT_REG_ISTATUS, &Istatus);
460 if (EFI_ERROR (Status)) {
461 return Status;
462 }
463
464 //
465 // Interrupt raised
466 //
467 if (Istatus & MPT_IMASK_REPLY) {
468 break;
469 }
470
471 gBS->Stall (Dev->StallPerPollUsec);
472 }
473
474 Status = In32 (Dev, MPT_REG_REP_Q, Reply);
475 if (EFI_ERROR (Status)) {
476 return Status;
477 }
478
479 //
480 // The driver is supposed to fetch replies until 0xffffffff is returned, which
481 // will reset the interrupt status. We put only one request, so we expect the
482 // next read reply to be the last.
483 //
484 Status = In32 (Dev, MPT_REG_REP_Q, &EmptyReply);
485 if (EFI_ERROR (Status) || (EmptyReply != MAX_UINT32)) {
486 return EFI_DEVICE_ERROR;
487 }
488
489 return EFI_SUCCESS;
490}
491
492STATIC
494MptScsiHandleReply (
495 IN MPT_SCSI_DEV *Dev,
496 IN UINT32 Reply,
498 )
499{
500 if (Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_READ) {
501 CopyMem (Packet->InDataBuffer, Dev->Dma->Data, Packet->InTransferLength);
502 }
503
504 if (Reply == Dev->Dma->IoRequest.Data.Header.MessageContext) {
505 //
506 // This is a turbo reply, everything is good
507 //
508 Packet->SenseDataLength = 0;
509 Packet->HostAdapterStatus = EFI_EXT_SCSI_STATUS_HOST_ADAPTER_OK;
510 Packet->TargetStatus = EFI_EXT_SCSI_STATUS_TARGET_GOOD;
511 } else if ((Reply & BIT31) != 0) {
512 DEBUG ((DEBUG_INFO, "%a: Full reply returned\n", __func__));
513 //
514 // When reply MSB is set, we got a full reply. Since we submitted only one
515 // reply frame, we know it's IoReply.
516 //
517 Dev->IoReplyEnqueued = FALSE;
518
519 Packet->TargetStatus = Dev->Dma->IoReply.Data.ScsiStatus;
520 //
521 // Make sure device only lowers SenseDataLength before copying sense
522 //
523 ASSERT (Dev->Dma->IoReply.Data.SenseCount <= Packet->SenseDataLength);
524 Packet->SenseDataLength =
525 (UINT8)MIN (Dev->Dma->IoReply.Data.SenseCount, Packet->SenseDataLength);
526 CopyMem (Packet->SenseData, Dev->Dma->Sense, Packet->SenseDataLength);
527
528 if (Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_READ) {
529 Packet->InTransferLength = Dev->Dma->IoReply.Data.TransferCount;
530 } else {
531 Packet->OutTransferLength = Dev->Dma->IoReply.Data.TransferCount;
532 }
533
534 switch (Dev->Dma->IoReply.Data.IocStatus) {
535 case MPT_SCSI_IOCSTATUS_SUCCESS:
536 Packet->HostAdapterStatus = EFI_EXT_SCSI_STATUS_HOST_ADAPTER_OK;
537 break;
538 case MPT_SCSI_IOCSTATUS_DEVICE_NOT_THERE:
539 Packet->HostAdapterStatus =
540 EFI_EXT_SCSI_STATUS_HOST_ADAPTER_SELECTION_TIMEOUT;
541 return EFI_TIMEOUT;
542 case MPT_SCSI_IOCSTATUS_DATA_UNDERRUN:
543 case MPT_SCSI_IOCSTATUS_DATA_OVERRUN:
544 Packet->HostAdapterStatus =
545 EFI_EXT_SCSI_STATUS_HOST_ADAPTER_DATA_OVERRUN_UNDERRUN;
546 break;
547 default:
548 Packet->HostAdapterStatus = EFI_EXT_SCSI_STATUS_HOST_ADAPTER_OTHER;
549 return EFI_DEVICE_ERROR;
550 }
551 } else {
552 DEBUG ((DEBUG_ERROR, "%a: unexpected reply (%x)\n", __func__, Reply));
553 return ReportHostAdapterError (Packet);
554 }
555
556 return EFI_SUCCESS;
557}
558
559//
560// Ext SCSI Pass Thru
561//
562
563STATIC
565EFIAPI
566MptScsiPassThru (
568 IN UINT8 *Target,
569 IN UINT64 Lun,
571 IN EFI_EVENT Event OPTIONAL
572 )
573{
574 EFI_STATUS Status;
575 MPT_SCSI_DEV *Dev;
576 UINT32 Reply;
577
578 Dev = MPT_SCSI_FROM_PASS_THRU (This);
579 //
580 // We only use first byte of target identifer
581 //
582 Status = MptScsiPopulateRequest (Dev, *Target, Lun, Packet);
583 if (EFI_ERROR (Status)) {
584 //
585 // MptScsiPopulateRequest modified packet according to the error
586 //
587 return Status;
588 }
589
590 Status = MptScsiSendRequest (Dev, Packet);
591 if (EFI_ERROR (Status)) {
592 return ReportHostAdapterError (Packet);
593 }
594
595 Status = MptScsiGetReply (Dev, &Reply);
596 if (EFI_ERROR (Status)) {
597 return ReportHostAdapterError (Packet);
598 }
599
600 return MptScsiHandleReply (Dev, Reply, Packet);
601}
602
603STATIC
604BOOLEAN
605IsTargetInitialized (
606 IN UINT8 *Target
607 )
608{
609 UINTN Idx;
610
611 for (Idx = 0; Idx < TARGET_MAX_BYTES; ++Idx) {
612 if (Target[Idx] != 0xFF) {
613 return TRUE;
614 }
615 }
616
617 return FALSE;
618}
619
620STATIC
622EFIAPI
623MptScsiGetNextTargetLun (
625 IN OUT UINT8 **Target,
626 IN OUT UINT64 *Lun
627 )
628{
629 MPT_SCSI_DEV *Dev;
630
631 Dev = MPT_SCSI_FROM_PASS_THRU (This);
632 //
633 // Currently support only LUN 0, so hardcode it
634 //
635 if (!IsTargetInitialized (*Target)) {
636 ZeroMem (*Target, TARGET_MAX_BYTES);
637 *Lun = 0;
638 } else if ((**Target > Dev->MaxTarget) || (*Lun > 0)) {
639 return EFI_INVALID_PARAMETER;
640 } else if (**Target < Dev->MaxTarget) {
641 //
642 // This device interface support 256 targets only, so it's enough to
643 // increment the LSB of Target, as it will never overflow.
644 //
645 **Target += 1;
646 } else {
647 return EFI_NOT_FOUND;
648 }
649
650 return EFI_SUCCESS;
651}
652
653STATIC
655EFIAPI
656MptScsiGetNextTarget (
658 IN OUT UINT8 **Target
659 )
660{
661 MPT_SCSI_DEV *Dev;
662
663 Dev = MPT_SCSI_FROM_PASS_THRU (This);
664 if (!IsTargetInitialized (*Target)) {
665 ZeroMem (*Target, TARGET_MAX_BYTES);
666 } else if (**Target > Dev->MaxTarget) {
667 return EFI_INVALID_PARAMETER;
668 } else if (**Target < Dev->MaxTarget) {
669 //
670 // This device interface support 256 targets only, so it's enough to
671 // increment the LSB of Target, as it will never overflow.
672 //
673 **Target += 1;
674 } else {
675 return EFI_NOT_FOUND;
676 }
677
678 return EFI_SUCCESS;
679}
680
681STATIC
683EFIAPI
684MptScsiBuildDevicePath (
686 IN UINT8 *Target,
687 IN UINT64 Lun,
688 IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath
689 )
690{
691 MPT_SCSI_DEV *Dev;
692 SCSI_DEVICE_PATH *ScsiDevicePath;
693
694 if (DevicePath == NULL) {
695 return EFI_INVALID_PARAMETER;
696 }
697
698 //
699 // This device support 256 targets only, so it's enough to dereference
700 // the LSB of Target.
701 //
702 Dev = MPT_SCSI_FROM_PASS_THRU (This);
703 if ((*Target > Dev->MaxTarget) || (Lun > 0)) {
704 return EFI_NOT_FOUND;
705 }
706
707 ScsiDevicePath = AllocateZeroPool (sizeof (*ScsiDevicePath));
708 if (ScsiDevicePath == NULL) {
709 return EFI_OUT_OF_RESOURCES;
710 }
711
712 ScsiDevicePath->Header.Type = MESSAGING_DEVICE_PATH;
713 ScsiDevicePath->Header.SubType = MSG_SCSI_DP;
714 ScsiDevicePath->Header.Length[0] = (UINT8)sizeof (*ScsiDevicePath);
715 ScsiDevicePath->Header.Length[1] = (UINT8)(sizeof (*ScsiDevicePath) >> 8);
716 ScsiDevicePath->Pun = *Target;
717 ScsiDevicePath->Lun = (UINT16)Lun;
718
719 *DevicePath = &ScsiDevicePath->Header;
720 return EFI_SUCCESS;
721}
722
723STATIC
725EFIAPI
726MptScsiGetTargetLun (
728 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
729 OUT UINT8 **Target,
730 OUT UINT64 *Lun
731 )
732{
733 MPT_SCSI_DEV *Dev;
734 SCSI_DEVICE_PATH *ScsiDevicePath;
735
736 if ((DevicePath == NULL) ||
737 (Target == NULL) || (*Target == NULL) || (Lun == NULL))
738 {
739 return EFI_INVALID_PARAMETER;
740 }
741
742 if ((DevicePath->Type != MESSAGING_DEVICE_PATH) ||
743 (DevicePath->SubType != MSG_SCSI_DP))
744 {
745 return EFI_UNSUPPORTED;
746 }
747
748 Dev = MPT_SCSI_FROM_PASS_THRU (This);
749 ScsiDevicePath = (SCSI_DEVICE_PATH *)DevicePath;
750 if ((ScsiDevicePath->Pun > Dev->MaxTarget) ||
751 (ScsiDevicePath->Lun > 0))
752 {
753 return EFI_NOT_FOUND;
754 }
755
756 ZeroMem (*Target, TARGET_MAX_BYTES);
757 //
758 // This device support 256 targets only, so it's enough to set the LSB
759 // of Target.
760 //
761 **Target = (UINT8)ScsiDevicePath->Pun;
762 *Lun = ScsiDevicePath->Lun;
763
764 return EFI_SUCCESS;
765}
766
767STATIC
769EFIAPI
770MptScsiResetChannel (
772 )
773{
774 return EFI_UNSUPPORTED;
775}
776
777STATIC
778VOID
779EFIAPI
780MptScsiExitBoot (
781 IN EFI_EVENT Event,
782 IN VOID *Context
783 )
784{
785 MPT_SCSI_DEV *Dev;
786
787 Dev = Context;
788 DEBUG ((DEBUG_VERBOSE, "%a: Context=0x%p\n", __func__, Context));
789 MptScsiReset (Dev);
790}
791
792STATIC
794EFIAPI
795MptScsiResetTargetLun (
797 IN UINT8 *Target,
798 IN UINT64 Lun
799 )
800{
801 return EFI_UNSUPPORTED;
802}
803
804//
805// Driver Binding
806//
807
808STATIC
810EFIAPI
811MptScsiControllerSupported (
813 IN EFI_HANDLE ControllerHandle,
814 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
815 )
816{
817 EFI_STATUS Status;
818 EFI_PCI_IO_PROTOCOL *PciIo;
819 PCI_TYPE00 Pci;
820
821 Status = gBS->OpenProtocol (
822 ControllerHandle,
823 &gEfiPciIoProtocolGuid,
824 (VOID **)&PciIo,
825 This->DriverBindingHandle,
826 ControllerHandle,
827 EFI_OPEN_PROTOCOL_BY_DRIVER
828 );
829 if (EFI_ERROR (Status)) {
830 return Status;
831 }
832
833 Status = PciIo->Pci.Read (
834 PciIo,
835 EfiPciIoWidthUint32,
836 0,
837 sizeof (Pci) / sizeof (UINT32),
838 &Pci
839 );
840 if (EFI_ERROR (Status)) {
841 goto Done;
842 }
843
844 if ((Pci.Hdr.VendorId == LSI_LOGIC_PCI_VENDOR_ID) &&
845 ((Pci.Hdr.DeviceId == LSI_53C1030_PCI_DEVICE_ID) ||
846 (Pci.Hdr.DeviceId == LSI_SAS1068_PCI_DEVICE_ID) ||
847 (Pci.Hdr.DeviceId == LSI_SAS1068E_PCI_DEVICE_ID)))
848 {
849 Status = EFI_SUCCESS;
850 } else {
851 Status = EFI_UNSUPPORTED;
852 }
853
854Done:
855 gBS->CloseProtocol (
856 ControllerHandle,
857 &gEfiPciIoProtocolGuid,
858 This->DriverBindingHandle,
859 ControllerHandle
860 );
861 return Status;
862}
863
864STATIC
866EFIAPI
867MptScsiControllerStart (
869 IN EFI_HANDLE ControllerHandle,
870 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
871 )
872{
873 EFI_STATUS Status;
874 MPT_SCSI_DEV *Dev;
875 UINTN Pages;
876 UINTN BytesMapped;
877
878 Dev = AllocateZeroPool (sizeof (*Dev));
879 if (Dev == NULL) {
880 return EFI_OUT_OF_RESOURCES;
881 }
882
883 Dev->Signature = MPT_SCSI_DEV_SIGNATURE;
884
885 Dev->MaxTarget = PcdGet8 (PcdMptScsiMaxTargetLimit);
886 Dev->StallPerPollUsec = PcdGet32 (PcdMptScsiStallPerPollUsec);
887
888 Status = gBS->OpenProtocol (
889 ControllerHandle,
890 &gEfiPciIoProtocolGuid,
891 (VOID **)&Dev->PciIo,
892 This->DriverBindingHandle,
893 ControllerHandle,
894 EFI_OPEN_PROTOCOL_BY_DRIVER
895 );
896 if (EFI_ERROR (Status)) {
897 goto FreePool;
898 }
899
900 Status = Dev->PciIo->Attributes (
901 Dev->PciIo,
903 0,
904 &Dev->OriginalPciAttributes
905 );
906 if (EFI_ERROR (Status)) {
907 goto CloseProtocol;
908 }
909
910 //
911 // Enable I/O Space & Bus-Mastering
912 //
913 Status = Dev->PciIo->Attributes (
914 Dev->PciIo,
918 NULL
919 );
920 if (EFI_ERROR (Status)) {
921 goto CloseProtocol;
922 }
923
924 //
925 // Signal device supports 64-bit DMA addresses
926 //
927 Status = Dev->PciIo->Attributes (
928 Dev->PciIo,
931 NULL
932 );
933 if (EFI_ERROR (Status)) {
934 //
935 // Warn user that device will only be using 32-bit DMA addresses.
936 //
937 // Note that this does not prevent the device/driver from working
938 // and therefore we only warn and continue as usual.
939 //
940 DEBUG ((
941 DEBUG_WARN,
942 "%a: failed to enable 64-bit DMA addresses\n",
943 __func__
944 ));
945 }
946
947 //
948 // Create buffers for data transfer
949 //
950 Pages = EFI_SIZE_TO_PAGES (sizeof (*Dev->Dma));
951 Status = Dev->PciIo->AllocateBuffer (
952 Dev->PciIo,
955 Pages,
956 (VOID **)&Dev->Dma,
957 EFI_PCI_ATTRIBUTE_MEMORY_CACHED
958 );
959 if (EFI_ERROR (Status)) {
960 goto RestoreAttributes;
961 }
962
963 BytesMapped = EFI_PAGES_TO_SIZE (Pages);
964 Status = Dev->PciIo->Map (
965 Dev->PciIo,
967 Dev->Dma,
968 &BytesMapped,
969 &Dev->DmaPhysical,
970 &Dev->DmaMapping
971 );
972 if (EFI_ERROR (Status)) {
973 goto FreeBuffer;
974 }
975
976 if (BytesMapped != EFI_PAGES_TO_SIZE (Pages)) {
977 Status = EFI_OUT_OF_RESOURCES;
978 goto Unmap;
979 }
980
981 Status = MptScsiInit (Dev);
982 if (EFI_ERROR (Status)) {
983 goto Unmap;
984 }
985
986 Status = gBS->CreateEvent (
987 EVT_SIGNAL_EXIT_BOOT_SERVICES,
988 TPL_CALLBACK,
989 &MptScsiExitBoot,
990 Dev,
991 &Dev->ExitBoot
992 );
993 if (EFI_ERROR (Status)) {
994 goto UninitDev;
995 }
996
997 //
998 // Host adapter channel, doesn't exist
999 //
1000 Dev->PassThruMode.AdapterId = MAX_UINT32;
1001 Dev->PassThruMode.Attributes =
1002 EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_PHYSICAL |
1003 EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL;
1004
1005 Dev->PassThru.Mode = &Dev->PassThruMode;
1006 Dev->PassThru.PassThru = &MptScsiPassThru;
1007 Dev->PassThru.GetNextTargetLun = &MptScsiGetNextTargetLun;
1008 Dev->PassThru.BuildDevicePath = &MptScsiBuildDevicePath;
1009 Dev->PassThru.GetTargetLun = &MptScsiGetTargetLun;
1010 Dev->PassThru.ResetChannel = &MptScsiResetChannel;
1011 Dev->PassThru.ResetTargetLun = &MptScsiResetTargetLun;
1012 Dev->PassThru.GetNextTarget = &MptScsiGetNextTarget;
1013
1014 Status = gBS->InstallProtocolInterface (
1015 &ControllerHandle,
1016 &gEfiExtScsiPassThruProtocolGuid,
1018 &Dev->PassThru
1019 );
1020 if (EFI_ERROR (Status)) {
1021 goto CloseExitBoot;
1022 }
1023
1024 return EFI_SUCCESS;
1025
1026CloseExitBoot:
1027 gBS->CloseEvent (Dev->ExitBoot);
1028
1029UninitDev:
1030 MptScsiReset (Dev);
1031
1032Unmap:
1033 Dev->PciIo->Unmap (
1034 Dev->PciIo,
1035 Dev->DmaMapping
1036 );
1037
1038FreeBuffer:
1039 Dev->PciIo->FreeBuffer (
1040 Dev->PciIo,
1041 Pages,
1042 Dev->Dma
1043 );
1044
1045RestoreAttributes:
1046 Dev->PciIo->Attributes (
1047 Dev->PciIo,
1049 Dev->OriginalPciAttributes,
1050 NULL
1051 );
1052
1053CloseProtocol:
1054 gBS->CloseProtocol (
1055 ControllerHandle,
1056 &gEfiPciIoProtocolGuid,
1057 This->DriverBindingHandle,
1058 ControllerHandle
1059 );
1060
1061FreePool:
1062 FreePool (Dev);
1063
1064 return Status;
1065}
1066
1067STATIC
1069EFIAPI
1070MptScsiControllerStop (
1072 IN EFI_HANDLE ControllerHandle,
1073 IN UINTN NumberOfChildren,
1074 IN EFI_HANDLE *ChildHandleBuffer
1075 )
1076{
1077 EFI_STATUS Status;
1079 MPT_SCSI_DEV *Dev;
1080
1081 Status = gBS->OpenProtocol (
1082 ControllerHandle,
1083 &gEfiExtScsiPassThruProtocolGuid,
1084 (VOID **)&PassThru,
1085 This->DriverBindingHandle,
1086 ControllerHandle,
1087 EFI_OPEN_PROTOCOL_GET_PROTOCOL // Lookup only
1088 );
1089 if (EFI_ERROR (Status)) {
1090 return Status;
1091 }
1092
1093 Dev = MPT_SCSI_FROM_PASS_THRU (PassThru);
1094
1095 Status = gBS->UninstallProtocolInterface (
1096 ControllerHandle,
1097 &gEfiExtScsiPassThruProtocolGuid,
1098 &Dev->PassThru
1099 );
1100 if (EFI_ERROR (Status)) {
1101 return Status;
1102 }
1103
1104 gBS->CloseEvent (Dev->ExitBoot);
1105
1106 MptScsiReset (Dev);
1107
1108 Dev->PciIo->Unmap (
1109 Dev->PciIo,
1110 Dev->DmaMapping
1111 );
1112
1113 Dev->PciIo->FreeBuffer (
1114 Dev->PciIo,
1115 EFI_SIZE_TO_PAGES (sizeof (*Dev->Dma)),
1116 Dev->Dma
1117 );
1118
1119 Dev->PciIo->Attributes (
1120 Dev->PciIo,
1122 Dev->OriginalPciAttributes,
1123 NULL
1124 );
1125
1126 gBS->CloseProtocol (
1127 ControllerHandle,
1128 &gEfiPciIoProtocolGuid,
1129 This->DriverBindingHandle,
1130 ControllerHandle
1131 );
1132
1133 FreePool (Dev);
1134
1135 return Status;
1136}
1137
1138STATIC
1139EFI_DRIVER_BINDING_PROTOCOL mMptScsiDriverBinding = {
1140 &MptScsiControllerSupported,
1141 &MptScsiControllerStart,
1142 &MptScsiControllerStop,
1143 MPT_SCSI_BINDING_VERSION,
1144 NULL, // ImageHandle, filled by EfiLibInstallDriverBindingComponentName2
1145 NULL, // DriverBindingHandle, filled as well
1146};
1147
1148//
1149// Component Name
1150//
1151
1152STATIC
1153EFI_UNICODE_STRING_TABLE mDriverNameTable[] = {
1154 { "eng;en", L"LSI Fusion MPT SCSI Driver" },
1155 { NULL, NULL }
1156};
1157
1158STATIC
1159EFI_COMPONENT_NAME_PROTOCOL mComponentName;
1160
1162EFIAPI
1163MptScsiGetDriverName (
1165 IN CHAR8 *Language,
1166 OUT CHAR16 **DriverName
1167 )
1168{
1169 return LookupUnicodeString2 (
1170 Language,
1171 This->SupportedLanguages,
1172 mDriverNameTable,
1173 DriverName,
1174 (BOOLEAN)(This == &mComponentName) // Iso639Language
1175 );
1176}
1177
1179EFIAPI
1180MptScsiGetDeviceName (
1182 IN EFI_HANDLE DeviceHandle,
1183 IN EFI_HANDLE ChildHandle,
1184 IN CHAR8 *Language,
1185 OUT CHAR16 **ControllerName
1186 )
1187{
1188 return EFI_UNSUPPORTED;
1189}
1190
1191STATIC
1192EFI_COMPONENT_NAME_PROTOCOL mComponentName = {
1193 &MptScsiGetDriverName,
1194 &MptScsiGetDeviceName,
1195 "eng" // SupportedLanguages, ISO 639-2 language codes
1196};
1197
1198STATIC
1199EFI_COMPONENT_NAME2_PROTOCOL mComponentName2 = {
1200 (EFI_COMPONENT_NAME2_GET_DRIVER_NAME)&MptScsiGetDriverName,
1201 (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME)&MptScsiGetDeviceName,
1202 "en" // SupportedLanguages, RFC 4646 language codes
1203};
1204
1205//
1206// Entry Point
1207//
1208
1210EFIAPI
1211MptScsiEntryPoint (
1212 IN EFI_HANDLE ImageHandle,
1213 IN EFI_SYSTEM_TABLE *SystemTable
1214 )
1215{
1217 ImageHandle,
1218 SystemTable,
1219 &mMptScsiDriverBinding,
1220 ImageHandle, // The handle to install onto
1221 &mComponentName,
1222 &mComponentName2
1223 );
1224}
UINT64 UINTN
VOID *EFIAPI CopyMem(OUT VOID *DestinationBuffer, IN CONST VOID *SourceBuffer, IN UINTN Length)
VOID *EFIAPI ZeroMem(OUT VOID *Buffer, IN UINTN Length)
EFI_STATUS(EFIAPI * EFI_COMPONENT_NAME2_GET_DRIVER_NAME)(IN EFI_COMPONENT_NAME2_PROTOCOL *This, IN CHAR8 *Language, OUT CHAR16 **DriverName)
EFI_STATUS(EFIAPI * EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME)(IN EFI_COMPONENT_NAME2_PROTOCOL *This, IN EFI_HANDLE ControllerHandle, IN EFI_HANDLE ChildHandle OPTIONAL, IN CHAR8 *Language, OUT CHAR16 **ControllerName)
#define MSG_SCSI_DP
Definition: DevicePath.h:346
#define MESSAGING_DEVICE_PATH
Definition: DevicePath.h:321
VOID *EFIAPI AllocateZeroPool(IN UINTN AllocationSize)
VOID EFIAPI FreePool(IN VOID *Buffer)
#define NULL
Definition: Base.h:319
#define STATIC
Definition: Base.h:264
#define MIN(a, b)
Definition: Base.h:1007
#define TRUE
Definition: Base.h:301
#define FALSE
Definition: Base.h:307
#define STATIC_ASSERT
Definition: Base.h:808
#define IN
Definition: Base.h:279
#define OUT
Definition: Base.h:284
#define DEBUG(Expression)
Definition: DebugLib.h:434
#define EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE
Clear for PCI controllers that can not genrate a DAC.
Definition: PciIo.h:64
@ EfiPciIoAttributeOperationGet
Definition: PciIo.h:103
@ EfiPciIoAttributeOperationEnable
Definition: PciIo.h:111
@ EfiPciIoAttributeOperationSet
Definition: PciIo.h:107
#define EFI_PCI_IO_ATTRIBUTE_BUS_MASTER
Enable the DMA bit in the PCI Config Header.
Definition: PciIo.h:59
@ EfiPciIoOperationBusMasterCommonBuffer
Definition: PciIo.h:90
#define EFI_PCI_IO_ATTRIBUTE_IO
Enable the I/O decode bit in the PCI Config Header.
Definition: PciIo.h:57
#define PcdGet8(TokenName)
Definition: PcdLib.h:336
#define PcdGet32(TokenName)
Definition: PcdLib.h:362
#define FixedPcdGet8(TokenName)
Definition: PcdLib.h:64
UINT64 EFI_PHYSICAL_ADDRESS
Definition: UefiBaseType.h:50
#define EFI_PAGES_TO_SIZE(Pages)
Definition: UefiBaseType.h:213
RETURN_STATUS EFI_STATUS
Definition: UefiBaseType.h:29
VOID * EFI_EVENT
Definition: UefiBaseType.h:37
#define EFI_SIZE_TO_PAGES(Size)
Definition: UefiBaseType.h:200
VOID * EFI_HANDLE
Definition: UefiBaseType.h:33
#define EFI_SUCCESS
Definition: UefiBaseType.h:112
EFI_BOOT_SERVICES * gBS
EFI_STATUS EFIAPI LookupUnicodeString2(IN CONST CHAR8 *Language, IN CONST CHAR8 *SupportedLanguages, IN CONST EFI_UNICODE_STRING_TABLE *UnicodeStringTable, OUT CHAR16 **UnicodeString, IN BOOLEAN Iso639Language)
Definition: UefiLib.c:801
EFI_STATUS EFIAPI EfiLibInstallDriverBindingComponentName2(IN CONST EFI_HANDLE ImageHandle, IN CONST EFI_SYSTEM_TABLE *SystemTable, IN EFI_DRIVER_BINDING_PROTOCOL *DriverBinding, IN EFI_HANDLE DriverBindingHandle, IN CONST EFI_COMPONENT_NAME_PROTOCOL *ComponentName OPTIONAL, IN CONST EFI_COMPONENT_NAME2_PROTOCOL *ComponentName2 OPTIONAL)
@ EfiBootServicesData
@ EFI_NATIVE_INTERFACE
Definition: UefiSpec.h:1193
@ AllocateAnyPages
Definition: UefiSpec.h:33
EFI_EXT_SCSI_PASS_THRU_MODE * Mode