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