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
;
367 ScsiGetDeviceLocation (
368 IN EFI_SCSI_IO_PROTOCOL
*This
,
374 Retrieves the device location in the SCSI channel.
377 This - Protocol instance pointer.
378 Target - A pointer to the Target ID of a SCSI device
380 Lun - A pointer to the LUN of the SCSI device on
384 EFI_SUCCESS - Retrieves the device location successfully.
385 EFI_INVALID_PARAMETER - The Target or Lun is NULL.
388 SCSI_IO_DEV
*ScsiIoDevice
;
390 if (Target
== NULL
|| Lun
== NULL
) {
391 return EFI_INVALID_PARAMETER
;
394 ScsiIoDevice
= SCSI_IO_DEV_FROM_THIS (This
);
396 *Target
= (UINT8
*) (UINTN
) ScsiIoDevice
->Pun
;
397 *Lun
= ScsiIoDevice
->Lun
;
405 IN EFI_SCSI_IO_PROTOCOL
*This
410 Resets the SCSI Bus that the SCSI Controller is attached to.
413 This - Protocol instance pointer.
416 EFI_SUCCESS - The SCSI bus is reset successfully.
417 EFI_DEVICE_ERROR - Errors encountered when resetting the SCSI bus.
418 EFI_UNSUPPORTED - The bus reset operation is not supported by the
419 SCSI Host Controller.
420 EFI_TIMEOUT - A timeout occurred while attempting to reset
424 SCSI_IO_DEV
*ScsiIoDevice
;
426 ScsiIoDevice
= SCSI_IO_DEV_FROM_THIS (This
);
428 return ScsiIoDevice
->ScsiPassThru
->ResetChannel (ScsiIoDevice
->ScsiPassThru
);
435 IN EFI_SCSI_IO_PROTOCOL
*This
440 Resets the SCSI Controller that the device handle specifies.
443 This - Protocol instance pointer.
447 EFI_SUCCESS - Reset the SCSI controller successfully.
448 EFI_DEVICE_ERROR - Errors are encountered when resetting the
450 EFI_UNSUPPORTED - The SCSI bus does not support a device
452 EFI_TIMEOUT - A timeout occurred while attempting to
453 reset the SCSI Controller.
456 SCSI_IO_DEV
*ScsiIoDevice
;
458 ScsiIoDevice
= SCSI_IO_DEV_FROM_THIS (This
);
460 return ScsiIoDevice
->ScsiPassThru
->ResetTarget (
461 ScsiIoDevice
->ScsiPassThru
,
469 ScsiExecuteSCSICommand (
470 IN EFI_SCSI_IO_PROTOCOL
*This
,
471 IN OUT EFI_SCSI_IO_SCSI_REQUEST_PACKET
*Packet
,
472 IN EFI_EVENT Event OPTIONAL
477 Sends a SCSI Request Packet to the SCSI Controller for execution.
480 This - Protocol instance pointer.
481 Packet - The SCSI request packet to send to the SCSI
482 Controller specified by the device handle.
483 Event - If the SCSI bus where the SCSI device is attached
484 does not support non-blocking I/O, then Event is
485 ignored, and blocking I/O is performed.
486 If Event is NULL, then blocking I/O is performed.
487 If Event is not NULL and non-blocking I/O is
488 supported, then non-blocking I/O is performed,
489 and Event will be signaled when the SCSI Request
492 EFI_SUCCESS - The SCSI Request Packet was sent by the host
493 successfully, and TransferLength bytes were
494 transferred to/from DataBuffer.See
495 HostAdapterStatus, TargetStatus,
496 SenseDataLength, and SenseData in that order
497 for additional status information.
498 EFI_WARN_BUFFER_TOO_SMALL - The SCSI Request Packet was executed,
499 but the entire DataBuffer could not be transferred.
500 The actual number of bytes transferred is returned
501 in TransferLength. See HostAdapterStatus,
502 TargetStatus, SenseDataLength, and SenseData in
503 that order for additional status information.
504 EFI_NOT_READY - The SCSI Request Packet could not be sent because
505 there are too many SCSI Command Packets already
506 queued.The caller may retry again later.
507 EFI_DEVICE_ERROR - A device error occurred while attempting to send
508 the SCSI Request Packet. See HostAdapterStatus,
509 TargetStatus, SenseDataLength, and SenseData in
510 that order for additional status information.
511 EFI_INVALID_PARAMETER - The contents of CommandPacket are invalid.
512 The SCSI Request Packet was not sent, so no
513 additional status information is available.
514 EFI_UNSUPPORTED - The command described by the SCSI Request Packet
515 is not supported by the SCSI initiator(i.e., SCSI
516 Host Controller). The SCSI Request Packet was not
517 sent, so no additional status information is
519 EFI_TIMEOUT - A timeout occurred while waiting for the SCSI
520 Request Packet to execute. See HostAdapterStatus,
521 TargetStatus, SenseDataLength, and SenseData in
522 that order for additional status information.
525 SCSI_IO_DEV
*ScsiIoDevice
;
528 EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*RequestPacket
;
530 if (Packet
== NULL
) {
531 return EFI_INVALID_PARAMETER
;
534 ScsiIoDevice
= SCSI_IO_DEV_FROM_THIS (This
);
536 RequestPacket
= (EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*) Packet
;
538 Status
= ScsiIoDevice
->ScsiPassThru
->PassThru (
539 ScsiIoDevice
->ScsiPassThru
,
549 ScsiScanCreateDevice (
550 EFI_DRIVER_BINDING_PROTOCOL
*This
,
551 EFI_HANDLE Controller
,
554 EFI_SCSI_PASS_THRU_PROTOCOL
*ScsiPassThru
,
555 EFI_DEVICE_PATH_PROTOCOL
*ParentDevicePath
561 TODO: Add function description
565 This - TODO: add argument description
566 Controller - TODO: add argument description
567 Pun - TODO: add argument description
568 Lun - TODO: add argument description
569 ScsiPassThru - TODO: add argument description
570 ParentDevicePath - TODO: add argument description
574 EFI_SUCCESS - TODO: Add description for return value
575 EFI_OUT_OF_RESOURCES - TODO: Add description for return value
576 EFI_SUCCESS - TODO: Add description for return value
581 SCSI_IO_DEV
*ScsiIoDevice
;
582 EFI_DEVICE_PATH_PROTOCOL
*ScsiDevicePath
;
584 Status
= gBS
->AllocatePool (
586 sizeof (SCSI_IO_DEV
),
587 (VOID
**) &ScsiIoDevice
589 if (EFI_ERROR (Status
)) {
593 ZeroMem (ScsiIoDevice
, sizeof (SCSI_IO_DEV
));
595 ScsiIoDevice
->Signature
= SCSI_IO_DEV_SIGNATURE
;
596 ScsiIoDevice
->ScsiPassThru
= ScsiPassThru
;
597 ScsiIoDevice
->Pun
= Pun
;
598 ScsiIoDevice
->Lun
= Lun
;
600 ScsiIoDevice
->ScsiIo
.GetDeviceType
= ScsiGetDeviceType
;
601 ScsiIoDevice
->ScsiIo
.GetDeviceLocation
= ScsiGetDeviceLocation
;
602 ScsiIoDevice
->ScsiIo
.ResetBus
= ScsiResetBus
;
603 ScsiIoDevice
->ScsiIo
.ResetDevice
= ScsiResetDevice
;
604 ScsiIoDevice
->ScsiIo
.ExecuteSCSICommand
= ScsiExecuteSCSICommand
;
606 if (!DiscoverScsiDevice (ScsiIoDevice
)) {
607 gBS
->FreePool (ScsiIoDevice
);
614 Status
= ScsiIoDevice
->ScsiPassThru
->BuildDevicePath (
615 ScsiIoDevice
->ScsiPassThru
,
620 if (Status
== EFI_OUT_OF_RESOURCES
) {
621 gBS
->FreePool (ScsiIoDevice
);
625 ScsiIoDevice
->DevicePath
= AppendDevicePathNode (
630 // The memory space for ScsiDevicePath is allocated in
631 // ScsiPassThru->BuildDevicePath() function; It is no longer used
632 // after EfiAppendDevicePathNode,so free the memory it occupies.
634 gBS
->FreePool (ScsiDevicePath
);
636 if (ScsiIoDevice
->DevicePath
== NULL
) {
637 gBS
->FreePool (ScsiIoDevice
);
638 return EFI_OUT_OF_RESOURCES
;
641 Status
= gBS
->InstallMultipleProtocolInterfaces (
642 &ScsiIoDevice
->Handle
,
643 &gEfiDevicePathProtocolGuid
,
644 ScsiIoDevice
->DevicePath
,
645 &gEfiScsiIoProtocolGuid
,
646 &ScsiIoDevice
->ScsiIo
,
649 if (EFI_ERROR (Status
)) {
650 gBS
->FreePool (ScsiIoDevice
);
654 &gEfiScsiPassThruProtocolGuid
,
655 (VOID
**) &ScsiPassThru
,
656 This
->DriverBindingHandle
,
657 ScsiIoDevice
->Handle
,
658 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
667 SCSI_IO_DEV
*ScsiIoDevice
673 TODO: Add function description
677 ScsiIoDevice - TODO: add argument description
681 TODO: add return values
686 EFI_SCSI_INQUIRY_DATA InquiryData
;
687 UINT32 InquiryDataLength
;
688 EFI_SCSI_SENSE_DATA SenseData
;
689 UINT8 SenseDataLength
;
690 UINT8 HostAdapterStatus
;
693 HostAdapterStatus
= 0;
696 // Using Inquiry command to scan for the device
698 InquiryDataLength
= sizeof (EFI_SCSI_INQUIRY_DATA
);
699 SenseDataLength
= sizeof (EFI_SCSI_SENSE_DATA
);
701 Status
= SubmitInquiryCommand (
702 &ScsiIoDevice
->ScsiIo
,
703 EfiScsiStallSeconds (1),
708 (VOID
*) &InquiryData
,
712 if (EFI_ERROR (Status
)) {
714 // ParseSenseData (&SenseData,SenseDataLength);
719 // Retrieved inquiry data successfully
721 if ((InquiryData
.Peripheral_Qualifier
!= 0) &&
722 (InquiryData
.Peripheral_Qualifier
!= 3)) {
726 if (InquiryData
.Peripheral_Qualifier
== 3) {
727 if (InquiryData
.Peripheral_Type
!= 0x1f) {
732 if ((0x1e >= InquiryData
.Peripheral_Type
) && (InquiryData
.Peripheral_Type
>= 0xa)) {
737 // valid device type and peripheral qualifier combination.
739 ScsiIoDevice
->ScsiDeviceType
= InquiryData
.Peripheral_Type
;
740 ScsiIoDevice
->RemovableDevice
= InquiryData
.RMB
;
741 if (InquiryData
.Version
== 0) {
742 ScsiIoDevice
->ScsiVersion
= 0;
745 // ANSI-approved version
747 ScsiIoDevice
->ScsiVersion
= (UINT8
) (InquiryData
.Version
& 0x03);