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