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