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