]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Bus/Scsi/ScsiBusDxe/ScsiBus.c
MdeModulePkg: Replace BSD License with BSD+Patent License
[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 - 2018, Intel Corporation. All rights reserved.<BR>
6 SPDX-License-Identifier: BSD-2-Clause-Patent
7
8 **/
9
10
11 #include "ScsiBus.h"
12
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 /**
148 Test to see if this driver supports ControllerHandle.
149
150 This service is called by the EFI boot service ConnectController(). In order
151 to make drivers as small as possible, there are a few calling restrictions for
152 this service. ConnectController() must follow these calling restrictions. If
153 any other agent wishes to call Supported() it must also follow these calling
154 restrictions.
155
156 @param This Protocol instance pointer.
157 @param ControllerHandle Handle of device to test
158 @param RemainingDevicePath Optional parameter use to pick a specific child
159 device to start.
160
161 @retval EFI_SUCCESS This driver supports this device
162 @retval EFI_ALREADY_STARTED This driver is already running on this device
163 @retval other This driver does not support this device
164
165 **/
166 EFI_STATUS
167 EFIAPI
168 SCSIBusDriverBindingSupported (
169 IN EFI_DRIVER_BINDING_PROTOCOL *This,
170 IN EFI_HANDLE Controller,
171 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
172 )
173 {
174 EFI_STATUS Status;
175 EFI_SCSI_PASS_THRU_PROTOCOL *PassThru;
176 EFI_EXT_SCSI_PASS_THRU_PROTOCOL *ExtPassThru;
177 UINT64 Lun;
178 UINT8 *TargetId;
179 SCSI_TARGET_ID ScsiTargetId;
180
181 TargetId = &ScsiTargetId.ScsiId.ExtScsi[0];
182 SetMem (TargetId, TARGET_MAX_BYTES, 0xFF);
183
184 //
185 // To keep backward compatibility, UEFI ExtPassThru Protocol is supported as well as
186 // EFI PassThru Protocol. From priority perspective, ExtPassThru Protocol is firstly
187 // tried to open on host controller handle. If fails, then PassThru Protocol is tried instead.
188 //
189 Status = gBS->OpenProtocol (
190 Controller,
191 &gEfiExtScsiPassThruProtocolGuid,
192 (VOID **)&ExtPassThru,
193 This->DriverBindingHandle,
194 Controller,
195 EFI_OPEN_PROTOCOL_BY_DRIVER
196 );
197
198 if (Status == EFI_ALREADY_STARTED) {
199 return EFI_SUCCESS;
200 } else if (!EFI_ERROR(Status)) {
201 //
202 // Check if RemainingDevicePath is NULL or the End of Device Path Node,
203 // if yes, return EFI_SUCCESS.
204 //
205 if ((RemainingDevicePath == NULL) || IsDevicePathEnd (RemainingDevicePath)) {
206 //
207 // Close protocol regardless of RemainingDevicePath validation
208 //
209 gBS->CloseProtocol (
210 Controller,
211 &gEfiExtScsiPassThruProtocolGuid,
212 This->DriverBindingHandle,
213 Controller
214 );
215 return EFI_SUCCESS;
216 } else {
217 //
218 // If RemainingDevicePath isn't the End of Device Path Node, check its validation
219 //
220 Status = ExtPassThru->GetTargetLun (ExtPassThru, RemainingDevicePath, &TargetId, &Lun);
221 //
222 // Close protocol regardless of RemainingDevicePath validation
223 //
224 gBS->CloseProtocol (
225 Controller,
226 &gEfiExtScsiPassThruProtocolGuid,
227 This->DriverBindingHandle,
228 Controller
229 );
230 if (!EFI_ERROR(Status)) {
231 return EFI_SUCCESS;
232 }
233 }
234 }
235
236 //
237 // Come here in 2 condition:
238 // 1. ExtPassThru doesn't exist.
239 // 2. ExtPassThru exists but RemainingDevicePath is invalid.
240 //
241 Status = gBS->OpenProtocol (
242 Controller,
243 &gEfiScsiPassThruProtocolGuid,
244 (VOID **)&PassThru,
245 This->DriverBindingHandle,
246 Controller,
247 EFI_OPEN_PROTOCOL_BY_DRIVER
248 );
249
250 if (Status == EFI_ALREADY_STARTED) {
251 return EFI_SUCCESS;
252 }
253
254 if (EFI_ERROR (Status)) {
255 return Status;
256 }
257
258 //
259 // Test RemainingDevicePath is valid or not.
260 //
261 if ((RemainingDevicePath != NULL) && !IsDevicePathEnd (RemainingDevicePath)) {
262 Status = PassThru->GetTargetLun (PassThru, RemainingDevicePath, &ScsiTargetId.ScsiId.Scsi, &Lun);
263 }
264
265 gBS->CloseProtocol (
266 Controller,
267 &gEfiScsiPassThruProtocolGuid,
268 This->DriverBindingHandle,
269 Controller
270 );
271 return Status;
272 }
273
274
275 /**
276 Start this driver on ControllerHandle.
277
278 This service is called by the EFI boot service ConnectController(). In order
279 to make drivers as small as possible, there are a few calling restrictions for
280 this service. ConnectController() must follow these calling restrictions. If
281 any other agent wishes to call Start() it must also follow these calling
282 restrictions.
283
284 @param This Protocol instance pointer.
285 @param ControllerHandle Handle of device to bind driver to
286 @param RemainingDevicePath Optional parameter use to pick a specific child
287 device to start.
288
289 @retval EFI_SUCCESS This driver is added to ControllerHandle
290 @retval EFI_ALREADY_STARTED This driver is already running on ControllerHandle
291 @retval other This driver does not support this device
292
293 **/
294 EFI_STATUS
295 EFIAPI
296 SCSIBusDriverBindingStart (
297 IN EFI_DRIVER_BINDING_PROTOCOL *This,
298 IN EFI_HANDLE Controller,
299 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
300 )
301 {
302 UINT64 Lun;
303 UINT8 *TargetId;
304 BOOLEAN ScanOtherPuns;
305 BOOLEAN FromFirstTarget;
306 BOOLEAN ExtScsiSupport;
307 EFI_STATUS Status;
308 EFI_STATUS DevicePathStatus;
309 EFI_STATUS PassThruStatus;
310 SCSI_BUS_DEVICE *ScsiBusDev;
311 SCSI_TARGET_ID ScsiTargetId;
312 EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
313 EFI_SCSI_PASS_THRU_PROTOCOL *ScsiInterface;
314 EFI_EXT_SCSI_PASS_THRU_PROTOCOL *ExtScsiInterface;
315 EFI_SCSI_BUS_PROTOCOL *BusIdentify;
316
317 TargetId = NULL;
318 ScanOtherPuns = TRUE;
319 FromFirstTarget = FALSE;
320 ExtScsiSupport = FALSE;
321 PassThruStatus = EFI_SUCCESS;
322
323 TargetId = &ScsiTargetId.ScsiId.ExtScsi[0];
324 SetMem (TargetId, TARGET_MAX_BYTES, 0xFF);
325
326 DevicePathStatus = gBS->OpenProtocol (
327 Controller,
328 &gEfiDevicePathProtocolGuid,
329 (VOID **) &ParentDevicePath,
330 This->DriverBindingHandle,
331 Controller,
332 EFI_OPEN_PROTOCOL_BY_DRIVER
333 );
334 if (EFI_ERROR (DevicePathStatus) && (DevicePathStatus != EFI_ALREADY_STARTED)) {
335 return DevicePathStatus;
336 }
337
338 //
339 // Report Status Code to indicate SCSI bus starts
340 //
341 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
342 EFI_PROGRESS_CODE,
343 (EFI_IO_BUS_SCSI | EFI_IOB_PC_INIT),
344 ParentDevicePath
345 );
346
347 //
348 // To keep backward compatibility, UEFI ExtPassThru Protocol is supported as well as
349 // EFI PassThru Protocol. From priority perspective, ExtPassThru Protocol is firstly
350 // tried to open on host controller handle. If fails, then PassThru Protocol is tried instead.
351 //
352 Status = gBS->OpenProtocol (
353 Controller,
354 &gEfiExtScsiPassThruProtocolGuid,
355 (VOID **) &ExtScsiInterface,
356 This->DriverBindingHandle,
357 Controller,
358 EFI_OPEN_PROTOCOL_BY_DRIVER
359 );
360 //
361 // Fail to open UEFI ExtendPassThru Protocol, then try to open EFI PassThru Protocol instead.
362 //
363 if (EFI_ERROR(Status) && (Status != EFI_ALREADY_STARTED)) {
364 Status = gBS->OpenProtocol (
365 Controller,
366 &gEfiScsiPassThruProtocolGuid,
367 (VOID **) &ScsiInterface,
368 This->DriverBindingHandle,
369 Controller,
370 EFI_OPEN_PROTOCOL_BY_DRIVER
371 );
372 //
373 // Fail to open EFI PassThru Protocol, Close the DevicePathProtocol if it is opened by this time.
374 //
375 if (EFI_ERROR (Status) && (Status != EFI_ALREADY_STARTED)) {
376 if (!EFI_ERROR(DevicePathStatus)) {
377 gBS->CloseProtocol (
378 Controller,
379 &gEfiDevicePathProtocolGuid,
380 This->DriverBindingHandle,
381 Controller
382 );
383 }
384 return Status;
385 }
386 } else {
387 //
388 // Succeed to open ExtPassThru Protocol, and meanwhile open PassThru Protocol
389 // with BY_DRIVER if it is also present on the handle. The intent is to prevent
390 // another SCSI Bus Driver to work on the same host handle.
391 //
392 ExtScsiSupport = TRUE;
393 PassThruStatus = gBS->OpenProtocol (
394 Controller,
395 &gEfiScsiPassThruProtocolGuid,
396 (VOID **) &ScsiInterface,
397 This->DriverBindingHandle,
398 Controller,
399 EFI_OPEN_PROTOCOL_BY_DRIVER
400 );
401 }
402
403 if (Status != EFI_ALREADY_STARTED) {
404 //
405 // Go through here means either ExtPassThru or PassThru Protocol is successfully opened
406 // on this handle for this time. Then construct Host controller private data.
407 //
408 ScsiBusDev = NULL;
409 ScsiBusDev = AllocateZeroPool(sizeof(SCSI_BUS_DEVICE));
410 if (ScsiBusDev == NULL) {
411 Status = EFI_OUT_OF_RESOURCES;
412 goto ErrorExit;
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 ScsiBusDev = SCSI_BUS_CONTROLLER_DEVICE_FROM_THIS (BusIdentify);
455 }
456
457 //
458 // Report Status Code to indicate detecting devices on bus
459 //
460 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
461 EFI_PROGRESS_CODE,
462 (EFI_IO_BUS_SCSI | EFI_IOB_PC_DETECT),
463 ParentDevicePath
464 );
465
466 Lun = 0;
467 if (RemainingDevicePath == NULL) {
468 //
469 // If RemainingDevicePath is NULL,
470 // must enumerate all SCSI devices anyway
471 //
472 FromFirstTarget = TRUE;
473 } else if (!IsDevicePathEnd (RemainingDevicePath)) {
474 //
475 // If RemainingDevicePath isn't the End of Device Path Node,
476 // only scan the specified device by RemainingDevicePath
477 //
478 if (ScsiBusDev->ExtScsiSupport) {
479 Status = ScsiBusDev->ExtScsiInterface->GetTargetLun (ScsiBusDev->ExtScsiInterface, RemainingDevicePath, &TargetId, &Lun);
480 } else {
481 Status = ScsiBusDev->ScsiInterface->GetTargetLun (ScsiBusDev->ScsiInterface, RemainingDevicePath, &ScsiTargetId.ScsiId.Scsi, &Lun);
482 }
483
484 if (EFI_ERROR (Status)) {
485 return Status;
486 }
487 } else {
488 //
489 // If RemainingDevicePath is the End of Device Path Node,
490 // skip enumerate any device and return EFI_SUCESSS
491 //
492 ScanOtherPuns = FALSE;
493 }
494
495 while(ScanOtherPuns) {
496 if (FromFirstTarget) {
497 //
498 // Remaining Device Path is NULL, scan all the possible Puns in the
499 // SCSI Channel.
500 //
501 if (ScsiBusDev->ExtScsiSupport) {
502 Status = ScsiBusDev->ExtScsiInterface->GetNextTargetLun (ScsiBusDev->ExtScsiInterface, &TargetId, &Lun);
503 } else {
504 Status = ScsiBusDev->ScsiInterface->GetNextDevice (ScsiBusDev->ScsiInterface, &ScsiTargetId.ScsiId.Scsi, &Lun);
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 // Avoid creating handle for the host adapter.
517 //
518 if (ScsiBusDev->ExtScsiSupport) {
519 if ((ScsiTargetId.ScsiId.Scsi) == ScsiBusDev->ExtScsiInterface->Mode->AdapterId) {
520 continue;
521 }
522 } else {
523 if ((ScsiTargetId.ScsiId.Scsi) == ScsiBusDev->ScsiInterface->Mode->AdapterId) {
524 continue;
525 }
526 }
527 //
528 // Scan for the scsi device, if it attaches to the scsi bus,
529 // then create handle and install scsi i/o protocol.
530 //
531 Status = ScsiScanCreateDevice (This, Controller, &ScsiTargetId, Lun, ScsiBusDev);
532 }
533 return EFI_SUCCESS;
534
535 ErrorExit:
536
537 if (ScsiBusDev != NULL) {
538 FreePool (ScsiBusDev);
539 }
540
541 if (ExtScsiSupport) {
542 gBS->CloseProtocol (
543 Controller,
544 &gEfiExtScsiPassThruProtocolGuid,
545 This->DriverBindingHandle,
546 Controller
547 );
548 if (!EFI_ERROR (PassThruStatus)) {
549 gBS->CloseProtocol (
550 Controller,
551 &gEfiScsiPassThruProtocolGuid,
552 This->DriverBindingHandle,
553 Controller
554 );
555 }
556 } else {
557 gBS->CloseProtocol (
558 Controller,
559 &gEfiScsiPassThruProtocolGuid,
560 This->DriverBindingHandle,
561 Controller
562 );
563 }
564 return Status;
565 }
566
567 /**
568 Stop this driver on ControllerHandle.
569
570 This service is called by the EFI boot service DisconnectController().
571 In order to make drivers as small as possible, there are a few calling
572 restrictions for this service. DisconnectController() must follow these
573 calling restrictions. If any other agent wishes to call Stop() it must also
574 follow these calling restrictions.
575
576 @param This Protocol instance pointer.
577 @param ControllerHandle Handle of device to stop driver on
578 @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of
579 children is zero stop the entire bus driver.
580 @param ChildHandleBuffer List of Child Handles to Stop.
581
582 @retval EFI_SUCCESS This driver is removed ControllerHandle
583 @retval other This driver was not removed from this device
584
585 **/
586 EFI_STATUS
587 EFIAPI
588 SCSIBusDriverBindingStop (
589 IN EFI_DRIVER_BINDING_PROTOCOL *This,
590 IN EFI_HANDLE Controller,
591 IN UINTN NumberOfChildren,
592 IN EFI_HANDLE *ChildHandleBuffer
593 )
594 {
595 EFI_STATUS Status;
596 BOOLEAN AllChildrenStopped;
597 UINTN Index;
598 EFI_SCSI_IO_PROTOCOL *ScsiIo;
599 SCSI_IO_DEV *ScsiIoDevice;
600 VOID *ScsiPassThru;
601 EFI_SCSI_BUS_PROTOCOL *Scsidentifier;
602 SCSI_BUS_DEVICE *ScsiBusDev;
603
604 if (NumberOfChildren == 0) {
605 //
606 // Get the SCSI_BUS_DEVICE
607 //
608 Status = gBS->OpenProtocol (
609 Controller,
610 &gEfiCallerIdGuid,
611 (VOID **) &Scsidentifier,
612 This->DriverBindingHandle,
613 Controller,
614 EFI_OPEN_PROTOCOL_GET_PROTOCOL
615 );
616
617 if (EFI_ERROR (Status)) {
618 return EFI_DEVICE_ERROR;
619 }
620
621 ScsiBusDev = SCSI_BUS_CONTROLLER_DEVICE_FROM_THIS (Scsidentifier);
622
623 //
624 // Uninstall SCSI Bus Protocol
625 //
626 gBS->UninstallProtocolInterface (
627 Controller,
628 &gEfiCallerIdGuid,
629 &ScsiBusDev->BusIdentify
630 );
631
632 //
633 // Close the bus driver
634 //
635 if (ScsiBusDev->ExtScsiSupport) {
636 //
637 // Close ExtPassThru Protocol from this controller handle
638 //
639 gBS->CloseProtocol (
640 Controller,
641 &gEfiExtScsiPassThruProtocolGuid,
642 This->DriverBindingHandle,
643 Controller
644 );
645 //
646 // When Start() succeeds to open ExtPassThru, it always tries to open PassThru BY_DRIVER.
647 // Its intent is to prevent another SCSI Bus Driver from woking on the same host handle.
648 // So Stop() needs to try to close PassThru if present here.
649 //
650 gBS->CloseProtocol (
651 Controller,
652 &gEfiScsiPassThruProtocolGuid,
653 This->DriverBindingHandle,
654 Controller
655 );
656 } else {
657 gBS->CloseProtocol (
658 Controller,
659 &gEfiScsiPassThruProtocolGuid,
660 This->DriverBindingHandle,
661 Controller
662 );
663 }
664
665 gBS->CloseProtocol (
666 Controller,
667 &gEfiDevicePathProtocolGuid,
668 This->DriverBindingHandle,
669 Controller
670 );
671 FreePool (ScsiBusDev);
672 return EFI_SUCCESS;
673 }
674
675 AllChildrenStopped = TRUE;
676
677 for (Index = 0; Index < NumberOfChildren; Index++) {
678
679 Status = gBS->OpenProtocol (
680 ChildHandleBuffer[Index],
681 &gEfiScsiIoProtocolGuid,
682 (VOID **) &ScsiIo,
683 This->DriverBindingHandle,
684 Controller,
685 EFI_OPEN_PROTOCOL_GET_PROTOCOL
686 );
687 if (EFI_ERROR (Status)) {
688 AllChildrenStopped = FALSE;
689 continue;
690 }
691
692 ScsiIoDevice = SCSI_IO_DEV_FROM_THIS (ScsiIo);
693 //
694 // Close the child handle
695 //
696 if (ScsiIoDevice->ExtScsiSupport) {
697 Status = gBS->CloseProtocol (
698 Controller,
699 &gEfiExtScsiPassThruProtocolGuid,
700 This->DriverBindingHandle,
701 ChildHandleBuffer[Index]
702 );
703
704 } else {
705 Status = gBS->CloseProtocol (
706 Controller,
707 &gEfiScsiPassThruProtocolGuid,
708 This->DriverBindingHandle,
709 ChildHandleBuffer[Index]
710 );
711 }
712
713 Status = gBS->UninstallMultipleProtocolInterfaces (
714 ChildHandleBuffer[Index],
715 &gEfiDevicePathProtocolGuid,
716 ScsiIoDevice->DevicePath,
717 &gEfiScsiIoProtocolGuid,
718 &ScsiIoDevice->ScsiIo,
719 NULL
720 );
721 if (EFI_ERROR (Status)) {
722 AllChildrenStopped = FALSE;
723 if (ScsiIoDevice->ExtScsiSupport) {
724 gBS->OpenProtocol (
725 Controller,
726 &gEfiExtScsiPassThruProtocolGuid,
727 &ScsiPassThru,
728 This->DriverBindingHandle,
729 ChildHandleBuffer[Index],
730 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
731 );
732 } else {
733 gBS->OpenProtocol (
734 Controller,
735 &gEfiScsiPassThruProtocolGuid,
736 &ScsiPassThru,
737 This->DriverBindingHandle,
738 ChildHandleBuffer[Index],
739 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
740 );
741 }
742 } else {
743 FreePool (ScsiIoDevice);
744 }
745 }
746
747 if (!AllChildrenStopped) {
748 return EFI_DEVICE_ERROR;
749 }
750
751 return EFI_SUCCESS;
752 }
753
754
755 /**
756 Retrieves the device type information of the SCSI Controller.
757
758 @param This Protocol instance pointer.
759 @param DeviceType A pointer to the device type information retrieved from
760 the SCSI Controller.
761
762 @retval EFI_SUCCESS Retrieves the device type information successfully.
763 @retval EFI_INVALID_PARAMETER The DeviceType is NULL.
764
765 **/
766 EFI_STATUS
767 EFIAPI
768 ScsiGetDeviceType (
769 IN EFI_SCSI_IO_PROTOCOL *This,
770 OUT UINT8 *DeviceType
771 )
772 {
773 SCSI_IO_DEV *ScsiIoDevice;
774
775 if (DeviceType == NULL) {
776 return EFI_INVALID_PARAMETER;
777 }
778
779 ScsiIoDevice = SCSI_IO_DEV_FROM_THIS (This);
780 *DeviceType = ScsiIoDevice->ScsiDeviceType;
781 return EFI_SUCCESS;
782 }
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 /**
861 Resets the SCSI Controller that the device handle specifies.
862
863 @param This Protocol instance pointer.
864
865 @retval EFI_SUCCESS Reset the SCSI controller successfully.
866 @retval EFI_DEVICE_ERROR Errors are encountered when resetting the SCSI Controller.
867 @retval EFI_UNSUPPORTED The SCSI bus does not support a device reset operation.
868 @retval EFI_TIMEOUT A timeout occurred while attempting to reset the
869 SCSI Controller.
870 **/
871 EFI_STATUS
872 EFIAPI
873 ScsiResetDevice (
874 IN EFI_SCSI_IO_PROTOCOL *This
875 )
876 {
877 SCSI_IO_DEV *ScsiIoDevice;
878 UINT8 Target[TARGET_MAX_BYTES];
879
880 ScsiIoDevice = SCSI_IO_DEV_FROM_THIS (This);
881
882 //
883 // Report Status Code to indicate reset happens
884 //
885 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
886 EFI_PROGRESS_CODE,
887 (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_PC_RESET),
888 ScsiIoDevice->ScsiBusDeviceData->DevicePath
889 );
890
891 CopyMem (Target,&ScsiIoDevice->Pun, TARGET_MAX_BYTES);
892
893
894 if (ScsiIoDevice->ExtScsiSupport) {
895 return ScsiIoDevice->ExtScsiPassThru->ResetTargetLun (
896 ScsiIoDevice->ExtScsiPassThru,
897 Target,
898 ScsiIoDevice->Lun
899 );
900 } else {
901 return ScsiIoDevice->ScsiPassThru->ResetTarget (
902 ScsiIoDevice->ScsiPassThru,
903 ScsiIoDevice->Pun.ScsiId.Scsi,
904 ScsiIoDevice->Lun
905 );
906 }
907 }
908
909
910 /**
911 Sends a SCSI Request Packet to the SCSI Controller for execution.
912
913 @param This Protocol instance pointer.
914 @param CommandPacket The SCSI request packet to send to the SCSI
915 Controller specified by the device handle.
916 @param Event If the SCSI bus where the SCSI device is attached
917 does not support non-blocking I/O, then Event is
918 ignored, and blocking I/O is performed.
919 If Event is NULL, then blocking I/O is performed.
920 If Event is not NULL and non-blocking I/O is
921 supported, then non-blocking I/O is performed,
922 and Event will be signaled when the SCSI Request
923 Packet completes.
924
925 @retval EFI_SUCCESS The SCSI Request Packet was sent by the host
926 successfully, and TransferLength bytes were
927 transferred to/from DataBuffer.See
928 HostAdapterStatus, TargetStatus,
929 SenseDataLength, and SenseData in that order
930 for additional status information.
931 @retval EFI_BAD_BUFFER_SIZE The SCSI Request Packet was executed,
932 but the entire DataBuffer could not be transferred.
933 The actual number of bytes transferred is returned
934 in TransferLength. See HostAdapterStatus,
935 TargetStatus, SenseDataLength, and SenseData in
936 that order for additional status information.
937 @retval EFI_NOT_READY The SCSI Request Packet could not be sent because
938 there are too many SCSI Command Packets already
939 queued.The caller may retry again later.
940 @retval EFI_DEVICE_ERROR A device error occurred while attempting to send
941 the SCSI Request Packet. See HostAdapterStatus,
942 TargetStatus, SenseDataLength, and SenseData in
943 that order for additional status information.
944 @retval EFI_INVALID_PARAMETER The contents of CommandPacket are invalid.
945 The SCSI Request Packet was not sent, so no
946 additional status information is available.
947 @retval EFI_UNSUPPORTED The command described by the SCSI Request Packet
948 is not supported by the SCSI initiator(i.e., SCSI
949 Host Controller). The SCSI Request Packet was not
950 sent, so no additional status information is
951 available.
952 @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI
953 Request Packet to execute. See HostAdapterStatus,
954 TargetStatus, SenseDataLength, and SenseData in
955 that order for additional status information.
956 **/
957 EFI_STATUS
958 EFIAPI
959 ScsiExecuteSCSICommand (
960 IN EFI_SCSI_IO_PROTOCOL *This,
961 IN OUT EFI_SCSI_IO_SCSI_REQUEST_PACKET *Packet,
962 IN EFI_EVENT Event OPTIONAL
963 )
964 {
965 SCSI_IO_DEV *ScsiIoDevice;
966 EFI_STATUS Status;
967 UINT8 Target[TARGET_MAX_BYTES];
968 EFI_EVENT PacketEvent;
969 EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *ExtRequestPacket;
970 SCSI_EVENT_DATA EventData;
971
972 PacketEvent = NULL;
973
974 if (Packet == NULL) {
975 return EFI_INVALID_PARAMETER;
976 }
977
978 ScsiIoDevice = SCSI_IO_DEV_FROM_THIS (This);
979 CopyMem (Target,&ScsiIoDevice->Pun, TARGET_MAX_BYTES);
980
981 if (ScsiIoDevice->ExtScsiSupport) {
982 ExtRequestPacket = (EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *) Packet;
983
984 if (((ScsiIoDevice->ExtScsiPassThru->Mode->Attributes & EFI_SCSI_PASS_THRU_ATTRIBUTES_NONBLOCKIO) != 0) && (Event != NULL)) {
985 Status = ScsiIoDevice->ExtScsiPassThru->PassThru (
986 ScsiIoDevice->ExtScsiPassThru,
987 Target,
988 ScsiIoDevice->Lun,
989 ExtRequestPacket,
990 Event
991 );
992 } else {
993 //
994 // If there's no event or the SCSI Device doesn't support NON-BLOCKING,
995 // let the 'Event' parameter for PassThru() be NULL.
996 //
997 Status = ScsiIoDevice->ExtScsiPassThru->PassThru (
998 ScsiIoDevice->ExtScsiPassThru,
999 Target,
1000 ScsiIoDevice->Lun,
1001 ExtRequestPacket,
1002 NULL
1003 );
1004 if ((!EFI_ERROR(Status)) && (Event != NULL)) {
1005 //
1006 // Signal Event to tell caller to pick up the SCSI IO packet if the
1007 // PassThru() succeeds.
1008 //
1009 gBS->SignalEvent (Event);
1010 }
1011 }
1012 } else {
1013
1014 mWorkingBuffer = AllocatePool (sizeof(EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET));
1015
1016 if (mWorkingBuffer == NULL) {
1017 return EFI_DEVICE_ERROR;
1018 }
1019
1020 //
1021 // Convert package into EFI1.0, EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET.
1022 //
1023 Status = ScsiioToPassThruPacket(Packet, (EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET*)mWorkingBuffer);
1024 if (EFI_ERROR(Status)) {
1025 FreePool(mWorkingBuffer);
1026 return Status;
1027 }
1028
1029 if (((ScsiIoDevice->ScsiPassThru->Mode->Attributes & EFI_SCSI_PASS_THRU_ATTRIBUTES_NONBLOCKIO) != 0) && (Event != NULL)) {
1030 EventData.Data1 = (VOID*)Packet;
1031 EventData.Data2 = Event;
1032 //
1033 // Create Event
1034 //
1035 Status = gBS->CreateEvent (
1036 EVT_NOTIFY_SIGNAL,
1037 TPL_NOTIFY,
1038 NotifyFunction,
1039 &EventData,
1040 &PacketEvent
1041 );
1042 if (EFI_ERROR(Status)) {
1043 FreePool(mWorkingBuffer);
1044 return Status;
1045 }
1046
1047 Status = ScsiIoDevice->ScsiPassThru->PassThru (
1048 ScsiIoDevice->ScsiPassThru,
1049 ScsiIoDevice->Pun.ScsiId.Scsi,
1050 ScsiIoDevice->Lun,
1051 mWorkingBuffer,
1052 PacketEvent
1053 );
1054
1055 if (EFI_ERROR(Status)) {
1056 FreePool(mWorkingBuffer);
1057 gBS->CloseEvent(PacketEvent);
1058 return Status;
1059 }
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 return Status;
1094 }
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 Tartget 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_OUT_OF_RESOURCES Fail to discover the device.
1109
1110 **/
1111 EFI_STATUS
1112 EFIAPI
1113 ScsiScanCreateDevice (
1114 IN EFI_DRIVER_BINDING_PROTOCOL *This,
1115 IN EFI_HANDLE Controller,
1116 IN SCSI_TARGET_ID *TargetId,
1117 IN UINT64 Lun,
1118 IN OUT SCSI_BUS_DEVICE *ScsiBusDev
1119 )
1120 {
1121 EFI_STATUS Status;
1122 SCSI_IO_DEV *ScsiIoDevice;
1123 EFI_DEVICE_PATH_PROTOCOL *ScsiDevicePath;
1124 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
1125 EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath;
1126 EFI_HANDLE DeviceHandle;
1127
1128 DevicePath = NULL;
1129 RemainingDevicePath = NULL;
1130 ScsiDevicePath = NULL;
1131 ScsiIoDevice = NULL;
1132
1133 //
1134 // Build Device Path
1135 //
1136 if (ScsiBusDev->ExtScsiSupport){
1137 Status = ScsiBusDev->ExtScsiInterface->BuildDevicePath (
1138 ScsiBusDev->ExtScsiInterface,
1139 &TargetId->ScsiId.ExtScsi[0],
1140 Lun,
1141 &ScsiDevicePath
1142 );
1143 } else {
1144 Status = ScsiBusDev->ScsiInterface->BuildDevicePath (
1145 ScsiBusDev->ScsiInterface,
1146 TargetId->ScsiId.Scsi,
1147 Lun,
1148 &ScsiDevicePath
1149 );
1150 }
1151
1152 if (EFI_ERROR(Status)) {
1153 return Status;
1154 }
1155
1156 DevicePath = AppendDevicePathNode (
1157 ScsiBusDev->DevicePath,
1158 ScsiDevicePath
1159 );
1160
1161 if (DevicePath == NULL) {
1162 Status = EFI_OUT_OF_RESOURCES;
1163 goto ErrorExit;
1164 }
1165
1166 DeviceHandle = NULL;
1167 RemainingDevicePath = DevicePath;
1168 Status = gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid, &RemainingDevicePath, &DeviceHandle);
1169 if (!EFI_ERROR (Status) && (DeviceHandle != NULL) && IsDevicePathEnd(RemainingDevicePath)) {
1170 //
1171 // The device has been started, directly return to fast boot.
1172 //
1173 Status = EFI_ALREADY_STARTED;
1174 goto ErrorExit;
1175 }
1176
1177 ScsiIoDevice = AllocateZeroPool (sizeof (SCSI_IO_DEV));
1178 if (ScsiIoDevice == NULL) {
1179 Status = EFI_OUT_OF_RESOURCES;
1180 goto ErrorExit;
1181 }
1182
1183 ScsiIoDevice->Signature = SCSI_IO_DEV_SIGNATURE;
1184 ScsiIoDevice->ScsiBusDeviceData = ScsiBusDev;
1185 CopyMem(&ScsiIoDevice->Pun, TargetId, TARGET_MAX_BYTES);
1186 ScsiIoDevice->Lun = Lun;
1187
1188 if (ScsiBusDev->ExtScsiSupport) {
1189 ScsiIoDevice->ExtScsiPassThru = ScsiBusDev->ExtScsiInterface;
1190 ScsiIoDevice->ExtScsiSupport = TRUE;
1191 ScsiIoDevice->ScsiIo.IoAlign = ScsiIoDevice->ExtScsiPassThru->Mode->IoAlign;
1192
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 if (!DiscoverScsiDevice (ScsiIoDevice)) {
1215 Status = EFI_OUT_OF_RESOURCES;
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 return EFI_SUCCESS;
1253
1254 ErrorExit:
1255
1256 //
1257 // The memory space for ScsiDevicePath is allocated in
1258 // ScsiPassThru->BuildDevicePath() function; It is no longer used
1259 // after AppendDevicePathNode,so free the memory it occupies.
1260 //
1261 FreePool (ScsiDevicePath);
1262
1263 if (DevicePath != NULL) {
1264 FreePool (DevicePath);
1265 }
1266
1267 if (ScsiIoDevice != NULL) {
1268 FreePool (ScsiIoDevice);
1269 }
1270
1271 return Status;
1272 }
1273
1274
1275 /**
1276 Discovery SCSI Device
1277
1278 @param ScsiIoDevice The pointer of SCSI_IO_DEV
1279
1280 @retval TRUE Find SCSI Device and verify it.
1281 @retval FALSE Unable to find SCSI Device.
1282
1283 **/
1284 BOOLEAN
1285 DiscoverScsiDevice (
1286 IN OUT SCSI_IO_DEV *ScsiIoDevice
1287 )
1288 {
1289 EFI_STATUS Status;
1290 UINT32 InquiryDataLength;
1291 UINT8 SenseDataLength;
1292 UINT8 HostAdapterStatus;
1293 UINT8 TargetStatus;
1294 EFI_SCSI_INQUIRY_DATA *InquiryData;
1295 EFI_SCSI_SENSE_DATA *SenseData;
1296 UINT8 MaxRetry;
1297 UINT8 Index;
1298 BOOLEAN ScsiDeviceFound;
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 ScsiDeviceFound = FALSE;
1307 goto Done;
1308 }
1309
1310 SenseData = AllocateAlignedBuffer (
1311 ScsiIoDevice,
1312 sizeof (EFI_SCSI_SENSE_DATA)
1313 );
1314 if (SenseData == NULL) {
1315 ScsiDeviceFound = FALSE;
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 ScsiDeviceFound = FALSE;
1346 goto Done;
1347 }
1348 break;
1349 }
1350 if ((Status == EFI_BAD_BUFFER_SIZE) ||
1351 (Status == EFI_INVALID_PARAMETER) ||
1352 (Status == EFI_UNSUPPORTED)) {
1353 ScsiDeviceFound = FALSE;
1354 goto Done;
1355 }
1356 }
1357
1358 if (Index == MaxRetry) {
1359 ScsiDeviceFound = FALSE;
1360 goto Done;
1361 }
1362
1363 //
1364 // Retrieved inquiry data successfully
1365 //
1366 if (InquiryData->Peripheral_Qualifier != 0) {
1367 ScsiDeviceFound = FALSE;
1368 goto Done;
1369 }
1370
1371 if (0x1e >= InquiryData->Peripheral_Type && InquiryData->Peripheral_Type >= 0xa) {
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 /**
1401 Convert EFI_SCSI_IO_SCSI_REQUEST_PACKET packet to EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET packet.
1402
1403 @param Packet The pointer of EFI_SCSI_IO_SCSI_REQUEST_PACKET
1404 @param CommandPacket The pointer of EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
1405
1406 **/
1407 EFI_STATUS
1408 EFIAPI
1409 ScsiioToPassThruPacket (
1410 IN EFI_SCSI_IO_SCSI_REQUEST_PACKET *Packet,
1411 OUT EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *CommandPacket
1412 )
1413 {
1414 //
1415 //EFI 1.10 doesn't support Bi-Direction Command.
1416 //
1417 if (Packet->DataDirection == EFI_SCSI_IO_DATA_DIRECTION_BIDIRECTIONAL) {
1418 return EFI_UNSUPPORTED;
1419 }
1420
1421 ZeroMem (CommandPacket, sizeof (EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET));
1422
1423 CommandPacket->Timeout = Packet->Timeout;
1424 CommandPacket->Cdb = Packet->Cdb;
1425 CommandPacket->CdbLength = Packet->CdbLength;
1426 CommandPacket->DataDirection = Packet->DataDirection;
1427 CommandPacket->HostAdapterStatus = Packet->HostAdapterStatus;
1428 CommandPacket->TargetStatus = Packet->TargetStatus;
1429 CommandPacket->SenseData = Packet->SenseData;
1430 CommandPacket->SenseDataLength = Packet->SenseDataLength;
1431
1432 if (Packet->DataDirection == EFI_SCSI_IO_DATA_DIRECTION_READ) {
1433 CommandPacket->DataBuffer = Packet->InDataBuffer;
1434 CommandPacket->TransferLength = Packet->InTransferLength;
1435 } else if (Packet->DataDirection == EFI_SCSI_IO_DATA_DIRECTION_WRITE) {
1436 CommandPacket->DataBuffer = Packet->OutDataBuffer;
1437 CommandPacket->TransferLength = Packet->OutTransferLength;
1438 }
1439 return EFI_SUCCESS;
1440 }
1441
1442
1443 /**
1444 Convert EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET packet to EFI_SCSI_IO_SCSI_REQUEST_PACKET packet.
1445
1446 @param ScsiPacket The pointer of EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
1447 @param Packet The pointer of EFI_SCSI_IO_SCSI_REQUEST_PACKET
1448
1449 **/
1450 EFI_STATUS
1451 EFIAPI
1452 PassThruToScsiioPacket (
1453 IN EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *ScsiPacket,
1454 OUT EFI_SCSI_IO_SCSI_REQUEST_PACKET *Packet
1455 )
1456 {
1457 Packet->Timeout = ScsiPacket->Timeout;
1458 Packet->Cdb = ScsiPacket->Cdb;
1459 Packet->CdbLength = ScsiPacket->CdbLength;
1460 Packet->DataDirection = ScsiPacket->DataDirection;
1461 Packet->HostAdapterStatus = ScsiPacket->HostAdapterStatus;
1462 Packet->TargetStatus = ScsiPacket->TargetStatus;
1463 Packet->SenseData = ScsiPacket->SenseData;
1464 Packet->SenseDataLength = ScsiPacket->SenseDataLength;
1465
1466 if (ScsiPacket->DataDirection == EFI_SCSI_IO_DATA_DIRECTION_READ) {
1467 Packet->InDataBuffer = ScsiPacket->DataBuffer;
1468 Packet->InTransferLength = ScsiPacket->TransferLength;
1469 } else if (Packet->DataDirection == EFI_SCSI_IO_DATA_DIRECTION_WRITE) {
1470 Packet->OutDataBuffer = ScsiPacket->DataBuffer;
1471 Packet->OutTransferLength = ScsiPacket->TransferLength;
1472 }
1473
1474 return EFI_SUCCESS;
1475 }
1476
1477 /**
1478 Notify Function in which convert EFI1.0 PassThru Packet back to UEF2.0
1479 SCSI IO Packet.
1480
1481 @param Event The instance of EFI_EVENT.
1482 @param Context The parameter passed in.
1483
1484 **/
1485 VOID
1486 EFIAPI
1487 NotifyFunction (
1488 IN EFI_EVENT Event,
1489 IN VOID *Context
1490 )
1491 {
1492 EFI_SCSI_IO_SCSI_REQUEST_PACKET *Packet;
1493 EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *ScsiPacket;
1494 EFI_EVENT CallerEvent;
1495 SCSI_EVENT_DATA *PassData;
1496
1497 PassData = (SCSI_EVENT_DATA*)Context;
1498 Packet = (EFI_SCSI_IO_SCSI_REQUEST_PACKET *)PassData->Data1;
1499 ScsiPacket = (EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET*)mWorkingBuffer;
1500
1501 //
1502 // Convert EFI1.0 PassThru packet to UEFI2.0 SCSI IO Packet.
1503 //
1504 PassThruToScsiioPacket(ScsiPacket, Packet);
1505
1506 //
1507 // After converting EFI1.0 PassThru Packet back to UEFI2.0 SCSI IO Packet,
1508 // free mWorkingBuffer.
1509 //
1510 gBS->FreePool(mWorkingBuffer);
1511
1512 //
1513 // Signal Event to tell caller to pick up UEFI2.0 SCSI IO Packet.
1514 //
1515 CallerEvent = PassData->Data2;
1516 gBS->CloseEvent(Event);
1517 gBS->SignalEvent(CallerEvent);
1518 }
1519