]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDisk.c
add error handling for input parameter.
[mirror_edk2.git] / MdeModulePkg / Bus / Scsi / ScsiDiskDxe / ScsiDisk.c
CommitLineData
3b2dbece 1/** @file\r
2 SCSI disk driver that layers on every SCSI IO protocol in the system.\r
6ad55b15 3\r
3b2dbece 4Copyright (c) 2006 - 2008, Intel Corporation. <BR>\r
5All rights reserved. This program and the accompanying materials\r
6are licensed and made available under the terms and conditions of the BSD License\r
7which accompanies this distribution. The full text of the license may be found at\r
8http://opensource.org/licenses/bsd-license.php\r
6ad55b15 9\r
3b2dbece 10THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
11WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
6ad55b15 12\r
3b2dbece 13**/\r
ed7748fe 14\r
6ad55b15 15\r
16#include "ScsiDisk.h"\r
17\r
9beb888e 18\r
6ad55b15 19EFI_DRIVER_BINDING_PROTOCOL gScsiDiskDriverBinding = {\r
20 ScsiDiskDriverBindingSupported,\r
21 ScsiDiskDriverBindingStart,\r
22 ScsiDiskDriverBindingStop,\r
23 0xa,\r
24 NULL,\r
25 NULL\r
26};\r
27\r
9b38ff34 28\r
6ad55b15 29/**\r
9beb888e 30 The user Entry Point for module ScsiDisk.\r
31\r
32 The user code starts with this function.\r
6ad55b15 33\r
9beb888e 34 @param ImageHandle The firmware allocated handle for the EFI image. \r
35 @param SystemTable A pointer to the EFI System Table.\r
6ad55b15 36 \r
37 @retval EFI_SUCCESS The entry point is executed successfully.\r
38 @retval other Some error occurs when executing this entry point.\r
39\r
40**/\r
41EFI_STATUS\r
42EFIAPI\r
43InitializeScsiDisk(\r
44 IN EFI_HANDLE ImageHandle,\r
45 IN EFI_SYSTEM_TABLE *SystemTable\r
46 )\r
47{\r
48 EFI_STATUS Status;\r
49\r
50 //\r
51 // Install driver model protocol(s).\r
52 //\r
70da5bc2 53 Status = EfiLibInstallDriverBindingComponentName2 (\r
6ad55b15 54 ImageHandle,\r
55 SystemTable,\r
56 &gScsiDiskDriverBinding,\r
57 ImageHandle,\r
58 &gScsiDiskComponentName,\r
70da5bc2 59 &gScsiDiskComponentName2\r
6ad55b15 60 );\r
61 ASSERT_EFI_ERROR (Status);\r
62\r
63\r
64 return Status;\r
65}\r
66\r
9beb888e 67/**\r
68 Test to see if this driver supports ControllerHandle.\r
69\r
70 This service is called by the EFI boot service ConnectController(). In order\r
71 to make drivers as small as possible, there are a few calling restrictions for\r
72 this service. ConnectController() must follow these calling restrictions.\r
73 If any other agent wishes to call Supported() it must also follow these\r
74 calling restrictions.\r
75\r
76 @param This Protocol instance pointer.\r
77 @param ControllerHandle Handle of device to test\r
78 @param RemainingDevicePath Optional parameter use to pick a specific child\r
79 device to start.\r
80\r
81 @retval EFI_SUCCESS This driver supports this device\r
82 @retval EFI_ALREADY_STARTED This driver is already running on this device\r
83 @retval other This driver does not support this device\r
84\r
85**/\r
6ad55b15 86EFI_STATUS\r
87EFIAPI\r
88ScsiDiskDriverBindingSupported (\r
89 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
90 IN EFI_HANDLE Controller,\r
9beb888e 91 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL\r
6ad55b15 92 )\r
6ad55b15 93{\r
94 EFI_STATUS Status;\r
95 EFI_SCSI_IO_PROTOCOL *ScsiIo;\r
96 UINT8 DeviceType;\r
97\r
98 Status = gBS->OpenProtocol (\r
99 Controller,\r
100 &gEfiScsiIoProtocolGuid,\r
101 (VOID **) &ScsiIo,\r
102 This->DriverBindingHandle,\r
103 Controller,\r
104 EFI_OPEN_PROTOCOL_BY_DRIVER\r
105 );\r
106 if (EFI_ERROR (Status)) {\r
107 return Status;\r
108 }\r
109\r
110 Status = ScsiIo->GetDeviceType (ScsiIo, &DeviceType);\r
111 if (!EFI_ERROR (Status)) {\r
112 if ((DeviceType == EFI_SCSI_TYPE_DISK) || (DeviceType == EFI_SCSI_TYPE_CDROM)) {\r
113 Status = EFI_SUCCESS;\r
114 } else {\r
115 Status = EFI_UNSUPPORTED;\r
116 }\r
117 }\r
118\r
119 gBS->CloseProtocol (\r
f36d6e66 120 Controller,\r
121 &gEfiScsiIoProtocolGuid,\r
122 This->DriverBindingHandle,\r
123 Controller\r
124 );\r
6ad55b15 125 return Status;\r
126}\r
127\r
9beb888e 128\r
129/**\r
130 Start this driver on ControllerHandle.\r
131\r
132 This service is called by the EFI boot service ConnectController(). In order\r
133 to make drivers as small as possible, there are a few calling restrictions for\r
134 this service. ConnectController() must follow these calling restrictions. If\r
135 any other agent wishes to call Start() it must also follow these calling\r
136 restrictions.\r
137\r
138 @param This Protocol instance pointer.\r
139 @param ControllerHandle Handle of device to bind driver to\r
140 @param RemainingDevicePath Optional parameter use to pick a specific child\r
141 device to start.\r
142\r
143 @retval EFI_SUCCESS This driver is added to ControllerHandle\r
144 @retval EFI_ALREADY_STARTED This driver is already running on ControllerHandle\r
145 @retval other This driver does not support this device\r
146\r
147**/\r
6ad55b15 148EFI_STATUS\r
149EFIAPI\r
150ScsiDiskDriverBindingStart (\r
151 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
152 IN EFI_HANDLE Controller,\r
9beb888e 153 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL\r
6ad55b15 154 )\r
6ad55b15 155{\r
156 EFI_STATUS Status;\r
157 EFI_SCSI_IO_PROTOCOL *ScsiIo;\r
158 SCSI_DISK_DEV *ScsiDiskDevice;\r
159 BOOLEAN Temp;\r
160 UINT8 Index;\r
161 UINT8 MaxRetry;\r
162 BOOLEAN NeedRetry;\r
163\r
9b38ff34 164 ScsiDiskDevice = (SCSI_DISK_DEV *) AllocateZeroPool (sizeof (SCSI_DISK_DEV));\r
165 if (ScsiDiskDevice == NULL) {\r
166 return EFI_OUT_OF_RESOURCES;\r
6ad55b15 167 }\r
168\r
6ad55b15 169 Status = gBS->OpenProtocol (\r
170 Controller,\r
171 &gEfiScsiIoProtocolGuid,\r
172 (VOID **) &ScsiIo,\r
173 This->DriverBindingHandle,\r
174 Controller,\r
175 EFI_OPEN_PROTOCOL_BY_DRIVER\r
176 );\r
177 if (EFI_ERROR (Status)) {\r
9b38ff34 178 FreePool (ScsiDiskDevice);\r
6ad55b15 179 return Status;\r
180 }\r
181\r
182 ScsiDiskDevice->Signature = SCSI_DISK_DEV_SIGNATURE;\r
183 ScsiDiskDevice->ScsiIo = ScsiIo;\r
184 ScsiDiskDevice->BlkIo.Media = &ScsiDiskDevice->BlkIoMedia;\r
185 ScsiDiskDevice->BlkIo.Reset = ScsiDiskReset;\r
186 ScsiDiskDevice->BlkIo.ReadBlocks = ScsiDiskReadBlocks;\r
187 ScsiDiskDevice->BlkIo.WriteBlocks = ScsiDiskWriteBlocks;\r
188 ScsiDiskDevice->BlkIo.FlushBlocks = ScsiDiskFlushBlocks;\r
189 ScsiDiskDevice->Handle = Controller;\r
190\r
191 ScsiIo->GetDeviceType (ScsiIo, &(ScsiDiskDevice->DeviceType));\r
192 switch (ScsiDiskDevice->DeviceType) {\r
193 case EFI_SCSI_TYPE_DISK:\r
194 ScsiDiskDevice->BlkIo.Media->BlockSize = 0x200;\r
195 break;\r
196\r
197 case EFI_SCSI_TYPE_CDROM:\r
198 ScsiDiskDevice->BlkIo.Media->BlockSize = 0x800;\r
199 break;\r
200 }\r
201 //\r
202 // The Sense Data Array's initial size is 6\r
203 //\r
204 ScsiDiskDevice->SenseDataNumber = 6;\r
9b38ff34 205 ScsiDiskDevice->SenseData = (EFI_SCSI_SENSE_DATA *) AllocateZeroPool (\r
206 sizeof (EFI_SCSI_SENSE_DATA) * ScsiDiskDevice->SenseDataNumber\r
207 );\r
208 if (ScsiDiskDevice->SenseData == NULL) {\r
6ad55b15 209 gBS->CloseProtocol (\r
210 Controller,\r
211 &gEfiScsiIoProtocolGuid,\r
212 This->DriverBindingHandle,\r
213 Controller\r
214 );\r
9b38ff34 215 FreePool (ScsiDiskDevice);\r
216 return EFI_OUT_OF_RESOURCES;\r
6ad55b15 217 }\r
218\r
6ad55b15 219 //\r
dfe687ca 220 // Retrieve device information\r
6ad55b15 221 //\r
222 MaxRetry = 2;\r
223 for (Index = 0; Index < MaxRetry; Index++) {\r
224 Status = ScsiDiskInquiryDevice (ScsiDiskDevice, &NeedRetry);\r
225 if (!EFI_ERROR (Status)) {\r
226 break;\r
227 }\r
228\r
229 if (!NeedRetry) {\r
9b38ff34 230 FreePool (ScsiDiskDevice->SenseData);\r
6ad55b15 231 gBS->CloseProtocol (\r
f36d6e66 232 Controller,\r
233 &gEfiScsiIoProtocolGuid,\r
234 This->DriverBindingHandle,\r
235 Controller\r
236 );\r
9b38ff34 237 FreePool (ScsiDiskDevice);\r
6ad55b15 238 return EFI_DEVICE_ERROR;\r
239 }\r
240 }\r
241 //\r
242 // The second parameter "TRUE" means must\r
243 // retrieve media capacity\r
244 //\r
245 Status = ScsiDiskDetectMedia (ScsiDiskDevice, TRUE, &Temp);\r
246 if (!EFI_ERROR (Status)) {\r
d14faa52 247 //\r
248 // Determine if Block IO should be produced on this controller handle\r
249 //\r
250 if (DetermineInstallBlockIo(Controller)) {\r
251 Status = gBS->InstallMultipleProtocolInterfaces (\r
252 &Controller,\r
253 &gEfiBlockIoProtocolGuid,\r
254 &ScsiDiskDevice->BlkIo,\r
255 NULL\r
256 );\r
257 if (!EFI_ERROR(Status)) {\r
258 ScsiDiskDevice->ControllerNameTable = NULL;\r
259 AddUnicodeString2 (\r
260 "eng",\r
261 gScsiDiskComponentName.SupportedLanguages,\r
262 &ScsiDiskDevice->ControllerNameTable,\r
263 L"SCSI Disk Device",\r
264 TRUE\r
265 );\r
266 AddUnicodeString2 (\r
267 "en",\r
268 gScsiDiskComponentName2.SupportedLanguages,\r
269 &ScsiDiskDevice->ControllerNameTable,\r
270 L"SCSI Disk Device",\r
271 FALSE\r
272 );\r
273 return EFI_SUCCESS;\r
274 }\r
275 } \r
6ad55b15 276 }\r
277\r
d14faa52 278 gBS->FreePool (ScsiDiskDevice->SenseData);\r
279 gBS->FreePool (ScsiDiskDevice);\r
280 gBS->CloseProtocol (\r
281 Controller,\r
282 &gEfiScsiIoProtocolGuid,\r
283 This->DriverBindingHandle,\r
284 Controller\r
285 );\r
286 return Status;\r
287 \r
6ad55b15 288}\r
289\r
9beb888e 290\r
291/**\r
292 Stop this driver on ControllerHandle.\r
293\r
294 This service is called by the EFI boot service DisconnectController().\r
295 In order to make drivers as small as possible, there are a few calling\r
296 restrictions for this service. DisconnectController() must follow these\r
297 calling restrictions. If any other agent wishes to call Stop() it must\r
298 also follow these calling restrictions.\r
299 \r
300 @param This Protocol instance pointer.\r
301 @param ControllerHandle Handle of device to stop driver on\r
302 @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of\r
303 children is zero stop the entire bus driver.\r
304 @param ChildHandleBuffer List of Child Handles to Stop.\r
305\r
306 @retval EFI_SUCCESS This driver is removed ControllerHandle\r
307 @retval other This driver was not removed from this device\r
308\r
309**/\r
6ad55b15 310EFI_STATUS\r
311EFIAPI\r
312ScsiDiskDriverBindingStop (\r
313 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
314 IN EFI_HANDLE Controller,\r
315 IN UINTN NumberOfChildren,\r
9beb888e 316 IN EFI_HANDLE *ChildHandleBuffer OPTIONAL\r
6ad55b15 317 )\r
6ad55b15 318{\r
319 EFI_BLOCK_IO_PROTOCOL *BlkIo;\r
320 SCSI_DISK_DEV *ScsiDiskDevice;\r
321 EFI_STATUS Status;\r
322\r
323 Status = gBS->OpenProtocol (\r
324 Controller,\r
325 &gEfiBlockIoProtocolGuid,\r
326 (VOID **) &BlkIo,\r
327 This->DriverBindingHandle,\r
328 Controller,\r
329 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
330 );\r
331 if (EFI_ERROR (Status)) {\r
332 return Status;\r
333 }\r
334\r
335 ScsiDiskDevice = SCSI_DISK_DEV_FROM_THIS (BlkIo);\r
336 Status = gBS->UninstallProtocolInterface (\r
337 Controller,\r
338 &gEfiBlockIoProtocolGuid,\r
339 &ScsiDiskDevice->BlkIo\r
340 );\r
341 if (!EFI_ERROR (Status)) {\r
342 gBS->CloseProtocol (\r
f36d6e66 343 Controller,\r
344 &gEfiScsiIoProtocolGuid,\r
345 This->DriverBindingHandle,\r
346 Controller\r
347 );\r
6ad55b15 348\r
349 ReleaseScsiDiskDeviceResources (ScsiDiskDevice);\r
350\r
351 return EFI_SUCCESS;\r
352 }\r
353 //\r
354 // errors met\r
355 //\r
356 return Status;\r
357}\r
358\r
9beb888e 359/**\r
360 Reset SCSI Disk.\r
361\r
6ad55b15 362\r
9beb888e 363 @param This The pointer of EFI_BLOCK_IO_PROTOCOL\r
364 @param ExtendedVerification The flag about if extend verificate\r
365\r
366 @retval EFI_SUCCESS The device was reset.\r
367 @retval EFI_DEVICE_ERROR The device is not functioning properly and could\r
368 not be reset.\r
369 @return EFI_STATUS is retured from EFI_SCSI_IO_PROTOCOL.ResetDevice().\r
370\r
371**/\r
6ad55b15 372EFI_STATUS\r
373EFIAPI\r
374ScsiDiskReset (\r
375 IN EFI_BLOCK_IO_PROTOCOL *This,\r
376 IN BOOLEAN ExtendedVerification\r
377 )\r
6ad55b15 378{\r
f36d6e66 379 EFI_TPL OldTpl;\r
6ad55b15 380 SCSI_DISK_DEV *ScsiDiskDevice;\r
381 EFI_STATUS Status;\r
6ad55b15 382\r
383 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
384\r
385 ScsiDiskDevice = SCSI_DISK_DEV_FROM_THIS (This);\r
386\r
387 Status = ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);\r
388\r
389 if (!ExtendedVerification) {\r
390 goto Done;\r
391 }\r
392\r
393 Status = ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo);\r
394\r
395Done:\r
396 gBS->RestoreTPL (OldTpl);\r
397 return Status;\r
398}\r
399\r
9beb888e 400/**\r
401 The function is to Read Block from SCSI Disk.\r
402\r
403 @param This The pointer of EFI_BLOCK_IO_PROTOCOL.\r
404 @param MediaId The Id of Media detected\r
405 @param Lba The logic block address\r
406 @param BufferSize The size of Buffer\r
407 @param Buffer The buffer to fill the read out data\r
408\r
409 @retval EFI_SUCCESS Successfully to read out block.\r
410 @retval EFI_DEVICE_ERROR Fail to detect media.\r
411 @retval EFI_NO_MEDIA Media is not present.\r
412 @retval EFI_MEDIA_CHANGED Media has changed.\r
413 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.\r
414 @retval EFI_INVALID_PARAMETER Invalid parameter passed in.\r
415\r
416**/\r
6ad55b15 417EFI_STATUS\r
418EFIAPI\r
419ScsiDiskReadBlocks (\r
420 IN EFI_BLOCK_IO_PROTOCOL *This,\r
421 IN UINT32 MediaId,\r
9beb888e 422 IN EFI_LBA Lba,\r
6ad55b15 423 IN UINTN BufferSize,\r
424 OUT VOID *Buffer\r
425 )\r
6ad55b15 426{\r
427 SCSI_DISK_DEV *ScsiDiskDevice;\r
428 EFI_BLOCK_IO_MEDIA *Media;\r
429 EFI_STATUS Status;\r
430 UINTN BlockSize;\r
431 UINTN NumberOfBlocks;\r
432 BOOLEAN MediaChange;\r
433 EFI_TPL OldTpl;\r
434\r
435 MediaChange = FALSE;\r
9beb888e 436 if (Buffer == NULL) {\r
6ad55b15 437 return EFI_INVALID_PARAMETER;\r
438 }\r
439\r
440 if (BufferSize == 0) {\r
441 return EFI_SUCCESS;\r
442 }\r
443\r
444 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
445\r
446 ScsiDiskDevice = SCSI_DISK_DEV_FROM_THIS (This);\r
447\r
9beb888e 448 if (!IS_DEVICE_FIXED(ScsiDiskDevice)) {\r
6ad55b15 449\r
450 Status = ScsiDiskDetectMedia (ScsiDiskDevice, FALSE, &MediaChange);\r
451 if (EFI_ERROR (Status)) {\r
452 Status = EFI_DEVICE_ERROR;\r
453 goto Done;\r
454 }\r
455\r
456 if (MediaChange) {\r
457 gBS->ReinstallProtocolInterface (\r
458 ScsiDiskDevice->Handle,\r
459 &gEfiBlockIoProtocolGuid,\r
460 &ScsiDiskDevice->BlkIo,\r
461 &ScsiDiskDevice->BlkIo\r
462 );\r
463 }\r
464 }\r
465 //\r
466 // Get the intrinsic block size\r
467 //\r
468 Media = ScsiDiskDevice->BlkIo.Media;\r
469 BlockSize = Media->BlockSize;\r
470\r
471 NumberOfBlocks = BufferSize / BlockSize;\r
472\r
473 if (!(Media->MediaPresent)) {\r
474 Status = EFI_NO_MEDIA;\r
475 goto Done;\r
476 }\r
477\r
478 if (MediaId != Media->MediaId) {\r
479 Status = EFI_MEDIA_CHANGED;\r
480 goto Done;\r
481 }\r
482\r
483 if (BufferSize % BlockSize != 0) {\r
484 Status = EFI_BAD_BUFFER_SIZE;\r
485 goto Done;\r
486 }\r
487\r
9beb888e 488 if (Lba > Media->LastBlock) {\r
6ad55b15 489 Status = EFI_INVALID_PARAMETER;\r
490 goto Done;\r
491 }\r
492\r
9beb888e 493 if ((Lba + NumberOfBlocks - 1) > Media->LastBlock) {\r
6ad55b15 494 Status = EFI_INVALID_PARAMETER;\r
495 goto Done;\r
496 }\r
497\r
498 if ((Media->IoAlign > 1) && (((UINTN) Buffer & (Media->IoAlign - 1)) != 0)) {\r
499 Status = EFI_INVALID_PARAMETER;\r
500 goto Done;\r
501 }\r
f36d6e66 502\r
6ad55b15 503 //\r
f36d6e66 504 // If all the parameters are valid, then perform read sectors command\r
6ad55b15 505 // to transfer data from device to host.\r
506 //\r
9beb888e 507 Status = ScsiDiskReadSectors (ScsiDiskDevice, Buffer, Lba, NumberOfBlocks);\r
6ad55b15 508\r
509Done:\r
510 gBS->RestoreTPL (OldTpl);\r
511 return Status;\r
512}\r
513\r
9beb888e 514/**\r
515 The function is to Write Block to SCSI Disk.\r
516\r
517 @param This The pointer of EFI_BLOCK_IO_PROTOCOL\r
518 @param MediaId The Id of Media detected\r
519 @param Lba The logic block address\r
520 @param BufferSize The size of Buffer\r
521 @param Buffer The buffer to fill the read out data\r
522\r
523 @retval EFI_SUCCESS Successfully to read out block.\r
524 @retval EFI_WRITE_PROTECTED The device can not be written to.\r
525 @retval EFI_DEVICE_ERROR Fail to detect media.\r
526 @retval EFI_NO_MEDIA Media is not present.\r
527 @retval EFI_MEDIA_CHNAGED Media has changed.\r
528 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.\r
529 @retval EFI_INVALID_PARAMETER Invalid parameter passed in.\r
530\r
531**/\r
6ad55b15 532EFI_STATUS\r
533EFIAPI\r
534ScsiDiskWriteBlocks (\r
535 IN EFI_BLOCK_IO_PROTOCOL *This,\r
536 IN UINT32 MediaId,\r
9beb888e 537 IN EFI_LBA Lba,\r
6ad55b15 538 IN UINTN BufferSize,\r
539 IN VOID *Buffer\r
540 )\r
6ad55b15 541{\r
542 SCSI_DISK_DEV *ScsiDiskDevice;\r
543 EFI_BLOCK_IO_MEDIA *Media;\r
544 EFI_STATUS Status;\r
545 UINTN BlockSize;\r
546 UINTN NumberOfBlocks;\r
547 BOOLEAN MediaChange;\r
548 EFI_TPL OldTpl;\r
549\r
550 MediaChange = FALSE;\r
9beb888e 551 if (Buffer == NULL) {\r
6ad55b15 552 return EFI_INVALID_PARAMETER;\r
553 }\r
554\r
555 if (BufferSize == 0) {\r
556 return EFI_SUCCESS;\r
557 }\r
558\r
559 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
560\r
561 ScsiDiskDevice = SCSI_DISK_DEV_FROM_THIS (This);\r
562\r
9beb888e 563 if (!IS_DEVICE_FIXED(ScsiDiskDevice)) {\r
6ad55b15 564\r
565 Status = ScsiDiskDetectMedia (ScsiDiskDevice, FALSE, &MediaChange);\r
566 if (EFI_ERROR (Status)) {\r
567 Status = EFI_DEVICE_ERROR;\r
568 goto Done;\r
569 }\r
570\r
571 if (MediaChange) {\r
572 gBS->ReinstallProtocolInterface (\r
573 ScsiDiskDevice->Handle,\r
574 &gEfiBlockIoProtocolGuid,\r
575 &ScsiDiskDevice->BlkIo,\r
576 &ScsiDiskDevice->BlkIo\r
577 );\r
578 }\r
579 }\r
580 //\r
581 // Get the intrinsic block size\r
582 //\r
583 Media = ScsiDiskDevice->BlkIo.Media;\r
584 BlockSize = Media->BlockSize;\r
585\r
586 NumberOfBlocks = BufferSize / BlockSize;\r
587\r
588 if (!(Media->MediaPresent)) {\r
589 Status = EFI_NO_MEDIA;\r
590 goto Done;\r
591 }\r
592\r
593 if (MediaId != Media->MediaId) {\r
594 Status = EFI_MEDIA_CHANGED;\r
595 goto Done;\r
596 }\r
597\r
598 if (BufferSize % BlockSize != 0) {\r
599 Status = EFI_BAD_BUFFER_SIZE;\r
600 goto Done;\r
601 }\r
602\r
9beb888e 603 if (Lba > Media->LastBlock) {\r
6ad55b15 604 Status = EFI_INVALID_PARAMETER;\r
605 goto Done;\r
606 }\r
607\r
9beb888e 608 if ((Lba + NumberOfBlocks - 1) > Media->LastBlock) {\r
6ad55b15 609 Status = EFI_INVALID_PARAMETER;\r
610 goto Done;\r
611 }\r
612\r
613 if ((Media->IoAlign > 1) && (((UINTN) Buffer & (Media->IoAlign - 1)) != 0)) {\r
614 Status = EFI_INVALID_PARAMETER;\r
615 goto Done;\r
616 }\r
617 //\r
618 // if all the parameters are valid, then perform read sectors command\r
619 // to transfer data from device to host.\r
620 //\r
9beb888e 621 Status = ScsiDiskWriteSectors (ScsiDiskDevice, Buffer, Lba, NumberOfBlocks);\r
6ad55b15 622\r
623Done:\r
624 gBS->RestoreTPL (OldTpl);\r
6ad55b15 625 return Status;\r
626}\r
627\r
9beb888e 628/**\r
629 Flush Block to Disk.\r
630\r
631 EFI_SUCCESS is returned directly.\r
632\r
633 @param This The pointer of EFI_BLOCK_IO_PROTOCOL\r
634\r
635 @retval EFI_SUCCESS All outstanding data was written to the device\r
636\r
637**/\r
6ad55b15 638EFI_STATUS\r
639EFIAPI\r
640ScsiDiskFlushBlocks (\r
641 IN EFI_BLOCK_IO_PROTOCOL *This\r
642 )\r
6ad55b15 643{\r
644 //\r
645 // return directly\r
646 //\r
647 return EFI_SUCCESS;\r
648}\r
649\r
6ad55b15 650\r
9beb888e 651/**\r
f36d6e66 652 Dectect Device and read out capacity ,if error occurs, parse the sense key.\r
6ad55b15 653\r
9beb888e 654 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV\r
655 @param MustReadCapacity The flag about reading device capacity\r
656 @param MediaChange The pointer of flag indicates if media has changed \r
6ad55b15 657\r
9beb888e 658 @retval EFI_DEVICE_ERROR Indicates that error occurs\r
659 @retval EFI_SUCCESS Successfully to detect media\r
6ad55b15 660\r
9beb888e 661**/\r
662EFI_STATUS\r
663ScsiDiskDetectMedia (\r
664 IN SCSI_DISK_DEV *ScsiDiskDevice,\r
665 IN BOOLEAN MustReadCapacity,\r
666 OUT BOOLEAN *MediaChange\r
667 )\r
6ad55b15 668{\r
669 EFI_STATUS Status;\r
670 EFI_STATUS ReadCapacityStatus;\r
671 EFI_SCSI_SENSE_DATA *SenseData;\r
672 UINTN NumberOfSenseKeys;\r
673 BOOLEAN NeedRetry;\r
674 BOOLEAN NeedReadCapacity;\r
675 UINT8 Index;\r
676 UINT8 MaxRetry;\r
677 EFI_BLOCK_IO_MEDIA OldMedia;\r
678 UINTN Action;\r
679\r
680 Status = EFI_SUCCESS;\r
681 ReadCapacityStatus = EFI_SUCCESS;\r
682 SenseData = NULL;\r
683 NumberOfSenseKeys = 0;\r
684 NeedReadCapacity = FALSE;\r
685 CopyMem (&OldMedia, ScsiDiskDevice->BlkIo.Media, sizeof (OldMedia));\r
6ad55b15 686 *MediaChange = FALSE;\r
6ad55b15 687 MaxRetry = 3;\r
f36d6e66 688\r
6ad55b15 689 for (Index = 0; Index < MaxRetry; Index++) {\r
690 Status = ScsiDiskTestUnitReady (\r
691 ScsiDiskDevice,\r
692 &NeedRetry,\r
693 &SenseData,\r
694 &NumberOfSenseKeys\r
695 );\r
696 if (!EFI_ERROR (Status)) {\r
697 break;\r
698 }\r
699\r
700 if (!NeedRetry) {\r
701 return Status;\r
702 }\r
703 }\r
704\r
705 if ((Index == MaxRetry) && EFI_ERROR (Status)) {\r
706 return EFI_DEVICE_ERROR;\r
707 }\r
708\r
709 Status = DetectMediaParsingSenseKeys (\r
710 ScsiDiskDevice,\r
711 SenseData,\r
712 NumberOfSenseKeys,\r
713 &Action\r
714 );\r
715 if (EFI_ERROR (Status)) {\r
716 return Status;\r
717 }\r
718 //\r
719 // ACTION_NO_ACTION: need not read capacity\r
720 // other action code: need read capacity\r
721 //\r
722 if (Action == ACTION_NO_ACTION) {\r
723 NeedReadCapacity = FALSE;\r
724 } else {\r
725 NeedReadCapacity = TRUE;\r
726 }\r
f36d6e66 727\r
6ad55b15 728 //\r
729 // either NeedReadCapacity is TRUE, or MustReadCapacity is TRUE,\r
730 // retrieve capacity via Read Capacity command\r
731 //\r
732 if (NeedReadCapacity || MustReadCapacity) {\r
6ad55b15 733 //\r
734 // retrieve media information\r
735 //\r
736 MaxRetry = 3;\r
737 for (Index = 0; Index < MaxRetry; Index++) {\r
738\r
739 ReadCapacityStatus = ScsiDiskReadCapacity (\r
740 ScsiDiskDevice,\r
741 &NeedRetry,\r
742 &SenseData,\r
743 &NumberOfSenseKeys\r
744 );\r
745 if (EFI_ERROR (ReadCapacityStatus) && !NeedRetry) {\r
746 return EFI_DEVICE_ERROR;\r
747 }\r
748 //\r
749 // analyze sense key to action\r
750 //\r
751 Status = DetectMediaParsingSenseKeys (\r
752 ScsiDiskDevice,\r
753 SenseData,\r
754 NumberOfSenseKeys,\r
755 &Action\r
756 );\r
757 //\r
758 // if Status is error, it may indicate crisis error,\r
759 // so return without retry.\r
760 //\r
761 if (EFI_ERROR (Status)) {\r
762 return Status;\r
763 }\r
764\r
765 switch (Action) {\r
766 case ACTION_NO_ACTION:\r
767 //\r
768 // no retry\r
769 //\r
770 Index = MaxRetry;\r
771 break;\r
772\r
773 case ACTION_RETRY_COMMAND_LATER:\r
774 //\r
775 // retry the ReadCapacity later and continuously, until the condition\r
776 // no longer emerges.\r
777 // stall time is 100000us, or say 0.1 second.\r
778 //\r
779 gBS->Stall (100000);\r
780 Index = 0;\r
781 break;\r
782\r
783 default:\r
784 //\r
785 // other cases, just retry the command\r
786 //\r
787 break;\r
788 }\r
789 }\r
790\r
791 if ((Index == MaxRetry) && EFI_ERROR (ReadCapacityStatus)) {\r
792 return EFI_DEVICE_ERROR;\r
793 }\r
794 }\r
795\r
796 if (ScsiDiskDevice->BlkIo.Media->MediaId != OldMedia.MediaId) {\r
797 //\r
798 // Media change information got from the device\r
799 //\r
800 *MediaChange = TRUE;\r
801 }\r
802\r
803 if (ScsiDiskDevice->BlkIo.Media->ReadOnly != OldMedia.ReadOnly) {\r
804 *MediaChange = TRUE;\r
805 ScsiDiskDevice->BlkIo.Media->MediaId += 1;\r
806 }\r
807\r
808 if (ScsiDiskDevice->BlkIo.Media->BlockSize != OldMedia.BlockSize) {\r
809 *MediaChange = TRUE;\r
810 ScsiDiskDevice->BlkIo.Media->MediaId += 1;\r
811 }\r
812\r
813 if (ScsiDiskDevice->BlkIo.Media->LastBlock != OldMedia.LastBlock) {\r
814 *MediaChange = TRUE;\r
815 ScsiDiskDevice->BlkIo.Media->MediaId += 1;\r
816 }\r
817\r
818 if (ScsiDiskDevice->BlkIo.Media->MediaPresent != OldMedia.MediaPresent) {\r
819 if (ScsiDiskDevice->BlkIo.Media->MediaPresent) {\r
820 //\r
821 // when change from no media to media present, reset the MediaId to 1.\r
822 //\r
823 ScsiDiskDevice->BlkIo.Media->MediaId = 1;\r
824 } else {\r
825 //\r
826 // when no media, reset the MediaId to zero.\r
827 //\r
828 ScsiDiskDevice->BlkIo.Media->MediaId = 0;\r
829 }\r
830\r
831 *MediaChange = TRUE;\r
832 }\r
833\r
834 return EFI_SUCCESS;\r
835}\r
836\r
6ad55b15 837\r
9beb888e 838/**\r
839 Send out Inquiry command to Device.\r
6ad55b15 840\r
9beb888e 841 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV\r
842 @param NeedRetry Indicates if needs try again when error happens\r
6ad55b15 843\r
9beb888e 844 @retval EFI_DEVICE_ERROR Indicates that error occurs\r
845 @retval EFI_SUCCESS Successfully to detect media\r
6ad55b15 846\r
9beb888e 847**/\r
848EFI_STATUS\r
849ScsiDiskInquiryDevice (\r
850 IN OUT SCSI_DISK_DEV *ScsiDiskDevice,\r
851 OUT BOOLEAN *NeedRetry\r
852 )\r
6ad55b15 853{\r
854 UINT32 InquiryDataLength;\r
855 UINT8 SenseDataLength;\r
856 UINT8 HostAdapterStatus;\r
857 UINT8 TargetStatus;\r
858 EFI_SCSI_SENSE_DATA *SenseDataArray;\r
859 UINTN NumberOfSenseKeys;\r
860 EFI_STATUS Status;\r
861 UINT8 MaxRetry;\r
862 UINT8 Index;\r
863\r
864 InquiryDataLength = sizeof (EFI_SCSI_INQUIRY_DATA);\r
865 SenseDataLength = 0;\r
866\r
d35be2a4 867 Status = ScsiInquiryCommand (\r
6ad55b15 868 ScsiDiskDevice->ScsiIo,\r
e72a3b3e 869 EFI_TIMER_PERIOD_SECONDS (1),\r
6ad55b15 870 NULL,\r
871 &SenseDataLength,\r
872 &HostAdapterStatus,\r
873 &TargetStatus,\r
874 (VOID *) &(ScsiDiskDevice->InquiryData),\r
875 &InquiryDataLength,\r
876 FALSE\r
877 );\r
6ad55b15 878 //\r
879 // no need to check HostAdapterStatus and TargetStatus\r
880 //\r
f36d6e66 881 if ((Status == EFI_SUCCESS) || (Status == EFI_WARN_BUFFER_TOO_SMALL)) {\r
882 ParseInquiryData (ScsiDiskDevice);\r
883 return EFI_SUCCESS;\r
884 \r
885 } else if (Status == EFI_NOT_READY) {\r
886 *NeedRetry = TRUE;\r
887 return EFI_DEVICE_ERROR;\r
888 \r
889 } else if ((Status == EFI_INVALID_PARAMETER) || (Status == EFI_UNSUPPORTED)) {\r
890 *NeedRetry = FALSE;\r
891 return EFI_DEVICE_ERROR;\r
892 }\r
893 //\r
894 // go ahead to check HostAdapterStatus and TargetStatus\r
895 // (EFI_TIMEOUT, EFI_DEVICE_ERROR)\r
896 //\r
897 \r
898 Status = CheckHostAdapterStatus (HostAdapterStatus);\r
899 if ((Status == EFI_TIMEOUT) || (Status == EFI_NOT_READY)) {\r
900 *NeedRetry = TRUE;\r
901 return EFI_DEVICE_ERROR;\r
902 } else if (Status == EFI_DEVICE_ERROR) {\r
903 //\r
904 // reset the scsi channel\r
905 //\r
6ad55b15 906 ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo);\r
907 *NeedRetry = FALSE;\r
908 return EFI_DEVICE_ERROR;\r
909 }\r
910\r
911 Status = CheckTargetStatus (TargetStatus);\r
912 if (Status == EFI_NOT_READY) {\r
913 //\r
914 // reset the scsi device\r
915 //\r
916 ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);\r
917 *NeedRetry = TRUE;\r
918 return EFI_DEVICE_ERROR;\r
f36d6e66 919\r
6ad55b15 920 } else if (Status == EFI_DEVICE_ERROR) {\r
921 *NeedRetry = FALSE;\r
922 return EFI_DEVICE_ERROR;\r
923 }\r
924 \r
925 //\r
b96cd313 926 // if goes here, meant ScsiInquiryCommand() failed.\r
6ad55b15 927 // if ScsiDiskRequestSenseKeys() succeeds at last,\r
b96cd313 928 // better retry ScsiInquiryCommand(). (by setting *NeedRetry = TRUE)\r
6ad55b15 929 //\r
930 MaxRetry = 3;\r
931 for (Index = 0; Index < MaxRetry; Index++) {\r
6ad55b15 932 Status = ScsiDiskRequestSenseKeys (\r
933 ScsiDiskDevice,\r
934 NeedRetry,\r
935 &SenseDataArray,\r
936 &NumberOfSenseKeys,\r
937 TRUE\r
938 );\r
939 if (!EFI_ERROR (Status)) {\r
940 *NeedRetry = TRUE;\r
941 return EFI_DEVICE_ERROR;\r
942 }\r
943\r
944 if (!*NeedRetry) {\r
945 return EFI_DEVICE_ERROR;\r
946 }\r
947 }\r
948 //\r
949 // ScsiDiskRequestSenseKeys() failed after several rounds of retry.\r
950 // set *NeedRetry = FALSE to avoid the outside caller try again.\r
951 //\r
952 *NeedRetry = FALSE;\r
953 return EFI_DEVICE_ERROR;\r
954}\r
955\r
9beb888e 956/**\r
957 To test deivice.\r
f36d6e66 958\r
959 When Test Unit Ready command succeeds, retrieve Sense Keys via Request Sense;\r
6ad55b15 960 When Test Unit Ready command encounters any error caused by host adapter or\r
961 target, return error without retrieving Sense Keys.\r
f36d6e66 962\r
9beb888e 963 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV\r
964 @param NeedRetry The pointer of flag indicates try again\r
965 @param SenseDataArray The pointer of an array of sense data\r
966 @param NumberOfSenseKeys The pointer of the number of sense data array\r
f36d6e66 967\r
9beb888e 968 @retval EFI_DEVICE_ERROR Indicates that error occurs\r
969 @retval EFI_SUCCESS Successfully to test unit\r
f36d6e66 970\r
9beb888e 971**/\r
972EFI_STATUS\r
973ScsiDiskTestUnitReady (\r
974 IN SCSI_DISK_DEV *ScsiDiskDevice,\r
975 OUT BOOLEAN *NeedRetry,\r
976 OUT EFI_SCSI_SENSE_DATA **SenseDataArray,\r
977 OUT UINTN *NumberOfSenseKeys\r
978 )\r
6ad55b15 979{\r
980 EFI_STATUS Status;\r
981 UINT8 SenseDataLength;\r
982 UINT8 HostAdapterStatus;\r
983 UINT8 TargetStatus;\r
984 UINT8 Index;\r
985 UINT8 MaxRetry;\r
986\r
987 SenseDataLength = 0;\r
988 *NumberOfSenseKeys = 0;\r
989\r
990 //\r
991 // Parameter 3 and 4: do not require sense data, retrieve it when needed.\r
992 //\r
d35be2a4 993 Status = ScsiTestUnitReadyCommand (\r
6ad55b15 994 ScsiDiskDevice->ScsiIo,\r
e72a3b3e 995 EFI_TIMER_PERIOD_SECONDS (1),\r
6ad55b15 996 NULL,\r
997 &SenseDataLength,\r
998 &HostAdapterStatus,\r
999 &TargetStatus\r
1000 );\r
f36d6e66 1001 //\r
1002 // no need to check HostAdapterStatus and TargetStatus\r
1003 //\r
6ad55b15 1004 if (Status == EFI_NOT_READY) {\r
6ad55b15 1005 *NeedRetry = TRUE;\r
1006 return EFI_DEVICE_ERROR;\r
f36d6e66 1007\r
6ad55b15 1008 } else if ((Status == EFI_INVALID_PARAMETER) || (Status == EFI_UNSUPPORTED)) {\r
6ad55b15 1009 *NeedRetry = FALSE;\r
1010 return EFI_DEVICE_ERROR;\r
1011 }\r
1012 //\r
f36d6e66 1013 // go ahead to check HostAdapterStatus and TargetStatus(in case of EFI_DEVICE_ERROR)\r
6ad55b15 1014 //\r
f36d6e66 1015\r
6ad55b15 1016 Status = CheckHostAdapterStatus (HostAdapterStatus);\r
1017 if ((Status == EFI_TIMEOUT) || (Status == EFI_NOT_READY)) {\r
1018 *NeedRetry = TRUE;\r
1019 return EFI_DEVICE_ERROR;\r
f36d6e66 1020\r
6ad55b15 1021 } else if (Status == EFI_DEVICE_ERROR) {\r
1022 //\r
1023 // reset the scsi channel\r
1024 //\r
1025 ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo);\r
1026 *NeedRetry = FALSE;\r
1027 return EFI_DEVICE_ERROR;\r
1028 }\r
1029\r
1030 Status = CheckTargetStatus (TargetStatus);\r
1031 if (Status == EFI_NOT_READY) {\r
1032 //\r
1033 // reset the scsi device\r
1034 //\r
1035 ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);\r
1036 *NeedRetry = TRUE;\r
1037 return EFI_DEVICE_ERROR;\r
f36d6e66 1038\r
6ad55b15 1039 } else if (Status == EFI_DEVICE_ERROR) {\r
1040 *NeedRetry = FALSE;\r
1041 return EFI_DEVICE_ERROR;\r
1042 }\r
1043\r
1044 MaxRetry = 3;\r
1045 for (Index = 0; Index < MaxRetry; Index++) {\r
6ad55b15 1046 Status = ScsiDiskRequestSenseKeys (\r
1047 ScsiDiskDevice,\r
1048 NeedRetry,\r
1049 SenseDataArray,\r
1050 NumberOfSenseKeys,\r
1051 FALSE\r
1052 );\r
1053 if (!EFI_ERROR (Status)) {\r
1054 return EFI_SUCCESS;\r
1055 }\r
1056\r
1057 if (!*NeedRetry) {\r
1058 return EFI_DEVICE_ERROR;\r
1059 }\r
1060 }\r
1061 //\r
1062 // ScsiDiskRequestSenseKeys() failed after several rounds of retry.\r
1063 // set *NeedRetry = FALSE to avoid the outside caller try again.\r
1064 //\r
1065 *NeedRetry = FALSE;\r
1066 return EFI_DEVICE_ERROR;\r
1067}\r
1068\r
9beb888e 1069/**\r
f36d6e66 1070 Parsing Sense Keys which got from request sense command.\r
6ad55b15 1071\r
9beb888e 1072 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV\r
1073 @param SenseData The pointer of EFI_SCSI_SENSE_DATA\r
1074 @param NumberOfSenseKeys The number of sense key \r
1075 @param Action The pointer of action which indicates what is need to do next\r
6ad55b15 1076\r
9beb888e 1077 @retval EFI_DEVICE_ERROR Indicates that error occurs\r
1078 @retval EFI_SUCCESS Successfully to complete the parsing\r
6ad55b15 1079\r
9beb888e 1080**/\r
1081EFI_STATUS\r
1082DetectMediaParsingSenseKeys (\r
1083 OUT SCSI_DISK_DEV *ScsiDiskDevice,\r
1084 IN EFI_SCSI_SENSE_DATA *SenseData,\r
1085 IN UINTN NumberOfSenseKeys,\r
1086 OUT UINTN *Action\r
1087 )\r
6ad55b15 1088{\r
1089 BOOLEAN RetryLater;\r
1090\r
1091 //\r
1092 // Default is to read capacity, unless..\r
1093 //\r
1094 *Action = ACTION_READ_CAPACITY;\r
1095\r
1096 if (NumberOfSenseKeys == 0) {\r
1097 *Action = ACTION_NO_ACTION;\r
1098 return EFI_SUCCESS;\r
1099 }\r
1100\r
1101 if (!ScsiDiskHaveSenseKey (SenseData, NumberOfSenseKeys)) {\r
1102 //\r
1103 // No Sense Key returned from last submitted command\r
1104 //\r
1105 *Action = ACTION_NO_ACTION;\r
1106 return EFI_SUCCESS;\r
1107 }\r
1108\r
1109 if (ScsiDiskIsNoMedia (SenseData, NumberOfSenseKeys)) {\r
1110 ScsiDiskDevice->BlkIo.Media->MediaPresent = FALSE;\r
1111 ScsiDiskDevice->BlkIo.Media->LastBlock = 0;\r
1112 *Action = ACTION_NO_ACTION;\r
1113 return EFI_SUCCESS;\r
1114 }\r
1115\r
1116 if (ScsiDiskIsMediaChange (SenseData, NumberOfSenseKeys)) {\r
1117 ScsiDiskDevice->BlkIo.Media->MediaId++;\r
1118 return EFI_SUCCESS;\r
1119 }\r
1120\r
1121 if (ScsiDiskIsMediaError (SenseData, NumberOfSenseKeys)) {\r
1122 ScsiDiskDevice->BlkIo.Media->MediaPresent = FALSE;\r
1123 ScsiDiskDevice->BlkIo.Media->LastBlock = 0;\r
1124 return EFI_DEVICE_ERROR;\r
1125 }\r
1126\r
1127 if (ScsiDiskIsHardwareError (SenseData, NumberOfSenseKeys)) {\r
1128 return EFI_DEVICE_ERROR;\r
1129 }\r
1130\r
1131 if (!ScsiDiskIsDriveReady (SenseData, NumberOfSenseKeys, &RetryLater)) {\r
1132 if (RetryLater) {\r
1133 *Action = ACTION_RETRY_COMMAND_LATER;\r
1134 return EFI_SUCCESS;\r
1135 }\r
1136\r
1137 return EFI_DEVICE_ERROR;\r
1138 }\r
1139\r
1140 return EFI_SUCCESS;\r
1141}\r
1142\r
6ad55b15 1143\r
9beb888e 1144/**\r
1145 Send read capacity command to device and get the device parameter.\r
6ad55b15 1146\r
9beb888e 1147 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV\r
1148 @param NeedRetry The pointer of flag indicates if need a retry\r
1149 @param SenseDataArray The pointer of an array of sense data\r
1150 @param NumberOfSenseKeys The number of sense key\r
6ad55b15 1151\r
9beb888e 1152 @retval EFI_DEVICE_ERROR Indicates that error occurs\r
1153 @retval EFI_SUCCESS Successfully to read capacity\r
6ad55b15 1154\r
9beb888e 1155**/\r
1156EFI_STATUS\r
1157ScsiDiskReadCapacity (\r
1158 IN OUT SCSI_DISK_DEV *ScsiDiskDevice,\r
1159 OUT BOOLEAN *NeedRetry,\r
1160 OUT EFI_SCSI_SENSE_DATA **SenseDataArray,\r
1161 OUT UINTN *NumberOfSenseKeys\r
1162 )\r
6ad55b15 1163{\r
b96cd313 1164 UINT8 HostAdapterStatus;\r
1165 UINT8 TargetStatus;\r
1166 EFI_STATUS CommandStatus;\r
1167 EFI_STATUS Status;\r
1168 UINT8 Index;\r
1169 UINT8 MaxRetry;\r
1170 UINT8 SenseDataLength;\r
1171 UINT8 ScsiVersion;\r
1172 UINT32 DataLength10;\r
1173 UINT32 DataLength16;\r
1174 EFI_SCSI_DISK_CAPACITY_DATA CapacityData10;\r
1175 EFI_SCSI_DISK_CAPACITY_DATA16 CapacityData16;\r
1176\r
1177\r
1178 SenseDataLength = 0;\r
1179 DataLength10 = sizeof (EFI_SCSI_DISK_CAPACITY_DATA);\r
1180 DataLength16 = sizeof (EFI_SCSI_DISK_CAPACITY_DATA16);\r
1181 ZeroMem (&CapacityData10, sizeof (EFI_SCSI_DISK_CAPACITY_DATA));\r
1182 ZeroMem (&CapacityData16, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16));\r
6ad55b15 1183\r
1184 *NumberOfSenseKeys = 0;\r
1185 *NeedRetry = FALSE;\r
b96cd313 1186 ScsiVersion = (UINT8)(ScsiDiskDevice->InquiryData.Version & 0x03);\r
1187\r
1188 if (ScsiVersion < SCSI_COMMAND_VERSION_3) {\r
1189 //\r
1190 // submit Read Capacity(10) Command. in this call,not request sense data\r
1191 //\r
1192 CommandStatus = ScsiReadCapacityCommand (\r
1193 ScsiDiskDevice->ScsiIo,\r
1194 EFI_TIMER_PERIOD_SECONDS(1),\r
1195 NULL,\r
1196 &SenseDataLength,\r
1197 &HostAdapterStatus,\r
1198 &TargetStatus,\r
1199 (VOID *) &CapacityData10,\r
1200 &DataLength10,\r
1201 FALSE\r
1202 );\r
1203 } else {\r
1204 //\r
1205 // submit Read Capacity(16) Command to get parameter LogicalBlocksPerPhysicalBlock\r
1206 // and LowestAlignedLba\r
1207 //\r
1208 CommandStatus = ScsiReadCapacity16Command (\r
1209 ScsiDiskDevice->ScsiIo,\r
1210 EFI_TIMER_PERIOD_SECONDS (1),\r
1211 NULL,\r
1212 &SenseDataLength,\r
1213 &HostAdapterStatus,\r
1214 &TargetStatus,\r
1215 (VOID *) &CapacityData16,\r
1216 &DataLength16,\r
1217 FALSE\r
1218 );\r
1219 }\r
1220 //\r
6ad55b15 1221 // no need to check HostAdapterStatus and TargetStatus\r
1222 //\r
f36d6e66 1223 if (CommandStatus == EFI_SUCCESS) {\r
b96cd313 1224 GetMediaInfo (ScsiDiskDevice, &CapacityData10,&CapacityData16);\r
f36d6e66 1225 return EFI_SUCCESS;\r
1226 \r
1227 } else if (CommandStatus == EFI_NOT_READY) {\r
1228 *NeedRetry = TRUE;\r
1229 return EFI_DEVICE_ERROR;\r
1230 \r
1231 } else if ((CommandStatus == EFI_INVALID_PARAMETER) || (CommandStatus == EFI_UNSUPPORTED)) {\r
1232 *NeedRetry = FALSE;\r
1233 return EFI_DEVICE_ERROR;\r
1234 }\r
1235 //\r
1236 // go ahead to check HostAdapterStatus and TargetStatus\r
1237 // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)\r
1238 //\r
1239 \r
1240 Status = CheckHostAdapterStatus (HostAdapterStatus);\r
1241 if ((Status == EFI_TIMEOUT) || (Status == EFI_NOT_READY)) {\r
1242 *NeedRetry = TRUE;\r
1243 return EFI_DEVICE_ERROR;\r
1244 \r
1245 } else if (Status == EFI_DEVICE_ERROR) {\r
6ad55b15 1246 //\r
1247 // reset the scsi channel\r
1248 //\r
1249 ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo);\r
1250 *NeedRetry = FALSE;\r
1251 return EFI_DEVICE_ERROR;\r
1252 }\r
1253\r
1254 Status = CheckTargetStatus (TargetStatus);\r
1255 if (Status == EFI_NOT_READY) {\r
1256 //\r
1257 // reset the scsi device\r
1258 //\r
1259 ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);\r
1260 *NeedRetry = TRUE;\r
1261 return EFI_DEVICE_ERROR;\r
f36d6e66 1262\r
6ad55b15 1263 } else if (Status == EFI_DEVICE_ERROR) {\r
1264 *NeedRetry = FALSE;\r
1265 return EFI_DEVICE_ERROR;\r
1266 }\r
1267 \r
1268 //\r
b96cd313 1269 // if goes here, meant ScsiReadCapacityCommand() failed.\r
6ad55b15 1270 // if ScsiDiskRequestSenseKeys() succeeds at last,\r
b96cd313 1271 // better retry ScsiReadCapacityCommand(). (by setting *NeedRetry = TRUE)\r
6ad55b15 1272 //\r
1273 MaxRetry = 3;\r
1274 for (Index = 0; Index < MaxRetry; Index++) {\r
1275\r
1276 Status = ScsiDiskRequestSenseKeys (\r
1277 ScsiDiskDevice,\r
1278 NeedRetry,\r
1279 SenseDataArray,\r
1280 NumberOfSenseKeys,\r
1281 TRUE\r
1282 );\r
1283 if (!EFI_ERROR (Status)) {\r
1284 *NeedRetry = TRUE;\r
1285 return EFI_DEVICE_ERROR;\r
1286 }\r
1287\r
1288 if (!*NeedRetry) {\r
1289 return EFI_DEVICE_ERROR;\r
1290 }\r
1291 }\r
1292 //\r
1293 // ScsiDiskRequestSenseKeys() failed after several rounds of retry.\r
1294 // set *NeedRetry = FALSE to avoid the outside caller try again.\r
1295 //\r
1296 *NeedRetry = FALSE;\r
1297 return EFI_DEVICE_ERROR;\r
1298}\r
1299\r
9beb888e 1300/**\r
1301 Check the HostAdapter status and re-interpret it in EFI_STATUS.\r
6ad55b15 1302\r
9beb888e 1303 @param HostAdapterStatus Host Adapter status\r
6ad55b15 1304\r
9beb888e 1305 @retval EFI_SUCCESS Host adapter is OK.\r
1306 @retval EFI_TIMEOUT Timeout.\r
1307 @retval EFI_NOT_READY Adapter NOT ready.\r
1308 @retval EFI_DEVICE_ERROR Adapter device error.\r
6ad55b15 1309\r
9beb888e 1310**/\r
1311EFI_STATUS\r
1312CheckHostAdapterStatus (\r
1313 IN UINT8 HostAdapterStatus\r
1314 )\r
6ad55b15 1315{\r
1316 switch (HostAdapterStatus) {\r
f36d6e66 1317 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_OK:\r
6ad55b15 1318 return EFI_SUCCESS;\r
1319\r
f36d6e66 1320 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_SELECTION_TIMEOUT:\r
1321 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_TIMEOUT:\r
1322 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_TIMEOUT_COMMAND:\r
6ad55b15 1323 return EFI_TIMEOUT;\r
1324\r
f36d6e66 1325 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_MESSAGE_REJECT:\r
1326 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_PARITY_ERROR:\r
1327 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_REQUEST_SENSE_FAILED:\r
1328 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_DATA_OVERRUN_UNDERRUN:\r
1329 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_BUS_RESET:\r
6ad55b15 1330 return EFI_NOT_READY;\r
1331\r
f36d6e66 1332 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_BUS_FREE:\r
1333 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_PHASE_ERROR:\r
6ad55b15 1334 return EFI_DEVICE_ERROR;\r
1335\r
1336 default:\r
1337 return EFI_SUCCESS;\r
1338 }\r
1339}\r
1340\r
6ad55b15 1341\r
9beb888e 1342/**\r
1343 Check the target status and re-interpret it in EFI_STATUS.\r
6ad55b15 1344\r
9beb888e 1345 @param TargetStatus Target status\r
6ad55b15 1346\r
9beb888e 1347 @retval EFI_NOT_READY Device is NOT ready.\r
1348 @retval EFI_DEVICE_ERROR \r
1349 @retval EFI_SUCCESS\r
6ad55b15 1350\r
9beb888e 1351**/\r
1352EFI_STATUS\r
1353CheckTargetStatus (\r
1354 IN UINT8 TargetStatus\r
1355 )\r
6ad55b15 1356{\r
1357 switch (TargetStatus) {\r
f36d6e66 1358 case EFI_EXT_SCSI_STATUS_TARGET_GOOD:\r
1359 case EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION:\r
1360 case EFI_EXT_SCSI_STATUS_TARGET_CONDITION_MET:\r
6ad55b15 1361 return EFI_SUCCESS;\r
1362\r
f36d6e66 1363 case EFI_EXT_SCSI_STATUS_TARGET_INTERMEDIATE:\r
1364 case EFI_EXT_SCSI_STATUS_TARGET_INTERMEDIATE_CONDITION_MET:\r
1365 case EFI_EXT_SCSI_STATUS_TARGET_BUSY:\r
1366 case EFI_EXT_SCSI_STATUS_TARGET_TASK_SET_FULL:\r
6ad55b15 1367 return EFI_NOT_READY;\r
1368\r
f36d6e66 1369 case EFI_EXT_SCSI_STATUS_TARGET_RESERVATION_CONFLICT:\r
6ad55b15 1370 return EFI_DEVICE_ERROR;\r
1371 break;\r
1372\r
1373 default:\r
1374 return EFI_SUCCESS;\r
1375 }\r
1376}\r
1377\r
f36d6e66 1378\r
9beb888e 1379/**\r
6ad55b15 1380 Retrieve all sense keys from the device.\r
f36d6e66 1381\r
9beb888e 1382 When encountering error during the process, if retrieve sense keys before\r
1383 error encounterred, it returns the sense keys with return status set to EFI_SUCCESS,\r
1384 and NeedRetry set to FALSE; otherwize, return the proper return status.\r
1385\r
1386 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV\r
1387 @param NeedRetry The pointer of flag indicates if need a retry\r
1388 @param SenseDataArray The pointer of an array of sense data\r
1389 @param NumberOfSenseKeys The number of sense key\r
1390 @param AskResetIfError The flag indicates if need reset when error occurs\r
1391\r
1392 @retval EFI_DEVICE_ERROR Indicates that error occurs\r
1393 @retval EFI_SUCCESS Successfully to request sense key\r
f36d6e66 1394\r
9beb888e 1395**/\r
1396EFI_STATUS\r
1397ScsiDiskRequestSenseKeys (\r
1398 IN OUT SCSI_DISK_DEV *ScsiDiskDevice,\r
1399 OUT BOOLEAN *NeedRetry,\r
1400 OUT EFI_SCSI_SENSE_DATA **SenseDataArray,\r
1401 OUT UINTN *NumberOfSenseKeys,\r
1402 IN BOOLEAN AskResetIfError\r
1403 )\r
6ad55b15 1404{\r
1405 EFI_SCSI_SENSE_DATA *PtrSenseData;\r
1406 UINT8 SenseDataLength;\r
1407 BOOLEAN SenseReq;\r
1408 EFI_STATUS Status;\r
1409 EFI_STATUS FallStatus;\r
1410 UINT8 HostAdapterStatus;\r
1411 UINT8 TargetStatus;\r
1412\r
1413 FallStatus = EFI_SUCCESS;\r
1414 SenseDataLength = sizeof (EFI_SCSI_SENSE_DATA);\r
1415\r
1416 ZeroMem (\r
1417 ScsiDiskDevice->SenseData,\r
1418 sizeof (EFI_SCSI_SENSE_DATA) * (ScsiDiskDevice->SenseDataNumber)\r
1419 );\r
1420\r
1421 *NumberOfSenseKeys = 0;\r
1422 *SenseDataArray = ScsiDiskDevice->SenseData;\r
1423 PtrSenseData = ScsiDiskDevice->SenseData;\r
1424\r
1425 for (SenseReq = TRUE; SenseReq;) {\r
d35be2a4 1426 Status = ScsiRequestSenseCommand (\r
6ad55b15 1427 ScsiDiskDevice->ScsiIo,\r
e72a3b3e 1428 EFI_TIMER_PERIOD_SECONDS (2),\r
6ad55b15 1429 PtrSenseData,\r
1430 &SenseDataLength,\r
1431 &HostAdapterStatus,\r
1432 &TargetStatus\r
1433 );\r
f36d6e66 1434 if ((Status == EFI_SUCCESS) || (Status == EFI_WARN_BUFFER_TOO_SMALL)) {\r
1435 FallStatus = EFI_SUCCESS;\r
1436 \r
1437 } else if ((Status == EFI_TIMEOUT) || (Status == EFI_NOT_READY)) {\r
1438 *NeedRetry = TRUE;\r
1439 FallStatus = EFI_DEVICE_ERROR;\r
1440 \r
1441 } else if ((Status == EFI_INVALID_PARAMETER) || (Status == EFI_UNSUPPORTED)) {\r
1442 *NeedRetry = FALSE;\r
1443 FallStatus = EFI_DEVICE_ERROR;\r
1444 \r
1445 } else if (Status == EFI_DEVICE_ERROR) {\r
1446 if (AskResetIfError) {\r
1447 ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);\r
1448 }\r
1449 \r
1450 FallStatus = EFI_DEVICE_ERROR;\r
6ad55b15 1451 }\r
1452\r
1453 if (EFI_ERROR (FallStatus)) {\r
1454 if (*NumberOfSenseKeys != 0) {\r
1455 *NeedRetry = FALSE;\r
1456 return EFI_SUCCESS;\r
1457 } else {\r
1458 return EFI_DEVICE_ERROR;\r
1459 }\r
1460 }\r
1461\r
1462 (*NumberOfSenseKeys) += 1;\r
1463\r
1464 //\r
1465 // no more sense key or number of sense keys exceeds predefined,\r
1466 // skip the loop.\r
1467 //\r
1468 if ((PtrSenseData->Sense_Key == EFI_SCSI_SK_NO_SENSE) || \r
1469 (*NumberOfSenseKeys == ScsiDiskDevice->SenseDataNumber)) {\r
1470 SenseReq = FALSE;\r
1471 }\r
6ad55b15 1472 PtrSenseData += 1;\r
6ad55b15 1473 }\r
6ad55b15 1474 return EFI_SUCCESS;\r
1475}\r
1476\r
6ad55b15 1477\r
9beb888e 1478/**\r
1479 Get information from media read capacity command.\r
6ad55b15 1480\r
9beb888e 1481 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV\r
1482 @param Capacity The pointer of EFI_SCSI_DISK_CAPACITY_DATA\r
6ad55b15 1483\r
9beb888e 1484**/\r
1485VOID\r
1486GetMediaInfo (\r
1487 IN OUT SCSI_DISK_DEV *ScsiDiskDevice,\r
b96cd313 1488 EFI_SCSI_DISK_CAPACITY_DATA *Capacity10,\r
1489 EFI_SCSI_DISK_CAPACITY_DATA16 *Capacity16\r
9beb888e 1490 )\r
6ad55b15 1491{\r
b96cd313 1492 UINT8 ScsiVersion;\r
1493 UINT8 *Ptr;\r
1494\r
1495 ScsiVersion = (UINT8)(ScsiDiskDevice->InquiryData.Version & 0x03);\r
1496 ScsiDiskDevice->BlkIo.Media->LowestAlignedLba = 0;\r
1497 ScsiDiskDevice->BlkIo.Media->LogicalBlocksPerPhysicalBlock = 1;\r
1498 \r
1499\r
1500 if (ScsiVersion < SCSI_COMMAND_VERSION_3) {\r
1501 ScsiDiskDevice->BlkIo.Media->LastBlock = (Capacity10->LastLba3 << 24) |\r
1502 (Capacity10->LastLba2 << 16) |\r
1503 (Capacity10->LastLba1 << 8) |\r
1504 Capacity10->LastLba0;\r
1505 \r
1506 ScsiDiskDevice->BlkIo.Media->BlockSize = (Capacity10->BlockSize3 << 24) |\r
1507 (Capacity10->BlockSize2 << 16) | \r
1508 (Capacity10->BlockSize1 << 8) |\r
1509 Capacity10->BlockSize0;\r
1510 ScsiDiskDevice->BlkIo.Revision = EFI_BLOCK_IO_PROTOCOL_REVISION; \r
1511 } else {\r
1512\r
1513 Ptr = (UINT8*)&ScsiDiskDevice->BlkIo.Media->LastBlock;\r
1514 *Ptr++ = Capacity16->LastLba0;\r
1515 *Ptr++ = Capacity16->LastLba1;\r
1516 *Ptr++ = Capacity16->LastLba2;\r
1517 *Ptr++ = Capacity16->LastLba3;\r
1518 *Ptr++ = Capacity16->LastLba4;\r
1519 *Ptr++ = Capacity16->LastLba5;\r
1520 *Ptr++ = Capacity16->LastLba6;\r
1521 *Ptr = Capacity16->LastLba7;\r
1522 \r
1523 ScsiDiskDevice->BlkIo.Media->BlockSize = (Capacity16->BlockSize3 << 24) |\r
1524 (Capacity16->BlockSize2 << 16) | \r
1525 (Capacity16->BlockSize1 << 8) |\r
1526 Capacity16->BlockSize0;\r
1527\r
1528 ScsiDiskDevice->BlkIo.Media->LowestAlignedLba = (Capacity16->LowestAlignLogic2 << 8)|(Capacity16->LowestAlignLogic1);\r
1529 ScsiDiskDevice->BlkIo.Media->LogicalBlocksPerPhysicalBlock = Capacity16->LogicPerPhysical;\r
1530 ScsiDiskDevice->BlkIo.Revision = EFI_BLOCK_IO_PROTOCOL_REVISION2; \r
1531 }\r
1532\r
6ad55b15 1533\r
1534 ScsiDiskDevice->BlkIo.Media->MediaPresent = TRUE;\r
b96cd313 1535 \r
6ad55b15 1536 if (ScsiDiskDevice->DeviceType == EFI_SCSI_TYPE_DISK) {\r
1537 ScsiDiskDevice->BlkIo.Media->BlockSize = 0x200;\r
1538 }\r
1539\r
1540 if (ScsiDiskDevice->DeviceType == EFI_SCSI_TYPE_CDROM) {\r
1541 ScsiDiskDevice->BlkIo.Media->BlockSize = 0x800;\r
1542 }\r
1543}\r
1544\r
9beb888e 1545/**\r
1546 Parse Inquiry data.\r
1547\r
1548 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV\r
1549\r
1550**/\r
6ad55b15 1551VOID\r
1552ParseInquiryData (\r
9beb888e 1553 IN OUT SCSI_DISK_DEV *ScsiDiskDevice\r
6ad55b15 1554 )\r
6ad55b15 1555{\r
fbfa4a1d 1556 ScsiDiskDevice->FixedDevice = (BOOLEAN) ((ScsiDiskDevice->InquiryData.Rmb == 1) ? 0 : 1);\r
6ad55b15 1557 ScsiDiskDevice->BlkIoMedia.RemovableMedia = (BOOLEAN) (!ScsiDiskDevice->FixedDevice);\r
1558}\r
1559\r
9beb888e 1560/**\r
1561 Read sector from SCSI Disk.\r
6ad55b15 1562\r
9beb888e 1563 @param ScsiDiskDevice The poiniter of SCSI_DISK_DEV\r
1564 @param Buffer The buffer to fill in the read out data\r
1565 @param Lba Logic block address\r
1566 @param NumberOfBlocks The number of blocks to read\r
6ad55b15 1567\r
9beb888e 1568 @retval EFI_DEVICE_ERROR Indicates a device error.\r
1569 @retval EFI_SUCCESS Operation is successful.\r
6ad55b15 1570\r
9beb888e 1571**/\r
1572EFI_STATUS\r
1573ScsiDiskReadSectors (\r
1574 IN SCSI_DISK_DEV *ScsiDiskDevice,\r
1575 OUT VOID *Buffer,\r
1576 IN EFI_LBA Lba,\r
1577 IN UINTN NumberOfBlocks\r
1578 )\r
6ad55b15 1579{\r
1580 UINTN BlocksRemaining;\r
1581 UINT32 Lba32;\r
1582 UINT8 *PtrBuffer;\r
1583 UINT32 BlockSize;\r
1584 UINT32 ByteCount;\r
1585 UINT32 MaxBlock;\r
1586 UINT32 SectorCount;\r
1587 UINT64 Timeout;\r
1588 EFI_STATUS Status;\r
1589 UINT8 Index;\r
1590 UINT8 MaxRetry;\r
1591 BOOLEAN NeedRetry;\r
1592 EFI_SCSI_SENSE_DATA *SenseData;\r
1593 UINTN NumberOfSenseKeys;\r
1594\r
1595 SenseData = NULL;\r
1596 NumberOfSenseKeys = 0;\r
1597\r
1598 Status = EFI_SUCCESS;\r
1599\r
1600 BlocksRemaining = NumberOfBlocks;\r
1601 BlockSize = ScsiDiskDevice->BlkIo.Media->BlockSize;\r
1602 //\r
1603 // limit the data bytes that can be transferred by one Read(10) Command\r
1604 //\r
1605 MaxBlock = 65536;\r
1606\r
1607 PtrBuffer = Buffer;\r
1608 Lba32 = (UINT32) Lba;\r
1609\r
1610 while (BlocksRemaining > 0) {\r
1611\r
1612 if (BlocksRemaining <= MaxBlock) {\r
1613\r
1614 SectorCount = (UINT16) BlocksRemaining;\r
1615 } else {\r
1616\r
1617 SectorCount = MaxBlock;\r
1618 }\r
1619\r
1620 ByteCount = SectorCount * BlockSize;\r
e72a3b3e 1621 Timeout = EFI_TIMER_PERIOD_SECONDS (2);\r
6ad55b15 1622\r
1623 MaxRetry = 2;\r
1624 for (Index = 0; Index < MaxRetry; Index++) {\r
1625\r
1626 Status = ScsiDiskRead10 (\r
1627 ScsiDiskDevice,\r
1628 &NeedRetry,\r
1629 &SenseData,\r
1630 &NumberOfSenseKeys,\r
1631 Timeout,\r
1632 PtrBuffer,\r
1633 &ByteCount,\r
1634 Lba32,\r
1635 SectorCount\r
1636 );\r
1637 if (!EFI_ERROR (Status)) {\r
1638 break;\r
1639 }\r
1640\r
1641 if (!NeedRetry) {\r
1642 return EFI_DEVICE_ERROR;\r
1643 }\r
1644\r
1645 }\r
1646\r
1647 if ((Index == MaxRetry) && (Status != EFI_SUCCESS)) {\r
1648 return EFI_DEVICE_ERROR;\r
1649 }\r
1650\r
1651 //\r
1652 // actual transferred sectors\r
1653 //\r
1654 SectorCount = ByteCount / BlockSize;\r
1655\r
1656 Lba32 += SectorCount;\r
1657 PtrBuffer = PtrBuffer + SectorCount * BlockSize;\r
1658 BlocksRemaining -= SectorCount;\r
1659 }\r
1660\r
1661 return EFI_SUCCESS;\r
1662}\r
1663\r
9beb888e 1664/**\r
1665 Write sector to SCSI Disk.\r
6ad55b15 1666\r
9beb888e 1667 @param ScsiDiskDevice The poiniter of SCSI_DISK_DEV\r
1668 @param Buffer The buffer of data to be written into SCSI Disk\r
1669 @param Lba Logic block address\r
1670 @param NumberOfBlocks The number of blocks to read\r
6ad55b15 1671\r
9beb888e 1672 @retval EFI_DEVICE_ERROR Indicates a device error.\r
1673 @retval EFI_SUCCESS Operation is successful.\r
6ad55b15 1674\r
9beb888e 1675**/\r
1676EFI_STATUS\r
1677ScsiDiskWriteSectors (\r
1678 IN SCSI_DISK_DEV *ScsiDiskDevice,\r
1679 IN VOID *Buffer,\r
1680 IN EFI_LBA Lba,\r
1681 IN UINTN NumberOfBlocks\r
1682 )\r
6ad55b15 1683{\r
1684 UINTN BlocksRemaining;\r
1685 UINT32 Lba32;\r
1686 UINT8 *PtrBuffer;\r
1687 UINT32 BlockSize;\r
1688 UINT32 ByteCount;\r
1689 UINT32 MaxBlock;\r
1690 UINT32 SectorCount;\r
1691 UINT64 Timeout;\r
1692 EFI_STATUS Status;\r
1693 UINT8 Index;\r
1694 UINT8 MaxRetry;\r
1695 BOOLEAN NeedRetry;\r
1696 EFI_SCSI_SENSE_DATA *SenseData;\r
1697 UINTN NumberOfSenseKeys;\r
1698\r
1699 SenseData = NULL;\r
1700 NumberOfSenseKeys = 0;\r
1701\r
1702 Status = EFI_SUCCESS;\r
1703\r
1704 BlocksRemaining = NumberOfBlocks;\r
1705 BlockSize = ScsiDiskDevice->BlkIo.Media->BlockSize;\r
1706 //\r
1707 // limit the data bytes that can be transferred by one Write(10) Command\r
1708 //\r
1709 MaxBlock = 65536;\r
1710\r
1711 PtrBuffer = Buffer;\r
1712 Lba32 = (UINT32) Lba;\r
1713\r
1714 while (BlocksRemaining > 0) {\r
1715\r
1716 if (BlocksRemaining <= MaxBlock) {\r
1717\r
1718 SectorCount = (UINT16) BlocksRemaining;\r
1719 } else {\r
1720\r
1721 SectorCount = MaxBlock;\r
1722 }\r
1723\r
1724 ByteCount = SectorCount * BlockSize;\r
e72a3b3e 1725 Timeout = EFI_TIMER_PERIOD_SECONDS (2);\r
6ad55b15 1726 MaxRetry = 2;\r
1727 for (Index = 0; Index < MaxRetry; Index++) {\r
1728 Status = ScsiDiskWrite10 (\r
1729 ScsiDiskDevice,\r
1730 &NeedRetry,\r
1731 &SenseData,\r
1732 &NumberOfSenseKeys,\r
1733 Timeout,\r
1734 PtrBuffer,\r
1735 &ByteCount,\r
1736 Lba32,\r
1737 SectorCount\r
1738 );\r
1739 if (!EFI_ERROR (Status)) {\r
1740 break;\r
1741 }\r
1742\r
1743 if (!NeedRetry) {\r
1744 return EFI_DEVICE_ERROR;\r
1745 }\r
1746 }\r
1747\r
1748 if ((Index == MaxRetry) && (Status != EFI_SUCCESS)) {\r
1749 return EFI_DEVICE_ERROR;\r
1750 }\r
1751 //\r
1752 // actual transferred sectors\r
1753 //\r
1754 SectorCount = ByteCount / BlockSize;\r
1755\r
1756 Lba32 += SectorCount;\r
1757 PtrBuffer = PtrBuffer + SectorCount * BlockSize;\r
1758 BlocksRemaining -= SectorCount;\r
1759 }\r
1760\r
1761 return EFI_SUCCESS;\r
1762}\r
1763\r
9beb888e 1764\r
1765/**\r
1766 Sumbmit Read command.\r
1767\r
1768 @param ScsiDiskDevice The pointer of ScsiDiskDevice\r
1769 @param NeedRetry The pointer of flag indicates if needs retry if error happens\r
1770 @param SenseDataArray NOT used yet in this function\r
1771 @param NumberOfSenseKeys The number of sense key\r
1772 @param Timeout The time to complete the command\r
1773 @param DataBuffer The buffer to fill with the read out data\r
1774 @param DataLength The length of buffer\r
1775 @param StartLba The start logic block address\r
1776 @param SectorSize The size of sector\r
1777\r
1778 @return EFI_STATUS is returned by calling ScsiRead10Command().\r
1779**/\r
6ad55b15 1780EFI_STATUS\r
1781ScsiDiskRead10 (\r
9beb888e 1782 IN SCSI_DISK_DEV *ScsiDiskDevice,\r
1783 OUT BOOLEAN *NeedRetry,\r
1784 OUT EFI_SCSI_SENSE_DATA **SenseDataArray, OPTIONAL\r
1785 OUT UINTN *NumberOfSenseKeys,\r
1786 IN UINT64 Timeout,\r
1787 OUT UINT8 *DataBuffer,\r
1788 IN OUT UINT32 *DataLength,\r
1789 IN UINT32 StartLba,\r
1790 IN UINT32 SectorSize\r
6ad55b15 1791 )\r
6ad55b15 1792{\r
1793 UINT8 SenseDataLength;\r
1794 EFI_STATUS Status;\r
1795 UINT8 HostAdapterStatus;\r
1796 UINT8 TargetStatus;\r
1797\r
1798 *NeedRetry = FALSE;\r
1799 *NumberOfSenseKeys = 0;\r
1800 SenseDataLength = 0;\r
d35be2a4 1801 Status = ScsiRead10Command (\r
6ad55b15 1802 ScsiDiskDevice->ScsiIo,\r
1803 Timeout,\r
1804 NULL,\r
1805 &SenseDataLength,\r
1806 &HostAdapterStatus,\r
1807 &TargetStatus,\r
1808 DataBuffer,\r
1809 DataLength,\r
1810 StartLba,\r
1811 SectorSize\r
1812 );\r
1813 return Status;\r
1814}\r
1815\r
6ad55b15 1816\r
9beb888e 1817/**\r
1818 Submit Write Command.\r
6ad55b15 1819\r
9beb888e 1820 @param ScsiDiskDevice The pointer of ScsiDiskDevice\r
1821 @param NeedRetry The pointer of flag indicates if needs retry if error happens\r
1822 @param SenseDataArray NOT used yet in this function\r
1823 @param NumberOfSenseKeys The number of sense key\r
1824 @param Timeout The time to complete the command\r
1825 @param DataBuffer The buffer to fill with the read out data\r
1826 @param DataLength The length of buffer\r
1827 @param StartLba The start logic block address\r
1828 @param SectorSize The size of sector\r
6ad55b15 1829\r
9beb888e 1830 @return EFI_STATUS is returned by calling ScsiWrite10Command().\r
6ad55b15 1831\r
9beb888e 1832**/\r
1833EFI_STATUS\r
1834ScsiDiskWrite10 (\r
1835 IN SCSI_DISK_DEV *ScsiDiskDevice,\r
1836 OUT BOOLEAN *NeedRetry,\r
1837 OUT EFI_SCSI_SENSE_DATA **SenseDataArray, OPTIONAL\r
1838 OUT UINTN *NumberOfSenseKeys,\r
1839 IN UINT64 Timeout,\r
1840 IN UINT8 *DataBuffer,\r
1841 IN OUT UINT32 *DataLength,\r
1842 IN UINT32 StartLba,\r
1843 IN UINT32 SectorSize\r
1844 )\r
6ad55b15 1845{\r
1846 EFI_STATUS Status;\r
1847 UINT8 SenseDataLength;\r
1848 UINT8 HostAdapterStatus;\r
1849 UINT8 TargetStatus;\r
1850\r
1851 *NeedRetry = FALSE;\r
1852 *NumberOfSenseKeys = 0;\r
1853 SenseDataLength = 0;\r
d35be2a4 1854 Status = ScsiWrite10Command (\r
6ad55b15 1855 ScsiDiskDevice->ScsiIo,\r
1856 Timeout,\r
1857 NULL,\r
1858 &SenseDataLength,\r
1859 &HostAdapterStatus,\r
1860 &TargetStatus,\r
1861 DataBuffer,\r
1862 DataLength,\r
1863 StartLba,\r
1864 SectorSize\r
1865 );\r
1866 return Status;\r
1867}\r
1868\r
9beb888e 1869\r
1870/**\r
1871 Check sense key to find if media presents.\r
1872\r
1873 @param SenseData The pointer of EFI_SCSI_SENSE_DATA\r
1874 @param SenseCounts The number of sense key\r
1875\r
1876 @retval TRUE NOT any media\r
1877 @retval FALSE Media presents\r
1878**/\r
6ad55b15 1879BOOLEAN\r
1880ScsiDiskIsNoMedia (\r
1881 IN EFI_SCSI_SENSE_DATA *SenseData,\r
1882 IN UINTN SenseCounts\r
1883 )\r
6ad55b15 1884{\r
1885 EFI_SCSI_SENSE_DATA *SensePtr;\r
1886 UINTN Index;\r
1887 BOOLEAN IsNoMedia;\r
1888\r
1889 IsNoMedia = FALSE;\r
1890 SensePtr = SenseData;\r
1891\r
1892 for (Index = 0; Index < SenseCounts; Index++) {\r
6ad55b15 1893 //\r
1894 // Sense Key is EFI_SCSI_SK_NOT_READY (0x2),\r
1895 // Additional Sense Code is ASC_NO_MEDIA (0x3A)\r
1896 //\r
1897 if ((SensePtr->Sense_Key == EFI_SCSI_SK_NOT_READY) &&\r
1898 (SensePtr->Addnl_Sense_Code == EFI_SCSI_ASC_NO_MEDIA)) {\r
1899 IsNoMedia = TRUE;\r
1900 }\r
6ad55b15 1901 SensePtr++;\r
1902 }\r
1903\r
1904 return IsNoMedia;\r
1905}\r
1906\r
9beb888e 1907\r
1908/**\r
1909 Parse sense key.\r
1910\r
1911 @param SenseData The pointer of EFI_SCSI_SENSE_DATA\r
1912 @param SenseCounts The number of sense key\r
1913\r
1914 @retval TRUE Error\r
1915 @retval FALSE NOT error\r
1916\r
1917**/\r
6ad55b15 1918BOOLEAN\r
1919ScsiDiskIsMediaError (\r
1920 IN EFI_SCSI_SENSE_DATA *SenseData,\r
1921 IN UINTN SenseCounts\r
1922 )\r
6ad55b15 1923{\r
1924 EFI_SCSI_SENSE_DATA *SensePtr;\r
1925 UINTN Index;\r
1926 BOOLEAN IsError;\r
1927\r
1928 IsError = FALSE;\r
1929 SensePtr = SenseData;\r
1930\r
1931 for (Index = 0; Index < SenseCounts; Index++) {\r
1932\r
1933 switch (SensePtr->Sense_Key) {\r
1934\r
1935 case EFI_SCSI_SK_MEDIUM_ERROR:\r
1936 //\r
1937 // Sense Key is EFI_SCSI_SK_MEDIUM_ERROR (0x3)\r
1938 //\r
1939 switch (SensePtr->Addnl_Sense_Code) {\r
1940\r
1941 //\r
1942 // fall through\r
1943 //\r
1944 case EFI_SCSI_ASC_MEDIA_ERR1:\r
1945\r
1946 //\r
1947 // fall through\r
1948 //\r
1949 case EFI_SCSI_ASC_MEDIA_ERR2:\r
1950\r
1951 //\r
1952 // fall through\r
1953 //\r
1954 case EFI_SCSI_ASC_MEDIA_ERR3:\r
1955 case EFI_SCSI_ASC_MEDIA_ERR4:\r
1956 IsError = TRUE;\r
1957 break;\r
1958\r
1959 default:\r
1960 break;\r
1961 }\r
1962\r
1963 break;\r
1964\r
1965 case EFI_SCSI_SK_NOT_READY:\r
1966 //\r
1967 // Sense Key is EFI_SCSI_SK_NOT_READY (0x2)\r
1968 //\r
1969 switch (SensePtr->Addnl_Sense_Code) {\r
1970 //\r
1971 // Additional Sense Code is ASC_MEDIA_UPSIDE_DOWN (0x6)\r
1972 //\r
1973 case EFI_SCSI_ASC_MEDIA_UPSIDE_DOWN:\r
1974 IsError = TRUE;\r
1975 break;\r
1976\r
1977 default:\r
1978 break;\r
1979 }\r
1980 break;\r
1981\r
1982 default:\r
1983 break;\r
1984 }\r
1985\r
1986 SensePtr++;\r
1987 }\r
1988\r
1989 return IsError;\r
1990}\r
1991\r
9beb888e 1992\r
1993/**\r
1994 Check sense key to find if hardware error happens.\r
1995\r
1996 @param SenseData The pointer of EFI_SCSI_SENSE_DATA\r
1997 @param SenseCounts The number of sense key\r
1998\r
1999 @retval TRUE Hardware error exits.\r
2000 @retval FALSE NO error.\r
2001\r
2002**/\r
6ad55b15 2003BOOLEAN\r
2004ScsiDiskIsHardwareError (\r
2005 IN EFI_SCSI_SENSE_DATA *SenseData,\r
2006 IN UINTN SenseCounts\r
2007 )\r
6ad55b15 2008{\r
2009 EFI_SCSI_SENSE_DATA *SensePtr;\r
2010 UINTN Index;\r
2011 BOOLEAN IsError;\r
2012\r
2013 IsError = FALSE;\r
2014 SensePtr = SenseData;\r
2015\r
2016 for (Index = 0; Index < SenseCounts; Index++) {\r
2017 \r
2018 //\r
2019 // Sense Key is EFI_SCSI_SK_HARDWARE_ERROR (0x4)\r
2020 //\r
2021 if (SensePtr->Sense_Key == EFI_SCSI_SK_HARDWARE_ERROR) {\r
2022 IsError = TRUE;\r
2023 }\r
2024\r
2025 SensePtr++;\r
2026 }\r
2027\r
2028 return IsError;\r
2029}\r
2030\r
9beb888e 2031\r
2032/**\r
2033 Check sense key to find if media has changed.\r
2034\r
2035 @param SenseData The pointer of EFI_SCSI_SENSE_DATA\r
2036 @param SenseCounts The number of sense key\r
2037\r
2038 @retval TRUE Media is changed.\r
2039 @retval FALSE Medit is NOT changed.\r
2040**/\r
6ad55b15 2041BOOLEAN\r
2042ScsiDiskIsMediaChange (\r
2043 IN EFI_SCSI_SENSE_DATA *SenseData,\r
2044 IN UINTN SenseCounts\r
2045 )\r
6ad55b15 2046{\r
2047 EFI_SCSI_SENSE_DATA *SensePtr;\r
2048 UINTN Index;\r
2049 BOOLEAN IsMediaChanged;\r
2050\r
2051 IsMediaChanged = FALSE;\r
2052 SensePtr = SenseData;\r
2053\r
2054 for (Index = 0; Index < SenseCounts; Index++) {\r
2055 //\r
2056 // Sense Key is EFI_SCSI_SK_UNIT_ATTENTION (0x6),\r
2057 // Additional sense code is EFI_SCSI_ASC_MEDIA_CHANGE (0x28)\r
2058 //\r
2059 if ((SensePtr->Sense_Key == EFI_SCSI_SK_UNIT_ATTENTION) &&\r
2060 (SensePtr->Addnl_Sense_Code == EFI_SCSI_ASC_MEDIA_CHANGE)) {\r
2061 IsMediaChanged = TRUE;\r
2062 }\r
2063\r
2064 SensePtr++;\r
2065 }\r
2066\r
2067 return IsMediaChanged;\r
2068}\r
2069\r
9beb888e 2070/**\r
2071 Check sense key to find if reset happens.\r
2072\r
2073 @param SenseData The pointer of EFI_SCSI_SENSE_DATA\r
2074 @param SenseCounts The number of sense key\r
2075\r
2076 @retval TRUE It is reset before.\r
2077 @retval FALSE It is NOT reset before.\r
2078\r
2079**/\r
6ad55b15 2080BOOLEAN\r
2081ScsiDiskIsResetBefore (\r
2082 IN EFI_SCSI_SENSE_DATA *SenseData,\r
2083 IN UINTN SenseCounts\r
2084 )\r
6ad55b15 2085{\r
2086 EFI_SCSI_SENSE_DATA *SensePtr;\r
2087 UINTN Index;\r
2088 BOOLEAN IsResetBefore;\r
2089\r
2090 IsResetBefore = FALSE;\r
2091 SensePtr = SenseData;\r
2092\r
2093 for (Index = 0; Index < SenseCounts; Index++) {\r
2094 \r
2095 //\r
2096 // Sense Key is EFI_SCSI_SK_UNIT_ATTENTION (0x6)\r
2097 // Additional Sense Code is EFI_SCSI_ASC_RESET (0x29)\r
2098 //\r
2099 if ((SensePtr->Sense_Key == EFI_SCSI_SK_UNIT_ATTENTION) &&\r
2100 (SensePtr->Addnl_Sense_Code == EFI_SCSI_ASC_RESET)) {\r
2101 IsResetBefore = TRUE;\r
2102 }\r
2103\r
2104 SensePtr++;\r
2105 }\r
2106\r
2107 return IsResetBefore;\r
2108}\r
2109\r
9beb888e 2110/**\r
2111 Check sense key to find if the drive is ready.\r
2112\r
2113 @param SenseData The pointer of EFI_SCSI_SENSE_DATA\r
2114 @param SenseCounts The number of sense key\r
2115 @param RetryLater The flag means if need a retry \r
2116\r
2117 @retval TRUE Drive is ready.\r
2118 @retval FALSE Drive is NOT ready.\r
2119\r
2120**/\r
6ad55b15 2121BOOLEAN\r
2122ScsiDiskIsDriveReady (\r
2123 IN EFI_SCSI_SENSE_DATA *SenseData,\r
2124 IN UINTN SenseCounts,\r
2125 OUT BOOLEAN *RetryLater\r
2126 )\r
6ad55b15 2127{\r
2128 EFI_SCSI_SENSE_DATA *SensePtr;\r
2129 UINTN Index;\r
2130 BOOLEAN IsReady;\r
2131\r
2132 IsReady = TRUE;\r
2133 *RetryLater = FALSE;\r
2134 SensePtr = SenseData;\r
2135\r
2136 for (Index = 0; Index < SenseCounts; Index++) {\r
2137\r
2138 switch (SensePtr->Sense_Key) {\r
2139\r
2140 case EFI_SCSI_SK_NOT_READY:\r
2141 //\r
2142 // Sense Key is EFI_SCSI_SK_NOT_READY (0x2)\r
2143 //\r
2144 switch (SensePtr->Addnl_Sense_Code) {\r
2145 case EFI_SCSI_ASC_NOT_READY:\r
2146 //\r
2147 // Additional Sense Code is EFI_SCSI_ASC_NOT_READY (0x4)\r
2148 //\r
2149 switch (SensePtr->Addnl_Sense_Code_Qualifier) {\r
2150 case EFI_SCSI_ASCQ_IN_PROGRESS:\r
2151 //\r
2152 // Additional Sense Code Qualifier is\r
2153 // EFI_SCSI_ASCQ_IN_PROGRESS (0x1)\r
2154 //\r
2155 IsReady = FALSE;\r
2156 *RetryLater = TRUE;\r
2157 break;\r
2158\r
2159 default:\r
2160 IsReady = FALSE;\r
2161 *RetryLater = FALSE;\r
2162 break;\r
2163 }\r
2164 break;\r
2165\r
2166 default:\r
2167 break;\r
2168 }\r
2169 break;\r
2170\r
2171 default:\r
2172 break;\r
2173 }\r
2174\r
2175 SensePtr++;\r
2176 }\r
2177\r
2178 return IsReady;\r
2179}\r
2180\r
9beb888e 2181/**\r
2182 Check sense key to find if it has sense key.\r
2183\r
2184 @param SenseData - The pointer of EFI_SCSI_SENSE_DATA\r
2185 @param SenseCounts - The number of sense key\r
2186\r
2187 @retval TRUE It has sense key.\r
2188 @retval FALSE It has NOT any sense key.\r
2189\r
2190**/\r
6ad55b15 2191BOOLEAN\r
2192ScsiDiskHaveSenseKey (\r
2193 IN EFI_SCSI_SENSE_DATA *SenseData,\r
2194 IN UINTN SenseCounts\r
2195 )\r
6ad55b15 2196{\r
2197 EFI_SCSI_SENSE_DATA *SensePtr;\r
2198 UINTN Index;\r
2199 BOOLEAN HaveSenseKey;\r
2200\r
2201 if (SenseCounts == 0) {\r
2202 HaveSenseKey = FALSE;\r
2203 } else {\r
2204 HaveSenseKey = TRUE;\r
2205 }\r
2206\r
2207 SensePtr = SenseData;\r
2208\r
2209 for (Index = 0; Index < SenseCounts; Index++) {\r
2210 \r
2211 //\r
2212 // Sense Key is SK_NO_SENSE (0x0)\r
2213 //\r
2214 if ((SensePtr->Sense_Key == EFI_SCSI_SK_NO_SENSE) &&\r
2215 (Index == 0)) {\r
2216 HaveSenseKey = FALSE;\r
2217 }\r
2218\r
2219 SensePtr++;\r
2220 }\r
2221\r
2222 return HaveSenseKey;\r
2223}\r
2224\r
9beb888e 2225/**\r
2226 Release resource about disk device.\r
2227\r
2228 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV\r
2229\r
2230**/\r
6ad55b15 2231VOID\r
2232ReleaseScsiDiskDeviceResources (\r
2233 IN SCSI_DISK_DEV *ScsiDiskDevice\r
2234 )\r
6ad55b15 2235{\r
2236 if (ScsiDiskDevice == NULL) {\r
2237 return ;\r
2238 }\r
2239\r
2240 if (ScsiDiskDevice->SenseData != NULL) {\r
9b38ff34 2241 FreePool (ScsiDiskDevice->SenseData);\r
6ad55b15 2242 ScsiDiskDevice->SenseData = NULL;\r
2243 }\r
2244\r
2245 if (ScsiDiskDevice->ControllerNameTable != NULL) {\r
2246 FreeUnicodeStringTable (ScsiDiskDevice->ControllerNameTable);\r
2247 ScsiDiskDevice->ControllerNameTable = NULL;\r
2248 }\r
2249\r
9b38ff34 2250 FreePool (ScsiDiskDevice);\r
6ad55b15 2251\r
2252 ScsiDiskDevice = NULL;\r
2253}\r
d14faa52 2254\r
2255/**\r
2256 Determine if Block Io should be produced.\r
2257 \r
2258\r
2259 @param ChildHandle Child Handle to retrive Parent information.\r
2260 \r
2261 @retval TRUE Should produce Block Io.\r
2262 @retval FALSE Should not produce Block Io.\r
2263\r
2264**/ \r
2265BOOLEAN\r
2266DetermineInstallBlockIo (\r
2267 IN EFI_HANDLE ChildHandle\r
2268 ) \r
2269{\r
2270 EFI_SCSI_PASS_THRU_PROTOCOL *ScsiPassThru;\r
2271 EFI_EXT_SCSI_PASS_THRU_PROTOCOL *ExtScsiPassThru;\r
2272\r
2273 //\r
2274 // Firstly, check if ExtScsiPassThru Protocol parent handle exists. If existence,\r
2275 // check its attribute, logic or physical.\r
2276 //\r
2277 ExtScsiPassThru = (EFI_EXT_SCSI_PASS_THRU_PROTOCOL *)GetParentProtocol (&gEfiExtScsiPassThruProtocolGuid, ChildHandle);\r
2278 if (ExtScsiPassThru != NULL) {\r
2279 if ((ExtScsiPassThru->Mode->Attributes & EFI_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL) != 0) {\r
2280 return TRUE;\r
2281 }\r
2282 }\r
2283\r
2284 //\r
2285 // Secondly, check if ScsiPassThru Protocol parent handle exists. If existence,\r
2286 // check its attribute, logic or physical.\r
2287 //\r
2288 ScsiPassThru = (EFI_SCSI_PASS_THRU_PROTOCOL *)GetParentProtocol (&gEfiScsiPassThruProtocolGuid, ChildHandle);\r
2289 if (ScsiPassThru != NULL) {\r
2290 if ((ScsiPassThru->Mode->Attributes & EFI_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL) != 0) {\r
2291 return TRUE;\r
2292 }\r
2293 }\r
2294 \r
2295 return FALSE;\r
2296}\r
2297\r
2298/**\r
2299 Search protocol database and check to see if the protocol\r
2300 specified by ProtocolGuid is present on a ControllerHandle and opened by\r
2301 ChildHandle with an attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.\r
2302 If the ControllerHandle is found, then the protocol specified by ProtocolGuid\r
2303 will be opened on it. \r
2304 \r
2305\r
2306 @param ProtocolGuid ProtocolGuid pointer.\r
2307 @param ChildHandle Child Handle to retrieve Parent information.\r
2308 \r
2309**/ \r
2310VOID *\r
2311EFIAPI\r
2312GetParentProtocol (\r
2313 IN EFI_GUID *ProtocolGuid,\r
2314 IN EFI_HANDLE ChildHandle\r
2315 ) \r
2316{\r
2317 UINTN Index;\r
2318 UINTN HandleCount;\r
2319 VOID *Interface; \r
2320 EFI_STATUS Status;\r
2321 EFI_HANDLE *HandleBuffer;\r
2322\r
2323 //\r
2324 // Retrieve the list of all handles from the handle database\r
2325 //\r
2326 Status = gBS->LocateHandleBuffer (\r
2327 ByProtocol,\r
2328 ProtocolGuid,\r
2329 NULL,\r
2330 &HandleCount,\r
2331 &HandleBuffer\r
2332 );\r
2333\r
2334 if (EFI_ERROR (Status)) {\r
2335 return NULL;\r
2336 }\r
2337\r
2338 //\r
2339 // Iterate to find who is parent handle that is opened with ProtocolGuid by ChildHandle \r
2340 //\r
2341 for (Index = 0; Index < HandleCount; Index++) {\r
2342 Status = EfiTestChildHandle (HandleBuffer[Index], ChildHandle, ProtocolGuid);\r
2343 if (!EFI_ERROR (Status)) {\r
2344 Status = gBS->HandleProtocol (HandleBuffer[Index], ProtocolGuid, (VOID **)&Interface);\r
2345 if (!EFI_ERROR (Status)) {\r
2346 gBS->FreePool (HandleBuffer);\r
2347 return Interface;\r
2348 }\r
2349 }\r
2350 }\r
2351\r
2352 gBS->FreePool (HandleBuffer);\r
2353 return NULL;\r
2354} \r
2355\r