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.
24 EFI_DRIVER_BINDING_PROTOCOL gSCSIBusDriverBinding
= {
25 SCSIBusDriverBindingSupported
,
26 SCSIBusDriverBindingStart
,
27 SCSIBusDriverBindingStop
,
35 SCSIBusDriverBindingSupported (
36 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
37 IN EFI_HANDLE Controller
,
38 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
49 // TODO: This - add argument and description to function comment
50 // TODO: Controller - add argument and description to function comment
51 // TODO: RemainingDevicePath - add argument and description to function comment
52 // TODO: EFI_UNSUPPORTED - add return value to function comment
53 // TODO: EFI_UNSUPPORTED - add return value to function comment
54 // TODO: EFI_SUCCESS - add return value to function comment
59 // If RemainingDevicePath is not NULL, it should verify that the first device
60 // path node in RemainingDevicePath is an ATAPI Device path node.
62 if (RemainingDevicePath
!= NULL
) {
63 if ((RemainingDevicePath
->Type
!= MESSAGING_DEVICE_PATH
) ||
64 (RemainingDevicePath
->SubType
!= MSG_ATAPI_DP
) ||
65 (DevicePathNodeLength (RemainingDevicePath
) != sizeof(ATAPI_DEVICE_PATH
))) {
66 return EFI_UNSUPPORTED
;
70 // check for the existence of SCSI Pass Thru Protocol
72 Status
= gBS
->OpenProtocol (
74 &gEfiScsiPassThruProtocolGuid
,
76 This
->DriverBindingHandle
,
78 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
80 if (EFI_ERROR (Status
) && (Status
!= EFI_ALREADY_STARTED
)) {
81 return EFI_UNSUPPORTED
;
89 SCSIBusDriverBindingStart (
90 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
91 IN EFI_HANDLE Controller
,
92 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
103 // TODO: This - add argument and description to function comment
104 // TODO: Controller - add argument and description to function comment
105 // TODO: RemainingDevicePath - add argument and description to function comment
108 EFI_DEVICE_PATH_PROTOCOL
*ParentDevicePath
;
109 EFI_SCSI_PASS_THRU_PROTOCOL
*ScsiPassThru
;
114 BOOLEAN ScanOtherPuns
;
118 Status
= gBS
->OpenProtocol (
120 &gEfiDevicePathProtocolGuid
,
121 (VOID
**) &ParentDevicePath
,
122 This
->DriverBindingHandle
,
124 EFI_OPEN_PROTOCOL_BY_DRIVER
126 if (EFI_ERROR (Status
) && Status
!= EFI_ALREADY_STARTED
) {
131 // Consume SCSI Pass Thru protocol.
133 Status
= gBS
->OpenProtocol (
135 &gEfiScsiPassThruProtocolGuid
,
136 (VOID
**) &ScsiPassThru
,
137 This
->DriverBindingHandle
,
139 EFI_OPEN_PROTOCOL_BY_DRIVER
141 if (EFI_ERROR (Status
) && Status
!= EFI_ALREADY_STARTED
) {
144 &gEfiDevicePathProtocolGuid
,
145 This
->DriverBindingHandle
,
151 if (RemainingDevicePath
== NULL
) {
152 StartPun
= 0xFFFFFFFF;
155 ScsiPassThru
->GetTargetLun (ScsiPassThru
, RemainingDevicePath
, &StartPun
, &StartLun
);
158 for (Pun
= StartPun
, ScanOtherPuns
= TRUE
; ScanOtherPuns
;) {
160 if (StartPun
== 0xFFFFFFFF) {
162 // Remaining Device Path is NULL, scan all the possible Puns in the
165 Status
= ScsiPassThru
->GetNextDevice (ScsiPassThru
, &Pun
, &Lun
);
166 if (EFI_ERROR (Status
)) {
168 // no legal Pun and Lun found any more
174 // Remaining Device Path is not NULL, only scan the specified Pun.
178 ScanOtherPuns
= FALSE
;
182 // Avoid creating handle for the host adapter.
184 if (Pun
== ScsiPassThru
->Mode
->AdapterId
) {
189 // Scan for the scsi device, if it attaches to the scsi bus,
190 // then create handle and install scsi i/o protocol.
192 Status
= ScsiScanCreateDevice (This
, Controller
, Pun
, Lun
, ScsiPassThru
, ParentDevicePath
);
200 SCSIBusDriverBindingStop (
201 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
202 IN EFI_HANDLE Controller
,
203 IN UINTN NumberOfChildren
,
204 IN EFI_HANDLE
*ChildHandleBuffer
215 // TODO: This - add argument and description to function comment
216 // TODO: Controller - add argument and description to function comment
217 // TODO: NumberOfChildren - add argument and description to function comment
218 // TODO: ChildHandleBuffer - add argument and description to function comment
219 // TODO: EFI_SUCCESS - add return value to function comment
220 // TODO: EFI_DEVICE_ERROR - add return value to function comment
221 // TODO: EFI_SUCCESS - add return value to function comment
224 BOOLEAN AllChildrenStopped
;
226 EFI_SCSI_IO_PROTOCOL
*ScsiIo
;
227 SCSI_IO_DEV
*ScsiIoDevice
;
228 EFI_SCSI_PASS_THRU_PROTOCOL
*ScsiPassThru
;
230 if (NumberOfChildren
== 0) {
232 // Close the bus driver
236 &gEfiScsiPassThruProtocolGuid
,
237 This
->DriverBindingHandle
,
242 &gEfiDevicePathProtocolGuid
,
243 This
->DriverBindingHandle
,
250 AllChildrenStopped
= TRUE
;
252 for (Index
= 0; Index
< NumberOfChildren
; Index
++) {
254 Status
= gBS
->OpenProtocol (
255 ChildHandleBuffer
[Index
],
256 &gEfiScsiIoProtocolGuid
,
258 This
->DriverBindingHandle
,
260 EFI_OPEN_PROTOCOL_GET_PROTOCOL
262 if (EFI_ERROR (Status
)) {
263 AllChildrenStopped
= FALSE
;
267 ScsiIoDevice
= SCSI_IO_DEV_FROM_THIS (ScsiIo
);
269 // Close the child handle
271 Status
= gBS
->CloseProtocol (
273 &gEfiScsiPassThruProtocolGuid
,
274 This
->DriverBindingHandle
,
275 ChildHandleBuffer
[Index
]
278 Status
= gBS
->UninstallMultipleProtocolInterfaces (
279 ChildHandleBuffer
[Index
],
280 &gEfiDevicePathProtocolGuid
,
281 ScsiIoDevice
->DevicePath
,
282 &gEfiScsiIoProtocolGuid
,
283 &ScsiIoDevice
->ScsiIo
,
286 if (EFI_ERROR (Status
)) {
287 AllChildrenStopped
= FALSE
;
290 &gEfiScsiPassThruProtocolGuid
,
291 (VOID
**) &ScsiPassThru
,
292 This
->DriverBindingHandle
,
293 ChildHandleBuffer
[Index
],
294 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
297 gBS
->FreePool (ScsiIoDevice
);
301 if (!AllChildrenStopped
) {
302 return EFI_DEVICE_ERROR
;
311 IN EFI_SCSI_IO_PROTOCOL
*This
,
312 OUT UINT8
*DeviceType
317 Retrieves the device type information of the SCSI Controller.
320 This - Protocol instance pointer.
321 DeviceType - A pointer to the device type information
322 retrieved from the SCSI Controller.
325 EFI_SUCCESS - Retrieves the device type information successfully.
326 EFI_INVALID_PARAMETER - The DeviceType is NULL.
329 SCSI_IO_DEV
*ScsiIoDevice
;
331 if (DeviceType
== NULL
) {
332 return EFI_INVALID_PARAMETER
;
335 ScsiIoDevice
= SCSI_IO_DEV_FROM_THIS (This
);
336 *DeviceType
= ScsiIoDevice
->ScsiDeviceType
;
343 ScsiGetDeviceLocation (
344 IN EFI_SCSI_IO_PROTOCOL
*This
,
350 Retrieves the device location in the SCSI channel.
353 This - Protocol instance pointer.
354 Target - A pointer to the Target ID of a SCSI device
356 Lun - A pointer to the LUN of the SCSI device on
360 EFI_SUCCESS - Retrieves the device location successfully.
361 EFI_INVALID_PARAMETER - The Target or Lun is NULL.
364 SCSI_IO_DEV
*ScsiIoDevice
;
366 if (Target
== NULL
|| Lun
== NULL
) {
367 return EFI_INVALID_PARAMETER
;
370 ScsiIoDevice
= SCSI_IO_DEV_FROM_THIS (This
);
372 *Target
= ScsiIoDevice
->Pun
;
373 *Lun
= ScsiIoDevice
->Lun
;
381 IN EFI_SCSI_IO_PROTOCOL
*This
386 Resets the SCSI Bus that the SCSI Controller is attached to.
389 This - Protocol instance pointer.
392 EFI_SUCCESS - The SCSI bus is reset successfully.
393 EFI_DEVICE_ERROR - Errors encountered when resetting the SCSI bus.
394 EFI_UNSUPPORTED - The bus reset operation is not supported by the
395 SCSI Host Controller.
396 EFI_TIMEOUT - A timeout occurred while attempting to reset
400 SCSI_IO_DEV
*ScsiIoDevice
;
402 ScsiIoDevice
= SCSI_IO_DEV_FROM_THIS (This
);
404 return ScsiIoDevice
->ScsiPassThru
->ResetChannel (ScsiIoDevice
->ScsiPassThru
);
411 IN EFI_SCSI_IO_PROTOCOL
*This
416 Resets the SCSI Controller that the device handle specifies.
419 This - Protocol instance pointer.
423 EFI_SUCCESS - Reset the SCSI controller successfully.
424 EFI_DEVICE_ERROR - Errors are encountered when resetting the
426 EFI_UNSUPPORTED - The SCSI bus does not support a device
428 EFI_TIMEOUT - A timeout occurred while attempting to
429 reset the SCSI Controller.
432 SCSI_IO_DEV
*ScsiIoDevice
;
434 ScsiIoDevice
= SCSI_IO_DEV_FROM_THIS (This
);
436 return ScsiIoDevice
->ScsiPassThru
->ResetTarget (
437 ScsiIoDevice
->ScsiPassThru
,
445 ScsiExecuteSCSICommand (
446 IN EFI_SCSI_IO_PROTOCOL
*This
,
447 IN OUT EFI_SCSI_IO_SCSI_REQUEST_PACKET
*Packet
,
448 IN EFI_EVENT Event OPTIONAL
453 Sends a SCSI Request Packet to the SCSI Controller for execution.
456 This - Protocol instance pointer.
457 Packet - The SCSI request packet to send to the SCSI
458 Controller specified by the device handle.
459 Event - If the SCSI bus where the SCSI device is attached
460 does not support non-blocking I/O, then Event is
461 ignored, and blocking I/O is performed.
462 If Event is NULL, then blocking I/O is performed.
463 If Event is not NULL and non-blocking I/O is
464 supported, then non-blocking I/O is performed,
465 and Event will be signaled when the SCSI Request
468 EFI_SUCCESS - The SCSI Request Packet was sent by the host
469 successfully, and TransferLength bytes were
470 transferred to/from DataBuffer.See
471 HostAdapterStatus, TargetStatus,
472 SenseDataLength, and SenseData in that order
473 for additional status information.
474 EFI_WARN_BUFFER_TOO_SMALL - The SCSI Request Packet was executed,
475 but the entire DataBuffer could not be transferred.
476 The actual number of bytes transferred is returned
477 in TransferLength. See HostAdapterStatus,
478 TargetStatus, SenseDataLength, and SenseData in
479 that order for additional status information.
480 EFI_NOT_READY - The SCSI Request Packet could not be sent because
481 there are too many SCSI Command Packets already
482 queued.The caller may retry again later.
483 EFI_DEVICE_ERROR - A device error occurred while attempting to send
484 the SCSI Request Packet. See HostAdapterStatus,
485 TargetStatus, SenseDataLength, and SenseData in
486 that order for additional status information.
487 EFI_INVALID_PARAMETER - The contents of CommandPacket are invalid.
488 The SCSI Request Packet was not sent, so no
489 additional status information is available.
490 EFI_UNSUPPORTED - The command described by the SCSI Request Packet
491 is not supported by the SCSI initiator(i.e., SCSI
492 Host Controller). The SCSI Request Packet was not
493 sent, so no additional status information is
495 EFI_TIMEOUT - A timeout occurred while waiting for the SCSI
496 Request Packet to execute. See HostAdapterStatus,
497 TargetStatus, SenseDataLength, and SenseData in
498 that order for additional status information.
501 SCSI_IO_DEV
*ScsiIoDevice
;
504 EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*RequestPacket
;
506 if (Packet
== NULL
) {
507 return EFI_INVALID_PARAMETER
;
510 ScsiIoDevice
= SCSI_IO_DEV_FROM_THIS (This
);
512 RequestPacket
= (EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
*) Packet
;
514 Status
= ScsiIoDevice
->ScsiPassThru
->PassThru (
515 ScsiIoDevice
->ScsiPassThru
,
525 ScsiScanCreateDevice (
526 EFI_DRIVER_BINDING_PROTOCOL
*This
,
527 EFI_HANDLE Controller
,
530 EFI_SCSI_PASS_THRU_PROTOCOL
*ScsiPassThru
,
531 EFI_DEVICE_PATH_PROTOCOL
*ParentDevicePath
537 TODO: Add function description
541 This - TODO: add argument description
542 Controller - TODO: add argument description
543 Pun - TODO: add argument description
544 Lun - TODO: add argument description
545 ScsiPassThru - TODO: add argument description
546 ParentDevicePath - TODO: add argument description
550 EFI_SUCCESS - TODO: Add description for return value
551 EFI_OUT_OF_RESOURCES - TODO: Add description for return value
552 EFI_SUCCESS - TODO: Add description for return value
557 SCSI_IO_DEV
*ScsiIoDevice
;
558 EFI_DEVICE_PATH_PROTOCOL
*ScsiDevicePath
;
560 Status
= gBS
->AllocatePool (
562 sizeof (SCSI_IO_DEV
),
563 (VOID
**) &ScsiIoDevice
565 if (EFI_ERROR (Status
)) {
569 ZeroMem (ScsiIoDevice
, sizeof (SCSI_IO_DEV
));
571 ScsiIoDevice
->Signature
= SCSI_IO_DEV_SIGNATURE
;
572 ScsiIoDevice
->ScsiPassThru
= ScsiPassThru
;
573 ScsiIoDevice
->Pun
= Pun
;
574 ScsiIoDevice
->Lun
= Lun
;
576 ScsiIoDevice
->ScsiIo
.GetDeviceType
= ScsiGetDeviceType
;
577 ScsiIoDevice
->ScsiIo
.GetDeviceLocation
= ScsiGetDeviceLocation
;
578 ScsiIoDevice
->ScsiIo
.ResetBus
= ScsiResetBus
;
579 ScsiIoDevice
->ScsiIo
.ResetDevice
= ScsiResetDevice
;
580 ScsiIoDevice
->ScsiIo
.ExecuteSCSICommand
= ScsiExecuteSCSICommand
;
582 if (!DiscoverScsiDevice (ScsiIoDevice
)) {
583 gBS
->FreePool (ScsiIoDevice
);
590 Status
= ScsiIoDevice
->ScsiPassThru
->BuildDevicePath (
591 ScsiIoDevice
->ScsiPassThru
,
596 if (Status
== EFI_OUT_OF_RESOURCES
) {
597 gBS
->FreePool (ScsiIoDevice
);
601 ScsiIoDevice
->DevicePath
= AppendDevicePathNode (
606 // The memory space for ScsiDevicePath is allocated in
607 // ScsiPassThru->BuildDevicePath() function; It is no longer used
608 // after EfiAppendDevicePathNode,so free the memory it occupies.
610 gBS
->FreePool (ScsiDevicePath
);
612 if (ScsiIoDevice
->DevicePath
== NULL
) {
613 gBS
->FreePool (ScsiIoDevice
);
614 return EFI_OUT_OF_RESOURCES
;
617 Status
= gBS
->InstallMultipleProtocolInterfaces (
618 &ScsiIoDevice
->Handle
,
619 &gEfiDevicePathProtocolGuid
,
620 ScsiIoDevice
->DevicePath
,
621 &gEfiScsiIoProtocolGuid
,
622 &ScsiIoDevice
->ScsiIo
,
625 if (EFI_ERROR (Status
)) {
626 gBS
->FreePool (ScsiIoDevice
);
630 &gEfiScsiPassThruProtocolGuid
,
631 (VOID
**) &ScsiPassThru
,
632 This
->DriverBindingHandle
,
633 ScsiIoDevice
->Handle
,
634 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
643 SCSI_IO_DEV
*ScsiIoDevice
649 TODO: Add function description
653 ScsiIoDevice - TODO: add argument description
657 TODO: add return values
662 EFI_SCSI_INQUIRY_DATA InquiryData
;
663 UINT32 InquiryDataLength
;
664 EFI_SCSI_SENSE_DATA SenseData
;
665 UINT8 SenseDataLength
;
666 UINT8 HostAdapterStatus
;
669 HostAdapterStatus
= 0;
672 // Using Inquiry command to scan for the device
674 InquiryDataLength
= sizeof (EFI_SCSI_INQUIRY_DATA
);
675 SenseDataLength
= sizeof (EFI_SCSI_SENSE_DATA
);
677 Status
= SubmitInquiryCommand (
678 &ScsiIoDevice
->ScsiIo
,
679 EfiScsiStallSeconds (1),
684 (VOID
*) &InquiryData
,
688 if (EFI_ERROR (Status
)) {
690 // ParseSenseData (&SenseData,SenseDataLength);
695 // Retrieved inquiry data successfully
697 if ((InquiryData
.Peripheral_Qualifier
!= 0) &&
698 (InquiryData
.Peripheral_Qualifier
!= 3)) {
702 if (InquiryData
.Peripheral_Qualifier
== 3) {
703 if (InquiryData
.Peripheral_Type
!= 0x1f) {
708 if ((0x1e >= InquiryData
.Peripheral_Type
) && (InquiryData
.Peripheral_Type
>= 0xa)) {
713 // valid device type and peripheral qualifier combination.
715 ScsiIoDevice
->ScsiDeviceType
= InquiryData
.Peripheral_Type
;
716 ScsiIoDevice
->RemovableDevice
= InquiryData
.RMB
;
717 if (InquiryData
.Version
== 0) {
718 ScsiIoDevice
->ScsiVersion
= 0;
721 // ANSI-approved version
723 ScsiIoDevice
->ScsiVersion
= (UINT8
) (InquiryData
.Version
& 0x03);