3 Copyright (c) 2006, Intel Corporation
\r
4 All rights reserved. This program and the accompanying materials
\r
5 are licensed and made available under the terms and conditions of the BSD License
\r
6 which accompanies this distribution. The full text of the license may be found at
\r
7 http://opensource.org/licenses/bsd-license.php
\r
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
\r
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
\r
23 // The package level header files this module uses
\r
28 // The protocols, PPI and GUID defintions for this module
\r
30 #include <Protocol/ScsiPassThru.h>
\r
31 #include <Protocol/ScsiPassThruExt.h>
\r
32 #include <Protocol/ScsiIo.h>
\r
33 #include <Protocol/ComponentName.h>
\r
34 #include <Protocol/DriverBinding.h>
\r
35 #include <Protocol/DevicePath.h>
\r
37 // The Library classes this module consumes
\r
39 #include <Library/DebugLib.h>
\r
40 #include <Library/UefiDriverEntryPoint.h>
\r
41 #include <Library/UefiLib.h>
\r
42 #include <Library/BaseMemoryLib.h>
\r
43 #include <Library/MemoryAllocationLib.h>
\r
44 #include <Library/ScsiLib.h>
\r
45 #include <Library/UefiBootServicesTableLib.h>
\r
46 #include <Library/DevicePathLib.h>
\r
48 #include "ScsiBus.h"
\r
50 EFI_DRIVER_BINDING_PROTOCOL gSCSIBusDriverBinding = {
\r
51 SCSIBusDriverBindingSupported,
\r
52 SCSIBusDriverBindingStart,
\r
53 SCSIBusDriverBindingStop,
\r
61 // The ScsiBusProtocol is just used to locate ScsiBusDev
\r
62 // structure in the SCSIBusDriverBindingStop(). Then we can
\r
63 // Close all opened protocols and release this structure.
\r
65 STATIC EFI_GUID mScsiBusProtocolGuid = EFI_SCSI_BUS_PROTOCOL_GUID;
\r
67 STATIC VOID *WorkingBuffer;
\r
72 ScsiioToPassThruPacket (
\r
73 IN EFI_SCSI_IO_SCSI_REQUEST_PACKET *Packet,
\r
74 IN OUT EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *CommandPacket
\r
82 PassThruToScsiioPacket (
\r
83 IN EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *ScsiPacket,
\r
84 IN OUT EFI_SCSI_IO_SCSI_REQUEST_PACKET *Packet
\r
97 The user Entry Point for module ScsiBus. The user code starts with this function.
\r
99 @param[in] ImageHandle The firmware allocated handle for the EFI image.
\r
100 @param[in] SystemTable A pointer to the EFI System Table.
\r
102 @retval EFI_SUCCESS The entry point is executed successfully.
\r
103 @retval other Some error occurs when executing this entry point.
\r
109 IN EFI_HANDLE ImageHandle,
\r
110 IN EFI_SYSTEM_TABLE *SystemTable
\r
116 // Install driver model protocol(s).
\r
118 Status = EfiLibInstallAllDriverProtocols (
\r
121 &gSCSIBusDriverBinding,
\r
123 &gScsiBusComponentName,
\r
127 ASSERT_EFI_ERROR (Status);
\r
135 SCSIBusDriverBindingSupported (
\r
136 IN EFI_DRIVER_BINDING_PROTOCOL *This,
\r
137 IN EFI_HANDLE Controller,
\r
138 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
\r
142 Routine Description:
\r
144 Test to see if this driver supports ControllerHandle. Any ControllerHandle
\r
145 that has ExtScsiPassThruProtocol/ScsiPassThruProtocol installed will be supported.
\r
149 This - Protocol instance pointer.
\r
150 Controller - Handle of device to test
\r
151 RemainingDevicePath - Not used
\r
155 EFI_SUCCESS - This driver supports this device.
\r
156 EFI_UNSUPPORTED - This driver does not support this device.
\r
162 EFI_SCSI_PASS_THRU_PROTOCOL *PassThru;
\r
163 EFI_EXT_SCSI_PASS_THRU_PROTOCOL *ExtPassThru;
\r
165 // Check for the existence of Extended SCSI Pass Thru Protocol and SCSI Pass Thru Protocol
\r
167 Status = gBS->OpenProtocol (
\r
169 &gEfiExtScsiPassThruProtocolGuid,
\r
170 (VOID **)&ExtPassThru,
\r
171 This->DriverBindingHandle,
\r
173 EFI_OPEN_PROTOCOL_BY_DRIVER
\r
176 if (Status == EFI_ALREADY_STARTED) {
\r
177 return EFI_SUCCESS;
\r
180 if (EFI_ERROR (Status)) {
\r
181 Status = gBS->OpenProtocol (
\r
183 &gEfiScsiPassThruProtocolGuid,
\r
184 (VOID **)&PassThru,
\r
185 This->DriverBindingHandle,
\r
187 EFI_OPEN_PROTOCOL_BY_DRIVER
\r
190 if (Status == EFI_ALREADY_STARTED) {
\r
191 return EFI_SUCCESS;
\r
194 if (EFI_ERROR (Status)) {
\r
198 gBS->CloseProtocol (
\r
200 &gEfiScsiPassThruProtocolGuid,
\r
201 This->DriverBindingHandle,
\r
204 return EFI_SUCCESS;
\r
207 gBS->CloseProtocol (
\r
209 &gEfiExtScsiPassThruProtocolGuid,
\r
210 This->DriverBindingHandle,
\r
214 return EFI_SUCCESS;
\r
219 SCSIBusDriverBindingStart (
\r
220 IN EFI_DRIVER_BINDING_PROTOCOL *This,
\r
221 IN EFI_HANDLE Controller,
\r
222 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
\r
226 Routine Description:
\r
227 Starting the SCSI Bus Driver
\r
230 This - Protocol instance pointer.
\r
231 Controller - Handle of device to test
\r
232 RemainingDevicePath - Not used
\r
235 EFI_SUCCESS - This driver supports this device.
\r
236 EFI_UNSUPPORTED - This driver does not support this device.
\r
237 EFI_DEVICE_ERROR - This driver cannot be started due to device Error
\r
240 // TODO: This - add argument and description to function comment
\r
241 // TODO: Controller - add argument and description to function comment
\r
242 // TODO: RemainingDevicePath - add argument and description to function comment
\r
246 BOOLEAN ScanOtherPuns;
\r
247 SCSI_BUS_DEVICE *ScsiBusDev;
\r
248 BOOLEAN FromFirstTarget;
\r
249 SCSI_TARGET_ID *ScsiTargetId;
\r
253 ScanOtherPuns = TRUE;
\r
254 FromFirstTarget = FALSE;
\r
256 // Allocate SCSI_BUS_DEVICE structure
\r
259 ScsiBusDev = AllocateZeroPool (sizeof (SCSI_BUS_DEVICE));
\r
260 if (ScsiBusDev == NULL) {
\r
261 return EFI_OUT_OF_RESOURCES;
\r
264 ScsiTargetId = NULL;
\r
265 ScsiTargetId = AllocateZeroPool (sizeof (SCSI_TARGET_ID));
\r
266 if (ScsiTargetId == NULL) {
\r
267 return EFI_OUT_OF_RESOURCES;
\r
270 TargetId = &ScsiTargetId->ScsiId.ExtScsi[0];
\r
272 Status = gBS->OpenProtocol (
\r
274 &gEfiDevicePathProtocolGuid,
\r
275 (VOID **) &(ScsiBusDev->DevicePath),
\r
276 This->DriverBindingHandle,
\r
278 EFI_OPEN_PROTOCOL_BY_DRIVER
\r
280 if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {
\r
281 gBS->FreePool (ScsiBusDev);
\r
286 // First consume Extended SCSI Pass Thru protocol, if fail, then consume
\r
287 // SCSI Pass Thru protocol
\r
289 Status = gBS->OpenProtocol (
\r
291 &gEfiExtScsiPassThruProtocolGuid,
\r
292 (VOID **) &(ScsiBusDev->ExtScsiInterface),
\r
293 This->DriverBindingHandle,
\r
295 EFI_OPEN_PROTOCOL_BY_DRIVER
\r
297 if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {
\r
298 Status = gBS->OpenProtocol (
\r
300 &gEfiScsiPassThruProtocolGuid,
\r
301 (VOID **) &(ScsiBusDev->ScsiInterface),
\r
302 This->DriverBindingHandle,
\r
304 EFI_OPEN_PROTOCOL_BY_DRIVER
\r
306 if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {
\r
307 gBS->CloseProtocol (
\r
309 &gEfiDevicePathProtocolGuid,
\r
310 This->DriverBindingHandle,
\r
313 gBS->FreePool (ScsiBusDev);
\r
316 DEBUG ((EFI_D_INFO, "Open Scsi Pass Thrugh Protocol\n"));
\r
317 ScsiBusDev->ExtScsiSupport = FALSE;
\r
319 DEBUG ((EFI_D_INFO, "Open Extended Scsi Pass Thrugh Protocol\n"));
\r
320 ScsiBusDev->ExtScsiSupport = TRUE;
\r
323 ScsiBusDev->Signature = SCSI_BUS_DEVICE_SIGNATURE;
\r
325 // Attach EFI_SCSI_BUS_PROTOCOL to controller handle
\r
327 Status = gBS->InstallProtocolInterface (
\r
329 &mScsiBusProtocolGuid,
\r
330 EFI_NATIVE_INTERFACE,
\r
331 &ScsiBusDev->BusIdentify
\r
334 if (EFI_ERROR (Status)) {
\r
335 gBS->CloseProtocol (
\r
337 &gEfiDevicePathProtocolGuid,
\r
338 This->DriverBindingHandle,
\r
341 if (ScsiBusDev->ExtScsiSupport) {
\r
342 gBS->CloseProtocol (
\r
344 &gEfiExtScsiPassThruProtocolGuid,
\r
345 This->DriverBindingHandle,
\r
349 gBS->CloseProtocol (
\r
351 &gEfiScsiPassThruProtocolGuid,
\r
352 This->DriverBindingHandle,
\r
356 gBS->FreePool (ScsiBusDev);
\r
360 if (RemainingDevicePath == NULL) {
\r
361 SetMem (ScsiTargetId, TARGET_MAX_BYTES,0xFF);
\r
363 FromFirstTarget = TRUE;
\r
365 if (ScsiBusDev->ExtScsiSupport) {
\r
366 ScsiBusDev->ExtScsiInterface->GetTargetLun (ScsiBusDev->ExtScsiInterface, RemainingDevicePath, &TargetId, &Lun);
\r
368 ScsiBusDev->ScsiInterface->GetTargetLun (ScsiBusDev->ScsiInterface, RemainingDevicePath, &ScsiTargetId->ScsiId.Scsi, &Lun);
\r
372 while(ScanOtherPuns) {
\r
373 if (FromFirstTarget) {
\r
375 // Remaining Device Path is NULL, scan all the possible Puns in the
\r
378 if (ScsiBusDev->ExtScsiSupport) {
\r
379 Status = ScsiBusDev->ExtScsiInterface->GetNextTargetLun (ScsiBusDev->ExtScsiInterface, &TargetId, &Lun);
\r
381 Status = ScsiBusDev->ScsiInterface->GetNextDevice (ScsiBusDev->ScsiInterface, &ScsiTargetId->ScsiId.Scsi, &Lun);
\r
383 if (EFI_ERROR (Status)) {
\r
385 // no legal Pun and Lun found any more
\r
390 ScanOtherPuns = FALSE;
\r
393 // Avoid creating handle for the host adapter.
\r
395 if (ScsiBusDev->ExtScsiSupport) {
\r
396 if ((ScsiTargetId->ScsiId.Scsi) == ScsiBusDev->ExtScsiInterface->Mode->AdapterId) {
\r
400 if ((ScsiTargetId->ScsiId.Scsi) == ScsiBusDev->ScsiInterface->Mode->AdapterId) {
\r
405 // Scan for the scsi device, if it attaches to the scsi bus,
\r
406 // then create handle and install scsi i/o protocol.
\r
408 Status = ScsiScanCreateDevice (This, Controller, ScsiTargetId, Lun, ScsiBusDev);
\r
415 SCSIBusDriverBindingStop (
\r
416 IN EFI_DRIVER_BINDING_PROTOCOL *This,
\r
417 IN EFI_HANDLE Controller,
\r
418 IN UINTN NumberOfChildren,
\r
419 IN EFI_HANDLE *ChildHandleBuffer
\r
423 Routine Description:
\r
430 // TODO: This - add argument and description to function comment
\r
431 // TODO: Controller - add argument and description to function comment
\r
432 // TODO: NumberOfChildren - add argument and description to function comment
\r
433 // TODO: ChildHandleBuffer - add argument and description to function comment
\r
434 // TODO: EFI_SUCCESS - add return value to function comment
\r
435 // TODO: EFI_DEVICE_ERROR - add return value to function comment
\r
436 // TODO: EFI_SUCCESS - add return value to function comment
\r
439 BOOLEAN AllChildrenStopped;
\r
441 EFI_SCSI_IO_PROTOCOL *ScsiIo;
\r
442 SCSI_IO_DEV *ScsiIoDevice;
\r
443 VOID *ScsiPassThru;
\r
444 EFI_SCSI_BUS_PROTOCOL *Scsidentifier;
\r
445 SCSI_BUS_DEVICE *ScsiBusDev;
\r
447 if (NumberOfChildren == 0) {
\r
449 // Get the SCSI_BUS_DEVICE
\r
451 Status = gBS->OpenProtocol (
\r
453 &mScsiBusProtocolGuid,
\r
454 (VOID **) &Scsidentifier,
\r
455 This->DriverBindingHandle,
\r
457 EFI_OPEN_PROTOCOL_GET_PROTOCOL
\r
460 if (EFI_ERROR (Status)) {
\r
461 return EFI_DEVICE_ERROR;
\r
464 ScsiBusDev = SCSI_BUS_CONTROLLER_DEVICE_FROM_THIS (Scsidentifier);
\r
467 // Uninstall SCSI Bus Protocol
\r
469 gBS->UninstallProtocolInterface (
\r
471 &mScsiBusProtocolGuid,
\r
472 &ScsiBusDev->BusIdentify
\r
476 // Close the bus driver
\r
478 if (ScsiBusDev->ExtScsiSupport) {
\r
479 gBS->CloseProtocol (
\r
481 &gEfiExtScsiPassThruProtocolGuid,
\r
482 This->DriverBindingHandle,
\r
486 gBS->CloseProtocol (
\r
488 &gEfiScsiPassThruProtocolGuid,
\r
489 This->DriverBindingHandle,
\r
494 gBS->CloseProtocol (
\r
496 &gEfiDevicePathProtocolGuid,
\r
497 This->DriverBindingHandle,
\r
500 gBS->FreePool (ScsiBusDev);
\r
501 return EFI_SUCCESS;
\r
504 AllChildrenStopped = TRUE;
\r
506 for (Index = 0; Index < NumberOfChildren; Index++) {
\r
508 Status = gBS->OpenProtocol (
\r
509 ChildHandleBuffer[Index],
\r
510 &gEfiScsiIoProtocolGuid,
\r
512 This->DriverBindingHandle,
\r
514 EFI_OPEN_PROTOCOL_GET_PROTOCOL
\r
516 if (EFI_ERROR (Status)) {
\r
517 AllChildrenStopped = FALSE;
\r
521 ScsiIoDevice = SCSI_IO_DEV_FROM_THIS (ScsiIo);
\r
523 // Close the child handle
\r
525 if (ScsiIoDevice->ExtScsiSupport) {
\r
526 Status = gBS->CloseProtocol (
\r
528 &gEfiExtScsiPassThruProtocolGuid,
\r
529 This->DriverBindingHandle,
\r
530 ChildHandleBuffer[Index]
\r
534 Status = gBS->CloseProtocol (
\r
536 &gEfiScsiPassThruProtocolGuid,
\r
537 This->DriverBindingHandle,
\r
538 ChildHandleBuffer[Index]
\r
542 Status = gBS->UninstallMultipleProtocolInterfaces (
\r
543 ChildHandleBuffer[Index],
\r
544 &gEfiDevicePathProtocolGuid,
\r
545 ScsiIoDevice->DevicePath,
\r
546 &gEfiScsiIoProtocolGuid,
\r
547 &ScsiIoDevice->ScsiIo,
\r
550 if (EFI_ERROR (Status)) {
\r
551 AllChildrenStopped = FALSE;
\r
552 if (ScsiIoDevice->ExtScsiSupport) {
\r
553 gBS->OpenProtocol (
\r
555 &gEfiExtScsiPassThruProtocolGuid,
\r
556 (VOID **) &(EFI_EXT_SCSI_PASS_THRU_PROTOCOL*)ScsiPassThru,
\r
557 This->DriverBindingHandle,
\r
558 ChildHandleBuffer[Index],
\r
559 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
\r
562 gBS->OpenProtocol (
\r
564 &gEfiScsiPassThruProtocolGuid,
\r
565 (VOID **) &(EFI_SCSI_PASS_THRU_PROTOCOL*)ScsiPassThru,
\r
566 This->DriverBindingHandle,
\r
567 ChildHandleBuffer[Index],
\r
568 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
\r
572 gBS->FreePool (ScsiIoDevice);
\r
576 if (!AllChildrenStopped) {
\r
577 return EFI_DEVICE_ERROR;
\r
580 return EFI_SUCCESS;
\r
585 ScsiGetDeviceType (
\r
586 IN EFI_SCSI_IO_PROTOCOL *This,
\r
587 OUT UINT8 *DeviceType
\r
591 Routine Description:
\r
592 Retrieves the device type information of the SCSI Controller.
\r
595 This - Protocol instance pointer.
\r
596 DeviceType - A pointer to the device type information
\r
597 retrieved from the SCSI Controller.
\r
600 EFI_SUCCESS - Retrieves the device type information successfully.
\r
601 EFI_INVALID_PARAMETER - The DeviceType is NULL.
\r
604 SCSI_IO_DEV *ScsiIoDevice;
\r
606 if (DeviceType == NULL) {
\r
607 return EFI_INVALID_PARAMETER;
\r
610 ScsiIoDevice = SCSI_IO_DEV_FROM_THIS (This);
\r
611 *DeviceType = ScsiIoDevice->ScsiDeviceType;
\r
612 return EFI_SUCCESS;
\r
617 ScsiGetDeviceLocation (
\r
618 IN EFI_SCSI_IO_PROTOCOL *This,
\r
619 IN OUT UINT8 **Target,
\r
623 Routine Description:
\r
624 Retrieves the device location in the SCSI channel.
\r
627 This - Protocol instance pointer.
\r
628 Target - A pointer to the Target ID of a SCSI device
\r
629 on the SCSI channel.
\r
630 Lun - A pointer to the LUN of the SCSI device on
\r
634 EFI_SUCCESS - Retrieves the device location successfully.
\r
635 EFI_INVALID_PARAMETER - The Target or Lun is NULL.
\r
638 SCSI_IO_DEV *ScsiIoDevice;
\r
640 if (Target == NULL || Lun == NULL) {
\r
641 return EFI_INVALID_PARAMETER;
\r
644 ScsiIoDevice = SCSI_IO_DEV_FROM_THIS (This);
\r
646 CopyMem (*Target,&ScsiIoDevice->Pun, TARGET_MAX_BYTES);
\r
648 *Lun = ScsiIoDevice->Lun;
\r
650 return EFI_SUCCESS;
\r
656 IN EFI_SCSI_IO_PROTOCOL *This
\r
660 Routine Description:
\r
661 Resets the SCSI Bus that the SCSI Controller is attached to.
\r
664 This - Protocol instance pointer.
\r
667 EFI_SUCCESS - The SCSI bus is reset successfully.
\r
668 EFI_DEVICE_ERROR - Errors encountered when resetting the SCSI bus.
\r
669 EFI_UNSUPPORTED - The bus reset operation is not supported by the
\r
670 SCSI Host Controller.
\r
671 EFI_TIMEOUT - A timeout occurred while attempting to reset
\r
675 SCSI_IO_DEV *ScsiIoDevice;
\r
677 ScsiIoDevice = SCSI_IO_DEV_FROM_THIS (This);
\r
679 if (ScsiIoDevice->ExtScsiSupport){
\r
680 return ScsiIoDevice->ExtScsiPassThru->ResetChannel (ScsiIoDevice->ExtScsiPassThru);
\r
682 return ScsiIoDevice->ScsiPassThru->ResetChannel (ScsiIoDevice->ScsiPassThru);
\r
689 IN EFI_SCSI_IO_PROTOCOL *This
\r
693 Routine Description:
\r
694 Resets the SCSI Controller that the device handle specifies.
\r
697 This - Protocol instance pointer.
\r
701 EFI_SUCCESS - Reset the SCSI controller successfully.
\r
702 EFI_DEVICE_ERROR - Errors are encountered when resetting the
\r
704 EFI_UNSUPPORTED - The SCSI bus does not support a device
\r
706 EFI_TIMEOUT - A timeout occurred while attempting to
\r
707 reset the SCSI Controller.
\r
710 SCSI_IO_DEV *ScsiIoDevice;
\r
711 UINT8 Target[TARGET_MAX_BYTES];
\r
713 ScsiIoDevice = SCSI_IO_DEV_FROM_THIS (This);
\r
714 CopyMem (Target,&ScsiIoDevice->Pun, TARGET_MAX_BYTES);
\r
717 if (ScsiIoDevice->ExtScsiSupport) {
\r
718 return ScsiIoDevice->ExtScsiPassThru->ResetTargetLun (
\r
719 ScsiIoDevice->ExtScsiPassThru,
\r
724 return ScsiIoDevice->ScsiPassThru->ResetTarget (
\r
725 ScsiIoDevice->ScsiPassThru,
\r
726 ScsiIoDevice->Pun.ScsiId.Scsi,
\r
734 ScsiExecuteSCSICommand (
\r
735 IN EFI_SCSI_IO_PROTOCOL *This,
\r
736 IN OUT EFI_SCSI_IO_SCSI_REQUEST_PACKET *Packet,
\r
737 IN EFI_EVENT Event OPTIONAL
\r
741 Routine Description:
\r
742 Sends a SCSI Request Packet to the SCSI Controller for execution.
\r
745 This - Protocol instance pointer.
\r
746 Packet - The SCSI request packet to send to the SCSI
\r
747 Controller specified by the device handle.
\r
748 Event - If the SCSI bus where the SCSI device is attached
\r
749 does not support non-blocking I/O, then Event is
\r
750 ignored, and blocking I/O is performed.
\r
751 If Event is NULL, then blocking I/O is performed.
\r
752 If Event is not NULL and non-blocking I/O is
\r
753 supported, then non-blocking I/O is performed,
\r
754 and Event will be signaled when the SCSI Request
\r
757 EFI_SUCCESS - The SCSI Request Packet was sent by the host
\r
758 successfully, and TransferLength bytes were
\r
759 transferred to/from DataBuffer.See
\r
760 HostAdapterStatus, TargetStatus,
\r
761 SenseDataLength, and SenseData in that order
\r
762 for additional status information.
\r
763 EFI_WARN_BUFFER_TOO_SMALL - The SCSI Request Packet was executed,
\r
764 but the entire DataBuffer could not be transferred.
\r
765 The actual number of bytes transferred is returned
\r
766 in TransferLength. See HostAdapterStatus,
\r
767 TargetStatus, SenseDataLength, and SenseData in
\r
768 that order for additional status information.
\r
769 EFI_NOT_READY - The SCSI Request Packet could not be sent because
\r
770 there are too many SCSI Command Packets already
\r
771 queued.The caller may retry again later.
\r
772 EFI_DEVICE_ERROR - A device error occurred while attempting to send
\r
773 the SCSI Request Packet. See HostAdapterStatus,
\r
774 TargetStatus, SenseDataLength, and SenseData in
\r
775 that order for additional status information.
\r
776 EFI_INVALID_PARAMETER - The contents of CommandPacket are invalid.
\r
777 The SCSI Request Packet was not sent, so no
\r
778 additional status information is available.
\r
779 EFI_UNSUPPORTED - The command described by the SCSI Request Packet
\r
780 is not supported by the SCSI initiator(i.e., SCSI
\r
781 Host Controller). The SCSI Request Packet was not
\r
782 sent, so no additional status information is
\r
784 EFI_TIMEOUT - A timeout occurred while waiting for the SCSI
\r
785 Request Packet to execute. See HostAdapterStatus,
\r
786 TargetStatus, SenseDataLength, and SenseData in
\r
787 that order for additional status information.
\r
790 SCSI_IO_DEV *ScsiIoDevice;
\r
792 UINT8 Target[TARGET_MAX_BYTES];
\r
793 EFI_EVENT PacketEvent;
\r
794 EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *ExtRequestPacket;
\r
795 SCSI_EVENT_DATA EventData;
\r
797 PacketEvent = NULL;
\r
799 if (Packet == NULL) {
\r
800 return EFI_INVALID_PARAMETER;
\r
803 ScsiIoDevice = SCSI_IO_DEV_FROM_THIS (This);
\r
804 CopyMem (Target,&ScsiIoDevice->Pun, TARGET_MAX_BYTES);
\r
806 if (ScsiIoDevice->ExtScsiSupport) {
\r
807 ExtRequestPacket = (EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *) Packet;
\r
808 Status = ScsiIoDevice->ExtScsiPassThru->PassThru (
\r
809 ScsiIoDevice->ExtScsiPassThru,
\r
817 Status = gBS->AllocatePool (
\r
818 EfiBootServicesData,
\r
819 sizeof(EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET),
\r
820 (VOID**)&WorkingBuffer
\r
823 if (EFI_ERROR (Status)) {
\r
824 return EFI_DEVICE_ERROR;
\r
828 // Convert package into EFI1.0, EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET.
\r
830 Status = ScsiioToPassThruPacket(Packet, (EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET*)WorkingBuffer);
\r
831 if (EFI_ERROR(Status)) {
\r
832 gBS->FreePool(WorkingBuffer);
\r
836 if ((ScsiIoDevice->ScsiPassThru->Mode->Attributes & EFI_SCSI_PASS_THRU_ATTRIBUTES_NONBLOCKIO) && (Event != NULL)) {
\r
837 EventData.Data1 = (VOID*)Packet;
\r
838 EventData.Data2 = Event;
\r
842 Status = gBS->CreateEvent (
\r
849 if (EFI_ERROR(Status)) {
\r
850 gBS->FreePool(WorkingBuffer);
\r
854 Status = ScsiIoDevice->ScsiPassThru->PassThru (
\r
855 ScsiIoDevice->ScsiPassThru,
\r
856 ScsiIoDevice->Pun.ScsiId.Scsi,
\r
862 if (EFI_ERROR(Status)) {
\r
863 gBS->FreePool(WorkingBuffer);
\r
864 gBS->CloseEvent(PacketEvent);
\r
870 // If there's no event or SCSI Device doesn't support NON-BLOCKING, just convert
\r
871 // EFI1.0 PassThru packet back to UEFI2.0 SCSI IO Packet.
\r
873 Status = ScsiIoDevice->ScsiPassThru->PassThru (
\r
874 ScsiIoDevice->ScsiPassThru,
\r
875 ScsiIoDevice->Pun.ScsiId.Scsi,
\r
880 if (EFI_ERROR(Status)) {
\r
881 gBS->FreePool(WorkingBuffer);
\r
885 PassThruToScsiioPacket((EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET*)WorkingBuffer,Packet);
\r
887 // After converting EFI1.0 PassThru Packet back to UEFI2.0 SCSI IO Packet,
\r
888 // free WorkingBuffer.
\r
890 gBS->FreePool(WorkingBuffer);
\r
898 ScsiScanCreateDevice (
\r
899 EFI_DRIVER_BINDING_PROTOCOL *This,
\r
900 EFI_HANDLE Controller,
\r
901 SCSI_TARGET_ID *TargetId,
\r
903 SCSI_BUS_DEVICE *ScsiBusDev
\r
907 Routine Description:
\r
909 Scan SCSI Bus to discover the device, and attach ScsiIoProtocol to it.
\r
913 This - Protocol instance pointer
\r
914 Controller - Controller handle
\r
915 Pun - The Pun of the SCSI device on the SCSI channel.
\r
916 Lun - The Lun of the SCSI device on the SCSI channel.
\r
917 ScsiBusDev - The pointer of SCSI_BUS_DEVICE
\r
921 EFI_SUCCESS - Successfully to discover the device and attach ScsiIoProtocol to it.
\r
922 EFI_OUT_OF_RESOURCES - Fail to discover the device.
\r
927 SCSI_IO_DEV *ScsiIoDevice;
\r
928 EFI_DEVICE_PATH_PROTOCOL *ScsiDevicePath;
\r
930 Status = gBS->AllocatePool (
\r
931 EfiBootServicesData,
\r
932 sizeof (SCSI_IO_DEV),
\r
933 (VOID **) &ScsiIoDevice
\r
935 if (EFI_ERROR (Status)) {
\r
939 ZeroMem (ScsiIoDevice, sizeof (SCSI_IO_DEV));
\r
941 ScsiIoDevice->Signature = SCSI_IO_DEV_SIGNATURE;
\r
942 CopyMem(&ScsiIoDevice->Pun, TargetId, TARGET_MAX_BYTES);
\r
943 ScsiIoDevice->Lun = Lun;
\r
945 if (ScsiBusDev->ExtScsiSupport) {
\r
946 ScsiIoDevice->ExtScsiPassThru = ScsiBusDev->ExtScsiInterface;
\r
947 ScsiIoDevice->ExtScsiSupport = TRUE;
\r
948 ScsiIoDevice->ScsiIo.IoAlign = ScsiIoDevice->ExtScsiPassThru->Mode->IoAlign;
\r
951 ScsiIoDevice->ScsiPassThru = ScsiBusDev->ScsiInterface;
\r
952 ScsiIoDevice->ExtScsiSupport = FALSE;
\r
953 ScsiIoDevice->ScsiIo.IoAlign = ScsiIoDevice->ScsiPassThru->Mode->IoAlign;
\r
956 ScsiIoDevice->ScsiIo.GetDeviceType = ScsiGetDeviceType;
\r
957 ScsiIoDevice->ScsiIo.GetDeviceLocation = ScsiGetDeviceLocation;
\r
958 ScsiIoDevice->ScsiIo.ResetBus = ScsiResetBus;
\r
959 ScsiIoDevice->ScsiIo.ResetDevice = ScsiResetDevice;
\r
960 ScsiIoDevice->ScsiIo.ExecuteScsiCommand = ScsiExecuteSCSICommand;
\r
963 if (!DiscoverScsiDevice (ScsiIoDevice)) {
\r
964 gBS->FreePool (ScsiIoDevice);
\r
965 return EFI_OUT_OF_RESOURCES;
\r
971 if (ScsiIoDevice->ExtScsiSupport){
\r
972 Status = ScsiIoDevice->ExtScsiPassThru->BuildDevicePath (
\r
973 ScsiIoDevice->ExtScsiPassThru,
\r
974 &ScsiIoDevice->Pun.ScsiId.ExtScsi[0],
\r
978 if (Status == EFI_OUT_OF_RESOURCES) {
\r
979 gBS->FreePool (ScsiIoDevice);
\r
983 Status = ScsiIoDevice->ScsiPassThru->BuildDevicePath (
\r
984 ScsiIoDevice->ScsiPassThru,
\r
985 ScsiIoDevice->Pun.ScsiId.Scsi,
\r
989 if (Status == EFI_OUT_OF_RESOURCES) {
\r
990 gBS->FreePool (ScsiIoDevice);
\r
995 ScsiIoDevice->DevicePath = AppendDevicePathNode (
\r
996 ScsiBusDev->DevicePath,
\r
1000 // The memory space for ScsiDevicePath is allocated in
\r
1001 // ScsiPassThru->BuildDevicePath() function; It is no longer used
\r
1002 // after EfiAppendDevicePathNode,so free the memory it occupies.
\r
1004 gBS->FreePool (ScsiDevicePath);
\r
1006 if (ScsiIoDevice->DevicePath == NULL) {
\r
1007 gBS->FreePool (ScsiIoDevice);
\r
1008 return EFI_OUT_OF_RESOURCES;
\r
1011 Status = gBS->InstallMultipleProtocolInterfaces (
\r
1012 &ScsiIoDevice->Handle,
\r
1013 &gEfiDevicePathProtocolGuid,
\r
1014 ScsiIoDevice->DevicePath,
\r
1015 &gEfiScsiIoProtocolGuid,
\r
1016 &ScsiIoDevice->ScsiIo,
\r
1019 if (EFI_ERROR (Status)) {
\r
1020 gBS->FreePool (ScsiIoDevice);
\r
1021 return EFI_OUT_OF_RESOURCES;
\r
1023 if (ScsiBusDev->ExtScsiSupport) {
\r
1024 gBS->OpenProtocol (
\r
1026 &gEfiExtScsiPassThruProtocolGuid,
\r
1027 (VOID **) &(ScsiBusDev->ExtScsiInterface),
\r
1028 This->DriverBindingHandle,
\r
1029 ScsiIoDevice->Handle,
\r
1030 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
\r
1033 gBS->OpenProtocol (
\r
1035 &gEfiScsiPassThruProtocolGuid,
\r
1036 (VOID **) &(ScsiBusDev->ScsiInterface),
\r
1037 This->DriverBindingHandle,
\r
1038 ScsiIoDevice->Handle,
\r
1039 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
\r
1043 return EFI_SUCCESS;
\r
1048 DiscoverScsiDevice (
\r
1049 SCSI_IO_DEV *ScsiIoDevice
\r
1053 Routine Description:
\r
1055 Discovery SCSI Device
\r
1059 ScsiIoDevice - The pointer of SCSI_IO_DEV
\r
1063 TRUE - Find SCSI Device and verify it.
\r
1064 FALSE - Unable to find SCSI Device.
\r
1068 EFI_STATUS Status;
\r
1069 UINT32 InquiryDataLength;
\r
1070 UINT8 SenseDataLength;
\r
1071 UINT8 HostAdapterStatus;
\r
1072 UINT8 TargetStatus;
\r
1073 EFI_SCSI_SENSE_DATA SenseData;
\r
1074 EFI_SCSI_INQUIRY_DATA InquiryData;
\r
1076 HostAdapterStatus = 0;
\r
1079 // Using Inquiry command to scan for the device
\r
1081 InquiryDataLength = sizeof (EFI_SCSI_INQUIRY_DATA);
\r
1082 SenseDataLength = sizeof (EFI_SCSI_SENSE_DATA);
\r
1084 Status = SubmitInquiryCommand (
\r
1085 &ScsiIoDevice->ScsiIo,
\r
1086 EfiScsiStallSeconds (1),
\r
1087 (VOID *) &SenseData,
\r
1089 &HostAdapterStatus,
\r
1091 (VOID *) &InquiryData,
\r
1092 &InquiryDataLength,
\r
1095 if (EFI_ERROR (Status)) {
\r
1097 // ParseSenseData (&SenseData,SenseDataLength);
\r
1102 // Retrieved inquiry data successfully
\r
1104 if ((InquiryData.Peripheral_Qualifier != 0) &&
\r
1105 (InquiryData.Peripheral_Qualifier != 3)) {
\r
1109 if (InquiryData.Peripheral_Qualifier == 3) {
\r
1110 if (InquiryData.Peripheral_Type != 0x1f) {
\r
1115 if (0x1e >= InquiryData.Peripheral_Type >= 0xa) {
\r
1120 // valid device type and peripheral qualifier combination.
\r
1122 ScsiIoDevice->ScsiDeviceType = InquiryData.Peripheral_Type;
\r
1123 ScsiIoDevice->RemovableDevice = InquiryData.RMB;
\r
1124 if (InquiryData.Version == 0) {
\r
1125 ScsiIoDevice->ScsiVersion = 0;
\r
1128 // ANSI-approved version
\r
1130 ScsiIoDevice->ScsiVersion = (UINT8) (InquiryData.Version & 0x03);
\r
1140 ScsiioToPassThruPacket (
\r
1141 IN EFI_SCSI_IO_SCSI_REQUEST_PACKET *Packet,
\r
1142 IN OUT EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *CommandPacket
\r
1146 Routine Description:
\r
1148 Convert EFI_SCSI_IO_SCSI_REQUEST_PACKET packet to
\r
1149 EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET packet
\r
1153 Packet - The pointer of EFI_SCSI_IO_SCSI_REQUEST_PACKET
\r
1154 CommandPacket - The pointer of EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
\r
1163 //EFI 1.10 doesn't support Bi-Direction Command.
\r
1165 if (Packet->DataDirection == EFI_SCSI_IO_DATA_DIRECTION_BIDIRECTIONAL) {
\r
1166 return EFI_UNSUPPORTED;
\r
1169 ZeroMem (CommandPacket, sizeof (EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET));
\r
1171 CommandPacket->Timeout = Packet->Timeout;
\r
1172 CommandPacket->Cdb = Packet->Cdb;
\r
1173 CommandPacket->CdbLength = Packet->CdbLength;
\r
1174 CommandPacket->DataDirection = Packet->DataDirection;
\r
1175 CommandPacket->HostAdapterStatus = Packet->HostAdapterStatus;
\r
1176 CommandPacket->TargetStatus = Packet->TargetStatus;
\r
1177 CommandPacket->SenseData = Packet->SenseData;
\r
1178 CommandPacket->SenseDataLength = Packet->SenseDataLength;
\r
1180 if (Packet->DataDirection == EFI_SCSI_IO_DATA_DIRECTION_READ) {
\r
1181 CommandPacket->DataBuffer = Packet->InDataBuffer;
\r
1182 CommandPacket->TransferLength = Packet->InTransferLength;
\r
1183 } else if (Packet->DataDirection == EFI_SCSI_IO_DATA_DIRECTION_WRITE) {
\r
1184 CommandPacket->DataBuffer = Packet->OutDataBuffer;
\r
1185 CommandPacket->TransferLength = Packet->OutTransferLength;
\r
1187 return EFI_SUCCESS;
\r
1194 PassThruToScsiioPacket (
\r
1195 IN EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *ScsiPacket,
\r
1196 IN OUT EFI_SCSI_IO_SCSI_REQUEST_PACKET *Packet
\r
1200 Routine Description:
\r
1202 Convert EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET packet to
\r
1203 EFI_SCSI_IO_SCSI_REQUEST_PACKET packet
\r
1207 ScsiPacket - The pointer of EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
\r
1208 Packet - The pointer of EFI_SCSI_IO_SCSI_REQUEST_PACKET
\r
1216 Packet->Timeout = ScsiPacket->Timeout;
\r
1217 Packet->Cdb = ScsiPacket->Cdb;
\r
1218 Packet->CdbLength = ScsiPacket->CdbLength;
\r
1219 Packet->DataDirection = ScsiPacket->DataDirection;
\r
1220 Packet->HostAdapterStatus = ScsiPacket->HostAdapterStatus;
\r
1221 Packet->TargetStatus = ScsiPacket->TargetStatus;
\r
1222 Packet->SenseData = ScsiPacket->SenseData;
\r
1223 Packet->SenseDataLength = ScsiPacket->SenseDataLength;
\r
1225 if (ScsiPacket->DataDirection == EFI_SCSI_IO_DATA_DIRECTION_READ) {
\r
1226 Packet->InDataBuffer = ScsiPacket->DataBuffer;
\r
1227 Packet->InTransferLength = ScsiPacket->TransferLength;
\r
1228 } else if (Packet->DataDirection == EFI_SCSI_IO_DATA_DIRECTION_WRITE) {
\r
1229 Packet->OutDataBuffer = ScsiPacket->DataBuffer;
\r
1230 Packet->OutTransferLength = ScsiPacket->TransferLength;
\r
1233 return EFI_SUCCESS;
\r
1247 Routine Description:
\r
1249 Notify Function in which convert EFI1.0 PassThru Packet back to UEF2.0
\r
1254 Event - The instance of EFI_EVENT.
\r
1255 Context - The parameter passed in.
\r
1263 EFI_SCSI_IO_SCSI_REQUEST_PACKET *Packet;
\r
1264 EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *ScsiPacket;
\r
1265 EFI_EVENT CallerEvent;
\r
1266 SCSI_EVENT_DATA *PassData;
\r
1268 PassData = (SCSI_EVENT_DATA*)Context;
\r
1269 Packet = (EFI_SCSI_IO_SCSI_REQUEST_PACKET *)PassData->Data1;
\r
1270 ScsiPacket = (EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET*)WorkingBuffer;
\r
1273 // Convert EFI1.0 PassThru packet to UEFI2.0 SCSI IO Packet.
\r
1275 PassThruToScsiioPacket(ScsiPacket, Packet);
\r
1278 // After converting EFI1.0 PassThru Packet back to UEFI2.0 SCSI IO Packet,
\r
1279 // free WorkingBuffer.
\r
1281 gBS->FreePool(WorkingBuffer);
\r
1284 // Signal Event to tell caller to pick up UEFI2.0 SCSI IO Packet.
\r
1286 CallerEvent = PassData->Data2;
\r
1287 gBS->CloseEvent(Event);
\r
1288 gBS->SignalEvent(CallerEvent);
\r