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