]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Bus/Usb/UsbBotPei/PeiAtapi.c
MdeModulePkg/IdeBusPei: Add RecoveryBlockIo2 support
[mirror_edk2.git] / MdeModulePkg / Bus / Usb / UsbBotPei / PeiAtapi.c
CommitLineData
4b1bf81c 1/** @file\r
2Pei USB ATATPI command implementations.\r
3\r
4Copyright (c) 1999 - 2010, Intel Corporation. All rights reserved.<BR>\r
5 \r
6This program and the accompanying materials\r
7are licensed and made available under the terms and conditions\r
8of the BSD License which accompanies this distribution. The\r
9full text of the license may be found at\r
10http://opensource.org/licenses/bsd-license.php\r
11\r
12THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
13WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
14\r
15**/\r
16\r
17#include "UsbBotPeim.h"\r
18#include "BotPeim.h"\r
19\r
20#define MAXSENSEKEY 5\r
21\r
22/**\r
23 Sends out ATAPI Inquiry Packet Command to the specified device. This command will\r
24 return INQUIRY data of the device.\r
25\r
26 @param PeiServices The pointer of EFI_PEI_SERVICES.\r
27 @param PeiBotDevice The pointer to PEI_BOT_DEVICE instance.\r
28\r
29 @retval EFI_SUCCESS Inquiry command completes successfully.\r
30 @retval EFI_DEVICE_ERROR Inquiry command failed.\r
31\r
32**/\r
33EFI_STATUS\r
34PeiUsbInquiry (\r
35 IN EFI_PEI_SERVICES **PeiServices,\r
36 IN PEI_BOT_DEVICE *PeiBotDevice\r
37 )\r
38{\r
39 ATAPI_PACKET_COMMAND Packet;\r
40 EFI_STATUS Status;\r
41 ATAPI_INQUIRY_DATA Idata;\r
42\r
43 //\r
44 // fill command packet\r
45 //\r
46 ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));\r
47 ZeroMem (&Idata, sizeof (ATAPI_INQUIRY_DATA));\r
48\r
49 Packet.Inquiry.opcode = ATA_CMD_INQUIRY;\r
50 Packet.Inquiry.page_code = 0;\r
51 Packet.Inquiry.allocation_length = 36;\r
52\r
53 //\r
54 // Send scsi INQUIRY command packet.\r
55 // According to SCSI Primary Commands-2 spec, host only needs to\r
56 // retrieve the first 36 bytes for standard INQUIRY data.\r
57 //\r
58 Status = PeiAtapiCommand (\r
59 PeiServices,\r
60 PeiBotDevice,\r
61 &Packet,\r
62 (UINT8) sizeof (ATAPI_PACKET_COMMAND),\r
63 &Idata,\r
64 36,\r
65 EfiUsbDataIn,\r
66 2000\r
67 );\r
68\r
69 if (EFI_ERROR (Status)) {\r
70 return EFI_DEVICE_ERROR;\r
71 }\r
72\r
73 if ((Idata.peripheral_type & 0x1f) == 0x05) {\r
74 PeiBotDevice->DeviceType = USBCDROM;\r
75 PeiBotDevice->Media.BlockSize = 0x800;\r
76 } else {\r
77 PeiBotDevice->DeviceType = USBFLOPPY;\r
78 PeiBotDevice->Media.BlockSize = 0x200;\r
79 }\r
80\r
81 return EFI_SUCCESS;\r
82}\r
83\r
84/**\r
85 Sends out ATAPI Test Unit Ready Packet Command to the specified device\r
86 to find out whether device is accessible.\r
87\r
88 @param PeiServices The pointer of EFI_PEI_SERVICES.\r
89 @param PeiBotDevice The pointer to PEI_BOT_DEVICE instance.\r
90\r
91 @retval EFI_SUCCESS TestUnit command executed successfully.\r
92 @retval EFI_DEVICE_ERROR Device cannot be executed TestUnit command successfully.\r
93\r
94**/\r
95EFI_STATUS\r
96PeiUsbTestUnitReady (\r
97 IN EFI_PEI_SERVICES **PeiServices,\r
98 IN PEI_BOT_DEVICE *PeiBotDevice\r
99 )\r
100{\r
101 ATAPI_PACKET_COMMAND Packet;\r
102 EFI_STATUS Status;\r
103\r
104 //\r
105 // fill command packet\r
106 //\r
107 ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));\r
108 Packet.TestUnitReady.opcode = ATA_CMD_TEST_UNIT_READY;\r
109\r
110 //\r
111 // send command packet\r
112 //\r
113 Status = PeiAtapiCommand (\r
114 PeiServices,\r
115 PeiBotDevice,\r
116 &Packet,\r
117 (UINT8) sizeof (ATAPI_PACKET_COMMAND),\r
118 NULL,\r
119 0,\r
120 EfiUsbNoData,\r
121 2000\r
122 );\r
123\r
124 if (EFI_ERROR (Status)) {\r
125 return EFI_DEVICE_ERROR;\r
126 }\r
127\r
128 return EFI_SUCCESS;\r
129}\r
130\r
131/**\r
132 Sends out ATAPI Request Sense Packet Command to the specified device.\r
133\r
134 @param PeiServices The pointer of EFI_PEI_SERVICES.\r
135 @param PeiBotDevice The pointer to PEI_BOT_DEVICE instance.\r
136 @param SenseCounts Length of sense buffer.\r
137 @param SenseKeyBuffer Pointer to sense buffer.\r
138\r
139 @retval EFI_SUCCESS Command executed successfully.\r
140 @retval EFI_DEVICE_ERROR Some device errors happen.\r
141\r
142**/\r
143EFI_STATUS\r
144PeiUsbRequestSense (\r
145 IN EFI_PEI_SERVICES **PeiServices,\r
146 IN PEI_BOT_DEVICE *PeiBotDevice,\r
147 OUT UINTN *SenseCounts,\r
148 IN UINT8 *SenseKeyBuffer\r
149 )\r
150{\r
151 EFI_STATUS Status;\r
152 ATAPI_PACKET_COMMAND Packet;\r
153 UINT8 *Ptr;\r
154 BOOLEAN SenseReq;\r
155 ATAPI_REQUEST_SENSE_DATA *Sense;\r
156\r
157 *SenseCounts = 0;\r
158\r
159 //\r
160 // fill command packet for Request Sense Packet Command\r
161 //\r
162 ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));\r
163 Packet.RequestSence.opcode = ATA_CMD_REQUEST_SENSE;\r
164 Packet.RequestSence.allocation_length = (UINT8) sizeof (ATAPI_REQUEST_SENSE_DATA);\r
165\r
166 Ptr = SenseKeyBuffer;\r
167\r
168 SenseReq = TRUE;\r
169\r
170 //\r
171 // request sense data from device continuously\r
172 // until no sense data exists in the device.\r
173 //\r
174 while (SenseReq) {\r
175 Sense = (ATAPI_REQUEST_SENSE_DATA *) Ptr;\r
176\r
177 //\r
178 // send out Request Sense Packet Command and get one Sense\r
179 // data form device.\r
180 //\r
181 Status = PeiAtapiCommand (\r
182 PeiServices,\r
183 PeiBotDevice,\r
184 &Packet,\r
185 (UINT8) sizeof (ATAPI_PACKET_COMMAND),\r
186 (VOID *) Ptr,\r
187 sizeof (ATAPI_REQUEST_SENSE_DATA),\r
188 EfiUsbDataIn,\r
189 2000\r
190 );\r
191\r
192 //\r
193 // failed to get Sense data\r
194 //\r
195 if (EFI_ERROR (Status)) {\r
196 if (*SenseCounts == 0) {\r
197 return EFI_DEVICE_ERROR;\r
198 } else {\r
199 return EFI_SUCCESS;\r
200 }\r
201 }\r
202\r
203 if (Sense->sense_key != ATA_SK_NO_SENSE) {\r
204\r
205 Ptr += sizeof (ATAPI_REQUEST_SENSE_DATA);\r
206 //\r
207 // Ptr is byte based pointer\r
208 //\r
209 (*SenseCounts)++;\r
210\r
211 if (*SenseCounts == MAXSENSEKEY) {\r
212 break;\r
213 }\r
214\r
215 } else {\r
216 //\r
217 // when no sense key, skip out the loop\r
218 //\r
219 SenseReq = FALSE;\r
220 }\r
221 }\r
222\r
223 return EFI_SUCCESS;\r
224}\r
225\r
226/**\r
227 Sends out ATAPI Read Capacity Packet Command to the specified device.\r
228 This command will return the information regarding the capacity of the\r
229 media in the device.\r
230\r
231 @param PeiServices The pointer of EFI_PEI_SERVICES.\r
232 @param PeiBotDevice The pointer to PEI_BOT_DEVICE instance.\r
233\r
234 @retval EFI_SUCCESS Command executed successfully.\r
235 @retval EFI_DEVICE_ERROR Some device errors happen.\r
236\r
237**/\r
238EFI_STATUS\r
239PeiUsbReadCapacity (\r
240 IN EFI_PEI_SERVICES **PeiServices,\r
241 IN PEI_BOT_DEVICE *PeiBotDevice\r
242 )\r
243{\r
244 EFI_STATUS Status;\r
245 ATAPI_PACKET_COMMAND Packet;\r
246 ATAPI_READ_CAPACITY_DATA Data;\r
247\r
248 ZeroMem (&Data, sizeof (ATAPI_READ_CAPACITY_DATA));\r
249 ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));\r
250\r
251 Packet.Inquiry.opcode = ATA_CMD_READ_CAPACITY;\r
252\r
253 //\r
254 // send command packet\r
255 //\r
256 Status = PeiAtapiCommand (\r
257 PeiServices,\r
258 PeiBotDevice,\r
259 &Packet,\r
260 (UINT8) sizeof (ATAPI_PACKET_COMMAND),\r
261 (VOID *) &Data,\r
262 sizeof (ATAPI_READ_CAPACITY_DATA),\r
263 EfiUsbDataIn,\r
264 2000\r
265 );\r
266\r
267 if (EFI_ERROR (Status)) {\r
268 return EFI_DEVICE_ERROR;\r
269 }\r
270\r
271 PeiBotDevice->Media.LastBlock = (Data.LastLba3 << 24) | (Data.LastLba2 << 16) | (Data.LastLba1 << 8) | Data.LastLba0;\r
272\r
273 PeiBotDevice->Media.MediaPresent = TRUE;\r
274\r
275 return EFI_SUCCESS;\r
276}\r
277\r
278/**\r
279 Sends out ATAPI Read Format Capacity Data Command to the specified device.\r
280 This command will return the information regarding the capacity of the\r
281 media in the device.\r
282\r
283 @param PeiServices The pointer of EFI_PEI_SERVICES.\r
284 @param PeiBotDevice The pointer to PEI_BOT_DEVICE instance.\r
285\r
286 @retval EFI_SUCCESS Command executed successfully.\r
287 @retval EFI_DEVICE_ERROR Some device errors happen.\r
288\r
289**/\r
290EFI_STATUS\r
291PeiUsbReadFormattedCapacity (\r
292 IN EFI_PEI_SERVICES **PeiServices,\r
293 IN PEI_BOT_DEVICE *PeiBotDevice\r
294 )\r
295{\r
296 EFI_STATUS Status;\r
297 ATAPI_PACKET_COMMAND Packet;\r
298 ATAPI_READ_FORMAT_CAPACITY_DATA FormatData;\r
299\r
300 ZeroMem (&FormatData, sizeof (ATAPI_READ_FORMAT_CAPACITY_DATA));\r
301 ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));\r
302\r
303 Packet.ReadFormatCapacity.opcode = ATA_CMD_READ_FORMAT_CAPACITY;\r
304 Packet.ReadFormatCapacity.allocation_length_lo = 12;\r
305\r
306 //\r
307 // send command packet\r
308 //\r
309 Status = PeiAtapiCommand (\r
310 PeiServices,\r
311 PeiBotDevice,\r
312 &Packet,\r
313 (UINT8) sizeof (ATAPI_PACKET_COMMAND),\r
314 (VOID *) &FormatData,\r
315 sizeof (ATAPI_READ_FORMAT_CAPACITY_DATA),\r
316 EfiUsbDataIn,\r
317 2000\r
318 );\r
319\r
320 if (EFI_ERROR (Status)) {\r
321 return EFI_DEVICE_ERROR;\r
322 }\r
323\r
324 if (FormatData.DesCode == 3) {\r
325 //\r
326 // Media is not present\r
327 //\r
328 PeiBotDevice->Media.MediaPresent = FALSE;\r
329 PeiBotDevice->Media.LastBlock = 0;\r
330\r
331 } else {\r
332\r
333 PeiBotDevice->Media.LastBlock = (FormatData.LastLba3 << 24) | (FormatData.LastLba2 << 16) | (FormatData.LastLba1 << 8) | FormatData.LastLba0;\r
334\r
335 PeiBotDevice->Media.LastBlock--;\r
336\r
337 PeiBotDevice->Media.MediaPresent = TRUE;\r
338 }\r
339\r
340 return EFI_SUCCESS;\r
341}\r
342\r
343/**\r
344 Execute Read(10) ATAPI command on a specific SCSI target.\r
345\r
346 Executes the ATAPI Read(10) command on the ATAPI target specified by PeiBotDevice.\r
347\r
348 @param PeiServices The pointer of EFI_PEI_SERVICES.\r
349 @param PeiBotDevice The pointer to PEI_BOT_DEVICE instance.\r
350 @param Buffer The pointer to data buffer.\r
351 @param Lba The start logic block address of reading.\r
352 @param NumberOfBlocks The block number of reading.\r
353\r
354 @retval EFI_SUCCESS Command executed successfully.\r
355 @retval EFI_DEVICE_ERROR Some device errors happen.\r
356\r
357**/\r
358EFI_STATUS\r
359PeiUsbRead10 (\r
360 IN EFI_PEI_SERVICES **PeiServices,\r
361 IN PEI_BOT_DEVICE *PeiBotDevice,\r
362 IN VOID *Buffer,\r
363 IN EFI_PEI_LBA Lba,\r
364 IN UINTN NumberOfBlocks\r
365 )\r
366{\r
367 ATAPI_PACKET_COMMAND Packet;\r
368 ATAPI_READ10_CMD *Read10Packet;\r
369 UINT16 MaxBlock;\r
370 UINT16 BlocksRemaining;\r
371 UINT16 SectorCount;\r
372 UINT32 Lba32;\r
373 UINT32 BlockSize;\r
374 UINT32 ByteCount;\r
375 VOID *PtrBuffer;\r
376 EFI_STATUS Status;\r
377 UINT16 TimeOut;\r
378\r
379 //\r
380 // prepare command packet for the Inquiry Packet Command.\r
381 //\r
382 ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));\r
383 Read10Packet = &Packet.Read10;\r
384 Lba32 = (UINT32) Lba;\r
385 PtrBuffer = Buffer;\r
386\r
387 BlockSize = (UINT32) PeiBotDevice->Media.BlockSize;\r
388\r
389 MaxBlock = (UINT16) (65535 / BlockSize);\r
390 BlocksRemaining = (UINT16) NumberOfBlocks;\r
391\r
392 Status = EFI_SUCCESS;\r
393 while (BlocksRemaining > 0) {\r
394\r
395 if (BlocksRemaining <= MaxBlock) {\r
396\r
397 SectorCount = BlocksRemaining;\r
398\r
399 } else {\r
400\r
401 SectorCount = MaxBlock;\r
402 }\r
403 //\r
404 // fill the Packet data structure\r
405 //\r
406 Read10Packet->opcode = ATA_CMD_READ_10;\r
407\r
408 //\r
409 // Lba0 ~ Lba3 specify the start logical block address of the data transfer.\r
410 // Lba0 is MSB, Lba3 is LSB\r
411 //\r
412 Read10Packet->Lba3 = (UINT8) (Lba32 & 0xff);\r
413 Read10Packet->Lba2 = (UINT8) (Lba32 >> 8);\r
414 Read10Packet->Lba1 = (UINT8) (Lba32 >> 16);\r
415 Read10Packet->Lba0 = (UINT8) (Lba32 >> 24);\r
416\r
417 //\r
418 // TranLen0 ~ TranLen1 specify the transfer length in block unit.\r
419 // TranLen0 is MSB, TranLen is LSB\r
420 //\r
421 Read10Packet->TranLen1 = (UINT8) (SectorCount & 0xff);\r
422 Read10Packet->TranLen0 = (UINT8) (SectorCount >> 8);\r
423\r
424 ByteCount = SectorCount * BlockSize;\r
425\r
426 TimeOut = (UINT16) (SectorCount * 2000);\r
427\r
428 //\r
429 // send command packet\r
430 //\r
431 Status = PeiAtapiCommand (\r
432 PeiServices,\r
433 PeiBotDevice,\r
434 &Packet,\r
435 (UINT8) sizeof (ATAPI_PACKET_COMMAND),\r
436 (VOID *) PtrBuffer,\r
437 ByteCount,\r
438 EfiUsbDataIn,\r
439 TimeOut\r
440 );\r
441\r
442 if (Status != EFI_SUCCESS) {\r
443 return Status;\r
444 }\r
445\r
446 Lba32 += SectorCount;\r
447 PtrBuffer = (UINT8 *) PtrBuffer + SectorCount * BlockSize;\r
448 BlocksRemaining = (UINT16) (BlocksRemaining - SectorCount);\r
449 }\r
450\r
451 return Status;\r
452}\r
453\r
454/** \r
455 Check if there is media according to sense data.\r
456\r
457 @param SenseData Pointer to sense data.\r
458 @param SenseCounts Count of sense data.\r
459\r
460 @retval TRUE No media\r
461 @retval FALSE Media exists\r
462\r
463**/\r
464BOOLEAN\r
465IsNoMedia (\r
466 IN ATAPI_REQUEST_SENSE_DATA *SenseData,\r
467 IN UINTN SenseCounts\r
468 )\r
469{\r
470 ATAPI_REQUEST_SENSE_DATA *SensePtr;\r
471 UINTN Index;\r
472 BOOLEAN NoMedia;\r
473\r
474 NoMedia = FALSE;\r
475 SensePtr = SenseData;\r
476\r
477 for (Index = 0; Index < SenseCounts; Index++) {\r
478\r
479 switch (SensePtr->sense_key) {\r
480\r
481 case ATA_SK_NOT_READY:\r
482 switch (SensePtr->addnl_sense_code) {\r
483 //\r
484 // if no media, fill IdeDev parameter with specific info.\r
485 //\r
486 case ATA_ASC_NO_MEDIA:\r
487 NoMedia = TRUE;\r
488 break;\r
489\r
490 default:\r
491 break;\r
492 }\r
493 break;\r
494\r
495 default:\r
496 break;\r
497 }\r
498\r
499 SensePtr++;\r
500 }\r
501\r
502 return NoMedia;\r
503}\r
504\r
505/** \r
506 Check if there is media error according to sense data.\r
507\r
508 @param SenseData Pointer to sense data.\r
509 @param SenseCounts Count of sense data.\r
510\r
511 @retval TRUE Media error\r
512 @retval FALSE No media error\r
513\r
514**/\r
515BOOLEAN\r
516IsMediaError (\r
517 IN ATAPI_REQUEST_SENSE_DATA *SenseData,\r
518 IN UINTN SenseCounts\r
519 )\r
520{\r
521 ATAPI_REQUEST_SENSE_DATA *SensePtr;\r
522 UINTN Index;\r
523 BOOLEAN Error;\r
524\r
525 SensePtr = SenseData;\r
526 Error = FALSE;\r
527\r
528 for (Index = 0; Index < SenseCounts; Index++) {\r
529\r
530 switch (SensePtr->sense_key) {\r
531 //\r
532 // Medium error case\r
533 //\r
534 case ATA_SK_MEDIUM_ERROR:\r
535 switch (SensePtr->addnl_sense_code) {\r
536 case ATA_ASC_MEDIA_ERR1:\r
537 //\r
538 // fall through\r
539 //\r
540 case ATA_ASC_MEDIA_ERR2:\r
541 //\r
542 // fall through\r
543 //\r
544 case ATA_ASC_MEDIA_ERR3:\r
545 //\r
546 // fall through\r
547 //\r
548 case ATA_ASC_MEDIA_ERR4:\r
549 Error = TRUE;\r
550 break;\r
551\r
552 default:\r
553 break;\r
554 }\r
555\r
556 break;\r
557\r
558 //\r
559 // Medium upside-down case\r
560 //\r
561 case ATA_SK_NOT_READY:\r
562 switch (SensePtr->addnl_sense_code) {\r
563 case ATA_ASC_MEDIA_UPSIDE_DOWN:\r
564 Error = TRUE;\r
565 break;\r
566\r
567 default:\r
568 break;\r
569 }\r
570 break;\r
571\r
572 default:\r
573 break;\r
574 }\r
575\r
576 SensePtr++;\r
577 }\r
578\r
579 return Error;\r
580}\r
581\r
582/** \r
583 Check if media is changed according to sense data.\r
584\r
585 @param SenseData Pointer to sense data.\r
586 @param SenseCounts Count of sense data.\r
587\r
588 @retval TRUE There is media change event.\r
589 @retval FALSE media is NOT changed.\r
590\r
591**/\r
592BOOLEAN\r
593IsMediaChange (\r
594 IN ATAPI_REQUEST_SENSE_DATA *SenseData,\r
595 IN UINTN SenseCounts\r
596 )\r
597{\r
598 ATAPI_REQUEST_SENSE_DATA *SensePtr;\r
599 UINTN Index;\r
600 BOOLEAN MediaChange;\r
601\r
602 MediaChange = FALSE;\r
603\r
604 SensePtr = SenseData;\r
605\r
606 for (Index = 0; Index < SenseCounts; Index++) {\r
607 //\r
608 // catch media change sense key and addition sense data\r
609 //\r
610 switch (SensePtr->sense_key) {\r
611 case ATA_SK_UNIT_ATTENTION:\r
612 switch (SensePtr->addnl_sense_code) {\r
613 case ATA_ASC_MEDIA_CHANGE:\r
614 MediaChange = TRUE;\r
615 break;\r
616\r
617 default:\r
618 break;\r
619 }\r
620 break;\r
621\r
622 default:\r
623 break;\r
624 }\r
625\r
626 SensePtr++;\r
627 }\r
628\r
629 return MediaChange;\r
630}\r