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