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