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