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