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