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