]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Bus/Scsi/ScsiBusDxe/ScsiBus.c
Allocate aligned buffer to satisfy the IoAlign requirement of high level protocol.
[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 - 2011, 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 // To keep backward compatibility, UEFI ExtPassThru Protocol is supported as well as
346 // EFI PassThru Protocol. From priority perspective, ExtPassThru Protocol is firstly
347 // tried to open on host controller handle. If fails, then PassThru Protocol is tried instead.
348 //
349 Status = gBS->OpenProtocol (
350 Controller,
351 &gEfiExtScsiPassThruProtocolGuid,
352 (VOID **) &ExtScsiInterface,
353 This->DriverBindingHandle,
354 Controller,
355 EFI_OPEN_PROTOCOL_BY_DRIVER
356 );
357 //
358 // Fail to open UEFI ExtendPassThru Protocol, then try to open EFI PassThru Protocol instead.
359 //
360 if (EFI_ERROR(Status) && (Status != EFI_ALREADY_STARTED)) {
361 Status = gBS->OpenProtocol (
362 Controller,
363 &gEfiScsiPassThruProtocolGuid,
364 (VOID **) &ScsiInterface,
365 This->DriverBindingHandle,
366 Controller,
367 EFI_OPEN_PROTOCOL_BY_DRIVER
368 );
369 //
370 // Fail to open EFI PassThru Protocol, Close the DevicePathProtocol if it is opened by this time.
371 //
372 if (EFI_ERROR (Status) && (Status != EFI_ALREADY_STARTED)) {
373 if (!EFI_ERROR(DevicePathStatus)) {
374 gBS->CloseProtocol (
375 Controller,
376 &gEfiDevicePathProtocolGuid,
377 This->DriverBindingHandle,
378 Controller
379 );
380 }
381 return Status;
382 }
383 } else {
384 //
385 // Succeed to open ExtPassThru Protocol, and meanwhile open PassThru Protocol
386 // with BY_DRIVER if it is also present on the handle. The intent is to prevent
387 // another SCSI Bus Driver to work on the same host handle.
388 //
389 ExtScsiSupport = TRUE;
390 PassThruStatus = gBS->OpenProtocol (
391 Controller,
392 &gEfiScsiPassThruProtocolGuid,
393 (VOID **) &ScsiInterface,
394 This->DriverBindingHandle,
395 Controller,
396 EFI_OPEN_PROTOCOL_BY_DRIVER
397 );
398 }
399
400 if (Status != EFI_ALREADY_STARTED) {
401 //
402 // Go through here means either ExtPassThru or PassThru Protocol is successfully opened
403 // on this handle for this time. Then construct Host controller private data.
404 //
405 ScsiBusDev = NULL;
406 ScsiBusDev = AllocateZeroPool(sizeof(SCSI_BUS_DEVICE));
407 if (ScsiBusDev == NULL) {
408 Status = EFI_OUT_OF_RESOURCES;
409 goto ErrorExit;
410 }
411 ScsiBusDev->Signature = SCSI_BUS_DEVICE_SIGNATURE;
412 ScsiBusDev->ExtScsiSupport = ExtScsiSupport;
413 ScsiBusDev->DevicePath = ParentDevicePath;
414 if (ScsiBusDev->ExtScsiSupport) {
415 ScsiBusDev->ExtScsiInterface = ExtScsiInterface;
416 } else {
417 ScsiBusDev->ScsiInterface = ScsiInterface;
418 }
419
420 //
421 // Install EFI_SCSI_BUS_PROTOCOL to the controller handle, So ScsiBusDev could be
422 // retrieved on this controller handle. With ScsiBusDev, we can know which PassThru
423 // Protocol is present on the handle, UEFI ExtPassThru Protocol or EFI PassThru Protocol.
424 //
425 Status = gBS->InstallProtocolInterface (
426 &Controller,
427 &gEfiCallerIdGuid,
428 EFI_NATIVE_INTERFACE,
429 &ScsiBusDev->BusIdentify
430 );
431 if (EFI_ERROR (Status)) {
432 goto ErrorExit;
433 }
434 } else {
435 //
436 // Go through here means Start() is re-invoked again, nothing special is required to do except
437 // picking up Host controller private information.
438 //
439 Status = gBS->OpenProtocol (
440 Controller,
441 &gEfiCallerIdGuid,
442 (VOID **) &BusIdentify,
443 This->DriverBindingHandle,
444 Controller,
445 EFI_OPEN_PROTOCOL_GET_PROTOCOL
446 );
447
448 if (EFI_ERROR (Status)) {
449 return Status;
450 }
451 ScsiBusDev = SCSI_BUS_CONTROLLER_DEVICE_FROM_THIS (BusIdentify);
452 }
453
454 Lun = 0;
455 if (RemainingDevicePath == NULL) {
456 //
457 // If RemainingDevicePath is NULL,
458 // must enumerate all SCSI devices anyway
459 //
460 FromFirstTarget = TRUE;
461 } else if (!IsDevicePathEnd (RemainingDevicePath)) {
462 //
463 // If RemainingDevicePath isn't the End of Device Path Node,
464 // only scan the specified device by RemainingDevicePath
465 //
466 if (ScsiBusDev->ExtScsiSupport) {
467 Status = ScsiBusDev->ExtScsiInterface->GetTargetLun (ScsiBusDev->ExtScsiInterface, RemainingDevicePath, &TargetId, &Lun);
468 } else {
469 Status = ScsiBusDev->ScsiInterface->GetTargetLun (ScsiBusDev->ScsiInterface, RemainingDevicePath, &ScsiTargetId.ScsiId.Scsi, &Lun);
470 }
471
472 if (EFI_ERROR (Status)) {
473 return Status;
474 }
475 } else {
476 //
477 // If RemainingDevicePath is the End of Device Path Node,
478 // skip enumerate any device and return EFI_SUCESSS
479 //
480 ScanOtherPuns = FALSE;
481 }
482
483 while(ScanOtherPuns) {
484 if (FromFirstTarget) {
485 //
486 // Remaining Device Path is NULL, scan all the possible Puns in the
487 // SCSI Channel.
488 //
489 if (ScsiBusDev->ExtScsiSupport) {
490 Status = ScsiBusDev->ExtScsiInterface->GetNextTargetLun (ScsiBusDev->ExtScsiInterface, &TargetId, &Lun);
491 } else {
492 Status = ScsiBusDev->ScsiInterface->GetNextDevice (ScsiBusDev->ScsiInterface, &ScsiTargetId.ScsiId.Scsi, &Lun);
493 }
494 if (EFI_ERROR (Status)) {
495 //
496 // no legal Pun and Lun found any more
497 //
498 break;
499 }
500 } else {
501 ScanOtherPuns = FALSE;
502 }
503 //
504 // Avoid creating handle for the host adapter.
505 //
506 if (ScsiBusDev->ExtScsiSupport) {
507 if ((ScsiTargetId.ScsiId.Scsi) == ScsiBusDev->ExtScsiInterface->Mode->AdapterId) {
508 continue;
509 }
510 } else {
511 if ((ScsiTargetId.ScsiId.Scsi) == ScsiBusDev->ScsiInterface->Mode->AdapterId) {
512 continue;
513 }
514 }
515 //
516 // Scan for the scsi device, if it attaches to the scsi bus,
517 // then create handle and install scsi i/o protocol.
518 //
519 Status = ScsiScanCreateDevice (This, Controller, &ScsiTargetId, Lun, ScsiBusDev);
520 }
521 return EFI_SUCCESS;
522
523 ErrorExit:
524
525 if (ScsiBusDev != NULL) {
526 FreePool (ScsiBusDev);
527 }
528
529 if (ExtScsiSupport) {
530 gBS->CloseProtocol (
531 Controller,
532 &gEfiExtScsiPassThruProtocolGuid,
533 This->DriverBindingHandle,
534 Controller
535 );
536 if (!EFI_ERROR (PassThruStatus)) {
537 gBS->CloseProtocol (
538 Controller,
539 &gEfiScsiPassThruProtocolGuid,
540 This->DriverBindingHandle,
541 Controller
542 );
543 }
544 } else {
545 gBS->CloseProtocol (
546 Controller,
547 &gEfiScsiPassThruProtocolGuid,
548 This->DriverBindingHandle,
549 Controller
550 );
551 }
552 return Status;
553 }
554
555 /**
556 Stop this driver on ControllerHandle.
557
558 This service is called by the EFI boot service DisconnectController().
559 In order to make drivers as small as possible, there are a few calling
560 restrictions for this service. DisconnectController() must follow these
561 calling restrictions. If any other agent wishes to call Stop() it must also
562 follow these calling restrictions.
563
564 @param This Protocol instance pointer.
565 @param ControllerHandle Handle of device to stop driver on
566 @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of
567 children is zero stop the entire bus driver.
568 @param ChildHandleBuffer List of Child Handles to Stop.
569
570 @retval EFI_SUCCESS This driver is removed ControllerHandle
571 @retval other This driver was not removed from this device
572
573 **/
574 EFI_STATUS
575 EFIAPI
576 SCSIBusDriverBindingStop (
577 IN EFI_DRIVER_BINDING_PROTOCOL *This,
578 IN EFI_HANDLE Controller,
579 IN UINTN NumberOfChildren,
580 IN EFI_HANDLE *ChildHandleBuffer
581 )
582 {
583 EFI_STATUS Status;
584 BOOLEAN AllChildrenStopped;
585 UINTN Index;
586 EFI_SCSI_IO_PROTOCOL *ScsiIo;
587 SCSI_IO_DEV *ScsiIoDevice;
588 VOID *ScsiPassThru;
589 EFI_SCSI_BUS_PROTOCOL *Scsidentifier;
590 SCSI_BUS_DEVICE *ScsiBusDev;
591
592 if (NumberOfChildren == 0) {
593 //
594 // Get the SCSI_BUS_DEVICE
595 //
596 Status = gBS->OpenProtocol (
597 Controller,
598 &gEfiCallerIdGuid,
599 (VOID **) &Scsidentifier,
600 This->DriverBindingHandle,
601 Controller,
602 EFI_OPEN_PROTOCOL_GET_PROTOCOL
603 );
604
605 if (EFI_ERROR (Status)) {
606 return EFI_DEVICE_ERROR;
607 }
608
609 ScsiBusDev = SCSI_BUS_CONTROLLER_DEVICE_FROM_THIS (Scsidentifier);
610
611 //
612 // Uninstall SCSI Bus Protocol
613 //
614 gBS->UninstallProtocolInterface (
615 Controller,
616 &gEfiCallerIdGuid,
617 &ScsiBusDev->BusIdentify
618 );
619
620 //
621 // Close the bus driver
622 //
623 if (ScsiBusDev->ExtScsiSupport) {
624 //
625 // Close ExtPassThru Protocol from this controller handle
626 //
627 gBS->CloseProtocol (
628 Controller,
629 &gEfiExtScsiPassThruProtocolGuid,
630 This->DriverBindingHandle,
631 Controller
632 );
633 //
634 // When Start() succeeds to open ExtPassThru, it always tries to open PassThru BY_DRIVER.
635 // Its intent is to prevent another SCSI Bus Driver from woking on the same host handle.
636 // So Stop() needs to try to close PassThru if present here.
637 //
638 gBS->CloseProtocol (
639 Controller,
640 &gEfiScsiPassThruProtocolGuid,
641 This->DriverBindingHandle,
642 Controller
643 );
644 } else {
645 gBS->CloseProtocol (
646 Controller,
647 &gEfiScsiPassThruProtocolGuid,
648 This->DriverBindingHandle,
649 Controller
650 );
651 }
652
653 gBS->CloseProtocol (
654 Controller,
655 &gEfiDevicePathProtocolGuid,
656 This->DriverBindingHandle,
657 Controller
658 );
659 FreePool (ScsiBusDev);
660 return EFI_SUCCESS;
661 }
662
663 AllChildrenStopped = TRUE;
664
665 for (Index = 0; Index < NumberOfChildren; Index++) {
666
667 Status = gBS->OpenProtocol (
668 ChildHandleBuffer[Index],
669 &gEfiScsiIoProtocolGuid,
670 (VOID **) &ScsiIo,
671 This->DriverBindingHandle,
672 Controller,
673 EFI_OPEN_PROTOCOL_GET_PROTOCOL
674 );
675 if (EFI_ERROR (Status)) {
676 AllChildrenStopped = FALSE;
677 continue;
678 }
679
680 ScsiIoDevice = SCSI_IO_DEV_FROM_THIS (ScsiIo);
681 //
682 // Close the child handle
683 //
684 if (ScsiIoDevice->ExtScsiSupport) {
685 Status = gBS->CloseProtocol (
686 Controller,
687 &gEfiExtScsiPassThruProtocolGuid,
688 This->DriverBindingHandle,
689 ChildHandleBuffer[Index]
690 );
691
692 } else {
693 Status = gBS->CloseProtocol (
694 Controller,
695 &gEfiScsiPassThruProtocolGuid,
696 This->DriverBindingHandle,
697 ChildHandleBuffer[Index]
698 );
699 }
700
701 Status = gBS->UninstallMultipleProtocolInterfaces (
702 ChildHandleBuffer[Index],
703 &gEfiDevicePathProtocolGuid,
704 ScsiIoDevice->DevicePath,
705 &gEfiScsiIoProtocolGuid,
706 &ScsiIoDevice->ScsiIo,
707 NULL
708 );
709 if (EFI_ERROR (Status)) {
710 AllChildrenStopped = FALSE;
711 if (ScsiIoDevice->ExtScsiSupport) {
712 gBS->OpenProtocol (
713 Controller,
714 &gEfiExtScsiPassThruProtocolGuid,
715 &ScsiPassThru,
716 This->DriverBindingHandle,
717 ChildHandleBuffer[Index],
718 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
719 );
720 } else {
721 gBS->OpenProtocol (
722 Controller,
723 &gEfiScsiPassThruProtocolGuid,
724 &ScsiPassThru,
725 This->DriverBindingHandle,
726 ChildHandleBuffer[Index],
727 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
728 );
729 }
730 } else {
731 FreePool (ScsiIoDevice);
732 }
733 }
734
735 if (!AllChildrenStopped) {
736 return EFI_DEVICE_ERROR;
737 }
738
739 return EFI_SUCCESS;
740 }
741
742
743 /**
744 Retrieves the device type information of the SCSI Controller.
745
746 @param This Protocol instance pointer.
747 @param DeviceType A pointer to the device type information retrieved from
748 the SCSI Controller.
749
750 @retval EFI_SUCCESS Retrieves the device type information successfully.
751 @retval EFI_INVALID_PARAMETER The DeviceType is NULL.
752
753 **/
754 EFI_STATUS
755 EFIAPI
756 ScsiGetDeviceType (
757 IN EFI_SCSI_IO_PROTOCOL *This,
758 OUT UINT8 *DeviceType
759 )
760 {
761 SCSI_IO_DEV *ScsiIoDevice;
762
763 if (DeviceType == NULL) {
764 return EFI_INVALID_PARAMETER;
765 }
766
767 ScsiIoDevice = SCSI_IO_DEV_FROM_THIS (This);
768 *DeviceType = ScsiIoDevice->ScsiDeviceType;
769 return EFI_SUCCESS;
770 }
771
772
773 /**
774 Retrieves the device location in the SCSI channel.
775
776 @param This Protocol instance pointer.
777 @param Target A pointer to the Target ID of a SCSI device
778 on the SCSI channel.
779 @param Lun A pointer to the LUN of the SCSI device on
780 the SCSI channel.
781
782 @retval EFI_SUCCESS Retrieves the device location successfully.
783 @retval EFI_INVALID_PARAMETER The Target or Lun is NULL.
784
785 **/
786 EFI_STATUS
787 EFIAPI
788 ScsiGetDeviceLocation (
789 IN EFI_SCSI_IO_PROTOCOL *This,
790 IN OUT UINT8 **Target,
791 OUT UINT64 *Lun
792 )
793 {
794 SCSI_IO_DEV *ScsiIoDevice;
795
796 if (Target == NULL || Lun == NULL) {
797 return EFI_INVALID_PARAMETER;
798 }
799
800 ScsiIoDevice = SCSI_IO_DEV_FROM_THIS (This);
801
802 CopyMem (*Target,&ScsiIoDevice->Pun, TARGET_MAX_BYTES);
803
804 *Lun = ScsiIoDevice->Lun;
805
806 return EFI_SUCCESS;
807 }
808
809 /**
810 Resets the SCSI Bus that the SCSI Controller is attached to.
811
812 @param This Protocol instance pointer.
813
814 @retval EFI_SUCCESS The SCSI bus is reset successfully.
815 @retval EFI_DEVICE_ERROR Errors encountered when resetting the SCSI bus.
816 @retval EFI_UNSUPPORTED The bus reset operation is not supported by the
817 SCSI Host Controller.
818 @retval EFI_TIMEOUT A timeout occurred while attempting to reset
819 the SCSI bus.
820 **/
821 EFI_STATUS
822 EFIAPI
823 ScsiResetBus (
824 IN EFI_SCSI_IO_PROTOCOL *This
825 )
826 {
827 SCSI_IO_DEV *ScsiIoDevice;
828
829 ScsiIoDevice = SCSI_IO_DEV_FROM_THIS (This);
830
831 if (ScsiIoDevice->ExtScsiSupport){
832 return ScsiIoDevice->ExtScsiPassThru->ResetChannel (ScsiIoDevice->ExtScsiPassThru);
833 } else {
834 return ScsiIoDevice->ScsiPassThru->ResetChannel (ScsiIoDevice->ScsiPassThru);
835 }
836 }
837
838
839 /**
840 Resets the SCSI Controller that the device handle specifies.
841
842 @param This Protocol instance pointer.
843
844 @retval EFI_SUCCESS Reset the SCSI controller successfully.
845 @retval EFI_DEVICE_ERROR Errors are encountered when resetting the SCSI Controller.
846 @retval EFI_UNSUPPORTED The SCSI bus does not support a device reset operation.
847 @retval EFI_TIMEOUT A timeout occurred while attempting to reset the
848 SCSI Controller.
849 **/
850 EFI_STATUS
851 EFIAPI
852 ScsiResetDevice (
853 IN EFI_SCSI_IO_PROTOCOL *This
854 )
855 {
856 SCSI_IO_DEV *ScsiIoDevice;
857 UINT8 Target[TARGET_MAX_BYTES];
858
859 ScsiIoDevice = SCSI_IO_DEV_FROM_THIS (This);
860 CopyMem (Target,&ScsiIoDevice->Pun, TARGET_MAX_BYTES);
861
862
863 if (ScsiIoDevice->ExtScsiSupport) {
864 return ScsiIoDevice->ExtScsiPassThru->ResetTargetLun (
865 ScsiIoDevice->ExtScsiPassThru,
866 Target,
867 ScsiIoDevice->Lun
868 );
869 } else {
870 return ScsiIoDevice->ScsiPassThru->ResetTarget (
871 ScsiIoDevice->ScsiPassThru,
872 ScsiIoDevice->Pun.ScsiId.Scsi,
873 ScsiIoDevice->Lun
874 );
875 }
876 }
877
878
879 /**
880 Sends a SCSI Request Packet to the SCSI Controller for execution.
881
882 @param This Protocol instance pointer.
883 @param CommandPacket The SCSI request packet to send to the SCSI
884 Controller specified by the device handle.
885 @param Event If the SCSI bus where the SCSI device is attached
886 does not support non-blocking I/O, then Event is
887 ignored, and blocking I/O is performed.
888 If Event is NULL, then blocking I/O is performed.
889 If Event is not NULL and non-blocking I/O is
890 supported, then non-blocking I/O is performed,
891 and Event will be signaled when the SCSI Request
892 Packet completes.
893
894 @retval EFI_SUCCESS The SCSI Request Packet was sent by the host
895 successfully, and TransferLength bytes were
896 transferred to/from DataBuffer.See
897 HostAdapterStatus, TargetStatus,
898 SenseDataLength, and SenseData in that order
899 for additional status information.
900 @retval EFI_BAD_BUFFER_SIZE The SCSI Request Packet was executed,
901 but the entire DataBuffer could not be transferred.
902 The actual number of bytes transferred is returned
903 in TransferLength. See HostAdapterStatus,
904 TargetStatus, SenseDataLength, and SenseData in
905 that order for additional status information.
906 @retval EFI_NOT_READY The SCSI Request Packet could not be sent because
907 there are too many SCSI Command Packets already
908 queued.The caller may retry again later.
909 @retval EFI_DEVICE_ERROR A device error occurred while attempting to send
910 the SCSI Request Packet. See HostAdapterStatus,
911 TargetStatus, SenseDataLength, and SenseData in
912 that order for additional status information.
913 @retval EFI_INVALID_PARAMETER The contents of CommandPacket are invalid.
914 The SCSI Request Packet was not sent, so no
915 additional status information is available.
916 @retval EFI_UNSUPPORTED The command described by the SCSI Request Packet
917 is not supported by the SCSI initiator(i.e., SCSI
918 Host Controller). The SCSI Request Packet was not
919 sent, so no additional status information is
920 available.
921 @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI
922 Request Packet to execute. See HostAdapterStatus,
923 TargetStatus, SenseDataLength, and SenseData in
924 that order for additional status information.
925 **/
926 EFI_STATUS
927 EFIAPI
928 ScsiExecuteSCSICommand (
929 IN EFI_SCSI_IO_PROTOCOL *This,
930 IN OUT EFI_SCSI_IO_SCSI_REQUEST_PACKET *Packet,
931 IN EFI_EVENT Event OPTIONAL
932 )
933 {
934 SCSI_IO_DEV *ScsiIoDevice;
935 EFI_STATUS Status;
936 UINT8 Target[TARGET_MAX_BYTES];
937 EFI_EVENT PacketEvent;
938 EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *ExtRequestPacket;
939 SCSI_EVENT_DATA EventData;
940
941 PacketEvent = NULL;
942
943 if (Packet == NULL) {
944 return EFI_INVALID_PARAMETER;
945 }
946
947 ScsiIoDevice = SCSI_IO_DEV_FROM_THIS (This);
948 CopyMem (Target,&ScsiIoDevice->Pun, TARGET_MAX_BYTES);
949
950 if (ScsiIoDevice->ExtScsiSupport) {
951 ExtRequestPacket = (EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *) Packet;
952 Status = ScsiIoDevice->ExtScsiPassThru->PassThru (
953 ScsiIoDevice->ExtScsiPassThru,
954 Target,
955 ScsiIoDevice->Lun,
956 ExtRequestPacket,
957 Event
958 );
959 } else {
960
961 mWorkingBuffer = AllocatePool (sizeof(EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET));
962
963 if (mWorkingBuffer == NULL) {
964 return EFI_DEVICE_ERROR;
965 }
966
967 //
968 // Convert package into EFI1.0, EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET.
969 //
970 Status = ScsiioToPassThruPacket(Packet, (EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET*)mWorkingBuffer);
971 if (EFI_ERROR(Status)) {
972 FreePool(mWorkingBuffer);
973 return Status;
974 }
975
976 if (((ScsiIoDevice->ScsiPassThru->Mode->Attributes & EFI_SCSI_PASS_THRU_ATTRIBUTES_NONBLOCKIO) != 0) && (Event != NULL)) {
977 EventData.Data1 = (VOID*)Packet;
978 EventData.Data2 = Event;
979 //
980 // Create Event
981 //
982 Status = gBS->CreateEvent (
983 EVT_NOTIFY_SIGNAL,
984 TPL_CALLBACK,
985 NotifyFunction,
986 &EventData,
987 &PacketEvent
988 );
989 if (EFI_ERROR(Status)) {
990 FreePool(mWorkingBuffer);
991 return Status;
992 }
993
994 Status = ScsiIoDevice->ScsiPassThru->PassThru (
995 ScsiIoDevice->ScsiPassThru,
996 ScsiIoDevice->Pun.ScsiId.Scsi,
997 ScsiIoDevice->Lun,
998 mWorkingBuffer,
999 PacketEvent
1000 );
1001
1002 if (EFI_ERROR(Status)) {
1003 FreePool(mWorkingBuffer);
1004 gBS->CloseEvent(PacketEvent);
1005 return Status;
1006 }
1007
1008 } else {
1009 //
1010 // If there's no event or SCSI Device doesn't support NON-BLOCKING, just convert
1011 // EFI1.0 PassThru packet back to UEFI2.0 SCSI IO Packet.
1012 //
1013 Status = ScsiIoDevice->ScsiPassThru->PassThru (
1014 ScsiIoDevice->ScsiPassThru,
1015 ScsiIoDevice->Pun.ScsiId.Scsi,
1016 ScsiIoDevice->Lun,
1017 mWorkingBuffer,
1018 Event
1019 );
1020 if (EFI_ERROR(Status)) {
1021 FreePool(mWorkingBuffer);
1022 return Status;
1023 }
1024
1025 PassThruToScsiioPacket((EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET*)mWorkingBuffer,Packet);
1026 //
1027 // After converting EFI1.0 PassThru Packet back to UEFI2.0 SCSI IO Packet,
1028 // free mWorkingBuffer.
1029 //
1030 FreePool(mWorkingBuffer);
1031 }
1032 }
1033 return Status;
1034 }
1035
1036
1037 /**
1038 Scan SCSI Bus to discover the device, and attach ScsiIoProtocol to it.
1039
1040 @param This Protocol instance pointer
1041 @param Controller Controller handle
1042 @param TargetId Tartget to be scanned
1043 @param Lun The Lun of the SCSI device on the SCSI channel.
1044 @param ScsiBusDev The pointer of SCSI_BUS_DEVICE
1045
1046 @retval EFI_SUCCESS Successfully to discover the device and attach
1047 ScsiIoProtocol to it.
1048 @retval EFI_OUT_OF_RESOURCES Fail to discover the device.
1049
1050 **/
1051 EFI_STATUS
1052 EFIAPI
1053 ScsiScanCreateDevice (
1054 IN EFI_DRIVER_BINDING_PROTOCOL *This,
1055 IN EFI_HANDLE Controller,
1056 IN SCSI_TARGET_ID *TargetId,
1057 IN UINT64 Lun,
1058 IN OUT SCSI_BUS_DEVICE *ScsiBusDev
1059 )
1060 {
1061 EFI_STATUS Status;
1062 SCSI_IO_DEV *ScsiIoDevice;
1063 EFI_DEVICE_PATH_PROTOCOL *ScsiDevicePath;
1064 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
1065 EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath;
1066 EFI_HANDLE DeviceHandle;
1067
1068 DevicePath = NULL;
1069 RemainingDevicePath = NULL;
1070 ScsiDevicePath = NULL;
1071 ScsiIoDevice = NULL;
1072
1073 //
1074 // Build Device Path
1075 //
1076 if (ScsiBusDev->ExtScsiSupport){
1077 Status = ScsiBusDev->ExtScsiInterface->BuildDevicePath (
1078 ScsiBusDev->ExtScsiInterface,
1079 &TargetId->ScsiId.ExtScsi[0],
1080 Lun,
1081 &ScsiDevicePath
1082 );
1083 } else {
1084 Status = ScsiBusDev->ScsiInterface->BuildDevicePath (
1085 ScsiBusDev->ScsiInterface,
1086 TargetId->ScsiId.Scsi,
1087 Lun,
1088 &ScsiDevicePath
1089 );
1090 }
1091
1092 if (EFI_ERROR(Status)) {
1093 return Status;
1094 }
1095
1096 DevicePath = AppendDevicePathNode (
1097 ScsiBusDev->DevicePath,
1098 ScsiDevicePath
1099 );
1100
1101 if (DevicePath == NULL) {
1102 Status = EFI_OUT_OF_RESOURCES;
1103 goto ErrorExit;
1104 }
1105
1106 DeviceHandle = NULL;
1107 RemainingDevicePath = DevicePath;
1108 Status = gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid, &RemainingDevicePath, &DeviceHandle);
1109 if (!EFI_ERROR (Status) && (DeviceHandle != NULL) && IsDevicePathEnd(RemainingDevicePath)) {
1110 //
1111 // The device has been started, directly return to fast boot.
1112 //
1113 Status = EFI_ALREADY_STARTED;
1114 goto ErrorExit;
1115 }
1116
1117 ScsiIoDevice = AllocateZeroPool (sizeof (SCSI_IO_DEV));
1118 if (ScsiIoDevice == NULL) {
1119 Status = EFI_OUT_OF_RESOURCES;
1120 goto ErrorExit;
1121 }
1122
1123 ScsiIoDevice->Signature = SCSI_IO_DEV_SIGNATURE;
1124 CopyMem(&ScsiIoDevice->Pun, TargetId, TARGET_MAX_BYTES);
1125 ScsiIoDevice->Lun = Lun;
1126
1127 if (ScsiBusDev->ExtScsiSupport) {
1128 ScsiIoDevice->ExtScsiPassThru = ScsiBusDev->ExtScsiInterface;
1129 ScsiIoDevice->ExtScsiSupport = TRUE;
1130 ScsiIoDevice->ScsiIo.IoAlign = ScsiIoDevice->ExtScsiPassThru->Mode->IoAlign;
1131
1132 } else {
1133 ScsiIoDevice->ScsiPassThru = ScsiBusDev->ScsiInterface;
1134 ScsiIoDevice->ExtScsiSupport = FALSE;
1135 ScsiIoDevice->ScsiIo.IoAlign = ScsiIoDevice->ScsiPassThru->Mode->IoAlign;
1136 }
1137
1138 ScsiIoDevice->ScsiIo.GetDeviceType = ScsiGetDeviceType;
1139 ScsiIoDevice->ScsiIo.GetDeviceLocation = ScsiGetDeviceLocation;
1140 ScsiIoDevice->ScsiIo.ResetBus = ScsiResetBus;
1141 ScsiIoDevice->ScsiIo.ResetDevice = ScsiResetDevice;
1142 ScsiIoDevice->ScsiIo.ExecuteScsiCommand = ScsiExecuteSCSICommand;
1143
1144 if (!DiscoverScsiDevice (ScsiIoDevice)) {
1145 Status = EFI_OUT_OF_RESOURCES;
1146 goto ErrorExit;
1147 }
1148
1149 ScsiIoDevice->DevicePath = DevicePath;
1150
1151 Status = gBS->InstallMultipleProtocolInterfaces (
1152 &ScsiIoDevice->Handle,
1153 &gEfiDevicePathProtocolGuid,
1154 ScsiIoDevice->DevicePath,
1155 &gEfiScsiIoProtocolGuid,
1156 &ScsiIoDevice->ScsiIo,
1157 NULL
1158 );
1159 if (EFI_ERROR (Status)) {
1160 goto ErrorExit;
1161 } else {
1162 if (ScsiBusDev->ExtScsiSupport) {
1163 gBS->OpenProtocol (
1164 Controller,
1165 &gEfiExtScsiPassThruProtocolGuid,
1166 (VOID **) &(ScsiBusDev->ExtScsiInterface),
1167 This->DriverBindingHandle,
1168 ScsiIoDevice->Handle,
1169 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
1170 );
1171 } else {
1172 gBS->OpenProtocol (
1173 Controller,
1174 &gEfiScsiPassThruProtocolGuid,
1175 (VOID **) &(ScsiBusDev->ScsiInterface),
1176 This->DriverBindingHandle,
1177 ScsiIoDevice->Handle,
1178 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
1179 );
1180 }
1181 }
1182 return EFI_SUCCESS;
1183
1184 ErrorExit:
1185
1186 //
1187 // The memory space for ScsiDevicePath is allocated in
1188 // ScsiPassThru->BuildDevicePath() function; It is no longer used
1189 // after AppendDevicePathNode,so free the memory it occupies.
1190 //
1191 FreePool (ScsiDevicePath);
1192
1193 if (DevicePath != NULL) {
1194 FreePool (DevicePath);
1195 }
1196
1197 if (ScsiIoDevice != NULL) {
1198 FreePool (ScsiIoDevice);
1199 }
1200
1201 return Status;
1202 }
1203
1204
1205 /**
1206 Discovery SCSI Device
1207
1208 @param ScsiIoDevice The pointer of SCSI_IO_DEV
1209
1210 @retval TRUE Find SCSI Device and verify it.
1211 @retval FALSE Unable to find SCSI Device.
1212
1213 **/
1214 BOOLEAN
1215 DiscoverScsiDevice (
1216 IN OUT SCSI_IO_DEV *ScsiIoDevice
1217 )
1218 {
1219 EFI_STATUS Status;
1220 UINT32 InquiryDataLength;
1221 UINT8 SenseDataLength;
1222 UINT8 HostAdapterStatus;
1223 UINT8 TargetStatus;
1224 EFI_SCSI_INQUIRY_DATA *InquiryData;
1225 UINT8 MaxRetry;
1226 UINT8 Index;
1227 BOOLEAN ScsiDeviceFound;
1228
1229 HostAdapterStatus = 0;
1230 TargetStatus = 0;
1231
1232 InquiryData = AllocateAlignedBuffer (ScsiIoDevice, sizeof (EFI_SCSI_INQUIRY_DATA));
1233 if (InquiryData == NULL) {
1234 ScsiDeviceFound = FALSE;
1235 goto Done;
1236 }
1237
1238 //
1239 // Using Inquiry command to scan for the device
1240 //
1241 InquiryDataLength = sizeof (EFI_SCSI_INQUIRY_DATA);
1242 SenseDataLength = 0;
1243 ZeroMem (InquiryData, InquiryDataLength);
1244
1245 MaxRetry = 2;
1246 for (Index = 0; Index < MaxRetry; Index++) {
1247 Status = ScsiInquiryCommand (
1248 &ScsiIoDevice->ScsiIo,
1249 EFI_TIMER_PERIOD_SECONDS (1),
1250 NULL,
1251 &SenseDataLength,
1252 &HostAdapterStatus,
1253 &TargetStatus,
1254 (VOID *) InquiryData,
1255 &InquiryDataLength,
1256 FALSE
1257 );
1258 if (!EFI_ERROR (Status)) {
1259 break;
1260 } else if ((Status == EFI_BAD_BUFFER_SIZE) ||
1261 (Status == EFI_INVALID_PARAMETER) ||
1262 (Status == EFI_UNSUPPORTED)) {
1263 ScsiDeviceFound = FALSE;
1264 goto Done;
1265 }
1266 }
1267
1268 if (Index == MaxRetry) {
1269 ScsiDeviceFound = FALSE;
1270 goto Done;
1271 }
1272
1273 //
1274 // Retrieved inquiry data successfully
1275 //
1276 if ((InquiryData->Peripheral_Qualifier != 0) &&
1277 (InquiryData->Peripheral_Qualifier != 3)) {
1278 ScsiDeviceFound = FALSE;
1279 goto Done;
1280 }
1281
1282 if (InquiryData->Peripheral_Qualifier == 3) {
1283 if (InquiryData->Peripheral_Type != 0x1f) {
1284 ScsiDeviceFound = FALSE;
1285 goto Done;
1286 }
1287 }
1288
1289 if (0x1e >= InquiryData->Peripheral_Type && InquiryData->Peripheral_Type >= 0xa) {
1290 ScsiDeviceFound = FALSE;
1291 goto Done;
1292 }
1293
1294 //
1295 // valid device type and peripheral qualifier combination.
1296 //
1297 ScsiIoDevice->ScsiDeviceType = InquiryData->Peripheral_Type;
1298 ScsiIoDevice->RemovableDevice = InquiryData->Rmb;
1299 if (InquiryData->Version == 0) {
1300 ScsiIoDevice->ScsiVersion = 0;
1301 } else {
1302 //
1303 // ANSI-approved version
1304 //
1305 ScsiIoDevice->ScsiVersion = (UINT8) (InquiryData->Version & 0x07);
1306 }
1307
1308 ScsiDeviceFound = TRUE;
1309
1310 Done:
1311 FreeAlignedBuffer (InquiryData, sizeof (EFI_SCSI_INQUIRY_DATA));
1312
1313 return ScsiDeviceFound;
1314 }
1315
1316
1317 /**
1318 Convert EFI_SCSI_IO_SCSI_REQUEST_PACKET packet to EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET packet.
1319
1320 @param Packet The pointer of EFI_SCSI_IO_SCSI_REQUEST_PACKET
1321 @param CommandPacket The pointer of EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
1322
1323 **/
1324 EFI_STATUS
1325 EFIAPI
1326 ScsiioToPassThruPacket (
1327 IN EFI_SCSI_IO_SCSI_REQUEST_PACKET *Packet,
1328 OUT EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *CommandPacket
1329 )
1330 {
1331 //
1332 //EFI 1.10 doesn't support Bi-Direction Command.
1333 //
1334 if (Packet->DataDirection == EFI_SCSI_IO_DATA_DIRECTION_BIDIRECTIONAL) {
1335 return EFI_UNSUPPORTED;
1336 }
1337
1338 ZeroMem (CommandPacket, sizeof (EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET));
1339
1340 CommandPacket->Timeout = Packet->Timeout;
1341 CommandPacket->Cdb = Packet->Cdb;
1342 CommandPacket->CdbLength = Packet->CdbLength;
1343 CommandPacket->DataDirection = Packet->DataDirection;
1344 CommandPacket->HostAdapterStatus = Packet->HostAdapterStatus;
1345 CommandPacket->TargetStatus = Packet->TargetStatus;
1346 CommandPacket->SenseData = Packet->SenseData;
1347 CommandPacket->SenseDataLength = Packet->SenseDataLength;
1348
1349 if (Packet->DataDirection == EFI_SCSI_IO_DATA_DIRECTION_READ) {
1350 CommandPacket->DataBuffer = Packet->InDataBuffer;
1351 CommandPacket->TransferLength = Packet->InTransferLength;
1352 } else if (Packet->DataDirection == EFI_SCSI_IO_DATA_DIRECTION_WRITE) {
1353 CommandPacket->DataBuffer = Packet->OutDataBuffer;
1354 CommandPacket->TransferLength = Packet->OutTransferLength;
1355 }
1356 return EFI_SUCCESS;
1357 }
1358
1359
1360 /**
1361 Convert EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET packet to EFI_SCSI_IO_SCSI_REQUEST_PACKET packet.
1362
1363 @param ScsiPacket The pointer of EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
1364 @param Packet The pointer of EFI_SCSI_IO_SCSI_REQUEST_PACKET
1365
1366 **/
1367 EFI_STATUS
1368 EFIAPI
1369 PassThruToScsiioPacket (
1370 IN EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *ScsiPacket,
1371 OUT EFI_SCSI_IO_SCSI_REQUEST_PACKET *Packet
1372 )
1373 {
1374 Packet->Timeout = ScsiPacket->Timeout;
1375 Packet->Cdb = ScsiPacket->Cdb;
1376 Packet->CdbLength = ScsiPacket->CdbLength;
1377 Packet->DataDirection = ScsiPacket->DataDirection;
1378 Packet->HostAdapterStatus = ScsiPacket->HostAdapterStatus;
1379 Packet->TargetStatus = ScsiPacket->TargetStatus;
1380 Packet->SenseData = ScsiPacket->SenseData;
1381 Packet->SenseDataLength = ScsiPacket->SenseDataLength;
1382
1383 if (ScsiPacket->DataDirection == EFI_SCSI_IO_DATA_DIRECTION_READ) {
1384 Packet->InDataBuffer = ScsiPacket->DataBuffer;
1385 Packet->InTransferLength = ScsiPacket->TransferLength;
1386 } else if (Packet->DataDirection == EFI_SCSI_IO_DATA_DIRECTION_WRITE) {
1387 Packet->OutDataBuffer = ScsiPacket->DataBuffer;
1388 Packet->OutTransferLength = ScsiPacket->TransferLength;
1389 }
1390
1391 return EFI_SUCCESS;
1392 }
1393
1394 /**
1395 Notify Function in which convert EFI1.0 PassThru Packet back to UEF2.0
1396 SCSI IO Packet.
1397
1398 @param Event The instance of EFI_EVENT.
1399 @param Context The parameter passed in.
1400
1401 **/
1402 VOID
1403 EFIAPI
1404 NotifyFunction (
1405 IN EFI_EVENT Event,
1406 IN VOID *Context
1407 )
1408 {
1409 EFI_SCSI_IO_SCSI_REQUEST_PACKET *Packet;
1410 EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *ScsiPacket;
1411 EFI_EVENT CallerEvent;
1412 SCSI_EVENT_DATA *PassData;
1413
1414 PassData = (SCSI_EVENT_DATA*)Context;
1415 Packet = (EFI_SCSI_IO_SCSI_REQUEST_PACKET *)PassData->Data1;
1416 ScsiPacket = (EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET*)mWorkingBuffer;
1417
1418 //
1419 // Convert EFI1.0 PassThru packet to UEFI2.0 SCSI IO Packet.
1420 //
1421 PassThruToScsiioPacket(ScsiPacket, Packet);
1422
1423 //
1424 // After converting EFI1.0 PassThru Packet back to UEFI2.0 SCSI IO Packet,
1425 // free mWorkingBuffer.
1426 //
1427 gBS->FreePool(mWorkingBuffer);
1428
1429 //
1430 // Signal Event to tell caller to pick up UEFI2.0 SCSI IO Packet.
1431 //
1432 CallerEvent = PassData->Data2;
1433 gBS->CloseEvent(Event);
1434 gBS->SignalEvent(CallerEvent);
1435 }
1436