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