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