3 Copyright (c) 2006, Intel Corporation
4 All rights reserved. This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
26 SCSIBusDriverBindingSupported (
27 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
28 IN EFI_HANDLE Controller
,
29 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
34 SCSIBusDriverBindingStart (
35 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
36 IN EFI_HANDLE Controller
,
37 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
42 SCSIBusDriverBindingStop (
43 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
44 IN EFI_HANDLE Controller
,
45 IN UINTN NumberOfChildren
,
46 IN EFI_HANDLE
*ChildHandleBuffer
49 EFI_DRIVER_BINDING_PROTOCOL gSCSIBusDriverBinding
= {
50 SCSIBusDriverBindingSupported
,
51 SCSIBusDriverBindingStart
,
52 SCSIBusDriverBindingStop
,
60 SCSIBusDriverBindingSupported (
61 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
62 IN EFI_HANDLE Controller
,
63 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
74 // TODO: This - add argument and description to function comment
75 // TODO: Controller - add argument and description to function comment
76 // TODO: RemainingDevicePath - add argument and description to function comment
77 // TODO: EFI_UNSUPPORTED - add return value to function comment
78 // TODO: EFI_UNSUPPORTED - add return value to function comment
79 // TODO: EFI_SUCCESS - add return value to function comment
84 // If RemainingDevicePath is not NULL, it should verify that the first device
85 // path node in RemainingDevicePath is an ATAPI Device path node.
87 if (RemainingDevicePath
!= NULL
) {
88 if ((RemainingDevicePath
->Type
!= MESSAGING_DEVICE_PATH
) ||
89 (RemainingDevicePath
->SubType
!= MSG_ATAPI_DP
) ||
90 (DevicePathNodeLength (RemainingDevicePath
) != sizeof(ATAPI_DEVICE_PATH
))) {
91 return EFI_UNSUPPORTED
;
95 // check for the existence of SCSI Pass Thru Protocol
97 Status
= gBS
->OpenProtocol (
99 &gEfiScsiPassThruProtocolGuid
,
101 This
->DriverBindingHandle
,
103 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
105 if (EFI_ERROR (Status
) && (Status
!= EFI_ALREADY_STARTED
)) {
106 return EFI_UNSUPPORTED
;
114 SCSIBusDriverBindingStart (
115 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
116 IN EFI_HANDLE Controller
,
117 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
128 // TODO: This - add argument and description to function comment
129 // TODO: Controller - add argument and description to function comment
130 // TODO: RemainingDevicePath - add argument and description to function comment
133 EFI_DEVICE_PATH_PROTOCOL
*ParentDevicePath
;
134 EFI_SCSI_PASS_THRU_PROTOCOL
*ScsiPassThru
;
139 BOOLEAN ScanOtherPuns
;
143 Status
= gBS
->OpenProtocol (
145 &gEfiDevicePathProtocolGuid
,
146 (VOID
**) &ParentDevicePath
,
147 This
->DriverBindingHandle
,
149 EFI_OPEN_PROTOCOL_BY_DRIVER
151 if (EFI_ERROR (Status
) && Status
!= EFI_ALREADY_STARTED
) {
156 // Consume SCSI Pass Thru protocol.
158 Status
= gBS
->OpenProtocol (
160 &gEfiScsiPassThruProtocolGuid
,
161 (VOID
**) &ScsiPassThru
,
162 This
->DriverBindingHandle
,
164 EFI_OPEN_PROTOCOL_BY_DRIVER
166 if (EFI_ERROR (Status
) && Status
!= EFI_ALREADY_STARTED
) {
169 &gEfiDevicePathProtocolGuid
,
170 This
->DriverBindingHandle
,
176 if (RemainingDevicePath
== NULL
) {
177 StartPun
= 0xFFFFFFFF;
180 ScsiPassThru
->GetTargetLun (ScsiPassThru
, RemainingDevicePath
, &StartPun
, &StartLun
);
183 for (Pun
= StartPun
, ScanOtherPuns
= TRUE
; ScanOtherPuns
;) {
185 if (StartPun
== 0xFFFFFFFF) {
187 // Remaining Device Path is NULL, scan all the possible Puns in the
190 Status
= ScsiPassThru
->GetNextDevice (ScsiPassThru
, &Pun
, &Lun
);
191 if (EFI_ERROR (Status
)) {
193 // no legal Pun and Lun found any more
199 // Remaining Device Path is not NULL, only scan the specified Pun.
203 ScanOtherPuns
= FALSE
;
207 // Avoid creating handle for the host adapter.
209 if (Pun
== ScsiPassThru
->Mode
->AdapterId
) {
214 // Scan for the scsi device, if it attaches to the scsi bus,
215 // then create handle and install scsi i/o protocol.
217 Status
= ScsiScanCreateDevice (This
, Controller
, Pun
, Lun
, ScsiPassThru
, ParentDevicePath
);
225 SCSIBusDriverBindingStop (
226 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
227 IN EFI_HANDLE Controller
,
228 IN UINTN NumberOfChildren
,
229 IN EFI_HANDLE
*ChildHandleBuffer
240 // TODO: This - add argument and description to function comment
241 // TODO: Controller - add argument and description to function comment
242 // TODO: NumberOfChildren - add argument and description to function comment
243 // TODO: ChildHandleBuffer - add argument and description to function comment
244 // TODO: EFI_SUCCESS - add return value to function comment
245 // TODO: EFI_DEVICE_ERROR - add return value to function comment
246 // TODO: EFI_SUCCESS - add return value to function comment
249 BOOLEAN AllChildrenStopped
;
251 EFI_SCSI_IO_PROTOCOL
*ScsiIo
;
252 SCSI_IO_DEV
*ScsiIoDevice
;
253 EFI_SCSI_PASS_THRU_PROTOCOL
*ScsiPassThru
;
255 if (NumberOfChildren
== 0) {
257 // Close the bus driver
261 &gEfiScsiPassThruProtocolGuid
,
262 This
->DriverBindingHandle
,
267 &gEfiDevicePathProtocolGuid
,
268 This
->DriverBindingHandle
,
275 AllChildrenStopped
= TRUE
;
277 for (Index
= 0; Index
< NumberOfChildren
; Index
++) {
279 Status
= gBS
->OpenProtocol (
280 ChildHandleBuffer
[Index
],
281 &gEfiScsiIoProtocolGuid
,
283 This
->DriverBindingHandle
,
285 EFI_OPEN_PROTOCOL_GET_PROTOCOL
287 if (EFI_ERROR (Status
)) {
288 AllChildrenStopped
= FALSE
;
292 ScsiIoDevice
= SCSI_IO_DEV_FROM_THIS (ScsiIo
);
294 // Close the child handle
296 Status
= gBS
->CloseProtocol (
298 &gEfiScsiPassThruProtocolGuid
,
299 This
->DriverBindingHandle
,
300 ChildHandleBuffer
[Index
]
303 Status
= gBS
->UninstallMultipleProtocolInterfaces (
304 ChildHandleBuffer
[Index
],
305 &gEfiDevicePathProtocolGuid
,
306 ScsiIoDevice
->DevicePath
,
307 &gEfiScsiIoProtocolGuid
,
308 &ScsiIoDevice
->ScsiIo
,
311 if (EFI_ERROR (Status
)) {
312 AllChildrenStopped
= FALSE
;
315 &gEfiScsiPassThruProtocolGuid
,
316 (VOID
**) &ScsiPassThru
,
317 This
->DriverBindingHandle
,
318 ChildHandleBuffer
[Index
],
319 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
322 gBS
->FreePool (ScsiIoDevice
);
326 if (!AllChildrenStopped
) {
327 return EFI_DEVICE_ERROR
;
336 IN EFI_SCSI_IO_PROTOCOL
*This
,
337 OUT UINT8
*DeviceType
342 Retrieves the device type information of the SCSI Controller.
345 This - Protocol instance pointer.
346 DeviceType - A pointer to the device type information
347 retrieved from the SCSI Controller.
350 EFI_SUCCESS - Retrieves the device type information successfully.
351 EFI_INVALID_PARAMETER - The DeviceType is NULL.
354 SCSI_IO_DEV
*ScsiIoDevice
;
356 if (DeviceType
== NULL
) {
357 return EFI_INVALID_PARAMETER
;
360 ScsiIoDevice
= SCSI_IO_DEV_FROM_THIS (This
);
361 *DeviceType
= ScsiIoDevice
->ScsiDeviceType
;
368 ScsiGetDeviceLocation (
369 IN EFI_SCSI_IO_PROTOCOL
*This
,
375 Retrieves the device location in the SCSI channel.
378 This - Protocol instance pointer.
379 Target - A pointer to the Target ID of a SCSI device
381 Lun - A pointer to the LUN of the SCSI device on
385 EFI_SUCCESS - Retrieves the device location successfully.
386 EFI_INVALID_PARAMETER - The Target or Lun is NULL.
389 SCSI_IO_DEV
*ScsiIoDevice
;
391 if (Target
== NULL
|| Lun
== NULL
) {
392 return EFI_INVALID_PARAMETER
;
395 ScsiIoDevice
= SCSI_IO_DEV_FROM_THIS (This
);
397 *Target
= ScsiIoDevice
->Pun
;
398 *Lun
= ScsiIoDevice
->Lun
;
406 IN EFI_SCSI_IO_PROTOCOL
*This
411 Resets the SCSI Bus that the SCSI Controller is attached to.
414 This - Protocol instance pointer.
417 EFI_SUCCESS - The SCSI bus is reset successfully.
418 EFI_DEVICE_ERROR - Errors encountered when resetting the SCSI bus.
419 EFI_UNSUPPORTED - The bus reset operation is not supported by the
420 SCSI Host Controller.
421 EFI_TIMEOUT - A timeout occurred while attempting to reset
425 SCSI_IO_DEV
*ScsiIoDevice
;
427 ScsiIoDevice
= SCSI_IO_DEV_FROM_THIS (This
);
429 return ScsiIoDevice
->ScsiPassThru
->ResetChannel (ScsiIoDevice
->ScsiPassThru
);
436 IN EFI_SCSI_IO_PROTOCOL
*This
441 Resets the SCSI Controller that the device handle specifies.
444 This - Protocol instance pointer.
448 EFI_SUCCESS - Reset the SCSI controller successfully.
449 EFI_DEVICE_ERROR - Errors are encountered when resetting the
451 EFI_UNSUPPORTED - The SCSI bus does not support a device
453 EFI_TIMEOUT - A timeout occurred while attempting to
454 reset the SCSI Controller.
457 SCSI_IO_DEV
*ScsiIoDevice
;
459 ScsiIoDevice
= SCSI_IO_DEV_FROM_THIS (This
);
461 return ScsiIoDevice
->ScsiPassThru
->ResetTarget (
462 ScsiIoDevice
->ScsiPassThru
,
470 ScsiExecuteSCSICommand (
471 IN EFI_SCSI_IO_PROTOCOL
*This
,
472 IN OUT EFI_SCSI_IO_SCSI_REQUEST_PACKET
*Packet
,
473 IN EFI_EVENT Event OPTIONAL
478 Sends a SCSI Request Packet to the SCSI Controller for execution.
481 This - Protocol instance pointer.
482 Packet - The SCSI request packet to send to the SCSI
483 Controller specified by the device handle.
484 Event - If the SCSI bus where the SCSI device is attached
485 does not support non-blocking I/O, then Event is
486 ignored, and blocking I/O is performed.
487 If Event is NULL, then blocking I/O is performed.
488 If Event is not NULL and non-blocking I/O is
489 supported, then non-blocking I/O is performed,
490 and Event will be signaled when the SCSI Request
493 EFI_SUCCESS - The SCSI Request Packet was sent by the host
494 successfully, and TransferLength bytes were
495 transferred to/from DataBuffer.See
496 HostAdapterStatus, TargetStatus,
497 SenseDataLength, and SenseData in that order
498 for additional status information.
499 EFI_WARN_BUFFER_TOO_SMALL - The SCSI Request Packet was executed,
500 but the entire DataBuffer could not be transferred.
501 The actual number of bytes transferred is returned
502 in TransferLength. See HostAdapterStatus,
503 TargetStatus, SenseDataLength, and SenseData in
504 that order for additional status information.
505 EFI_NOT_READY - The SCSI Request Packet could not be sent because
506 there are too many SCSI Command Packets already
507 queued.The caller may retry again later.
508 EFI_DEVICE_ERROR - A device error occurred while attempting to send
509 the SCSI Request Packet. See HostAdapterStatus,
510 TargetStatus, SenseDataLength, and SenseData in
511 that order for additional status information.
512 EFI_INVALID_PARAMETER - The contents of CommandPacket are invalid.
513 The SCSI Request Packet was not sent, so no
514 additional status information is available.
515 EFI_UNSUPPORTED - The command described by the SCSI Request Packet
516 is not supported by the SCSI initiator(i.e., SCSI
517 Host Controller). The SCSI Request Packet was not
518 sent, so no additional status information is
520 EFI_TIMEOUT - A timeout occurred while waiting for the SCSI
521 Request Packet to execute. See HostAdapterStatus,
522 TargetStatus, SenseDataLength, and SenseData in
523 that order for additional status information.
526 SCSI_IO_DEV
*ScsiIoDevice
;
529 EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*RequestPacket
;
531 if (Packet
== NULL
) {
532 return EFI_INVALID_PARAMETER
;
535 ScsiIoDevice
= SCSI_IO_DEV_FROM_THIS (This
);
537 RequestPacket
= (EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*) Packet
;
539 Status
= ScsiIoDevice
->ScsiPassThru
->PassThru (
540 ScsiIoDevice
->ScsiPassThru
,
550 ScsiScanCreateDevice (
551 EFI_DRIVER_BINDING_PROTOCOL
*This
,
552 EFI_HANDLE Controller
,
555 EFI_SCSI_PASS_THRU_PROTOCOL
*ScsiPassThru
,
556 EFI_DEVICE_PATH_PROTOCOL
*ParentDevicePath
562 TODO: Add function description
566 This - TODO: add argument description
567 Controller - TODO: add argument description
568 Pun - TODO: add argument description
569 Lun - TODO: add argument description
570 ScsiPassThru - TODO: add argument description
571 ParentDevicePath - TODO: add argument description
575 EFI_SUCCESS - TODO: Add description for return value
576 EFI_OUT_OF_RESOURCES - TODO: Add description for return value
577 EFI_SUCCESS - TODO: Add description for return value
582 SCSI_IO_DEV
*ScsiIoDevice
;
583 EFI_DEVICE_PATH_PROTOCOL
*ScsiDevicePath
;
585 Status
= gBS
->AllocatePool (
587 sizeof (SCSI_IO_DEV
),
588 (VOID
**) &ScsiIoDevice
590 if (EFI_ERROR (Status
)) {
594 ZeroMem (ScsiIoDevice
, sizeof (SCSI_IO_DEV
));
596 ScsiIoDevice
->Signature
= SCSI_IO_DEV_SIGNATURE
;
597 ScsiIoDevice
->ScsiPassThru
= ScsiPassThru
;
598 ScsiIoDevice
->Pun
= Pun
;
599 ScsiIoDevice
->Lun
= Lun
;
601 ScsiIoDevice
->ScsiIo
.GetDeviceType
= ScsiGetDeviceType
;
602 ScsiIoDevice
->ScsiIo
.GetDeviceLocation
= ScsiGetDeviceLocation
;
603 ScsiIoDevice
->ScsiIo
.ResetBus
= ScsiResetBus
;
604 ScsiIoDevice
->ScsiIo
.ResetDevice
= ScsiResetDevice
;
605 ScsiIoDevice
->ScsiIo
.ExecuteSCSICommand
= ScsiExecuteSCSICommand
;
607 if (!DiscoverScsiDevice (ScsiIoDevice
)) {
608 gBS
->FreePool (ScsiIoDevice
);
615 Status
= ScsiIoDevice
->ScsiPassThru
->BuildDevicePath (
616 ScsiIoDevice
->ScsiPassThru
,
621 if (Status
== EFI_OUT_OF_RESOURCES
) {
622 gBS
->FreePool (ScsiIoDevice
);
626 ScsiIoDevice
->DevicePath
= AppendDevicePathNode (
631 // The memory space for ScsiDevicePath is allocated in
632 // ScsiPassThru->BuildDevicePath() function; It is no longer used
633 // after EfiAppendDevicePathNode,so free the memory it occupies.
635 gBS
->FreePool (ScsiDevicePath
);
637 if (ScsiIoDevice
->DevicePath
== NULL
) {
638 gBS
->FreePool (ScsiIoDevice
);
639 return EFI_OUT_OF_RESOURCES
;
642 Status
= gBS
->InstallMultipleProtocolInterfaces (
643 &ScsiIoDevice
->Handle
,
644 &gEfiDevicePathProtocolGuid
,
645 ScsiIoDevice
->DevicePath
,
646 &gEfiScsiIoProtocolGuid
,
647 &ScsiIoDevice
->ScsiIo
,
650 if (EFI_ERROR (Status
)) {
651 gBS
->FreePool (ScsiIoDevice
);
655 &gEfiScsiPassThruProtocolGuid
,
656 (VOID
**) &ScsiPassThru
,
657 This
->DriverBindingHandle
,
658 ScsiIoDevice
->Handle
,
659 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
668 SCSI_IO_DEV
*ScsiIoDevice
674 TODO: Add function description
678 ScsiIoDevice - TODO: add argument description
682 TODO: add return values
687 EFI_SCSI_INQUIRY_DATA InquiryData
;
688 UINT32 InquiryDataLength
;
689 EFI_SCSI_SENSE_DATA SenseData
;
690 UINT8 SenseDataLength
;
691 UINT8 HostAdapterStatus
;
694 HostAdapterStatus
= 0;
697 // Using Inquiry command to scan for the device
699 InquiryDataLength
= sizeof (EFI_SCSI_INQUIRY_DATA
);
700 SenseDataLength
= sizeof (EFI_SCSI_SENSE_DATA
);
702 Status
= SubmitInquiryCommand (
703 &ScsiIoDevice
->ScsiIo
,
704 EfiScsiStallSeconds (1),
709 (VOID
*) &InquiryData
,
713 if (EFI_ERROR (Status
)) {
715 // ParseSenseData (&SenseData,SenseDataLength);
720 // Retrieved inquiry data successfully
722 if ((InquiryData
.Peripheral_Qualifier
!= 0) &&
723 (InquiryData
.Peripheral_Qualifier
!= 3)) {
727 if (InquiryData
.Peripheral_Qualifier
== 3) {
728 if (InquiryData
.Peripheral_Type
!= 0x1f) {
733 if ((0x1e >= InquiryData
.Peripheral_Type
) && (InquiryData
.Peripheral_Type
>= 0xa)) {
738 // valid device type and peripheral qualifier combination.
740 ScsiIoDevice
->ScsiDeviceType
= InquiryData
.Peripheral_Type
;
741 ScsiIoDevice
->RemovableDevice
= InquiryData
.RMB
;
742 if (InquiryData
.Version
== 0) {
743 ScsiIoDevice
->ScsiVersion
= 0;
746 // ANSI-approved version
748 ScsiIoDevice
->ScsiVersion
= (UINT8
) (InquiryData
.Version
& 0x03);