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