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