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