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