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