]> git.proxmox.com Git - mirror_edk2.git/blob - OvmfPkg/MptScsiDxe/MptScsi.c
OvmfPkg: Apply uncrustify changes
[mirror_edk2.git] / OvmfPkg / MptScsiDxe / MptScsi.c
1 /** @file
2
3 This driver produces Extended SCSI Pass Thru Protocol instances for
4 LSI Fusion MPT SCSI devices.
5
6 Copyright (C) 2020, Oracle and/or its affiliates.
7
8 SPDX-License-Identifier: BSD-2-Clause-Patent
9
10 **/
11
12 #include <IndustryStandard/FusionMptScsi.h>
13 #include <IndustryStandard/Pci.h>
14 #include <Library/BaseLib.h>
15 #include <Library/BaseMemoryLib.h>
16 #include <Library/DebugLib.h>
17 #include <Library/MemoryAllocationLib.h>
18 #include <Library/PcdLib.h>
19 #include <Library/UefiBootServicesTableLib.h>
20 #include <Library/UefiLib.h>
21 #include <Protocol/PciIo.h>
22 #include <Protocol/PciRootBridgeIo.h>
23 #include <Protocol/ScsiPassThruExt.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
36 typedef struct {
37 MPT_SCSI_REQUEST_ALIGNED IoRequest;
38 MPT_SCSI_IO_REPLY_ALIGNED IoReply;
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];
51 } MPT_SCSI_DMA_BUFFER;
52
53 #define MPT_SCSI_DEV_SIGNATURE SIGNATURE_32 ('M','P','T','S')
54 typedef struct {
55 UINT32 Signature;
56 EFI_EXT_SCSI_PASS_THRU_PROTOCOL PassThru;
57 EFI_EXT_SCSI_PASS_THRU_MODE PassThruMode;
58 UINT8 MaxTarget;
59 UINT32 StallPerPollUsec;
60 EFI_PCI_IO_PROTOCOL *PciIo;
61 UINT64 OriginalPciAttributes;
62 EFI_EVENT ExitBoot;
63 MPT_SCSI_DMA_BUFFER *Dma;
64 EFI_PHYSICAL_ADDRESS DmaPhysical;
65 VOID *DmaMapping;
66 BOOLEAN IoReplyEnqueued;
67 } MPT_SCSI_DEV;
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
85 STATIC
86 EFI_STATUS
87 Out32 (
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
103 STATIC
104 EFI_STATUS
105 In32 (
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
121 STATIC
122 EFI_STATUS
123 MptDoorbell (
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
136 STATIC
137 EFI_STATUS
138 MptScsiReset (
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
171 STATIC
172 EFI_STATUS
173 MptScsiInit (
174 IN MPT_SCSI_DEV *Dev
175 )
176 {
177 EFI_STATUS Status;
178
179 union {
180 MPT_IO_CONTROLLER_INIT_REQUEST Data;
181 UINT32 Uint32;
182 } AlignedReq;
183 MPT_IO_CONTROLLER_INIT_REQUEST *Req;
184 MPT_IO_CONTROLLER_INIT_REPLY Reply;
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;
199 STATIC_ASSERT (
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 //
212 STATIC_ASSERT (
213 sizeof (*Req) % sizeof (UINT32) == 0,
214 "Req must be multiple of UINT32"
215 );
216 STATIC_ASSERT (
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 //
249 STATIC_ASSERT (
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
275 STATIC
276 EFI_STATUS
277 ReportHostAdapterError (
278 OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet
279 )
280 {
281 DEBUG ((DEBUG_ERROR, "%a: fatal error in scsi request\n", __FUNCTION__));
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
290 STATIC
291 EFI_STATUS
292 ReportHostAdapterOverrunError (
293 OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet
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
303 STATIC
304 EFI_STATUS
305 MptScsiPopulateRequest (
306 IN MPT_SCSI_DEV *Dev,
307 IN UINT8 Target,
308 IN UINT64 Lun,
309 IN OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet
310 )
311 {
312 MPT_SCSI_REQUEST_WITH_SG *Request;
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 //
388 STATIC_ASSERT (
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
413 STATIC
414 EFI_STATUS
415 MptScsiSendRequest (
416 IN MPT_SCSI_DEV *Dev,
417 IN OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet
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
443 STATIC
444 EFI_STATUS
445 MptScsiGetReply (
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
492 STATIC
493 EFI_STATUS
494 MptScsiHandleReply (
495 IN MPT_SCSI_DEV *Dev,
496 IN UINT32 Reply,
497 OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet
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", __FUNCTION__));
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", __FUNCTION__, Reply));
553 return ReportHostAdapterError (Packet);
554 }
555
556 return EFI_SUCCESS;
557 }
558
559 //
560 // Ext SCSI Pass Thru
561 //
562
563 STATIC
564 EFI_STATUS
565 EFIAPI
566 MptScsiPassThru (
567 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,
568 IN UINT8 *Target,
569 IN UINT64 Lun,
570 IN OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet,
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
603 STATIC
604 BOOLEAN
605 IsTargetInitialized (
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
620 STATIC
621 EFI_STATUS
622 EFIAPI
623 MptScsiGetNextTargetLun (
624 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,
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
653 STATIC
654 EFI_STATUS
655 EFIAPI
656 MptScsiGetNextTarget (
657 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,
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
681 STATIC
682 EFI_STATUS
683 EFIAPI
684 MptScsiBuildDevicePath (
685 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,
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
723 STATIC
724 EFI_STATUS
725 EFIAPI
726 MptScsiGetTargetLun (
727 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,
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
767 STATIC
768 EFI_STATUS
769 EFIAPI
770 MptScsiResetChannel (
771 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This
772 )
773 {
774 return EFI_UNSUPPORTED;
775 }
776
777 STATIC
778 VOID
779 EFIAPI
780 MptScsiExitBoot (
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", __FUNCTION__, Context));
789 MptScsiReset (Dev);
790 }
791
792 STATIC
793 EFI_STATUS
794 EFIAPI
795 MptScsiResetTargetLun (
796 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,
797 IN UINT8 *Target,
798 IN UINT64 Lun
799 )
800 {
801 return EFI_UNSUPPORTED;
802 }
803
804 //
805 // Driver Binding
806 //
807
808 STATIC
809 EFI_STATUS
810 EFIAPI
811 MptScsiControllerSupported (
812 IN EFI_DRIVER_BINDING_PROTOCOL *This,
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
854 Done:
855 gBS->CloseProtocol (
856 ControllerHandle,
857 &gEfiPciIoProtocolGuid,
858 This->DriverBindingHandle,
859 ControllerHandle
860 );
861 return Status;
862 }
863
864 STATIC
865 EFI_STATUS
866 EFIAPI
867 MptScsiControllerStart (
868 IN EFI_DRIVER_BINDING_PROTOCOL *This,
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,
902 EfiPciIoAttributeOperationGet,
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,
915 EfiPciIoAttributeOperationEnable,
916 (EFI_PCI_IO_ATTRIBUTE_IO |
917 EFI_PCI_IO_ATTRIBUTE_BUS_MASTER),
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,
929 EfiPciIoAttributeOperationEnable,
930 EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE,
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 __FUNCTION__
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,
953 AllocateAnyPages,
954 EfiBootServicesData,
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,
966 EfiPciIoOperationBusMasterCommonBuffer,
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,
1017 EFI_NATIVE_INTERFACE,
1018 &Dev->PassThru
1019 );
1020 if (EFI_ERROR (Status)) {
1021 goto CloseExitBoot;
1022 }
1023
1024 return EFI_SUCCESS;
1025
1026 CloseExitBoot:
1027 gBS->CloseEvent (Dev->ExitBoot);
1028
1029 UninitDev:
1030 MptScsiReset (Dev);
1031
1032 Unmap:
1033 Dev->PciIo->Unmap (
1034 Dev->PciIo,
1035 Dev->DmaMapping
1036 );
1037
1038 FreeBuffer:
1039 Dev->PciIo->FreeBuffer (
1040 Dev->PciIo,
1041 Pages,
1042 Dev->Dma
1043 );
1044
1045 RestoreAttributes:
1046 Dev->PciIo->Attributes (
1047 Dev->PciIo,
1048 EfiPciIoAttributeOperationSet,
1049 Dev->OriginalPciAttributes,
1050 NULL
1051 );
1052
1053 CloseProtocol:
1054 gBS->CloseProtocol (
1055 ControllerHandle,
1056 &gEfiPciIoProtocolGuid,
1057 This->DriverBindingHandle,
1058 ControllerHandle
1059 );
1060
1061 FreePool:
1062 FreePool (Dev);
1063
1064 return Status;
1065 }
1066
1067 STATIC
1068 EFI_STATUS
1069 EFIAPI
1070 MptScsiControllerStop (
1071 IN EFI_DRIVER_BINDING_PROTOCOL *This,
1072 IN EFI_HANDLE ControllerHandle,
1073 IN UINTN NumberOfChildren,
1074 IN EFI_HANDLE *ChildHandleBuffer
1075 )
1076 {
1077 EFI_STATUS Status;
1078 EFI_EXT_SCSI_PASS_THRU_PROTOCOL *PassThru;
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,
1121 EfiPciIoAttributeOperationSet,
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
1138 STATIC
1139 EFI_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
1152 STATIC
1153 EFI_UNICODE_STRING_TABLE mDriverNameTable[] = {
1154 { "eng;en", L"LSI Fusion MPT SCSI Driver" },
1155 { NULL, NULL }
1156 };
1157
1158 STATIC
1159 EFI_COMPONENT_NAME_PROTOCOL mComponentName;
1160
1161 EFI_STATUS
1162 EFIAPI
1163 MptScsiGetDriverName (
1164 IN EFI_COMPONENT_NAME_PROTOCOL *This,
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
1178 EFI_STATUS
1179 EFIAPI
1180 MptScsiGetDeviceName (
1181 IN EFI_COMPONENT_NAME_PROTOCOL *This,
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
1191 STATIC
1192 EFI_COMPONENT_NAME_PROTOCOL mComponentName = {
1193 &MptScsiGetDriverName,
1194 &MptScsiGetDeviceName,
1195 "eng" // SupportedLanguages, ISO 639-2 language codes
1196 };
1197
1198 STATIC
1199 EFI_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
1209 EFI_STATUS
1210 EFIAPI
1211 MptScsiEntryPoint (
1212 IN EFI_HANDLE ImageHandle,
1213 IN EFI_SYSTEM_TABLE *SystemTable
1214 )
1215 {
1216 return EfiLibInstallDriverBindingComponentName2 (
1217 ImageHandle,
1218 SystemTable,
1219 &mMptScsiDriverBinding,
1220 ImageHandle, // The handle to install onto
1221 &mComponentName,
1222 &mComponentName2
1223 );
1224 }