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