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