]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Bus/Scsi/ScsiBusDxe/ScsiBus.c
1. Add missing CloseProtocol in case RemainingDevicePath is NULL or EndOfDp
[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
d548f0a1 5Copyright (c) 2006 - 2010, 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
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
f36d6e66 432 ScsiBusDev->ExtScsiInterface->GetTargetLun (ScsiBusDev->ExtScsiInterface, RemainingDevicePath, &TargetId, &Lun); \r
70c94b3b 433 } else {\r
d548f0a1 434 ScsiBusDev->ScsiInterface->GetTargetLun (ScsiBusDev->ScsiInterface, RemainingDevicePath, &ScsiTargetId.ScsiId.Scsi, &Lun);\r
70c94b3b 435 }\r
af4a6385 436\r
437 } else {\r
438 //\r
439 // If RemainingDevicePath is the End of Device Path Node,\r
440 // skip enumerate any device and return EFI_SUCESSS\r
441 // \r
442 ScanOtherPuns = FALSE;\r
3a10d471 443 }\r
444\r
70c94b3b 445 while(ScanOtherPuns) {\r
446 if (FromFirstTarget) {\r
3a10d471 447 //\r
448 // Remaining Device Path is NULL, scan all the possible Puns in the\r
449 // SCSI Channel.\r
450 //\r
70c94b3b 451 if (ScsiBusDev->ExtScsiSupport) {\r
452 Status = ScsiBusDev->ExtScsiInterface->GetNextTargetLun (ScsiBusDev->ExtScsiInterface, &TargetId, &Lun);\r
453 } else {\r
d548f0a1 454 Status = ScsiBusDev->ScsiInterface->GetNextDevice (ScsiBusDev->ScsiInterface, &ScsiTargetId.ScsiId.Scsi, &Lun);\r
70c94b3b 455 }\r
3a10d471 456 if (EFI_ERROR (Status)) {\r
457 //\r
458 // no legal Pun and Lun found any more\r
459 //\r
460 break;\r
461 }\r
462 } else {\r
3a10d471 463 ScanOtherPuns = FALSE;\r
464 }\r
3a10d471 465 //\r
466 // Avoid creating handle for the host adapter.\r
467 //\r
70c94b3b 468 if (ScsiBusDev->ExtScsiSupport) {\r
d548f0a1 469 if ((ScsiTargetId.ScsiId.Scsi) == ScsiBusDev->ExtScsiInterface->Mode->AdapterId) {\r
70c94b3b 470 continue;\r
471 }\r
472 } else {\r
d548f0a1 473 if ((ScsiTargetId.ScsiId.Scsi) == ScsiBusDev->ScsiInterface->Mode->AdapterId) {\r
70c94b3b 474 continue;\r
475 }\r
3a10d471 476 }\r
3a10d471 477 //\r
478 // Scan for the scsi device, if it attaches to the scsi bus,\r
479 // then create handle and install scsi i/o protocol.\r
480 //\r
d548f0a1 481 Status = ScsiScanCreateDevice (This, Controller, &ScsiTargetId, Lun, ScsiBusDev);\r
3a10d471 482 }\r
f36d6e66 483 return EFI_SUCCESS;\r
9b38ff34 484\r
f36d6e66 485ErrorExit:\r
486 \r
487 if (ScsiBusDev != NULL) {\r
9b38ff34 488 FreePool (ScsiBusDev);\r
f36d6e66 489 }\r
490 \r
491 if (ExtScsiSupport) {\r
492 gBS->CloseProtocol (\r
493 Controller,\r
494 &gEfiExtScsiPassThruProtocolGuid,\r
495 This->DriverBindingHandle,\r
496 Controller\r
497 );\r
498 if (!EFI_ERROR (PassThruStatus)) {\r
499 gBS->CloseProtocol (\r
500 Controller,\r
501 &gEfiScsiPassThruProtocolGuid,\r
502 This->DriverBindingHandle,\r
503 Controller\r
504 );\r
505 }\r
506 } else {\r
507 gBS->CloseProtocol (\r
508 Controller,\r
509 &gEfiScsiPassThruProtocolGuid,\r
510 This->DriverBindingHandle,\r
511 Controller\r
512 );\r
513 }\r
3a10d471 514 return Status;\r
515}\r
516\r
9beb888e 517/**\r
518 Stop this driver on ControllerHandle.\r
519\r
520 This service is called by the EFI boot service DisconnectController().\r
521 In order to make drivers as small as possible, there are a few calling\r
522 restrictions for this service. DisconnectController() must follow these\r
523 calling restrictions. If any other agent wishes to call Stop() it must also\r
524 follow these calling restrictions.\r
525 \r
526 @param This Protocol instance pointer.\r
527 @param ControllerHandle Handle of device to stop driver on\r
528 @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of\r
529 children is zero stop the entire bus driver.\r
530 @param ChildHandleBuffer List of Child Handles to Stop.\r
531\r
532 @retval EFI_SUCCESS This driver is removed ControllerHandle\r
533 @retval other This driver was not removed from this device\r
534\r
535**/\r
3a10d471 536EFI_STATUS\r
537EFIAPI\r
538SCSIBusDriverBindingStop (\r
539 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
540 IN EFI_HANDLE Controller,\r
541 IN UINTN NumberOfChildren,\r
542 IN EFI_HANDLE *ChildHandleBuffer\r
543 )\r
3a10d471 544{\r
545 EFI_STATUS Status;\r
546 BOOLEAN AllChildrenStopped;\r
547 UINTN Index;\r
548 EFI_SCSI_IO_PROTOCOL *ScsiIo;\r
549 SCSI_IO_DEV *ScsiIoDevice;\r
70c94b3b 550 VOID *ScsiPassThru;\r
551 EFI_SCSI_BUS_PROTOCOL *Scsidentifier;\r
552 SCSI_BUS_DEVICE *ScsiBusDev;\r
3a10d471 553\r
554 if (NumberOfChildren == 0) {\r
70c94b3b 555 //\r
556 // Get the SCSI_BUS_DEVICE\r
557 //\r
558 Status = gBS->OpenProtocol (\r
559 Controller,\r
560 &mScsiBusProtocolGuid,\r
561 (VOID **) &Scsidentifier,\r
562 This->DriverBindingHandle,\r
563 Controller,\r
564 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
565 );\r
c52fa98c 566\r
70c94b3b 567 if (EFI_ERROR (Status)) {\r
568 return EFI_DEVICE_ERROR;\r
569 }\r
570\r
571 ScsiBusDev = SCSI_BUS_CONTROLLER_DEVICE_FROM_THIS (Scsidentifier);\r
572\r
573 //\r
574 // Uninstall SCSI Bus Protocol\r
575 //\r
576 gBS->UninstallProtocolInterface (\r
577 Controller,\r
578 &mScsiBusProtocolGuid,\r
579 &ScsiBusDev->BusIdentify\r
580 );\r
c52fa98c 581\r
3a10d471 582 //\r
583 // Close the bus driver\r
584 //\r
70c94b3b 585 if (ScsiBusDev->ExtScsiSupport) {\r
1e5914b5 586 //\r
587 // Close ExtPassThru Protocol from this controller handle\r
588 //\r
70c94b3b 589 gBS->CloseProtocol (\r
590 Controller,\r
591 &gEfiExtScsiPassThruProtocolGuid,\r
592 This->DriverBindingHandle,\r
593 Controller\r
594 );\r
1e5914b5 595 //\r
596 // When Start() succeeds to open ExtPassThru, it always tries to open PassThru BY_DRIVER.\r
597 // Its intent is to prevent another SCSI Bus Driver from woking on the same host handle. \r
598 // So Stop() needs to try to close PassThru if present here.\r
599 //\r
600 gBS->CloseProtocol (\r
601 Controller,\r
602 &gEfiScsiPassThruProtocolGuid,\r
603 This->DriverBindingHandle,\r
604 Controller\r
605 );\r
70c94b3b 606 } else {\r
607 gBS->CloseProtocol (\r
608 Controller,\r
609 &gEfiScsiPassThruProtocolGuid,\r
610 This->DriverBindingHandle,\r
611 Controller\r
612 );\r
613 }\r
3a10d471 614\r
70c94b3b 615 gBS->CloseProtocol (\r
616 Controller,\r
617 &gEfiDevicePathProtocolGuid,\r
618 This->DriverBindingHandle,\r
619 Controller\r
620 );\r
6c94a00d 621 FreePool (ScsiBusDev);\r
3a10d471 622 return EFI_SUCCESS;\r
623 }\r
624\r
625 AllChildrenStopped = TRUE;\r
626\r
627 for (Index = 0; Index < NumberOfChildren; Index++) {\r
628\r
629 Status = gBS->OpenProtocol (\r
630 ChildHandleBuffer[Index],\r
631 &gEfiScsiIoProtocolGuid,\r
632 (VOID **) &ScsiIo,\r
633 This->DriverBindingHandle,\r
634 Controller,\r
635 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
636 );\r
637 if (EFI_ERROR (Status)) {\r
638 AllChildrenStopped = FALSE;\r
639 continue;\r
640 }\r
641\r
642 ScsiIoDevice = SCSI_IO_DEV_FROM_THIS (ScsiIo);\r
643 //\r
644 // Close the child handle\r
645 //\r
70c94b3b 646 if (ScsiIoDevice->ExtScsiSupport) {\r
647 Status = gBS->CloseProtocol (\r
648 Controller,\r
649 &gEfiExtScsiPassThruProtocolGuid,\r
650 This->DriverBindingHandle,\r
651 ChildHandleBuffer[Index]\r
652 );\r
653\r
654 } else {\r
655 Status = gBS->CloseProtocol (\r
656 Controller,\r
657 &gEfiScsiPassThruProtocolGuid,\r
658 This->DriverBindingHandle,\r
659 ChildHandleBuffer[Index]\r
660 );\r
661 }\r
3a10d471 662\r
663 Status = gBS->UninstallMultipleProtocolInterfaces (\r
664 ChildHandleBuffer[Index],\r
665 &gEfiDevicePathProtocolGuid,\r
666 ScsiIoDevice->DevicePath,\r
667 &gEfiScsiIoProtocolGuid,\r
668 &ScsiIoDevice->ScsiIo,\r
669 NULL\r
670 );\r
671 if (EFI_ERROR (Status)) {\r
672 AllChildrenStopped = FALSE;\r
70c94b3b 673 if (ScsiIoDevice->ExtScsiSupport) {\r
674 gBS->OpenProtocol (\r
675 Controller,\r
676 &gEfiExtScsiPassThruProtocolGuid,\r
84b5c78e 677 &ScsiPassThru,\r
70c94b3b 678 This->DriverBindingHandle,\r
679 ChildHandleBuffer[Index],\r
680 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
681 );\r
682 } else {\r
683 gBS->OpenProtocol (\r
684 Controller,\r
685 &gEfiScsiPassThruProtocolGuid,\r
84b5c78e 686 &ScsiPassThru,\r
70c94b3b 687 This->DriverBindingHandle,\r
688 ChildHandleBuffer[Index],\r
689 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
690 );\r
691 }\r
3a10d471 692 } else {\r
6c94a00d 693 FreePool (ScsiIoDevice);\r
3a10d471 694 }\r
695 }\r
696\r
697 if (!AllChildrenStopped) {\r
698 return EFI_DEVICE_ERROR;\r
699 }\r
700\r
701 return EFI_SUCCESS;\r
702}\r
703\r
9beb888e 704\r
705/**\r
706 Retrieves the device type information of the SCSI Controller.\r
707\r
708 @param This Protocol instance pointer.\r
709 @param DeviceType A pointer to the device type information retrieved from\r
710 the SCSI Controller. \r
711\r
712 @retval EFI_SUCCESS Retrieves the device type information successfully.\r
713 @retval EFI_INVALID_PARAMETER The DeviceType is NULL.\r
714 \r
715**/\r
3a10d471 716EFI_STATUS\r
717EFIAPI\r
718ScsiGetDeviceType (\r
719 IN EFI_SCSI_IO_PROTOCOL *This,\r
720 OUT UINT8 *DeviceType\r
721 )\r
3a10d471 722{\r
723 SCSI_IO_DEV *ScsiIoDevice;\r
724\r
725 if (DeviceType == NULL) {\r
726 return EFI_INVALID_PARAMETER;\r
727 }\r
728\r
729 ScsiIoDevice = SCSI_IO_DEV_FROM_THIS (This);\r
730 *DeviceType = ScsiIoDevice->ScsiDeviceType;\r
731 return EFI_SUCCESS;\r
732}\r
733\r
9beb888e 734\r
735/**\r
736 Retrieves the device location in the SCSI channel.\r
737\r
738 @param This Protocol instance pointer.\r
739 @param Target A pointer to the Target ID of a SCSI device\r
740 on the SCSI channel.\r
741 @param Lun A pointer to the LUN of the SCSI device on\r
742 the SCSI channel.\r
743\r
744 @retval EFI_SUCCESS Retrieves the device location successfully.\r
745 @retval EFI_INVALID_PARAMETER The Target or Lun is NULL.\r
746\r
747**/\r
3a10d471 748EFI_STATUS\r
749EFIAPI\r
750ScsiGetDeviceLocation (\r
751 IN EFI_SCSI_IO_PROTOCOL *This,\r
70c94b3b 752 IN OUT UINT8 **Target,\r
3a10d471 753 OUT UINT64 *Lun\r
754 )\r
3a10d471 755{\r
756 SCSI_IO_DEV *ScsiIoDevice;\r
757\r
758 if (Target == NULL || Lun == NULL) {\r
759 return EFI_INVALID_PARAMETER;\r
760 }\r
761\r
f36d6e66 762 ScsiIoDevice = SCSI_IO_DEV_FROM_THIS (This);\r
3a10d471 763\r
70c94b3b 764 CopyMem (*Target,&ScsiIoDevice->Pun, TARGET_MAX_BYTES);\r
765\r
f36d6e66 766 *Lun = ScsiIoDevice->Lun;\r
3a10d471 767\r
768 return EFI_SUCCESS;\r
769}\r
770\r
9beb888e 771/**\r
772 Resets the SCSI Bus that the SCSI Controller is attached to.\r
773\r
774 @param This Protocol instance pointer.\r
775\r
776 @retval EFI_SUCCESS The SCSI bus is reset successfully.\r
777 @retval EFI_DEVICE_ERROR Errors encountered when resetting the SCSI bus.\r
778 @retval EFI_UNSUPPORTED The bus reset operation is not supported by the\r
779 SCSI Host Controller.\r
780 @retval EFI_TIMEOUT A timeout occurred while attempting to reset \r
781 the SCSI bus.\r
782**/\r
3a10d471 783EFI_STATUS\r
784EFIAPI\r
785ScsiResetBus (\r
786 IN EFI_SCSI_IO_PROTOCOL *This\r
787 )\r
3a10d471 788{\r
789 SCSI_IO_DEV *ScsiIoDevice;\r
790\r
791 ScsiIoDevice = SCSI_IO_DEV_FROM_THIS (This);\r
792\r
70c94b3b 793 if (ScsiIoDevice->ExtScsiSupport){\r
794 return ScsiIoDevice->ExtScsiPassThru->ResetChannel (ScsiIoDevice->ExtScsiPassThru);\r
795 } else {\r
796 return ScsiIoDevice->ScsiPassThru->ResetChannel (ScsiIoDevice->ScsiPassThru);\r
797 }\r
3a10d471 798}\r
799\r
9beb888e 800\r
801/**\r
802 Resets the SCSI Controller that the device handle specifies.\r
803\r
804 @param This Protocol instance pointer.\r
805\r
806 @retval EFI_SUCCESS Reset the SCSI controller successfully.\r
807 @retval EFI_DEVICE_ERROR Errors are encountered when resetting the SCSI Controller.\r
808 @retval EFI_UNSUPPORTED The SCSI bus does not support a device reset operation.\r
809 @retval EFI_TIMEOUT A timeout occurred while attempting to reset the\r
810 SCSI Controller.\r
811**/\r
3a10d471 812EFI_STATUS\r
813EFIAPI\r
814ScsiResetDevice (\r
815 IN EFI_SCSI_IO_PROTOCOL *This\r
816 )\r
3a10d471 817{\r
f36d6e66 818 SCSI_IO_DEV *ScsiIoDevice;\r
70c94b3b 819 UINT8 Target[TARGET_MAX_BYTES];\r
3a10d471 820\r
821 ScsiIoDevice = SCSI_IO_DEV_FROM_THIS (This);\r
70c94b3b 822 CopyMem (Target,&ScsiIoDevice->Pun, TARGET_MAX_BYTES);\r
823\r
3a10d471 824\r
70c94b3b 825 if (ScsiIoDevice->ExtScsiSupport) {\r
826 return ScsiIoDevice->ExtScsiPassThru->ResetTargetLun (\r
827 ScsiIoDevice->ExtScsiPassThru,\r
828 Target,\r
829 ScsiIoDevice->Lun\r
830 );\r
831 } else {\r
832 return ScsiIoDevice->ScsiPassThru->ResetTarget (\r
833 ScsiIoDevice->ScsiPassThru,\r
834 ScsiIoDevice->Pun.ScsiId.Scsi,\r
835 ScsiIoDevice->Lun\r
836 );\r
837 }\r
3a10d471 838}\r
839\r
f36d6e66 840\r
9beb888e 841/**\r
f36d6e66 842 Sends a SCSI Request Packet to the SCSI Controller for execution.\r
f36d6e66 843\r
9beb888e 844 @param This Protocol instance pointer.\r
845 @param CommandPacket The SCSI request packet to send to the SCSI \r
f36d6e66 846 Controller specified by the device handle.\r
9beb888e 847 @param Event If the SCSI bus where the SCSI device is attached\r
f36d6e66 848 does not support non-blocking I/O, then Event is \r
849 ignored, and blocking I/O is performed. \r
850 If Event is NULL, then blocking I/O is performed.\r
851 If Event is not NULL and non-blocking I/O is \r
852 supported, then non-blocking I/O is performed,\r
853 and Event will be signaled when the SCSI Request\r
854 Packet completes.\r
9beb888e 855\r
856 @retval EFI_SUCCESS The SCSI Request Packet was sent by the host \r
857 successfully, and TransferLength bytes were \r
858 transferred to/from DataBuffer.See \r
859 HostAdapterStatus, TargetStatus, \r
860 SenseDataLength, and SenseData in that order\r
861 for additional status information.\r
862 @retval EFI_BAD_BUFFER_SIZE The SCSI Request Packet was executed, \r
863 but the entire DataBuffer could not be transferred.\r
864 The actual number of bytes transferred is returned\r
865 in TransferLength. See HostAdapterStatus, \r
866 TargetStatus, SenseDataLength, and SenseData in \r
867 that order for additional status information.\r
868 @retval EFI_NOT_READY The SCSI Request Packet could not be sent because \r
869 there are too many SCSI Command Packets already \r
870 queued.The caller may retry again later.\r
871 @retval EFI_DEVICE_ERROR A device error occurred while attempting to send \r
872 the SCSI Request Packet. See HostAdapterStatus, \r
873 TargetStatus, SenseDataLength, and SenseData in \r
874 that order for additional status information.\r
875 @retval EFI_INVALID_PARAMETER The contents of CommandPacket are invalid. \r
876 The SCSI Request Packet was not sent, so no \r
877 additional status information is available.\r
878 @retval EFI_UNSUPPORTED The command described by the SCSI Request Packet\r
879 is not supported by the SCSI initiator(i.e., SCSI \r
880 Host Controller). The SCSI Request Packet was not\r
881 sent, so no additional status information is \r
882 available.\r
883 @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI \r
884 Request Packet to execute. See HostAdapterStatus,\r
885 TargetStatus, SenseDataLength, and SenseData in \r
886 that order for additional status information.\r
887**/\r
888EFI_STATUS\r
889EFIAPI\r
890ScsiExecuteSCSICommand (\r
891 IN EFI_SCSI_IO_PROTOCOL *This,\r
892 IN OUT EFI_SCSI_IO_SCSI_REQUEST_PACKET *Packet,\r
893 IN EFI_EVENT Event OPTIONAL\r
894 )\r
3a10d471 895{\r
f36d6e66 896 SCSI_IO_DEV *ScsiIoDevice;\r
897 EFI_STATUS Status;\r
70c94b3b 898 UINT8 Target[TARGET_MAX_BYTES];\r
899 EFI_EVENT PacketEvent;\r
900 EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *ExtRequestPacket;\r
f36d6e66 901 SCSI_EVENT_DATA EventData; \r
3a10d471 902\r
70c94b3b 903 PacketEvent = NULL;\r
f36d6e66 904 \r
3a10d471 905 if (Packet == NULL) {\r
906 return EFI_INVALID_PARAMETER;\r
907 }\r
908\r
909 ScsiIoDevice = SCSI_IO_DEV_FROM_THIS (This);\r
70c94b3b 910 CopyMem (Target,&ScsiIoDevice->Pun, TARGET_MAX_BYTES);\r
c52fa98c 911\r
70c94b3b 912 if (ScsiIoDevice->ExtScsiSupport) {\r
913 ExtRequestPacket = (EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *) Packet;\r
914 Status = ScsiIoDevice->ExtScsiPassThru->PassThru (\r
915 ScsiIoDevice->ExtScsiPassThru,\r
916 Target,\r
917 ScsiIoDevice->Lun,\r
918 ExtRequestPacket,\r
919 Event\r
920 );\r
921 } else {\r
3a10d471 922\r
9b38ff34 923 mWorkingBuffer = AllocatePool (sizeof(EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET));\r
3a10d471 924\r
9b38ff34 925 if (mWorkingBuffer == NULL) {\r
70c94b3b 926 return EFI_DEVICE_ERROR;\r
927 }\r
928\r
929 //\r
c52fa98c 930 // Convert package into EFI1.0, EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET.\r
70c94b3b 931 //\r
9beb888e 932 Status = ScsiioToPassThruPacket(Packet, (EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET*)mWorkingBuffer);\r
70c94b3b 933 if (EFI_ERROR(Status)) {\r
9beb888e 934 FreePool(mWorkingBuffer);\r
70c94b3b 935 return Status;\r
936 }\r
937\r
7077edb3 938 if (((ScsiIoDevice->ScsiPassThru->Mode->Attributes & EFI_SCSI_PASS_THRU_ATTRIBUTES_NONBLOCKIO) != 0) && (Event != NULL)) {\r
70c94b3b 939 EventData.Data1 = (VOID*)Packet;\r
940 EventData.Data2 = Event;\r
941 //\r
942 // Create Event\r
943 //\r
944 Status = gBS->CreateEvent (\r
945 EVT_NOTIFY_SIGNAL,\r
946 TPL_CALLBACK,\r
947 NotifyFunction,\r
948 &EventData,\r
949 &PacketEvent\r
950 );\r
951 if (EFI_ERROR(Status)) {\r
9beb888e 952 FreePool(mWorkingBuffer);\r
70c94b3b 953 return Status;\r
954 }\r
c52fa98c 955\r
70c94b3b 956 Status = ScsiIoDevice->ScsiPassThru->PassThru (\r
957 ScsiIoDevice->ScsiPassThru,\r
958 ScsiIoDevice->Pun.ScsiId.Scsi,\r
959 ScsiIoDevice->Lun,\r
9beb888e 960 mWorkingBuffer,\r
70c94b3b 961 PacketEvent\r
962 );\r
963\r
964 if (EFI_ERROR(Status)) {\r
9b38ff34 965 FreePool(mWorkingBuffer);\r
70c94b3b 966 gBS->CloseEvent(PacketEvent);\r
967 return Status;\r
968 }\r
c52fa98c 969\r
70c94b3b 970 } else {\r
971 //\r
972 // If there's no event or SCSI Device doesn't support NON-BLOCKING, just convert\r
973 // EFI1.0 PassThru packet back to UEFI2.0 SCSI IO Packet.\r
974 //\r
975 Status = ScsiIoDevice->ScsiPassThru->PassThru (\r
976 ScsiIoDevice->ScsiPassThru,\r
977 ScsiIoDevice->Pun.ScsiId.Scsi,\r
978 ScsiIoDevice->Lun,\r
9beb888e 979 mWorkingBuffer,\r
70c94b3b 980 Event\r
981 );\r
982 if (EFI_ERROR(Status)) {\r
9beb888e 983 FreePool(mWorkingBuffer);\r
70c94b3b 984 return Status;\r
985 }\r
986\r
9beb888e 987 PassThruToScsiioPacket((EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET*)mWorkingBuffer,Packet);\r
70c94b3b 988 //\r
989 // After converting EFI1.0 PassThru Packet back to UEFI2.0 SCSI IO Packet,\r
9beb888e 990 // free mWorkingBuffer.\r
70c94b3b 991 //\r
9beb888e 992 FreePool(mWorkingBuffer);\r
70c94b3b 993 }\r
994 }\r
3a10d471 995 return Status;\r
996}\r
997\r
3a10d471 998\r
9beb888e 999/**\r
70c94b3b 1000 Scan SCSI Bus to discover the device, and attach ScsiIoProtocol to it.\r
3a10d471 1001\r
9beb888e 1002 @param This Protocol instance pointer\r
1003 @param Controller Controller handle\r
1004 @param TargetId Tartget to be scanned\r
1005 @param Lun The Lun of the SCSI device on the SCSI channel.\r
1006 @param ScsiBusDev The pointer of SCSI_BUS_DEVICE\r
3a10d471 1007\r
9beb888e 1008 @retval EFI_SUCCESS Successfully to discover the device and attach\r
1009 ScsiIoProtocol to it.\r
1010 @retval EFI_OUT_OF_RESOURCES Fail to discover the device.\r
3a10d471 1011\r
9beb888e 1012**/\r
1013EFI_STATUS\r
1014EFIAPI\r
1015ScsiScanCreateDevice (\r
1016 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
1017 IN EFI_HANDLE Controller,\r
1018 IN SCSI_TARGET_ID *TargetId,\r
1019 IN UINT64 Lun,\r
1020 IN OUT SCSI_BUS_DEVICE *ScsiBusDev\r
1021 )\r
3a10d471 1022{\r
1023 EFI_STATUS Status;\r
1024 SCSI_IO_DEV *ScsiIoDevice;\r
1025 EFI_DEVICE_PATH_PROTOCOL *ScsiDevicePath;\r
1026\r
9beb888e 1027 ScsiIoDevice = AllocateZeroPool (sizeof (SCSI_IO_DEV));\r
1028 if (ScsiIoDevice == NULL) {\r
1029 return EFI_OUT_OF_RESOURCES;\r
3a10d471 1030 }\r
1031\r
3a10d471 1032 ScsiIoDevice->Signature = SCSI_IO_DEV_SIGNATURE;\r
70c94b3b 1033 CopyMem(&ScsiIoDevice->Pun, TargetId, TARGET_MAX_BYTES);\r
3a10d471 1034 ScsiIoDevice->Lun = Lun;\r
1035\r
70c94b3b 1036 if (ScsiBusDev->ExtScsiSupport) {\r
1037 ScsiIoDevice->ExtScsiPassThru = ScsiBusDev->ExtScsiInterface;\r
1038 ScsiIoDevice->ExtScsiSupport = TRUE;\r
1039 ScsiIoDevice->ScsiIo.IoAlign = ScsiIoDevice->ExtScsiPassThru->Mode->IoAlign;\r
1040\r
1041 } else {\r
1042 ScsiIoDevice->ScsiPassThru = ScsiBusDev->ScsiInterface;\r
1043 ScsiIoDevice->ExtScsiSupport = FALSE;\r
1044 ScsiIoDevice->ScsiIo.IoAlign = ScsiIoDevice->ScsiPassThru->Mode->IoAlign;\r
1045 }\r
1046\r
3a10d471 1047 ScsiIoDevice->ScsiIo.GetDeviceType = ScsiGetDeviceType;\r
70c94b3b 1048 ScsiIoDevice->ScsiIo.GetDeviceLocation = ScsiGetDeviceLocation;\r
3a10d471 1049 ScsiIoDevice->ScsiIo.ResetBus = ScsiResetBus;\r
1050 ScsiIoDevice->ScsiIo.ResetDevice = ScsiResetDevice;\r
24e734d2 1051 ScsiIoDevice->ScsiIo.ExecuteScsiCommand = ScsiExecuteSCSICommand;\r
3a10d471 1052\r
70c94b3b 1053\r
3a10d471 1054 if (!DiscoverScsiDevice (ScsiIoDevice)) {\r
9beb888e 1055 FreePool (ScsiIoDevice);\r
70c94b3b 1056 return EFI_OUT_OF_RESOURCES;\r
3a10d471 1057 }\r
70c94b3b 1058\r
3a10d471 1059 //\r
1060 // Set Device Path\r
1061 //\r
6c94a00d 1062 ScsiDevicePath = NULL;\r
70c94b3b 1063 if (ScsiIoDevice->ExtScsiSupport){\r
1064 Status = ScsiIoDevice->ExtScsiPassThru->BuildDevicePath (\r
1065 ScsiIoDevice->ExtScsiPassThru,\r
1066 &ScsiIoDevice->Pun.ScsiId.ExtScsi[0],\r
1067 ScsiIoDevice->Lun,\r
1068 &ScsiDevicePath\r
1069 );\r
70c94b3b 1070 } else {\r
1071 Status = ScsiIoDevice->ScsiPassThru->BuildDevicePath (\r
1072 ScsiIoDevice->ScsiPassThru,\r
1073 ScsiIoDevice->Pun.ScsiId.Scsi,\r
1074 ScsiIoDevice->Lun,\r
1075 &ScsiDevicePath\r
1076 );\r
1068a653 1077 }\r
1078\r
ef13cf23 1079 if (EFI_ERROR(Status)) {\r
1068a653 1080 FreePool (ScsiIoDevice);\r
1081 return Status;\r
3a10d471 1082 }\r
c52fa98c 1083\r
3a10d471 1084 ScsiIoDevice->DevicePath = AppendDevicePathNode (\r
70c94b3b 1085 ScsiBusDev->DevicePath,\r
3a10d471 1086 ScsiDevicePath\r
1087 );\r
1088 //\r
1089 // The memory space for ScsiDevicePath is allocated in\r
1090 // ScsiPassThru->BuildDevicePath() function; It is no longer used\r
1091 // after EfiAppendDevicePathNode,so free the memory it occupies.\r
1092 //\r
6c94a00d 1093 FreePool (ScsiDevicePath);\r
3a10d471 1094\r
1095 if (ScsiIoDevice->DevicePath == NULL) {\r
6c94a00d 1096 FreePool (ScsiIoDevice);\r
3a10d471 1097 return EFI_OUT_OF_RESOURCES;\r
1098 }\r
c52fa98c 1099\r
3a10d471 1100 Status = gBS->InstallMultipleProtocolInterfaces (\r
1101 &ScsiIoDevice->Handle,\r
1102 &gEfiDevicePathProtocolGuid,\r
1103 ScsiIoDevice->DevicePath,\r
1104 &gEfiScsiIoProtocolGuid,\r
1105 &ScsiIoDevice->ScsiIo,\r
1106 NULL\r
1107 );\r
1108 if (EFI_ERROR (Status)) {\r
1068a653 1109 FreePool (ScsiIoDevice->DevicePath);\r
9b38ff34 1110 FreePool (ScsiIoDevice);\r
70c94b3b 1111 return EFI_OUT_OF_RESOURCES;\r
3a10d471 1112 } else {\r
70c94b3b 1113 if (ScsiBusDev->ExtScsiSupport) {\r
1114 gBS->OpenProtocol (\r
1115 Controller,\r
1116 &gEfiExtScsiPassThruProtocolGuid,\r
1117 (VOID **) &(ScsiBusDev->ExtScsiInterface),\r
1118 This->DriverBindingHandle,\r
1119 ScsiIoDevice->Handle,\r
1120 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
1121 );\r
1122 } else {\r
1123 gBS->OpenProtocol (\r
1124 Controller,\r
1125 &gEfiScsiPassThruProtocolGuid,\r
1126 (VOID **) &(ScsiBusDev->ScsiInterface),\r
1127 This->DriverBindingHandle,\r
1128 ScsiIoDevice->Handle,\r
1129 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
1130 );\r
1131 }\r
3a10d471 1132 }\r
3a10d471 1133 return EFI_SUCCESS;\r
1134}\r
1135\r
3a10d471 1136\r
9beb888e 1137/**\r
70c94b3b 1138 Discovery SCSI Device\r
3a10d471 1139\r
9beb888e 1140 @param ScsiIoDevice The pointer of SCSI_IO_DEV\r
3a10d471 1141\r
9beb888e 1142 @retval TRUE Find SCSI Device and verify it.\r
1143 @retval FALSE Unable to find SCSI Device.\r
3a10d471 1144\r
9beb888e 1145**/\r
1146BOOLEAN\r
1147DiscoverScsiDevice (\r
1148 IN OUT SCSI_IO_DEV *ScsiIoDevice\r
1149 )\r
3a10d471 1150{\r
1151 EFI_STATUS Status;\r
3a10d471 1152 UINT32 InquiryDataLength;\r
3a10d471 1153 UINT8 SenseDataLength;\r
1154 UINT8 HostAdapterStatus;\r
1155 UINT8 TargetStatus;\r
70c94b3b 1156 EFI_SCSI_SENSE_DATA SenseData;\r
1157 EFI_SCSI_INQUIRY_DATA InquiryData;\r
3a10d471 1158\r
1159 HostAdapterStatus = 0;\r
1160 TargetStatus = 0;\r
1161 //\r
1162 // Using Inquiry command to scan for the device\r
1163 //\r
1164 InquiryDataLength = sizeof (EFI_SCSI_INQUIRY_DATA);\r
1165 SenseDataLength = sizeof (EFI_SCSI_SENSE_DATA);\r
1166\r
d35be2a4 1167 Status = ScsiInquiryCommand (\r
3a10d471 1168 &ScsiIoDevice->ScsiIo,\r
e72a3b3e 1169 EFI_TIMER_PERIOD_SECONDS (1),\r
3a10d471 1170 (VOID *) &SenseData,\r
1171 &SenseDataLength,\r
1172 &HostAdapterStatus,\r
1173 &TargetStatus,\r
1174 (VOID *) &InquiryData,\r
1175 &InquiryDataLength,\r
1176 FALSE\r
1177 );\r
d1a8a1dc 1178 if (EFI_ERROR (Status) && Status != EFI_BAD_BUFFER_SIZE) {\r
3a10d471 1179 return FALSE;\r
1180 }\r
1181 //\r
1182 // Retrieved inquiry data successfully\r
1183 //\r
1184 if ((InquiryData.Peripheral_Qualifier != 0) &&\r
1185 (InquiryData.Peripheral_Qualifier != 3)) {\r
1186 return FALSE;\r
1187 }\r
1188\r
1189 if (InquiryData.Peripheral_Qualifier == 3) {\r
1190 if (InquiryData.Peripheral_Type != 0x1f) {\r
1191 return FALSE;\r
1192 }\r
1193 }\r
1194\r
67a58d0f 1195 if (0x1e >= InquiryData.Peripheral_Type && InquiryData.Peripheral_Type >= 0xa) {\r
3a10d471 1196 return FALSE;\r
1197 }\r
c52fa98c 1198\r
3a10d471 1199 //\r
1200 // valid device type and peripheral qualifier combination.\r
1201 //\r
1202 ScsiIoDevice->ScsiDeviceType = InquiryData.Peripheral_Type;\r
fbfa4a1d 1203 ScsiIoDevice->RemovableDevice = InquiryData.Rmb;\r
3a10d471 1204 if (InquiryData.Version == 0) {\r
1205 ScsiIoDevice->ScsiVersion = 0;\r
1206 } else {\r
1207 //\r
1208 // ANSI-approved version\r
1209 //\r
1210 ScsiIoDevice->ScsiVersion = (UINT8) (InquiryData.Version & 0x03);\r
1211 }\r
1212\r
1213 return TRUE;\r
1214}\r
70c94b3b 1215\r
1216\r
9beb888e 1217/**\r
1218 Convert EFI_SCSI_IO_SCSI_REQUEST_PACKET packet to EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET packet.\r
1219\r
1220 @param Packet The pointer of EFI_SCSI_IO_SCSI_REQUEST_PACKET\r
1221 @param CommandPacket The pointer of EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET\r
1222\r
1223**/\r
70c94b3b 1224EFI_STATUS\r
1225EFIAPI\r
1226ScsiioToPassThruPacket (\r
1227 IN EFI_SCSI_IO_SCSI_REQUEST_PACKET *Packet,\r
9beb888e 1228 OUT EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *CommandPacket\r
70c94b3b 1229 )\r
70c94b3b 1230{\r
1231 //\r
1232 //EFI 1.10 doesn't support Bi-Direction Command.\r
1233 //\r
1234 if (Packet->DataDirection == EFI_SCSI_IO_DATA_DIRECTION_BIDIRECTIONAL) {\r
1235 return EFI_UNSUPPORTED;\r
1236 }\r
c52fa98c 1237\r
70c94b3b 1238 ZeroMem (CommandPacket, sizeof (EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET));\r
1239\r
1240 CommandPacket->Timeout = Packet->Timeout;\r
1241 CommandPacket->Cdb = Packet->Cdb;\r
1242 CommandPacket->CdbLength = Packet->CdbLength;\r
1243 CommandPacket->DataDirection = Packet->DataDirection;\r
1244 CommandPacket->HostAdapterStatus = Packet->HostAdapterStatus;\r
1245 CommandPacket->TargetStatus = Packet->TargetStatus;\r
1246 CommandPacket->SenseData = Packet->SenseData;\r
1247 CommandPacket->SenseDataLength = Packet->SenseDataLength;\r
1248\r
1249 if (Packet->DataDirection == EFI_SCSI_IO_DATA_DIRECTION_READ) {\r
1250 CommandPacket->DataBuffer = Packet->InDataBuffer;\r
1251 CommandPacket->TransferLength = Packet->InTransferLength;\r
1252 } else if (Packet->DataDirection == EFI_SCSI_IO_DATA_DIRECTION_WRITE) {\r
1253 CommandPacket->DataBuffer = Packet->OutDataBuffer;\r
1254 CommandPacket->TransferLength = Packet->OutTransferLength;\r
1255 }\r
1256 return EFI_SUCCESS;\r
1257}\r
1258\r
1259\r
9beb888e 1260/**\r
1261 Convert EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET packet to EFI_SCSI_IO_SCSI_REQUEST_PACKET packet.\r
1262\r
1263 @param ScsiPacket The pointer of EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET\r
1264 @param Packet The pointer of EFI_SCSI_IO_SCSI_REQUEST_PACKET\r
1265\r
1266**/\r
70c94b3b 1267EFI_STATUS\r
1268EFIAPI\r
1269PassThruToScsiioPacket (\r
1270 IN EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *ScsiPacket,\r
9beb888e 1271 OUT EFI_SCSI_IO_SCSI_REQUEST_PACKET *Packet\r
70c94b3b 1272 )\r
70c94b3b 1273{\r
1274 Packet->Timeout = ScsiPacket->Timeout;\r
1275 Packet->Cdb = ScsiPacket->Cdb;\r
1276 Packet->CdbLength = ScsiPacket->CdbLength;\r
1277 Packet->DataDirection = ScsiPacket->DataDirection;\r
1278 Packet->HostAdapterStatus = ScsiPacket->HostAdapterStatus;\r
1279 Packet->TargetStatus = ScsiPacket->TargetStatus;\r
1280 Packet->SenseData = ScsiPacket->SenseData;\r
1281 Packet->SenseDataLength = ScsiPacket->SenseDataLength;\r
1282\r
1283 if (ScsiPacket->DataDirection == EFI_SCSI_IO_DATA_DIRECTION_READ) {\r
1284 Packet->InDataBuffer = ScsiPacket->DataBuffer;\r
1285 Packet->InTransferLength = ScsiPacket->TransferLength;\r
1286 } else if (Packet->DataDirection == EFI_SCSI_IO_DATA_DIRECTION_WRITE) {\r
1287 Packet->OutDataBuffer = ScsiPacket->DataBuffer;\r
1288 Packet->OutTransferLength = ScsiPacket->TransferLength;\r
1289 }\r
c52fa98c 1290\r
70c94b3b 1291 return EFI_SUCCESS;\r
1292}\r
1293\r
9beb888e 1294/**\r
1295 Notify Function in which convert EFI1.0 PassThru Packet back to UEF2.0\r
1296 SCSI IO Packet.\r
70c94b3b 1297\r
9beb888e 1298 @param Event The instance of EFI_EVENT.\r
1299 @param Context The parameter passed in.\r
70c94b3b 1300\r
9beb888e 1301**/\r
70c94b3b 1302VOID\r
1303EFIAPI\r
1304NotifyFunction (\r
9beb888e 1305 IN EFI_EVENT Event,\r
1306 IN VOID *Context\r
70c94b3b 1307 )\r
70c94b3b 1308{\r
1309 EFI_SCSI_IO_SCSI_REQUEST_PACKET *Packet;\r
1310 EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *ScsiPacket;\r
1311 EFI_EVENT CallerEvent;\r
c52fa98c 1312 SCSI_EVENT_DATA *PassData;\r
70c94b3b 1313\r
1314 PassData = (SCSI_EVENT_DATA*)Context;\r
1315 Packet = (EFI_SCSI_IO_SCSI_REQUEST_PACKET *)PassData->Data1;\r
9beb888e 1316 ScsiPacket = (EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET*)mWorkingBuffer;\r
70c94b3b 1317\r
1318 //\r
1319 // Convert EFI1.0 PassThru packet to UEFI2.0 SCSI IO Packet.\r
1320 //\r
1321 PassThruToScsiioPacket(ScsiPacket, Packet);\r
c52fa98c 1322\r
70c94b3b 1323 //\r
1324 // After converting EFI1.0 PassThru Packet back to UEFI2.0 SCSI IO Packet,\r
9beb888e 1325 // free mWorkingBuffer.\r
70c94b3b 1326 //\r
9beb888e 1327 gBS->FreePool(mWorkingBuffer);\r
70c94b3b 1328\r
1329 //\r
1330 // Signal Event to tell caller to pick up UEFI2.0 SCSI IO Packet.\r
1331 //\r
1332 CallerEvent = PassData->Data2;\r
1333 gBS->CloseEvent(Event);\r
1334 gBS->SignalEvent(CallerEvent);\r
1335}\r
9beb888e 1336\r