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