]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Bus/Scsi/ScsiBusDxe/ScsiBus.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / MdeModulePkg / Bus / Scsi / ScsiBusDxe / ScsiBus.c
1 /** @file
2 SCSI Bus driver that layers on every SCSI Pass Thru and
3 Extended SCSI Pass Thru protocol in the system.
4
5 Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
6 SPDX-License-Identifier: BSD-2-Clause-Patent
7
8 **/
9
10 #include "ScsiBus.h"
11
12 EFI_DRIVER_BINDING_PROTOCOL gSCSIBusDriverBinding = {
13 SCSIBusDriverBindingSupported,
14 SCSIBusDriverBindingStart,
15 SCSIBusDriverBindingStop,
16 0xa,
17 NULL,
18 NULL
19 };
20
21 VOID *mWorkingBuffer;
22
23 /**
24 Convert EFI_SCSI_IO_SCSI_REQUEST_PACKET packet to EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET packet.
25
26 @param Packet The pointer of EFI_SCSI_IO_SCSI_REQUEST_PACKET
27 @param CommandPacket The pointer of EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
28
29 **/
30 EFI_STATUS
31 EFIAPI
32 ScsiioToPassThruPacket (
33 IN EFI_SCSI_IO_SCSI_REQUEST_PACKET *Packet,
34 OUT EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *CommandPacket
35 );
36
37 /**
38 Convert EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET packet to EFI_SCSI_IO_SCSI_REQUEST_PACKET packet.
39
40 @param ScsiPacket The pointer of EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
41 @param Packet The pointer of EFI_SCSI_IO_SCSI_REQUEST_PACKET
42
43 **/
44 EFI_STATUS
45 EFIAPI
46 PassThruToScsiioPacket (
47 IN EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *ScsiPacket,
48 OUT EFI_SCSI_IO_SCSI_REQUEST_PACKET *Packet
49 );
50
51 /**
52 Notify Function in which convert EFI1.0 PassThru Packet back to UEF2.0
53 SCSI IO Packet.
54
55 @param Event The instance of EFI_EVENT.
56 @param Context The parameter passed in.
57
58 **/
59 VOID
60 EFIAPI
61 NotifyFunction (
62 IN EFI_EVENT Event,
63 IN VOID *Context
64 );
65
66 /**
67 Allocates an aligned buffer for SCSI device.
68
69 This function allocates an aligned buffer for the SCSI device to perform
70 SCSI pass through operations. The alignment requirement is from SCSI pass
71 through interface.
72
73 @param ScsiIoDevice The SCSI child device involved for the operation.
74 @param BufferSize The request buffer size.
75
76 @return A pointer to the aligned buffer or NULL if the allocation fails.
77
78 **/
79 VOID *
80 AllocateAlignedBuffer (
81 IN SCSI_IO_DEV *ScsiIoDevice,
82 IN UINTN BufferSize
83 )
84 {
85 return AllocateAlignedPages (EFI_SIZE_TO_PAGES (BufferSize), ScsiIoDevice->ScsiIo.IoAlign);
86 }
87
88 /**
89 Frees an aligned buffer for SCSI device.
90
91 This function frees an aligned buffer for the SCSI device to perform
92 SCSI pass through operations.
93
94 @param Buffer The aligned buffer to be freed.
95 @param BufferSize The request buffer size.
96
97 **/
98 VOID
99 FreeAlignedBuffer (
100 IN VOID *Buffer,
101 IN UINTN BufferSize
102 )
103 {
104 if (Buffer != NULL) {
105 FreeAlignedPages (Buffer, EFI_SIZE_TO_PAGES (BufferSize));
106 }
107 }
108
109 /**
110 The user Entry Point for module ScsiBus. The user code starts with this function.
111
112 @param ImageHandle The firmware allocated handle for the EFI image.
113 @param SystemTable A pointer to the EFI System Table.
114
115 @retval EFI_SUCCESS The entry point is executed successfully.
116 @retval other Some error occurs when executing this entry point.
117
118 **/
119 EFI_STATUS
120 EFIAPI
121 InitializeScsiBus (
122 IN EFI_HANDLE ImageHandle,
123 IN EFI_SYSTEM_TABLE *SystemTable
124 )
125 {
126 EFI_STATUS Status;
127
128 //
129 // Install driver model protocol(s).
130 //
131 Status = EfiLibInstallDriverBindingComponentName2 (
132 ImageHandle,
133 SystemTable,
134 &gSCSIBusDriverBinding,
135 ImageHandle,
136 &gScsiBusComponentName,
137 &gScsiBusComponentName2
138 );
139 ASSERT_EFI_ERROR (Status);
140
141 return Status;
142 }
143
144 /**
145 Test to see if this driver supports ControllerHandle.
146
147 This service is called by the EFI boot service ConnectController(). In order
148 to make drivers as small as possible, there are a few calling restrictions for
149 this service. ConnectController() must follow these calling restrictions. If
150 any other agent wishes to call Supported() it must also follow these calling
151 restrictions.
152
153 @param This Protocol instance pointer.
154 @param ControllerHandle Handle of device to test
155 @param RemainingDevicePath Optional parameter use to pick a specific child
156 device to start.
157
158 @retval EFI_SUCCESS This driver supports this device
159 @retval EFI_ALREADY_STARTED This driver is already running on this device
160 @retval other This driver does not support this device
161
162 **/
163 EFI_STATUS
164 EFIAPI
165 SCSIBusDriverBindingSupported (
166 IN EFI_DRIVER_BINDING_PROTOCOL *This,
167 IN EFI_HANDLE Controller,
168 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
169 )
170 {
171 EFI_STATUS Status;
172 EFI_SCSI_PASS_THRU_PROTOCOL *PassThru;
173 EFI_EXT_SCSI_PASS_THRU_PROTOCOL *ExtPassThru;
174 UINT64 Lun;
175 UINT8 *TargetId;
176 SCSI_TARGET_ID ScsiTargetId;
177
178 TargetId = &ScsiTargetId.ScsiId.ExtScsi[0];
179 SetMem (TargetId, TARGET_MAX_BYTES, 0xFF);
180
181 //
182 // To keep backward compatibility, UEFI ExtPassThru Protocol is supported as well as
183 // EFI PassThru Protocol. From priority perspective, ExtPassThru Protocol is firstly
184 // tried to open on host controller handle. If fails, then PassThru Protocol is tried instead.
185 //
186 Status = gBS->OpenProtocol (
187 Controller,
188 &gEfiExtScsiPassThruProtocolGuid,
189 (VOID **)&ExtPassThru,
190 This->DriverBindingHandle,
191 Controller,
192 EFI_OPEN_PROTOCOL_BY_DRIVER
193 );
194
195 if (Status == EFI_ALREADY_STARTED) {
196 return EFI_SUCCESS;
197 } else if (!EFI_ERROR (Status)) {
198 //
199 // Check if RemainingDevicePath is NULL or the End of Device Path Node,
200 // if yes, return EFI_SUCCESS.
201 //
202 if ((RemainingDevicePath == NULL) || IsDevicePathEnd (RemainingDevicePath)) {
203 //
204 // Close protocol regardless of RemainingDevicePath validation
205 //
206 gBS->CloseProtocol (
207 Controller,
208 &gEfiExtScsiPassThruProtocolGuid,
209 This->DriverBindingHandle,
210 Controller
211 );
212 return EFI_SUCCESS;
213 } else {
214 //
215 // If RemainingDevicePath isn't the End of Device Path Node, check its validation
216 //
217 Status = ExtPassThru->GetTargetLun (ExtPassThru, RemainingDevicePath, &TargetId, &Lun);
218 //
219 // Close protocol regardless of RemainingDevicePath validation
220 //
221 gBS->CloseProtocol (
222 Controller,
223 &gEfiExtScsiPassThruProtocolGuid,
224 This->DriverBindingHandle,
225 Controller
226 );
227 if (!EFI_ERROR (Status)) {
228 return EFI_SUCCESS;
229 }
230 }
231 }
232
233 //
234 // Come here in 2 condition:
235 // 1. ExtPassThru doesn't exist.
236 // 2. ExtPassThru exists but RemainingDevicePath is invalid.
237 //
238 Status = gBS->OpenProtocol (
239 Controller,
240 &gEfiScsiPassThruProtocolGuid,
241 (VOID **)&PassThru,
242 This->DriverBindingHandle,
243 Controller,
244 EFI_OPEN_PROTOCOL_BY_DRIVER
245 );
246
247 if (Status == EFI_ALREADY_STARTED) {
248 return EFI_SUCCESS;
249 }
250
251 if (EFI_ERROR (Status)) {
252 return Status;
253 }
254
255 //
256 // Test RemainingDevicePath is valid or not.
257 //
258 if ((RemainingDevicePath != NULL) && !IsDevicePathEnd (RemainingDevicePath)) {
259 Status = PassThru->GetTargetLun (PassThru, RemainingDevicePath, &ScsiTargetId.ScsiId.Scsi, &Lun);
260 }
261
262 gBS->CloseProtocol (
263 Controller,
264 &gEfiScsiPassThruProtocolGuid,
265 This->DriverBindingHandle,
266 Controller
267 );
268 return Status;
269 }
270
271 /**
272 Start this driver on ControllerHandle.
273
274 This service is called by the EFI boot service ConnectController(). In order
275 to make drivers as small as possible, there are a few calling restrictions for
276 this service. ConnectController() must follow these calling restrictions. If
277 any other agent wishes to call Start() it must also follow these calling
278 restrictions.
279
280 @param This Protocol instance pointer.
281 @param ControllerHandle Handle of device to bind driver to
282 @param RemainingDevicePath Optional parameter use to pick a specific child
283 device to start.
284
285 @retval EFI_SUCCESS This driver is added to ControllerHandle
286 @retval EFI_ALREADY_STARTED This driver is already running on ControllerHandle
287 @retval other This driver does not support this device
288
289 **/
290 EFI_STATUS
291 EFIAPI
292 SCSIBusDriverBindingStart (
293 IN EFI_DRIVER_BINDING_PROTOCOL *This,
294 IN EFI_HANDLE Controller,
295 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
296 )
297 {
298 UINT64 Lun;
299 UINT8 *TargetId;
300 BOOLEAN ScanOtherPuns;
301 BOOLEAN FromFirstTarget;
302 BOOLEAN ExtScsiSupport;
303 EFI_STATUS Status;
304 EFI_STATUS DevicePathStatus;
305 EFI_STATUS PassThruStatus;
306 SCSI_BUS_DEVICE *ScsiBusDev;
307 SCSI_TARGET_ID ScsiTargetId;
308 EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
309 EFI_SCSI_PASS_THRU_PROTOCOL *ScsiInterface;
310 EFI_EXT_SCSI_PASS_THRU_PROTOCOL *ExtScsiInterface;
311 EFI_SCSI_BUS_PROTOCOL *BusIdentify;
312
313 TargetId = NULL;
314 ScanOtherPuns = TRUE;
315 FromFirstTarget = FALSE;
316 ExtScsiSupport = FALSE;
317 PassThruStatus = EFI_SUCCESS;
318
319 TargetId = &ScsiTargetId.ScsiId.ExtScsi[0];
320 SetMem (TargetId, TARGET_MAX_BYTES, 0xFF);
321
322 DevicePathStatus = gBS->OpenProtocol (
323 Controller,
324 &gEfiDevicePathProtocolGuid,
325 (VOID **)&ParentDevicePath,
326 This->DriverBindingHandle,
327 Controller,
328 EFI_OPEN_PROTOCOL_BY_DRIVER
329 );
330 if (EFI_ERROR (DevicePathStatus) && (DevicePathStatus != EFI_ALREADY_STARTED)) {
331 return DevicePathStatus;
332 }
333
334 //
335 // Report Status Code to indicate SCSI bus starts
336 //
337 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
338 EFI_PROGRESS_CODE,
339 (EFI_IO_BUS_SCSI | EFI_IOB_PC_INIT),
340 ParentDevicePath
341 );
342
343 //
344 // To keep backward compatibility, UEFI ExtPassThru Protocol is supported as well as
345 // EFI PassThru Protocol. From priority perspective, ExtPassThru Protocol is firstly
346 // tried to open on host controller handle. If fails, then PassThru Protocol is tried instead.
347 //
348 Status = gBS->OpenProtocol (
349 Controller,
350 &gEfiExtScsiPassThruProtocolGuid,
351 (VOID **)&ExtScsiInterface,
352 This->DriverBindingHandle,
353 Controller,
354 EFI_OPEN_PROTOCOL_BY_DRIVER
355 );
356 //
357 // Fail to open UEFI ExtendPassThru Protocol, then try to open EFI PassThru Protocol instead.
358 //
359 if (EFI_ERROR (Status) && (Status != EFI_ALREADY_STARTED)) {
360 Status = gBS->OpenProtocol (
361 Controller,
362 &gEfiScsiPassThruProtocolGuid,
363 (VOID **)&ScsiInterface,
364 This->DriverBindingHandle,
365 Controller,
366 EFI_OPEN_PROTOCOL_BY_DRIVER
367 );
368 //
369 // Fail to open EFI PassThru Protocol, Close the DevicePathProtocol if it is opened by this time.
370 //
371 if (EFI_ERROR (Status) && (Status != EFI_ALREADY_STARTED)) {
372 if (!EFI_ERROR (DevicePathStatus)) {
373 gBS->CloseProtocol (
374 Controller,
375 &gEfiDevicePathProtocolGuid,
376 This->DriverBindingHandle,
377 Controller
378 );
379 }
380
381 return Status;
382 }
383 } else {
384 //
385 // Succeed to open ExtPassThru Protocol, and meanwhile open PassThru Protocol
386 // with BY_DRIVER if it is also present on the handle. The intent is to prevent
387 // another SCSI Bus Driver to work on the same host handle.
388 //
389 ExtScsiSupport = TRUE;
390 PassThruStatus = gBS->OpenProtocol (
391 Controller,
392 &gEfiScsiPassThruProtocolGuid,
393 (VOID **)&ScsiInterface,
394 This->DriverBindingHandle,
395 Controller,
396 EFI_OPEN_PROTOCOL_BY_DRIVER
397 );
398 }
399
400 if (Status != EFI_ALREADY_STARTED) {
401 //
402 // Go through here means either ExtPassThru or PassThru Protocol is successfully opened
403 // on this handle for this time. Then construct Host controller private data.
404 //
405 ScsiBusDev = NULL;
406 ScsiBusDev = AllocateZeroPool (sizeof (SCSI_BUS_DEVICE));
407 if (ScsiBusDev == NULL) {
408 Status = EFI_OUT_OF_RESOURCES;
409 goto ErrorExit;
410 }
411
412 ScsiBusDev->Signature = SCSI_BUS_DEVICE_SIGNATURE;
413 ScsiBusDev->ExtScsiSupport = ExtScsiSupport;
414 ScsiBusDev->DevicePath = ParentDevicePath;
415 if (ScsiBusDev->ExtScsiSupport) {
416 ScsiBusDev->ExtScsiInterface = ExtScsiInterface;
417 } else {
418 ScsiBusDev->ScsiInterface = ScsiInterface;
419 }
420
421 //
422 // Install EFI_SCSI_BUS_PROTOCOL to the controller handle, So ScsiBusDev could be
423 // retrieved on this controller handle. With ScsiBusDev, we can know which PassThru
424 // Protocol is present on the handle, UEFI ExtPassThru Protocol or EFI PassThru Protocol.
425 //
426 Status = gBS->InstallProtocolInterface (
427 &Controller,
428 &gEfiCallerIdGuid,
429 EFI_NATIVE_INTERFACE,
430 &ScsiBusDev->BusIdentify
431 );
432 if (EFI_ERROR (Status)) {
433 goto ErrorExit;
434 }
435 } else {
436 //
437 // Go through here means Start() is re-invoked again, nothing special is required to do except
438 // picking up Host controller private information.
439 //
440 Status = gBS->OpenProtocol (
441 Controller,
442 &gEfiCallerIdGuid,
443 (VOID **)&BusIdentify,
444 This->DriverBindingHandle,
445 Controller,
446 EFI_OPEN_PROTOCOL_GET_PROTOCOL
447 );
448
449 if (EFI_ERROR (Status)) {
450 return Status;
451 }
452
453 ScsiBusDev = SCSI_BUS_CONTROLLER_DEVICE_FROM_THIS (BusIdentify);
454 }
455
456 //
457 // Report Status Code to indicate detecting devices on bus
458 //
459 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
460 EFI_PROGRESS_CODE,
461 (EFI_IO_BUS_SCSI | EFI_IOB_PC_DETECT),
462 ParentDevicePath
463 );
464
465 Lun = 0;
466 if (RemainingDevicePath == NULL) {
467 //
468 // If RemainingDevicePath is NULL,
469 // must enumerate all SCSI devices anyway
470 //
471 FromFirstTarget = TRUE;
472 } else if (!IsDevicePathEnd (RemainingDevicePath)) {
473 //
474 // If RemainingDevicePath isn't the End of Device Path Node,
475 // only scan the specified device by RemainingDevicePath
476 //
477 if (ScsiBusDev->ExtScsiSupport) {
478 Status = ScsiBusDev->ExtScsiInterface->GetTargetLun (ScsiBusDev->ExtScsiInterface, RemainingDevicePath, &TargetId, &Lun);
479 } else {
480 Status = ScsiBusDev->ScsiInterface->GetTargetLun (ScsiBusDev->ScsiInterface, RemainingDevicePath, &ScsiTargetId.ScsiId.Scsi, &Lun);
481 }
482
483 if (EFI_ERROR (Status)) {
484 return Status;
485 }
486 } else {
487 //
488 // If RemainingDevicePath is the End of Device Path Node,
489 // skip enumerate any device and return EFI_SUCCESS
490 //
491 ScanOtherPuns = FALSE;
492 }
493
494 while (ScanOtherPuns) {
495 if (FromFirstTarget) {
496 //
497 // Remaining Device Path is NULL, scan all the possible Puns in the
498 // SCSI Channel.
499 //
500 if (ScsiBusDev->ExtScsiSupport) {
501 Status = ScsiBusDev->ExtScsiInterface->GetNextTargetLun (ScsiBusDev->ExtScsiInterface, &TargetId, &Lun);
502 } else {
503 Status = ScsiBusDev->ScsiInterface->GetNextDevice (ScsiBusDev->ScsiInterface, &ScsiTargetId.ScsiId.Scsi, &Lun);
504 }
505
506 if (EFI_ERROR (Status)) {
507 //
508 // no legal Pun and Lun found any more
509 //
510 break;
511 }
512 } else {
513 ScanOtherPuns = FALSE;
514 }
515
516 //
517 // Avoid creating handle for the host adapter.
518 //
519 if (ScsiBusDev->ExtScsiSupport) {
520 if ((ScsiTargetId.ScsiId.Scsi) == ScsiBusDev->ExtScsiInterface->Mode->AdapterId) {
521 continue;
522 }
523 } else {
524 if ((ScsiTargetId.ScsiId.Scsi) == ScsiBusDev->ScsiInterface->Mode->AdapterId) {
525 continue;
526 }
527 }
528
529 //
530 // Scan for the scsi device, if it attaches to the scsi bus,
531 // then create handle and install scsi i/o protocol.
532 //
533 Status = ScsiScanCreateDevice (This, Controller, &ScsiTargetId, Lun, ScsiBusDev);
534 }
535
536 return EFI_SUCCESS;
537
538 ErrorExit:
539
540 if (ScsiBusDev != NULL) {
541 FreePool (ScsiBusDev);
542 }
543
544 if (ExtScsiSupport) {
545 gBS->CloseProtocol (
546 Controller,
547 &gEfiExtScsiPassThruProtocolGuid,
548 This->DriverBindingHandle,
549 Controller
550 );
551 if (!EFI_ERROR (PassThruStatus)) {
552 gBS->CloseProtocol (
553 Controller,
554 &gEfiScsiPassThruProtocolGuid,
555 This->DriverBindingHandle,
556 Controller
557 );
558 }
559 } else {
560 gBS->CloseProtocol (
561 Controller,
562 &gEfiScsiPassThruProtocolGuid,
563 This->DriverBindingHandle,
564 Controller
565 );
566 }
567
568 return Status;
569 }
570
571 /**
572 Stop this driver on ControllerHandle.
573
574 This service is called by the EFI boot service DisconnectController().
575 In order to make drivers as small as possible, there are a few calling
576 restrictions for this service. DisconnectController() must follow these
577 calling restrictions. If any other agent wishes to call Stop() it must also
578 follow these calling restrictions.
579
580 @param This Protocol instance pointer.
581 @param ControllerHandle Handle of device to stop driver on
582 @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of
583 children is zero stop the entire bus driver.
584 @param ChildHandleBuffer List of Child Handles to Stop.
585
586 @retval EFI_SUCCESS This driver is removed ControllerHandle
587 @retval other This driver was not removed from this device
588
589 **/
590 EFI_STATUS
591 EFIAPI
592 SCSIBusDriverBindingStop (
593 IN EFI_DRIVER_BINDING_PROTOCOL *This,
594 IN EFI_HANDLE Controller,
595 IN UINTN NumberOfChildren,
596 IN EFI_HANDLE *ChildHandleBuffer
597 )
598 {
599 EFI_STATUS Status;
600 BOOLEAN AllChildrenStopped;
601 UINTN Index;
602 EFI_SCSI_IO_PROTOCOL *ScsiIo;
603 SCSI_IO_DEV *ScsiIoDevice;
604 VOID *ScsiPassThru;
605 EFI_SCSI_BUS_PROTOCOL *Scsidentifier;
606 SCSI_BUS_DEVICE *ScsiBusDev;
607
608 if (NumberOfChildren == 0) {
609 //
610 // Get the SCSI_BUS_DEVICE
611 //
612 Status = gBS->OpenProtocol (
613 Controller,
614 &gEfiCallerIdGuid,
615 (VOID **)&Scsidentifier,
616 This->DriverBindingHandle,
617 Controller,
618 EFI_OPEN_PROTOCOL_GET_PROTOCOL
619 );
620
621 if (EFI_ERROR (Status)) {
622 return EFI_DEVICE_ERROR;
623 }
624
625 ScsiBusDev = SCSI_BUS_CONTROLLER_DEVICE_FROM_THIS (Scsidentifier);
626
627 //
628 // Uninstall SCSI Bus Protocol
629 //
630 gBS->UninstallProtocolInterface (
631 Controller,
632 &gEfiCallerIdGuid,
633 &ScsiBusDev->BusIdentify
634 );
635
636 //
637 // Close the bus driver
638 //
639 if (ScsiBusDev->ExtScsiSupport) {
640 //
641 // Close ExtPassThru Protocol from this controller handle
642 //
643 gBS->CloseProtocol (
644 Controller,
645 &gEfiExtScsiPassThruProtocolGuid,
646 This->DriverBindingHandle,
647 Controller
648 );
649 //
650 // When Start() succeeds to open ExtPassThru, it always tries to open PassThru BY_DRIVER.
651 // Its intent is to prevent another SCSI Bus Driver from working on the same host handle.
652 // So Stop() needs to try to close PassThru if present here.
653 //
654 gBS->CloseProtocol (
655 Controller,
656 &gEfiScsiPassThruProtocolGuid,
657 This->DriverBindingHandle,
658 Controller
659 );
660 } else {
661 gBS->CloseProtocol (
662 Controller,
663 &gEfiScsiPassThruProtocolGuid,
664 This->DriverBindingHandle,
665 Controller
666 );
667 }
668
669 gBS->CloseProtocol (
670 Controller,
671 &gEfiDevicePathProtocolGuid,
672 This->DriverBindingHandle,
673 Controller
674 );
675 FreePool (ScsiBusDev);
676 return EFI_SUCCESS;
677 }
678
679 AllChildrenStopped = TRUE;
680
681 for (Index = 0; Index < NumberOfChildren; Index++) {
682 Status = gBS->OpenProtocol (
683 ChildHandleBuffer[Index],
684 &gEfiScsiIoProtocolGuid,
685 (VOID **)&ScsiIo,
686 This->DriverBindingHandle,
687 Controller,
688 EFI_OPEN_PROTOCOL_GET_PROTOCOL
689 );
690 if (EFI_ERROR (Status)) {
691 AllChildrenStopped = FALSE;
692 continue;
693 }
694
695 ScsiIoDevice = SCSI_IO_DEV_FROM_THIS (ScsiIo);
696 //
697 // Close the child handle
698 //
699 if (ScsiIoDevice->ExtScsiSupport) {
700 Status = gBS->CloseProtocol (
701 Controller,
702 &gEfiExtScsiPassThruProtocolGuid,
703 This->DriverBindingHandle,
704 ChildHandleBuffer[Index]
705 );
706 } else {
707 Status = gBS->CloseProtocol (
708 Controller,
709 &gEfiScsiPassThruProtocolGuid,
710 This->DriverBindingHandle,
711 ChildHandleBuffer[Index]
712 );
713 }
714
715 Status = gBS->UninstallMultipleProtocolInterfaces (
716 ChildHandleBuffer[Index],
717 &gEfiDevicePathProtocolGuid,
718 ScsiIoDevice->DevicePath,
719 &gEfiScsiIoProtocolGuid,
720 &ScsiIoDevice->ScsiIo,
721 NULL
722 );
723 if (EFI_ERROR (Status)) {
724 AllChildrenStopped = FALSE;
725 if (ScsiIoDevice->ExtScsiSupport) {
726 gBS->OpenProtocol (
727 Controller,
728 &gEfiExtScsiPassThruProtocolGuid,
729 &ScsiPassThru,
730 This->DriverBindingHandle,
731 ChildHandleBuffer[Index],
732 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
733 );
734 } else {
735 gBS->OpenProtocol (
736 Controller,
737 &gEfiScsiPassThruProtocolGuid,
738 &ScsiPassThru,
739 This->DriverBindingHandle,
740 ChildHandleBuffer[Index],
741 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
742 );
743 }
744 } else {
745 FreePool (ScsiIoDevice);
746 }
747 }
748
749 if (!AllChildrenStopped) {
750 return EFI_DEVICE_ERROR;
751 }
752
753 return EFI_SUCCESS;
754 }
755
756 /**
757 Retrieves the device type information of the SCSI Controller.
758
759 @param This Protocol instance pointer.
760 @param DeviceType A pointer to the device type information retrieved from
761 the SCSI Controller.
762
763 @retval EFI_SUCCESS Retrieves the device type information successfully.
764 @retval EFI_INVALID_PARAMETER The DeviceType is NULL.
765
766 **/
767 EFI_STATUS
768 EFIAPI
769 ScsiGetDeviceType (
770 IN EFI_SCSI_IO_PROTOCOL *This,
771 OUT UINT8 *DeviceType
772 )
773 {
774 SCSI_IO_DEV *ScsiIoDevice;
775
776 if (DeviceType == NULL) {
777 return EFI_INVALID_PARAMETER;
778 }
779
780 ScsiIoDevice = SCSI_IO_DEV_FROM_THIS (This);
781 *DeviceType = ScsiIoDevice->ScsiDeviceType;
782 return EFI_SUCCESS;
783 }
784
785 /**
786 Retrieves the device location in the SCSI channel.
787
788 @param This Protocol instance pointer.
789 @param Target A pointer to the Target ID of a SCSI device
790 on the SCSI channel.
791 @param Lun A pointer to the LUN of the SCSI device on
792 the SCSI channel.
793
794 @retval EFI_SUCCESS Retrieves the device location successfully.
795 @retval EFI_INVALID_PARAMETER The Target or Lun is NULL.
796
797 **/
798 EFI_STATUS
799 EFIAPI
800 ScsiGetDeviceLocation (
801 IN EFI_SCSI_IO_PROTOCOL *This,
802 IN OUT UINT8 **Target,
803 OUT UINT64 *Lun
804 )
805 {
806 SCSI_IO_DEV *ScsiIoDevice;
807
808 if ((Target == NULL) || (Lun == NULL)) {
809 return EFI_INVALID_PARAMETER;
810 }
811
812 ScsiIoDevice = SCSI_IO_DEV_FROM_THIS (This);
813
814 CopyMem (*Target, &ScsiIoDevice->Pun, TARGET_MAX_BYTES);
815
816 *Lun = ScsiIoDevice->Lun;
817
818 return EFI_SUCCESS;
819 }
820
821 /**
822 Resets the SCSI Bus that the SCSI Controller is attached to.
823
824 @param This Protocol instance pointer.
825
826 @retval EFI_SUCCESS The SCSI bus is reset successfully.
827 @retval EFI_DEVICE_ERROR Errors encountered when resetting the SCSI bus.
828 @retval EFI_UNSUPPORTED The bus reset operation is not supported by the
829 SCSI Host Controller.
830 @retval EFI_TIMEOUT A timeout occurred while attempting to reset
831 the SCSI bus.
832 **/
833 EFI_STATUS
834 EFIAPI
835 ScsiResetBus (
836 IN EFI_SCSI_IO_PROTOCOL *This
837 )
838 {
839 SCSI_IO_DEV *ScsiIoDevice;
840
841 ScsiIoDevice = SCSI_IO_DEV_FROM_THIS (This);
842
843 //
844 // Report Status Code to indicate reset happens
845 //
846 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
847 EFI_PROGRESS_CODE,
848 (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_PC_RESET),
849 ScsiIoDevice->ScsiBusDeviceData->DevicePath
850 );
851
852 if (ScsiIoDevice->ExtScsiSupport) {
853 return ScsiIoDevice->ExtScsiPassThru->ResetChannel (ScsiIoDevice->ExtScsiPassThru);
854 } else {
855 return ScsiIoDevice->ScsiPassThru->ResetChannel (ScsiIoDevice->ScsiPassThru);
856 }
857 }
858
859 /**
860 Resets the SCSI Controller that the device handle specifies.
861
862 @param This Protocol instance pointer.
863
864 @retval EFI_SUCCESS Reset the SCSI controller successfully.
865 @retval EFI_DEVICE_ERROR Errors are encountered when resetting the SCSI Controller.
866 @retval EFI_UNSUPPORTED The SCSI bus does not support a device reset operation.
867 @retval EFI_TIMEOUT A timeout occurred while attempting to reset the
868 SCSI Controller.
869 **/
870 EFI_STATUS
871 EFIAPI
872 ScsiResetDevice (
873 IN EFI_SCSI_IO_PROTOCOL *This
874 )
875 {
876 SCSI_IO_DEV *ScsiIoDevice;
877 UINT8 Target[TARGET_MAX_BYTES];
878
879 ScsiIoDevice = SCSI_IO_DEV_FROM_THIS (This);
880
881 //
882 // Report Status Code to indicate reset happens
883 //
884 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
885 EFI_PROGRESS_CODE,
886 (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_PC_RESET),
887 ScsiIoDevice->ScsiBusDeviceData->DevicePath
888 );
889
890 CopyMem (Target, &ScsiIoDevice->Pun, TARGET_MAX_BYTES);
891
892 if (ScsiIoDevice->ExtScsiSupport) {
893 return ScsiIoDevice->ExtScsiPassThru->ResetTargetLun (
894 ScsiIoDevice->ExtScsiPassThru,
895 Target,
896 ScsiIoDevice->Lun
897 );
898 } else {
899 return ScsiIoDevice->ScsiPassThru->ResetTarget (
900 ScsiIoDevice->ScsiPassThru,
901 ScsiIoDevice->Pun.ScsiId.Scsi,
902 ScsiIoDevice->Lun
903 );
904 }
905 }
906
907 /**
908 Sends a SCSI Request Packet to the SCSI Controller for execution.
909
910 @param This Protocol instance pointer.
911 @param CommandPacket The SCSI request packet to send to the SCSI
912 Controller specified by the device handle.
913 @param Event If the SCSI bus where the SCSI device is attached
914 does not support non-blocking I/O, then Event is
915 ignored, and blocking I/O is performed.
916 If Event is NULL, then blocking I/O is performed.
917 If Event is not NULL and non-blocking I/O is
918 supported, then non-blocking I/O is performed,
919 and Event will be signaled when the SCSI Request
920 Packet completes.
921
922 @retval EFI_SUCCESS The SCSI Request Packet was sent by the host
923 successfully, and TransferLength bytes were
924 transferred to/from DataBuffer.See
925 HostAdapterStatus, TargetStatus,
926 SenseDataLength, and SenseData in that order
927 for additional status information.
928 @retval EFI_BAD_BUFFER_SIZE The SCSI Request Packet was executed,
929 but the entire DataBuffer could not be transferred.
930 The actual number of bytes transferred is returned
931 in TransferLength. See HostAdapterStatus,
932 TargetStatus, SenseDataLength, and SenseData in
933 that order for additional status information.
934 @retval EFI_NOT_READY The SCSI Request Packet could not be sent because
935 there are too many SCSI Command Packets already
936 queued.The caller may retry again later.
937 @retval EFI_DEVICE_ERROR A device error occurred while attempting to send
938 the SCSI Request Packet. See HostAdapterStatus,
939 TargetStatus, SenseDataLength, and SenseData in
940 that order for additional status information.
941 @retval EFI_INVALID_PARAMETER The contents of CommandPacket are invalid.
942 The SCSI Request Packet was not sent, so no
943 additional status information is available.
944 @retval EFI_UNSUPPORTED The command described by the SCSI Request Packet
945 is not supported by the SCSI initiator(i.e., SCSI
946 Host Controller). The SCSI Request Packet was not
947 sent, so no additional status information is
948 available.
949 @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI
950 Request Packet to execute. See HostAdapterStatus,
951 TargetStatus, SenseDataLength, and SenseData in
952 that order for additional status information.
953 **/
954 EFI_STATUS
955 EFIAPI
956 ScsiExecuteSCSICommand (
957 IN EFI_SCSI_IO_PROTOCOL *This,
958 IN OUT EFI_SCSI_IO_SCSI_REQUEST_PACKET *Packet,
959 IN EFI_EVENT Event OPTIONAL
960 )
961 {
962 SCSI_IO_DEV *ScsiIoDevice;
963 EFI_STATUS Status;
964 UINT8 Target[TARGET_MAX_BYTES];
965 EFI_EVENT PacketEvent;
966 EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *ExtRequestPacket;
967 SCSI_EVENT_DATA EventData;
968
969 PacketEvent = NULL;
970
971 if (Packet == NULL) {
972 return EFI_INVALID_PARAMETER;
973 }
974
975 ScsiIoDevice = SCSI_IO_DEV_FROM_THIS (This);
976 CopyMem (Target, &ScsiIoDevice->Pun, TARGET_MAX_BYTES);
977
978 if (ScsiIoDevice->ExtScsiSupport) {
979 ExtRequestPacket = (EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *)Packet;
980
981 if (((ScsiIoDevice->ExtScsiPassThru->Mode->Attributes & EFI_SCSI_PASS_THRU_ATTRIBUTES_NONBLOCKIO) != 0) && (Event != NULL)) {
982 Status = ScsiIoDevice->ExtScsiPassThru->PassThru (
983 ScsiIoDevice->ExtScsiPassThru,
984 Target,
985 ScsiIoDevice->Lun,
986 ExtRequestPacket,
987 Event
988 );
989 } else {
990 //
991 // If there's no event or the SCSI Device doesn't support NON-BLOCKING,
992 // let the 'Event' parameter for PassThru() be NULL.
993 //
994 Status = ScsiIoDevice->ExtScsiPassThru->PassThru (
995 ScsiIoDevice->ExtScsiPassThru,
996 Target,
997 ScsiIoDevice->Lun,
998 ExtRequestPacket,
999 NULL
1000 );
1001 if ((!EFI_ERROR (Status)) && (Event != NULL)) {
1002 //
1003 // Signal Event to tell caller to pick up the SCSI IO packet if the
1004 // PassThru() succeeds.
1005 //
1006 gBS->SignalEvent (Event);
1007 }
1008 }
1009 } else {
1010 mWorkingBuffer = AllocatePool (sizeof (EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET));
1011
1012 if (mWorkingBuffer == NULL) {
1013 return EFI_DEVICE_ERROR;
1014 }
1015
1016 //
1017 // Convert package into EFI1.0, EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET.
1018 //
1019 Status = ScsiioToPassThruPacket (Packet, (EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *)mWorkingBuffer);
1020 if (EFI_ERROR (Status)) {
1021 FreePool (mWorkingBuffer);
1022 return Status;
1023 }
1024
1025 if (((ScsiIoDevice->ScsiPassThru->Mode->Attributes & EFI_SCSI_PASS_THRU_ATTRIBUTES_NONBLOCKIO) != 0) && (Event != NULL)) {
1026 EventData.Data1 = (VOID *)Packet;
1027 EventData.Data2 = Event;
1028 //
1029 // Create Event
1030 //
1031 Status = gBS->CreateEvent (
1032 EVT_NOTIFY_SIGNAL,
1033 TPL_NOTIFY,
1034 NotifyFunction,
1035 &EventData,
1036 &PacketEvent
1037 );
1038 if (EFI_ERROR (Status)) {
1039 FreePool (mWorkingBuffer);
1040 return Status;
1041 }
1042
1043 Status = ScsiIoDevice->ScsiPassThru->PassThru (
1044 ScsiIoDevice->ScsiPassThru,
1045 ScsiIoDevice->Pun.ScsiId.Scsi,
1046 ScsiIoDevice->Lun,
1047 mWorkingBuffer,
1048 PacketEvent
1049 );
1050
1051 if (EFI_ERROR (Status)) {
1052 FreePool (mWorkingBuffer);
1053 gBS->CloseEvent (PacketEvent);
1054 return Status;
1055 }
1056 } else {
1057 //
1058 // If there's no event or SCSI Device doesn't support NON-BLOCKING, just convert
1059 // EFI1.0 PassThru packet back to UEFI2.0 SCSI IO Packet.
1060 //
1061 Status = ScsiIoDevice->ScsiPassThru->PassThru (
1062 ScsiIoDevice->ScsiPassThru,
1063 ScsiIoDevice->Pun.ScsiId.Scsi,
1064 ScsiIoDevice->Lun,
1065 mWorkingBuffer,
1066 NULL
1067 );
1068 if (EFI_ERROR (Status)) {
1069 FreePool (mWorkingBuffer);
1070 return Status;
1071 }
1072
1073 PassThruToScsiioPacket ((EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *)mWorkingBuffer, Packet);
1074 //
1075 // After converting EFI1.0 PassThru Packet back to UEFI2.0 SCSI IO Packet,
1076 // free mWorkingBuffer.
1077 //
1078 FreePool (mWorkingBuffer);
1079
1080 //
1081 // Signal Event to tell caller to pick up the SCSI IO Packet.
1082 //
1083 if (Event != NULL) {
1084 gBS->SignalEvent (Event);
1085 }
1086 }
1087 }
1088
1089 return Status;
1090 }
1091
1092 /**
1093 Scan SCSI Bus to discover the device, and attach ScsiIoProtocol to it.
1094
1095 @param This Protocol instance pointer
1096 @param Controller Controller handle
1097 @param TargetId Target to be scanned
1098 @param Lun The Lun of the SCSI device on the SCSI channel.
1099 @param ScsiBusDev The pointer of SCSI_BUS_DEVICE
1100
1101 @retval EFI_SUCCESS Successfully to discover the device and attach
1102 ScsiIoProtocol to it.
1103 @retval EFI_OUT_OF_RESOURCES Fail to discover the device.
1104
1105 **/
1106 EFI_STATUS
1107 EFIAPI
1108 ScsiScanCreateDevice (
1109 IN EFI_DRIVER_BINDING_PROTOCOL *This,
1110 IN EFI_HANDLE Controller,
1111 IN SCSI_TARGET_ID *TargetId,
1112 IN UINT64 Lun,
1113 IN OUT SCSI_BUS_DEVICE *ScsiBusDev
1114 )
1115 {
1116 EFI_STATUS Status;
1117 SCSI_IO_DEV *ScsiIoDevice;
1118 EFI_DEVICE_PATH_PROTOCOL *ScsiDevicePath;
1119 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
1120 EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath;
1121 EFI_HANDLE DeviceHandle;
1122
1123 DevicePath = NULL;
1124 RemainingDevicePath = NULL;
1125 ScsiDevicePath = NULL;
1126 ScsiIoDevice = NULL;
1127
1128 //
1129 // Build Device Path
1130 //
1131 if (ScsiBusDev->ExtScsiSupport) {
1132 Status = ScsiBusDev->ExtScsiInterface->BuildDevicePath (
1133 ScsiBusDev->ExtScsiInterface,
1134 &TargetId->ScsiId.ExtScsi[0],
1135 Lun,
1136 &ScsiDevicePath
1137 );
1138 } else {
1139 Status = ScsiBusDev->ScsiInterface->BuildDevicePath (
1140 ScsiBusDev->ScsiInterface,
1141 TargetId->ScsiId.Scsi,
1142 Lun,
1143 &ScsiDevicePath
1144 );
1145 }
1146
1147 if (EFI_ERROR (Status)) {
1148 return Status;
1149 }
1150
1151 DevicePath = AppendDevicePathNode (
1152 ScsiBusDev->DevicePath,
1153 ScsiDevicePath
1154 );
1155
1156 if (DevicePath == NULL) {
1157 Status = EFI_OUT_OF_RESOURCES;
1158 goto ErrorExit;
1159 }
1160
1161 DeviceHandle = NULL;
1162 RemainingDevicePath = DevicePath;
1163 Status = gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid, &RemainingDevicePath, &DeviceHandle);
1164 if (!EFI_ERROR (Status) && (DeviceHandle != NULL) && IsDevicePathEnd (RemainingDevicePath)) {
1165 //
1166 // The device has been started, directly return to fast boot.
1167 //
1168 Status = EFI_ALREADY_STARTED;
1169 goto ErrorExit;
1170 }
1171
1172 ScsiIoDevice = AllocateZeroPool (sizeof (SCSI_IO_DEV));
1173 if (ScsiIoDevice == NULL) {
1174 Status = EFI_OUT_OF_RESOURCES;
1175 goto ErrorExit;
1176 }
1177
1178 ScsiIoDevice->Signature = SCSI_IO_DEV_SIGNATURE;
1179 ScsiIoDevice->ScsiBusDeviceData = ScsiBusDev;
1180 CopyMem (&ScsiIoDevice->Pun, TargetId, TARGET_MAX_BYTES);
1181 ScsiIoDevice->Lun = Lun;
1182
1183 if (ScsiBusDev->ExtScsiSupport) {
1184 ScsiIoDevice->ExtScsiPassThru = ScsiBusDev->ExtScsiInterface;
1185 ScsiIoDevice->ExtScsiSupport = TRUE;
1186 ScsiIoDevice->ScsiIo.IoAlign = ScsiIoDevice->ExtScsiPassThru->Mode->IoAlign;
1187 } else {
1188 ScsiIoDevice->ScsiPassThru = ScsiBusDev->ScsiInterface;
1189 ScsiIoDevice->ExtScsiSupport = FALSE;
1190 ScsiIoDevice->ScsiIo.IoAlign = ScsiIoDevice->ScsiPassThru->Mode->IoAlign;
1191 }
1192
1193 ScsiIoDevice->ScsiIo.GetDeviceType = ScsiGetDeviceType;
1194 ScsiIoDevice->ScsiIo.GetDeviceLocation = ScsiGetDeviceLocation;
1195 ScsiIoDevice->ScsiIo.ResetBus = ScsiResetBus;
1196 ScsiIoDevice->ScsiIo.ResetDevice = ScsiResetDevice;
1197 ScsiIoDevice->ScsiIo.ExecuteScsiCommand = ScsiExecuteSCSICommand;
1198
1199 //
1200 // Report Status Code here since the new SCSI device will be discovered
1201 //
1202 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
1203 EFI_PROGRESS_CODE,
1204 (EFI_IO_BUS_SCSI | EFI_IOB_PC_ENABLE),
1205 ScsiBusDev->DevicePath
1206 );
1207
1208 if (!DiscoverScsiDevice (ScsiIoDevice)) {
1209 Status = EFI_OUT_OF_RESOURCES;
1210 goto ErrorExit;
1211 }
1212
1213 ScsiIoDevice->DevicePath = DevicePath;
1214
1215 Status = gBS->InstallMultipleProtocolInterfaces (
1216 &ScsiIoDevice->Handle,
1217 &gEfiDevicePathProtocolGuid,
1218 ScsiIoDevice->DevicePath,
1219 &gEfiScsiIoProtocolGuid,
1220 &ScsiIoDevice->ScsiIo,
1221 NULL
1222 );
1223 if (EFI_ERROR (Status)) {
1224 goto ErrorExit;
1225 } else {
1226 if (ScsiBusDev->ExtScsiSupport) {
1227 gBS->OpenProtocol (
1228 Controller,
1229 &gEfiExtScsiPassThruProtocolGuid,
1230 (VOID **)&(ScsiBusDev->ExtScsiInterface),
1231 This->DriverBindingHandle,
1232 ScsiIoDevice->Handle,
1233 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
1234 );
1235 } else {
1236 gBS->OpenProtocol (
1237 Controller,
1238 &gEfiScsiPassThruProtocolGuid,
1239 (VOID **)&(ScsiBusDev->ScsiInterface),
1240 This->DriverBindingHandle,
1241 ScsiIoDevice->Handle,
1242 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
1243 );
1244 }
1245 }
1246
1247 return EFI_SUCCESS;
1248
1249 ErrorExit:
1250
1251 //
1252 // The memory space for ScsiDevicePath is allocated in
1253 // ScsiPassThru->BuildDevicePath() function; It is no longer used
1254 // after AppendDevicePathNode,so free the memory it occupies.
1255 //
1256 FreePool (ScsiDevicePath);
1257
1258 if (DevicePath != NULL) {
1259 FreePool (DevicePath);
1260 }
1261
1262 if (ScsiIoDevice != NULL) {
1263 FreePool (ScsiIoDevice);
1264 }
1265
1266 return Status;
1267 }
1268
1269 /**
1270 Discovery SCSI Device
1271
1272 @param ScsiIoDevice The pointer of SCSI_IO_DEV
1273
1274 @retval TRUE Find SCSI Device and verify it.
1275 @retval FALSE Unable to find SCSI Device.
1276
1277 **/
1278 BOOLEAN
1279 DiscoverScsiDevice (
1280 IN OUT SCSI_IO_DEV *ScsiIoDevice
1281 )
1282 {
1283 EFI_STATUS Status;
1284 UINT32 InquiryDataLength;
1285 UINT8 SenseDataLength;
1286 UINT8 HostAdapterStatus;
1287 UINT8 TargetStatus;
1288 EFI_SCSI_INQUIRY_DATA *InquiryData;
1289 EFI_SCSI_SENSE_DATA *SenseData;
1290 UINT8 MaxRetry;
1291 UINT8 Index;
1292 BOOLEAN ScsiDeviceFound;
1293
1294 HostAdapterStatus = 0;
1295 TargetStatus = 0;
1296 SenseData = NULL;
1297
1298 InquiryData = AllocateAlignedBuffer (ScsiIoDevice, sizeof (EFI_SCSI_INQUIRY_DATA));
1299 if (InquiryData == NULL) {
1300 ScsiDeviceFound = FALSE;
1301 goto Done;
1302 }
1303
1304 SenseData = AllocateAlignedBuffer (
1305 ScsiIoDevice,
1306 sizeof (EFI_SCSI_SENSE_DATA)
1307 );
1308 if (SenseData == NULL) {
1309 ScsiDeviceFound = FALSE;
1310 goto Done;
1311 }
1312
1313 //
1314 // Using Inquiry command to scan for the device
1315 //
1316 InquiryDataLength = sizeof (EFI_SCSI_INQUIRY_DATA);
1317 SenseDataLength = sizeof (EFI_SCSI_SENSE_DATA);
1318 ZeroMem (InquiryData, InquiryDataLength);
1319 ZeroMem (SenseData, SenseDataLength);
1320
1321 MaxRetry = 2;
1322 for (Index = 0; Index < MaxRetry; Index++) {
1323 Status = ScsiInquiryCommand (
1324 &ScsiIoDevice->ScsiIo,
1325 SCSI_BUS_TIMEOUT,
1326 SenseData,
1327 &SenseDataLength,
1328 &HostAdapterStatus,
1329 &TargetStatus,
1330 (VOID *)InquiryData,
1331 &InquiryDataLength,
1332 FALSE
1333 );
1334 if (!EFI_ERROR (Status)) {
1335 if ((HostAdapterStatus == EFI_SCSI_IO_STATUS_HOST_ADAPTER_OK) &&
1336 (TargetStatus == EFI_SCSI_IO_STATUS_TARGET_CHECK_CONDITION) &&
1337 (SenseData->Error_Code == 0x70) &&
1338 (SenseData->Sense_Key == EFI_SCSI_SK_ILLEGAL_REQUEST))
1339 {
1340 ScsiDeviceFound = FALSE;
1341 goto Done;
1342 }
1343
1344 break;
1345 }
1346
1347 if ((Status == EFI_BAD_BUFFER_SIZE) ||
1348 (Status == EFI_INVALID_PARAMETER) ||
1349 (Status == EFI_UNSUPPORTED))
1350 {
1351 ScsiDeviceFound = FALSE;
1352 goto Done;
1353 }
1354 }
1355
1356 if (Index == MaxRetry) {
1357 ScsiDeviceFound = FALSE;
1358 goto Done;
1359 }
1360
1361 //
1362 // Retrieved inquiry data successfully
1363 //
1364 if (InquiryData->Peripheral_Qualifier != 0) {
1365 ScsiDeviceFound = FALSE;
1366 goto Done;
1367 }
1368
1369 if ((InquiryData->Peripheral_Type >= EFI_SCSI_TYPE_RESERVED_LOW) &&
1370 (InquiryData->Peripheral_Type <= EFI_SCSI_TYPE_RESERVED_HIGH))
1371 {
1372 ScsiDeviceFound = FALSE;
1373 goto Done;
1374 }
1375
1376 //
1377 // valid device type and peripheral qualifier combination.
1378 //
1379 ScsiIoDevice->ScsiDeviceType = InquiryData->Peripheral_Type;
1380 ScsiIoDevice->RemovableDevice = InquiryData->Rmb;
1381 if (InquiryData->Version == 0) {
1382 ScsiIoDevice->ScsiVersion = 0;
1383 } else {
1384 //
1385 // ANSI-approved version
1386 //
1387 ScsiIoDevice->ScsiVersion = (UINT8)(InquiryData->Version & 0x07);
1388 }
1389
1390 ScsiDeviceFound = TRUE;
1391
1392 Done:
1393 FreeAlignedBuffer (SenseData, sizeof (EFI_SCSI_SENSE_DATA));
1394 FreeAlignedBuffer (InquiryData, sizeof (EFI_SCSI_INQUIRY_DATA));
1395
1396 return ScsiDeviceFound;
1397 }
1398
1399 /**
1400 Convert EFI_SCSI_IO_SCSI_REQUEST_PACKET packet to EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET packet.
1401
1402 @param Packet The pointer of EFI_SCSI_IO_SCSI_REQUEST_PACKET
1403 @param CommandPacket The pointer of EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
1404
1405 **/
1406 EFI_STATUS
1407 EFIAPI
1408 ScsiioToPassThruPacket (
1409 IN EFI_SCSI_IO_SCSI_REQUEST_PACKET *Packet,
1410 OUT EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *CommandPacket
1411 )
1412 {
1413 //
1414 // EFI 1.10 doesn't support Bi-Direction Command.
1415 //
1416 if (Packet->DataDirection == EFI_SCSI_IO_DATA_DIRECTION_BIDIRECTIONAL) {
1417 return EFI_UNSUPPORTED;
1418 }
1419
1420 ZeroMem (CommandPacket, sizeof (EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET));
1421
1422 CommandPacket->Timeout = Packet->Timeout;
1423 CommandPacket->Cdb = Packet->Cdb;
1424 CommandPacket->CdbLength = Packet->CdbLength;
1425 CommandPacket->DataDirection = Packet->DataDirection;
1426 CommandPacket->HostAdapterStatus = Packet->HostAdapterStatus;
1427 CommandPacket->TargetStatus = Packet->TargetStatus;
1428 CommandPacket->SenseData = Packet->SenseData;
1429 CommandPacket->SenseDataLength = Packet->SenseDataLength;
1430
1431 if (Packet->DataDirection == EFI_SCSI_IO_DATA_DIRECTION_READ) {
1432 CommandPacket->DataBuffer = Packet->InDataBuffer;
1433 CommandPacket->TransferLength = Packet->InTransferLength;
1434 } else if (Packet->DataDirection == EFI_SCSI_IO_DATA_DIRECTION_WRITE) {
1435 CommandPacket->DataBuffer = Packet->OutDataBuffer;
1436 CommandPacket->TransferLength = Packet->OutTransferLength;
1437 }
1438
1439 return EFI_SUCCESS;
1440 }
1441
1442 /**
1443 Convert EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET packet to EFI_SCSI_IO_SCSI_REQUEST_PACKET packet.
1444
1445 @param ScsiPacket The pointer of EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
1446 @param Packet The pointer of EFI_SCSI_IO_SCSI_REQUEST_PACKET
1447
1448 **/
1449 EFI_STATUS
1450 EFIAPI
1451 PassThruToScsiioPacket (
1452 IN EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *ScsiPacket,
1453 OUT EFI_SCSI_IO_SCSI_REQUEST_PACKET *Packet
1454 )
1455 {
1456 Packet->Timeout = ScsiPacket->Timeout;
1457 Packet->Cdb = ScsiPacket->Cdb;
1458 Packet->CdbLength = ScsiPacket->CdbLength;
1459 Packet->DataDirection = ScsiPacket->DataDirection;
1460 Packet->HostAdapterStatus = ScsiPacket->HostAdapterStatus;
1461 Packet->TargetStatus = ScsiPacket->TargetStatus;
1462 Packet->SenseData = ScsiPacket->SenseData;
1463 Packet->SenseDataLength = ScsiPacket->SenseDataLength;
1464
1465 if (ScsiPacket->DataDirection == EFI_SCSI_IO_DATA_DIRECTION_READ) {
1466 Packet->InDataBuffer = ScsiPacket->DataBuffer;
1467 Packet->InTransferLength = ScsiPacket->TransferLength;
1468 } else if (Packet->DataDirection == EFI_SCSI_IO_DATA_DIRECTION_WRITE) {
1469 Packet->OutDataBuffer = ScsiPacket->DataBuffer;
1470 Packet->OutTransferLength = ScsiPacket->TransferLength;
1471 }
1472
1473 return EFI_SUCCESS;
1474 }
1475
1476 /**
1477 Notify Function in which convert EFI1.0 PassThru Packet back to UEF2.0
1478 SCSI IO Packet.
1479
1480 @param Event The instance of EFI_EVENT.
1481 @param Context The parameter passed in.
1482
1483 **/
1484 VOID
1485 EFIAPI
1486 NotifyFunction (
1487 IN EFI_EVENT Event,
1488 IN VOID *Context
1489 )
1490 {
1491 EFI_SCSI_IO_SCSI_REQUEST_PACKET *Packet;
1492 EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *ScsiPacket;
1493 EFI_EVENT CallerEvent;
1494 SCSI_EVENT_DATA *PassData;
1495
1496 PassData = (SCSI_EVENT_DATA *)Context;
1497 Packet = (EFI_SCSI_IO_SCSI_REQUEST_PACKET *)PassData->Data1;
1498 ScsiPacket = (EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *)mWorkingBuffer;
1499
1500 //
1501 // Convert EFI1.0 PassThru packet to UEFI2.0 SCSI IO Packet.
1502 //
1503 PassThruToScsiioPacket (ScsiPacket, Packet);
1504
1505 //
1506 // After converting EFI1.0 PassThru Packet back to UEFI2.0 SCSI IO Packet,
1507 // free mWorkingBuffer.
1508 //
1509 gBS->FreePool (mWorkingBuffer);
1510
1511 //
1512 // Signal Event to tell caller to pick up UEFI2.0 SCSI IO Packet.
1513 //
1514 CallerEvent = PassData->Data2;
1515 gBS->CloseEvent (Event);
1516 gBS->SignalEvent (CallerEvent);
1517 }