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