TianoCore EDK2 master
Loading...
Searching...
No Matches
LsiScsi.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#include "LsiScsi.h"
27
30Out8 (
31 IN LSI_SCSI_DEV *Dev,
32 IN UINT32 Addr,
33 IN UINT8 Data
34 )
35{
36 return Dev->PciIo->Io.Write (
37 Dev->PciIo,
38 EfiPciIoWidthUint8,
39 PCI_BAR_IDX0,
40 Addr,
41 1,
42 &Data
43 );
44}
45
48Out32 (
49 IN LSI_SCSI_DEV *Dev,
50 IN UINT32 Addr,
51 IN UINT32 Data
52 )
53{
54 return Dev->PciIo->Io.Write (
55 Dev->PciIo,
56 EfiPciIoWidthUint32,
57 PCI_BAR_IDX0,
58 Addr,
59 1,
60 &Data
61 );
62}
63
66In8 (
67 IN LSI_SCSI_DEV *Dev,
68 IN UINT32 Addr,
69 OUT UINT8 *Data
70 )
71{
72 return Dev->PciIo->Io.Read (
73 Dev->PciIo,
74 EfiPciIoWidthUint8,
75 PCI_BAR_IDX0,
76 Addr,
77 1,
78 Data
79 );
80}
81
84In32 (
85 IN LSI_SCSI_DEV *Dev,
86 IN UINT32 Addr,
87 OUT UINT32 *Data
88 )
89{
90 return Dev->PciIo->Io.Read (
91 Dev->PciIo,
92 EfiPciIoWidthUint32,
93 PCI_BAR_IDX0,
94 Addr,
95 1,
96 Data
97 );
98}
99
100STATIC
102LsiScsiReset (
103 IN LSI_SCSI_DEV *Dev
104 )
105{
106 return Out8 (Dev, LSI_REG_ISTAT0, LSI_ISTAT0_SRST);
107}
108
109STATIC
111ReportHostAdapterOverrunError (
113 )
114{
115 Packet->SenseDataLength = 0;
116 Packet->HostAdapterStatus =
117 EFI_EXT_SCSI_STATUS_HOST_ADAPTER_DATA_OVERRUN_UNDERRUN;
118 Packet->TargetStatus = EFI_EXT_SCSI_STATUS_TARGET_GOOD;
119 return EFI_BAD_BUFFER_SIZE;
120}
121
146STATIC
149 IN LSI_SCSI_DEV *Dev,
150 IN UINT8 Target,
151 IN UINT64 Lun,
153 )
154{
155 if ((Target > Dev->MaxTarget) || (Lun > Dev->MaxLun) ||
156 (Packet->DataDirection > EFI_EXT_SCSI_DATA_DIRECTION_BIDIRECTIONAL) ||
157 //
158 // Trying to receive, but destination pointer is NULL, or contradicting
159 // transfer direction
160 //
161 ((Packet->InTransferLength > 0) &&
162 ((Packet->InDataBuffer == NULL) ||
163 (Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_WRITE)
164 )
165 ) ||
166
167 //
168 // Trying to send, but source pointer is NULL, or contradicting transfer
169 // direction
170 //
171 ((Packet->OutTransferLength > 0) &&
172 ((Packet->OutDataBuffer == NULL) ||
173 (Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_READ)
174 )
175 )
176 )
177 {
178 return EFI_INVALID_PARAMETER;
179 }
180
181 if ((Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_BIDIRECTIONAL) ||
182 ((Packet->InTransferLength > 0) && (Packet->OutTransferLength > 0)) ||
183 (Packet->CdbLength > sizeof Dev->Dma->Cdb))
184 {
185 return EFI_UNSUPPORTED;
186 }
187
188 if (Packet->InTransferLength > sizeof Dev->Dma->Data) {
189 Packet->InTransferLength = sizeof Dev->Dma->Data;
190 return ReportHostAdapterOverrunError (Packet);
191 }
192
193 if (Packet->OutTransferLength > sizeof Dev->Dma->Data) {
194 Packet->OutTransferLength = sizeof Dev->Dma->Data;
195 return ReportHostAdapterOverrunError (Packet);
196 }
197
198 return EFI_SUCCESS;
199}
200
224STATIC
227 IN LSI_SCSI_DEV *Dev,
228 IN UINT8 Target,
229 IN UINT64 Lun,
231 )
232{
233 EFI_STATUS Status;
234 UINT32 *Script;
235 UINT8 *Cdb;
236 UINT8 *MsgOut;
237 UINT8 *MsgIn;
238 UINT8 *ScsiStatus;
239 UINT8 *Data;
240 UINT8 DStat;
241 UINT8 SIst0;
242 UINT8 SIst1;
243 UINT32 Csbc;
244 UINT32 CsbcBase;
245 UINT32 Transferred;
246
247 Script = Dev->Dma->Script;
248 Cdb = Dev->Dma->Cdb;
249 Data = Dev->Dma->Data;
250 MsgIn = Dev->Dma->MsgIn;
251 MsgOut = &Dev->Dma->MsgOut;
252 ScsiStatus = &Dev->Dma->Status;
253
254 *ScsiStatus = 0xFF;
255
256 DStat = 0;
257 SIst0 = 0;
258 SIst1 = 0;
259
260 SetMem (Cdb, sizeof Dev->Dma->Cdb, 0x00);
261 CopyMem (Cdb, Packet->Cdb, Packet->CdbLength);
262
263 //
264 // Fetch the first Cumulative SCSI Byte Count (CSBC).
265 //
266 // CSBC is a cumulative counter of the actual number of bytes that have been
267 // transferred across the SCSI bus during data phases, i.e. it will not
268 // count bytes sent in command, status, message in and out phases.
269 //
270 Status = In32 (Dev, LSI_REG_CSBC, &CsbcBase);
271 if (EFI_ERROR (Status)) {
272 goto Error;
273 }
274
275 //
276 // Clean up the DMA buffer for the script.
277 //
278 SetMem (Script, sizeof Dev->Dma->Script, 0x00);
279
280 //
281 // Compose the script to transfer data between the host and the device.
282 //
283 // References:
284 // * LSI53C895A PCI to Ultra2 SCSI Controller Version 2.2
285 // - Chapter 5 SCSI SCRIPT Instruction Set
286 // * SEABIOS lsi-scsi driver
287 //
288 // All instructions used here consist of 2 32bit words. The first word
289 // contains the command to execute. The second word is loaded into the
290 // DMA SCRIPTS Pointer Save (DSPS) register as either the DMA address
291 // for data transmission or the address/offset for the jump command.
292 // Some commands, such as the selection of the target, don't need to
293 // transfer data through DMA or jump to another instruction, then DSPS
294 // has to be zero.
295 //
296 // There are 3 major parts in this script. The first part (1~3) contains
297 // the instructions to select target and LUN and send the SCSI command
298 // from the request packet. The second part (4~7) is to handle the
299 // potential disconnection and prepare for the data transmission. The
300 // instructions in the third part (8~10) transmit the given data and
301 // collect the result. Instruction 11 raises the interrupt and marks the
302 // end of the script.
303 //
304
305 //
306 // 1. Select target.
307 //
308 *Script++ = LSI_INS_TYPE_IO | LSI_INS_IO_OPC_SEL | (UINT32)Target << 16;
309 *Script++ = 0x00000000;
310
311 //
312 // 2. Select LUN.
313 //
314 *MsgOut = 0x80 | (UINT8)Lun; // 0x80: Identify bit
315 *Script++ = LSI_INS_TYPE_BLK | LSI_INS_BLK_SCSIP_MSG_OUT |
316 (UINT32)sizeof Dev->Dma->MsgOut;
317 *Script++ = LSI_SCSI_DMA_ADDR (Dev, MsgOut);
318
319 //
320 // 3. Send the SCSI Command.
321 //
322 *Script++ = LSI_INS_TYPE_BLK | LSI_INS_BLK_SCSIP_CMD |
323 (UINT32)sizeof Dev->Dma->Cdb;
324 *Script++ = LSI_SCSI_DMA_ADDR (Dev, Cdb);
325
326 //
327 // 4. Check whether the current SCSI phase is "Message In" or not
328 // and jump to 7 if it is.
329 // Note: LSI_INS_TC_RA stands for "Relative Address Mode", so the
330 // offset 0x18 in the second word means jumping forward
331 // 3 (0x18/8) instructions.
332 //
333 *Script++ = LSI_INS_TYPE_TC | LSI_INS_TC_OPC_JMP |
334 LSI_INS_TC_SCSIP_MSG_IN | LSI_INS_TC_RA |
335 LSI_INS_TC_CP;
336 *Script++ = 0x00000018;
337
338 //
339 // 5. Read "Message" from the initiator to trigger reselect.
340 //
341 *Script++ = LSI_INS_TYPE_BLK | LSI_INS_BLK_SCSIP_MSG_IN |
342 (UINT32)sizeof Dev->Dma->MsgIn;
343 *Script++ = LSI_SCSI_DMA_ADDR (Dev, MsgIn);
344
345 //
346 // 6. Wait reselect.
347 //
348 *Script++ = LSI_INS_TYPE_IO | LSI_INS_IO_OPC_WAIT_RESEL;
349 *Script++ = 0x00000000;
350
351 //
352 // 7. Read "Message" from the initiator again
353 //
354 *Script++ = LSI_INS_TYPE_BLK | LSI_INS_BLK_SCSIP_MSG_IN |
355 (UINT32)sizeof Dev->Dma->MsgIn;
356 *Script++ = LSI_SCSI_DMA_ADDR (Dev, MsgIn);
357
358 //
359 // 8. Set the DMA command for the read/write operations.
360 // Note: Some requests, e.g. "TEST UNIT READY", do not come with
361 // allocated InDataBuffer or OutDataBuffer. We skip the DMA
362 // data command for those requests or this script would fail
363 // with LSI_SIST0_SGE due to the zero data length.
364 //
365 // LsiScsiCheckRequest() prevents both integer overflows in the command
366 // opcodes, and buffer overflows.
367 //
368 if (Packet->InTransferLength > 0) {
369 ASSERT (Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_READ);
370 ASSERT (Packet->InTransferLength <= sizeof Dev->Dma->Data);
371 *Script++ = LSI_INS_TYPE_BLK | LSI_INS_BLK_SCSIP_DAT_IN |
372 Packet->InTransferLength;
373 *Script++ = LSI_SCSI_DMA_ADDR (Dev, Data);
374 } else if (Packet->OutTransferLength > 0) {
375 ASSERT (Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_WRITE);
376 ASSERT (Packet->OutTransferLength <= sizeof Dev->Dma->Data);
377 CopyMem (Data, Packet->OutDataBuffer, Packet->OutTransferLength);
378 *Script++ = LSI_INS_TYPE_BLK | LSI_INS_BLK_SCSIP_DAT_OUT |
379 Packet->OutTransferLength;
380 *Script++ = LSI_SCSI_DMA_ADDR (Dev, Data);
381 }
382
383 //
384 // 9. Get the SCSI status.
385 //
386 *Script++ = LSI_INS_TYPE_BLK | LSI_INS_BLK_SCSIP_STAT |
387 (UINT32)sizeof Dev->Dma->Status;
388 *Script++ = LSI_SCSI_DMA_ADDR (Dev, Status);
389
390 //
391 // 10. Get the SCSI message.
392 //
393 *Script++ = LSI_INS_TYPE_BLK | LSI_INS_BLK_SCSIP_MSG_IN |
394 (UINT32)sizeof Dev->Dma->MsgIn;
395 *Script++ = LSI_SCSI_DMA_ADDR (Dev, MsgIn);
396
397 //
398 // 11. Raise the interrupt to end the script.
399 //
400 *Script++ = LSI_INS_TYPE_TC | LSI_INS_TC_OPC_INT |
401 LSI_INS_TC_SCSIP_DAT_OUT | LSI_INS_TC_JMP;
402 *Script++ = 0x00000000;
403
404 //
405 // Make sure the size of the script doesn't exceed the buffer.
406 //
407 ASSERT (Script <= Dev->Dma->Script + ARRAY_SIZE (Dev->Dma->Script));
408
409 //
410 // The controller starts to execute the script once the DMA Script
411 // Pointer (DSP) register is set.
412 //
413 Status = Out32 (Dev, LSI_REG_DSP, LSI_SCSI_DMA_ADDR (Dev, Script));
414 if (EFI_ERROR (Status)) {
415 goto Error;
416 }
417
418 //
419 // Poll the device registers (DSTAT, SIST0, and SIST1) until the SIR
420 // bit sets.
421 //
422 for ( ; ;) {
423 Status = In8 (Dev, LSI_REG_DSTAT, &DStat);
424 if (EFI_ERROR (Status)) {
425 goto Error;
426 }
427
428 Status = In8 (Dev, LSI_REG_SIST0, &SIst0);
429 if (EFI_ERROR (Status)) {
430 goto Error;
431 }
432
433 Status = In8 (Dev, LSI_REG_SIST1, &SIst1);
434 if (EFI_ERROR (Status)) {
435 goto Error;
436 }
437
438 if ((SIst0 != 0) || (SIst1 != 0)) {
439 goto Error;
440 }
441
442 //
443 // Check the SIR (SCRIPTS Interrupt Instruction Received) bit.
444 //
445 if (DStat & LSI_DSTAT_SIR) {
446 break;
447 }
448
449 gBS->Stall (Dev->StallPerPollUsec);
450 }
451
452 //
453 // Check if everything is good.
454 // SCSI Message Code 0x00: COMMAND COMPLETE
455 // SCSI Status Code 0x00: Good
456 //
457 if ((MsgIn[0] != 0) || (*ScsiStatus != 0)) {
458 goto Error;
459 }
460
461 //
462 // Fetch CSBC again to calculate the transferred bytes and update
463 // InTransferLength/OutTransferLength.
464 //
465 // Note: The number of transferred bytes is bounded by
466 // "sizeof Dev->Dma->Data", so it's safe to subtract CsbcBase
467 // from Csbc. If the CSBC register wraps around, the correct
468 // difference is ensured by the standard C modular arithmetic.
469 //
470 Status = In32 (Dev, LSI_REG_CSBC, &Csbc);
471 if (EFI_ERROR (Status)) {
472 goto Error;
473 }
474
475 Transferred = Csbc - CsbcBase;
476 if (Packet->InTransferLength > 0) {
477 if (Transferred <= Packet->InTransferLength) {
478 Packet->InTransferLength = Transferred;
479 } else {
480 goto Error;
481 }
482 } else if (Packet->OutTransferLength > 0) {
483 if (Transferred <= Packet->OutTransferLength) {
484 Packet->OutTransferLength = Transferred;
485 } else {
486 goto Error;
487 }
488 }
489
490 //
491 // Copy Data to InDataBuffer if necessary.
492 //
493 if (Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_READ) {
494 CopyMem (Packet->InDataBuffer, Data, Packet->InTransferLength);
495 }
496
497 //
498 // Always set SenseDataLength to 0.
499 // The instructions of LSI53C895A don't reply sense data. Instead, it
500 // relies on the SCSI command, "REQUEST SENSE", to get sense data. We set
501 // SenseDataLength to 0 to notify ScsiDiskDxe that there is no sense data
502 // written even if this request is processed successfully, so that It will
503 // issue "REQUEST SENSE" later to retrieve sense data.
504 //
505 Packet->SenseDataLength = 0;
506 Packet->HostAdapterStatus = EFI_EXT_SCSI_STATUS_HOST_ADAPTER_OK;
507 Packet->TargetStatus = EFI_EXT_SCSI_STATUS_TARGET_GOOD;
508
509 return EFI_SUCCESS;
510
511Error:
512 DEBUG ((
513 DEBUG_VERBOSE,
514 "%a: dstat: %02X, sist0: %02X, sist1: %02X\n",
515 __func__,
516 DStat,
517 SIst0,
518 SIst1
519 ));
520 //
521 // Update the request packet to reflect the status.
522 //
523 if (*ScsiStatus != 0xFF) {
524 Packet->TargetStatus = *ScsiStatus;
525 } else {
526 Packet->TargetStatus = EFI_EXT_SCSI_STATUS_TARGET_TASK_ABORTED;
527 }
528
529 if (SIst0 & LSI_SIST0_PAR) {
530 Packet->HostAdapterStatus = EFI_EXT_SCSI_STATUS_HOST_ADAPTER_PARITY_ERROR;
531 } else if (SIst0 & LSI_SIST0_RST) {
532 Packet->HostAdapterStatus = EFI_EXT_SCSI_STATUS_HOST_ADAPTER_BUS_RESET;
533 } else if (SIst0 & LSI_SIST0_UDC) {
534 //
535 // The target device is disconnected unexpectedly. According to UEFI spec,
536 // this is TIMEOUT_COMMAND.
537 //
538 Packet->HostAdapterStatus = EFI_EXT_SCSI_STATUS_HOST_ADAPTER_TIMEOUT_COMMAND;
539 } else if (SIst0 & LSI_SIST0_SGE) {
540 Packet->HostAdapterStatus = EFI_EXT_SCSI_STATUS_HOST_ADAPTER_DATA_OVERRUN_UNDERRUN;
541 } else if (SIst1 & LSI_SIST1_HTH) {
542 Packet->HostAdapterStatus = EFI_EXT_SCSI_STATUS_HOST_ADAPTER_TIMEOUT;
543 } else if (SIst1 & LSI_SIST1_GEN) {
544 Packet->HostAdapterStatus = EFI_EXT_SCSI_STATUS_HOST_ADAPTER_TIMEOUT;
545 } else if (SIst1 & LSI_SIST1_STO) {
546 Packet->HostAdapterStatus = EFI_EXT_SCSI_STATUS_HOST_ADAPTER_SELECTION_TIMEOUT;
547 } else {
548 Packet->HostAdapterStatus = EFI_EXT_SCSI_STATUS_HOST_ADAPTER_OTHER;
549 }
550
551 //
552 // SenseData may be used to inspect the error. Since we don't set sense data,
553 // SenseDataLength has to be 0.
554 //
555 Packet->SenseDataLength = 0;
556
557 return EFI_DEVICE_ERROR;
558}
559
560//
561// The next seven functions implement EFI_EXT_SCSI_PASS_THRU_PROTOCOL
562// for the LSI 53C895A SCSI Controller. Refer to UEFI Spec 2.3.1 + Errata C,
563// sections
564// - 14.1 SCSI Driver Model Overview,
565// - 14.7 Extended SCSI Pass Thru Protocol.
566//
567
569EFIAPI
570LsiScsiPassThru (
572 IN UINT8 *Target,
573 IN UINT64 Lun,
575 IN EFI_EVENT Event OPTIONAL
576 )
577{
578 EFI_STATUS Status;
579 LSI_SCSI_DEV *Dev;
580
581 Dev = LSI_SCSI_FROM_PASS_THRU (This);
582 Status = LsiScsiCheckRequest (Dev, *Target, Lun, Packet);
583 if (EFI_ERROR (Status)) {
584 return Status;
585 }
586
587 return LsiScsiProcessRequest (Dev, *Target, Lun, Packet);
588}
589
591EFIAPI
592LsiScsiGetNextTargetLun (
594 IN OUT UINT8 **TargetPointer,
595 IN OUT UINT64 *Lun
596 )
597{
598 LSI_SCSI_DEV *Dev;
599 UINTN Idx;
600 UINT8 *Target;
601 UINT16 LastTarget;
602
603 //
604 // the TargetPointer input parameter is unnecessarily a pointer-to-pointer
605 //
606 Target = *TargetPointer;
607
608 //
609 // Search for first non-0xFF byte. If not found, return first target & LUN.
610 //
611 for (Idx = 0; Idx < TARGET_MAX_BYTES && Target[Idx] == 0xFF; ++Idx) {
612 }
613
614 if (Idx == TARGET_MAX_BYTES) {
615 SetMem (Target, TARGET_MAX_BYTES, 0x00);
616 *Lun = 0;
617 return EFI_SUCCESS;
618 }
619
620 CopyMem (&LastTarget, Target, sizeof LastTarget);
621
622 //
623 // increment (target, LUN) pair if valid on input
624 //
625 Dev = LSI_SCSI_FROM_PASS_THRU (This);
626 if ((LastTarget > Dev->MaxTarget) || (*Lun > Dev->MaxLun)) {
627 return EFI_INVALID_PARAMETER;
628 }
629
630 if (*Lun < Dev->MaxLun) {
631 ++*Lun;
632 return EFI_SUCCESS;
633 }
634
635 if (LastTarget < Dev->MaxTarget) {
636 *Lun = 0;
637 ++LastTarget;
638 CopyMem (Target, &LastTarget, sizeof LastTarget);
639 return EFI_SUCCESS;
640 }
641
642 return EFI_NOT_FOUND;
643}
644
646EFIAPI
647LsiScsiBuildDevicePath (
649 IN UINT8 *Target,
650 IN UINT64 Lun,
651 IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath
652 )
653{
654 UINT16 TargetValue;
655 LSI_SCSI_DEV *Dev;
656 SCSI_DEVICE_PATH *ScsiDevicePath;
657
658 if (DevicePath == NULL) {
659 return EFI_INVALID_PARAMETER;
660 }
661
662 CopyMem (&TargetValue, Target, sizeof TargetValue);
663 Dev = LSI_SCSI_FROM_PASS_THRU (This);
664 if ((TargetValue > Dev->MaxTarget) || (Lun > Dev->MaxLun) || (Lun > 0xFFFF)) {
665 return EFI_NOT_FOUND;
666 }
667
668 ScsiDevicePath = AllocatePool (sizeof *ScsiDevicePath);
669 if (ScsiDevicePath == NULL) {
670 return EFI_OUT_OF_RESOURCES;
671 }
672
673 ScsiDevicePath->Header.Type = MESSAGING_DEVICE_PATH;
674 ScsiDevicePath->Header.SubType = MSG_SCSI_DP;
675 ScsiDevicePath->Header.Length[0] = (UINT8)sizeof *ScsiDevicePath;
676 ScsiDevicePath->Header.Length[1] = (UINT8)(sizeof *ScsiDevicePath >> 8);
677 ScsiDevicePath->Pun = TargetValue;
678 ScsiDevicePath->Lun = (UINT16)Lun;
679
680 *DevicePath = &ScsiDevicePath->Header;
681 return EFI_SUCCESS;
682}
683
685EFIAPI
686LsiScsiGetTargetLun (
688 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
689 OUT UINT8 **TargetPointer,
690 OUT UINT64 *Lun
691 )
692{
693 SCSI_DEVICE_PATH *ScsiDevicePath;
694 LSI_SCSI_DEV *Dev;
695 UINT8 *Target;
696
697 if ((DevicePath == NULL) || (TargetPointer == NULL) || (*TargetPointer == NULL) ||
698 (Lun == NULL))
699 {
700 return EFI_INVALID_PARAMETER;
701 }
702
703 if ((DevicePath->Type != MESSAGING_DEVICE_PATH) ||
704 (DevicePath->SubType != MSG_SCSI_DP))
705 {
706 return EFI_UNSUPPORTED;
707 }
708
709 ScsiDevicePath = (SCSI_DEVICE_PATH *)DevicePath;
710 Dev = LSI_SCSI_FROM_PASS_THRU (This);
711 if ((ScsiDevicePath->Pun > Dev->MaxTarget) ||
712 (ScsiDevicePath->Lun > Dev->MaxLun))
713 {
714 return EFI_NOT_FOUND;
715 }
716
717 Target = *TargetPointer;
718 ZeroMem (Target, TARGET_MAX_BYTES);
719 CopyMem (Target, &ScsiDevicePath->Pun, sizeof ScsiDevicePath->Pun);
720 *Lun = ScsiDevicePath->Lun;
721
722 return EFI_SUCCESS;
723}
724
726EFIAPI
727LsiScsiResetChannel (
729 )
730{
731 return EFI_UNSUPPORTED;
732}
733
735EFIAPI
736LsiScsiResetTargetLun (
738 IN UINT8 *Target,
739 IN UINT64 Lun
740 )
741{
742 return EFI_UNSUPPORTED;
743}
744
746EFIAPI
747LsiScsiGetNextTarget (
749 IN OUT UINT8 **TargetPointer
750 )
751{
752 LSI_SCSI_DEV *Dev;
753 UINTN Idx;
754 UINT8 *Target;
755 UINT16 LastTarget;
756
757 //
758 // the TargetPointer input parameter is unnecessarily a pointer-to-pointer
759 //
760 Target = *TargetPointer;
761
762 //
763 // Search for first non-0xFF byte. If not found, return first target.
764 //
765 for (Idx = 0; Idx < TARGET_MAX_BYTES && Target[Idx] == 0xFF; ++Idx) {
766 }
767
768 if (Idx == TARGET_MAX_BYTES) {
769 SetMem (Target, TARGET_MAX_BYTES, 0x00);
770 return EFI_SUCCESS;
771 }
772
773 CopyMem (&LastTarget, Target, sizeof LastTarget);
774
775 //
776 // increment target if valid on input
777 //
778 Dev = LSI_SCSI_FROM_PASS_THRU (This);
779 if (LastTarget > Dev->MaxTarget) {
780 return EFI_INVALID_PARAMETER;
781 }
782
783 if (LastTarget < Dev->MaxTarget) {
784 ++LastTarget;
785 CopyMem (Target, &LastTarget, sizeof LastTarget);
786 return EFI_SUCCESS;
787 }
788
789 return EFI_NOT_FOUND;
790}
791
792STATIC
793VOID
794EFIAPI
795LsiScsiExitBoot (
796 IN EFI_EVENT Event,
797 IN VOID *Context
798 )
799{
800 LSI_SCSI_DEV *Dev;
801
802 Dev = Context;
803 DEBUG ((DEBUG_VERBOSE, "%a: Context=0x%p\n", __func__, Context));
804 LsiScsiReset (Dev);
805}
806
807//
808// Probe, start and stop functions of this driver, called by the DXE core for
809// specific devices.
810//
811// The following specifications document these interfaces:
812// - Driver Writer's Guide for UEFI 2.3.1 v1.01, 9 Driver Binding Protocol
813// - UEFI Spec 2.3.1 + Errata C, 10.1 EFI Driver Binding Protocol
814//
815
817EFIAPI
818LsiScsiControllerSupported (
820 IN EFI_HANDLE ControllerHandle,
821 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
822 )
823{
824 EFI_STATUS Status;
825 EFI_PCI_IO_PROTOCOL *PciIo;
826 PCI_TYPE00 Pci;
827
828 Status = gBS->OpenProtocol (
829 ControllerHandle,
830 &gEfiPciIoProtocolGuid,
831 (VOID **)&PciIo,
832 This->DriverBindingHandle,
833 ControllerHandle,
834 EFI_OPEN_PROTOCOL_BY_DRIVER
835 );
836 if (EFI_ERROR (Status)) {
837 return Status;
838 }
839
840 Status = PciIo->Pci.Read (
841 PciIo,
842 EfiPciIoWidthUint32,
843 0,
844 sizeof (Pci) / sizeof (UINT32),
845 &Pci
846 );
847 if (EFI_ERROR (Status)) {
848 goto Done;
849 }
850
851 if ((Pci.Hdr.VendorId == LSI_LOGIC_PCI_VENDOR_ID) &&
852 (Pci.Hdr.DeviceId == LSI_53C895A_PCI_DEVICE_ID))
853 {
854 Status = EFI_SUCCESS;
855 } else {
856 Status = EFI_UNSUPPORTED;
857 }
858
859Done:
860 gBS->CloseProtocol (
861 ControllerHandle,
862 &gEfiPciIoProtocolGuid,
863 This->DriverBindingHandle,
864 ControllerHandle
865 );
866 return Status;
867}
868
870EFIAPI
871LsiScsiControllerStart (
873 IN EFI_HANDLE ControllerHandle,
874 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
875 )
876{
877 EFI_STATUS Status;
878 LSI_SCSI_DEV *Dev;
879 UINTN Pages;
880 UINTN BytesMapped;
881
882 Dev = AllocateZeroPool (sizeof (*Dev));
883 if (Dev == NULL) {
884 return EFI_OUT_OF_RESOURCES;
885 }
886
887 Dev->Signature = LSI_SCSI_DEV_SIGNATURE;
888
890 FixedPcdGet8 (PcdLsiScsiMaxTargetLimit) < 8,
891 "LSI 53C895A supports targets [0..7]"
892 );
894 FixedPcdGet8 (PcdLsiScsiMaxLunLimit) < 128,
895 "LSI 53C895A supports LUNs [0..127]"
896 );
897 Dev->MaxTarget = PcdGet8 (PcdLsiScsiMaxTargetLimit);
898 Dev->MaxLun = PcdGet8 (PcdLsiScsiMaxLunLimit);
899 Dev->StallPerPollUsec = PcdGet32 (PcdLsiScsiStallPerPollUsec);
900
901 Status = gBS->OpenProtocol (
902 ControllerHandle,
903 &gEfiPciIoProtocolGuid,
904 (VOID **)&Dev->PciIo,
905 This->DriverBindingHandle,
906 ControllerHandle,
907 EFI_OPEN_PROTOCOL_BY_DRIVER
908 );
909 if (EFI_ERROR (Status)) {
910 goto FreePool;
911 }
912
913 Status = Dev->PciIo->Attributes (
914 Dev->PciIo,
916 0,
917 &Dev->OrigPciAttrs
918 );
919 if (EFI_ERROR (Status)) {
920 goto CloseProtocol;
921 }
922
923 //
924 // Enable I/O Space & Bus-Mastering
925 //
926 Status = Dev->PciIo->Attributes (
927 Dev->PciIo,
931 NULL
932 );
933 if (EFI_ERROR (Status)) {
934 goto CloseProtocol;
935 }
936
937 //
938 // Create buffers for data transfer
939 //
940 Pages = EFI_SIZE_TO_PAGES (sizeof (*Dev->Dma));
941 Status = Dev->PciIo->AllocateBuffer (
942 Dev->PciIo,
945 Pages,
946 (VOID **)&Dev->Dma,
947 EFI_PCI_ATTRIBUTE_MEMORY_CACHED
948 );
949 if (EFI_ERROR (Status)) {
950 goto RestoreAttributes;
951 }
952
953 BytesMapped = EFI_PAGES_TO_SIZE (Pages);
954 Status = Dev->PciIo->Map (
955 Dev->PciIo,
957 Dev->Dma,
958 &BytesMapped,
959 &Dev->DmaPhysical,
960 &Dev->DmaMapping
961 );
962 if (EFI_ERROR (Status)) {
963 goto FreeBuffer;
964 }
965
966 if (BytesMapped != EFI_PAGES_TO_SIZE (Pages)) {
967 Status = EFI_OUT_OF_RESOURCES;
968 goto Unmap;
969 }
970
971 Status = LsiScsiReset (Dev);
972 if (EFI_ERROR (Status)) {
973 goto Unmap;
974 }
975
976 Status = gBS->CreateEvent (
977 EVT_SIGNAL_EXIT_BOOT_SERVICES,
978 TPL_CALLBACK,
979 &LsiScsiExitBoot,
980 Dev,
981 &Dev->ExitBoot
982 );
983 if (EFI_ERROR (Status)) {
984 goto UninitDev;
985 }
986
987 //
988 // Host adapter channel, doesn't exist
989 //
990 Dev->PassThruMode.AdapterId = MAX_UINT32;
991 Dev->PassThruMode.Attributes =
992 EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_PHYSICAL |
993 EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL;
994
995 Dev->PassThru.Mode = &Dev->PassThruMode;
996 Dev->PassThru.PassThru = &LsiScsiPassThru;
997 Dev->PassThru.GetNextTargetLun = &LsiScsiGetNextTargetLun;
998 Dev->PassThru.BuildDevicePath = &LsiScsiBuildDevicePath;
999 Dev->PassThru.GetTargetLun = &LsiScsiGetTargetLun;
1000 Dev->PassThru.ResetChannel = &LsiScsiResetChannel;
1001 Dev->PassThru.ResetTargetLun = &LsiScsiResetTargetLun;
1002 Dev->PassThru.GetNextTarget = &LsiScsiGetNextTarget;
1003
1004 Status = gBS->InstallProtocolInterface (
1005 &ControllerHandle,
1006 &gEfiExtScsiPassThruProtocolGuid,
1008 &Dev->PassThru
1009 );
1010 if (EFI_ERROR (Status)) {
1011 goto CloseExitBoot;
1012 }
1013
1014 return EFI_SUCCESS;
1015
1016CloseExitBoot:
1017 gBS->CloseEvent (Dev->ExitBoot);
1018
1019UninitDev:
1020 LsiScsiReset (Dev);
1021
1022Unmap:
1023 Dev->PciIo->Unmap (
1024 Dev->PciIo,
1025 Dev->DmaMapping
1026 );
1027
1028FreeBuffer:
1029 Dev->PciIo->FreeBuffer (
1030 Dev->PciIo,
1031 Pages,
1032 Dev->Dma
1033 );
1034
1035RestoreAttributes:
1036 Dev->PciIo->Attributes (
1037 Dev->PciIo,
1039 Dev->OrigPciAttrs,
1040 NULL
1041 );
1042
1043CloseProtocol:
1044 gBS->CloseProtocol (
1045 ControllerHandle,
1046 &gEfiPciIoProtocolGuid,
1047 This->DriverBindingHandle,
1048 ControllerHandle
1049 );
1050
1051FreePool:
1052 FreePool (Dev);
1053
1054 return Status;
1055}
1056
1058EFIAPI
1059LsiScsiControllerStop (
1061 IN EFI_HANDLE ControllerHandle,
1062 IN UINTN NumberOfChildren,
1063 IN EFI_HANDLE *ChildHandleBuffer
1064 )
1065{
1066 EFI_STATUS Status;
1068 LSI_SCSI_DEV *Dev;
1069
1070 Status = gBS->OpenProtocol (
1071 ControllerHandle,
1072 &gEfiExtScsiPassThruProtocolGuid,
1073 (VOID **)&PassThru,
1074 This->DriverBindingHandle,
1075 ControllerHandle,
1076 EFI_OPEN_PROTOCOL_GET_PROTOCOL // Lookup only
1077 );
1078 if (EFI_ERROR (Status)) {
1079 return Status;
1080 }
1081
1082 Dev = LSI_SCSI_FROM_PASS_THRU (PassThru);
1083
1084 Status = gBS->UninstallProtocolInterface (
1085 ControllerHandle,
1086 &gEfiExtScsiPassThruProtocolGuid,
1087 &Dev->PassThru
1088 );
1089 if (EFI_ERROR (Status)) {
1090 return Status;
1091 }
1092
1093 gBS->CloseEvent (Dev->ExitBoot);
1094
1095 LsiScsiReset (Dev);
1096
1097 Dev->PciIo->Unmap (
1098 Dev->PciIo,
1099 Dev->DmaMapping
1100 );
1101
1102 Dev->PciIo->FreeBuffer (
1103 Dev->PciIo,
1104 EFI_SIZE_TO_PAGES (sizeof (*Dev->Dma)),
1105 Dev->Dma
1106 );
1107
1108 Dev->PciIo->Attributes (
1109 Dev->PciIo,
1111 Dev->OrigPciAttrs,
1112 NULL
1113 );
1114
1115 gBS->CloseProtocol (
1116 ControllerHandle,
1117 &gEfiPciIoProtocolGuid,
1118 This->DriverBindingHandle,
1119 ControllerHandle
1120 );
1121
1122 FreePool (Dev);
1123
1124 return Status;
1125}
1126
1127//
1128// The static object that groups the Supported() (ie. probe), Start() and
1129// Stop() functions of the driver together. Refer to UEFI Spec 2.3.1 + Errata
1130// C, 10.1 EFI Driver Binding Protocol.
1131//
1132STATIC
1133EFI_DRIVER_BINDING_PROTOCOL gDriverBinding = {
1134 &LsiScsiControllerSupported,
1135 &LsiScsiControllerStart,
1136 &LsiScsiControllerStop,
1137 0x10, // Version, must be in [0x10 .. 0xFFFFFFEF] for IHV-developed drivers
1138 NULL, // ImageHandle, to be overwritten by
1139 // EfiLibInstallDriverBindingComponentName2() in LsiScsiEntryPoint()
1140 NULL // DriverBindingHandle, ditto
1141};
1142
1143//
1144// The purpose of the following scaffolding (EFI_COMPONENT_NAME_PROTOCOL and
1145// EFI_COMPONENT_NAME2_PROTOCOL implementation) is to format the driver's name
1146// in English, for display on standard console devices. This is recommended for
1147// UEFI drivers that follow the UEFI Driver Model. Refer to the Driver Writer's
1148// Guide for UEFI 2.3.1 v1.01, 11 UEFI Driver and Controller Names.
1149//
1150// Device type names ("LSI 53C895A SCSI Controller") are not formatted because
1151// the driver supports only that device type. Therefore the driver name
1152// suffices for unambiguous identification.
1153//
1154
1155STATIC
1156EFI_UNICODE_STRING_TABLE mDriverNameTable[] = {
1157 { "eng;en", L"LSI 53C895A SCSI Controller Driver" },
1158 { NULL, NULL }
1159};
1160
1161STATIC
1162EFI_COMPONENT_NAME_PROTOCOL gComponentName;
1163
1165EFIAPI
1166LsiScsiGetDriverName (
1168 IN CHAR8 *Language,
1169 OUT CHAR16 **DriverName
1170 )
1171{
1172 return LookupUnicodeString2 (
1173 Language,
1174 This->SupportedLanguages,
1175 mDriverNameTable,
1176 DriverName,
1177 (BOOLEAN)(This == &gComponentName) // Iso639Language
1178 );
1179}
1180
1182EFIAPI
1183LsiScsiGetDeviceName (
1185 IN EFI_HANDLE DeviceHandle,
1186 IN EFI_HANDLE ChildHandle,
1187 IN CHAR8 *Language,
1188 OUT CHAR16 **ControllerName
1189 )
1190{
1191 return EFI_UNSUPPORTED;
1192}
1193
1194STATIC
1195EFI_COMPONENT_NAME_PROTOCOL gComponentName = {
1196 &LsiScsiGetDriverName,
1197 &LsiScsiGetDeviceName,
1198 "eng" // SupportedLanguages, ISO 639-2 language codes
1199};
1200
1201STATIC
1202EFI_COMPONENT_NAME2_PROTOCOL gComponentName2 = {
1203 (EFI_COMPONENT_NAME2_GET_DRIVER_NAME)&LsiScsiGetDriverName,
1204 (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME)&LsiScsiGetDeviceName,
1205 "en" // SupportedLanguages, RFC 4646 language codes
1206};
1207
1208//
1209// Entry point of this driver
1210//
1212EFIAPI
1213LsiScsiEntryPoint (
1214 IN EFI_HANDLE ImageHandle,
1215 IN EFI_SYSTEM_TABLE *SystemTable
1216 )
1217{
1219 ImageHandle,
1220 SystemTable,
1221 &gDriverBinding,
1222 ImageHandle, // The handle to install onto
1223 &gComponentName,
1224 &gComponentName2
1225 );
1226}
UINT64 UINTN
VOID *EFIAPI CopyMem(OUT VOID *DestinationBuffer, IN CONST VOID *SourceBuffer, IN UINTN Length)
VOID *EFIAPI SetMem(OUT VOID *Buffer, IN UINTN Length, IN UINT8 Value)
Definition: SetMemWrapper.c:38
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)
STATIC EFI_STATUS LsiScsiCheckRequest(IN LSI_SCSI_DEV *Dev, IN UINT8 Target, IN UINT64 Lun, IN OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet)
Definition: LsiScsi.c:148
STATIC EFI_STATUS LsiScsiProcessRequest(IN LSI_SCSI_DEV *Dev, IN UINT8 Target, IN UINT64 Lun, IN OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet)
Definition: LsiScsi.c:226
#define NULL
Definition: Base.h:319
#define STATIC
Definition: Base.h:264
#define STATIC_ASSERT
Definition: Base.h:808
#define ARRAY_SIZE(Array)
Definition: Base.h:1393
#define IN
Definition: Base.h:279
#define OUT
Definition: Base.h:284
#define DEBUG(Expression)
Definition: DebugLib.h:434
@ 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
VOID *EFIAPI AllocatePool(IN UINTN AllocationSize)
#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