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