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