]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Bus/Usb/UsbBotPei/PeiAtapi.c
MdeModulePkg: Replace BSD License with BSD+Patent License
[mirror_edk2.git] / MdeModulePkg / Bus / Usb / UsbBotPei / PeiAtapi.c
1 /** @file
2 Pei USB ATATPI 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
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
214 } else {
215 //
216 // when no sense key, skip out the loop
217 //
218 SenseReq = FALSE;
219 }
220 }
221
222 return EFI_SUCCESS;
223 }
224
225 /**
226 Sends out ATAPI Read Capacity Packet Command to the specified device.
227 This command will return the information regarding the capacity of the
228 media in the device.
229
230 @param PeiServices The pointer of EFI_PEI_SERVICES.
231 @param PeiBotDevice The pointer to PEI_BOT_DEVICE instance.
232
233 @retval EFI_SUCCESS Command executed successfully.
234 @retval EFI_DEVICE_ERROR Some device errors happen.
235
236 **/
237 EFI_STATUS
238 PeiUsbReadCapacity (
239 IN EFI_PEI_SERVICES **PeiServices,
240 IN PEI_BOT_DEVICE *PeiBotDevice
241 )
242 {
243 EFI_STATUS Status;
244 ATAPI_PACKET_COMMAND Packet;
245 ATAPI_READ_CAPACITY_DATA Data;
246 UINT32 LastBlock;
247
248 ZeroMem (&Data, sizeof (ATAPI_READ_CAPACITY_DATA));
249 ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));
250
251 Packet.Inquiry.opcode = ATA_CMD_READ_CAPACITY;
252
253 //
254 // send command packet
255 //
256 Status = PeiAtapiCommand (
257 PeiServices,
258 PeiBotDevice,
259 &Packet,
260 (UINT8) sizeof (ATAPI_PACKET_COMMAND),
261 (VOID *) &Data,
262 sizeof (ATAPI_READ_CAPACITY_DATA),
263 EfiUsbDataIn,
264 2000
265 );
266
267 if (EFI_ERROR (Status)) {
268 return EFI_DEVICE_ERROR;
269 }
270 LastBlock = ((UINT32) Data.LastLba3 << 24) | (Data.LastLba2 << 16) | (Data.LastLba1 << 8) | Data.LastLba0;
271
272 if (LastBlock == 0xFFFFFFFF) {
273 DEBUG ((EFI_D_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
341 } else {
342 LastBlock = ((UINT32) FormatData.LastLba3 << 24) | (FormatData.LastLba2 << 16) | (FormatData.LastLba1 << 8) | FormatData.LastLba0;
343 if (LastBlock == 0xFFFFFFFF) {
344 DEBUG ((EFI_D_INFO, "The usb device LBA count is larger than 0xFFFFFFFF!\n"));
345 }
346
347 PeiBotDevice->Media.LastBlock = LastBlock;
348
349 PeiBotDevice->Media.LastBlock--;
350
351 PeiBotDevice->Media.MediaPresent = TRUE;
352
353 PeiBotDevice->Media2.MediaPresent = TRUE;
354 PeiBotDevice->Media2.LastBlock = PeiBotDevice->Media.LastBlock;
355 }
356
357 return EFI_SUCCESS;
358 }
359
360 /**
361 Execute Read(10) ATAPI command on a specific SCSI target.
362
363 Executes the ATAPI Read(10) command on the ATAPI target specified by PeiBotDevice.
364
365 @param PeiServices The pointer of EFI_PEI_SERVICES.
366 @param PeiBotDevice The pointer to PEI_BOT_DEVICE instance.
367 @param Buffer The pointer to data buffer.
368 @param Lba The start logic block address of reading.
369 @param NumberOfBlocks The block number of reading.
370
371 @retval EFI_SUCCESS Command executed successfully.
372 @retval EFI_DEVICE_ERROR Some device errors happen.
373
374 **/
375 EFI_STATUS
376 PeiUsbRead10 (
377 IN EFI_PEI_SERVICES **PeiServices,
378 IN PEI_BOT_DEVICE *PeiBotDevice,
379 IN VOID *Buffer,
380 IN EFI_PEI_LBA Lba,
381 IN UINTN NumberOfBlocks
382 )
383 {
384 ATAPI_PACKET_COMMAND Packet;
385 ATAPI_READ10_CMD *Read10Packet;
386 UINT16 MaxBlock;
387 UINT16 BlocksRemaining;
388 UINT16 SectorCount;
389 UINT32 Lba32;
390 UINT32 BlockSize;
391 UINT32 ByteCount;
392 VOID *PtrBuffer;
393 EFI_STATUS Status;
394 UINT16 TimeOut;
395
396 //
397 // prepare command packet for the Inquiry Packet Command.
398 //
399 ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));
400 Read10Packet = &Packet.Read10;
401 Lba32 = (UINT32) Lba;
402 PtrBuffer = Buffer;
403
404 BlockSize = (UINT32) PeiBotDevice->Media.BlockSize;
405
406 MaxBlock = (UINT16) (65535 / BlockSize);
407 BlocksRemaining = (UINT16) NumberOfBlocks;
408
409 Status = EFI_SUCCESS;
410 while (BlocksRemaining > 0) {
411
412 if (BlocksRemaining <= MaxBlock) {
413
414 SectorCount = BlocksRemaining;
415
416 } else {
417
418 SectorCount = MaxBlock;
419 }
420 //
421 // fill the Packet data structure
422 //
423 Read10Packet->opcode = ATA_CMD_READ_10;
424
425 //
426 // Lba0 ~ Lba3 specify the start logical block address of the data transfer.
427 // Lba0 is MSB, Lba3 is LSB
428 //
429 Read10Packet->Lba3 = (UINT8) (Lba32 & 0xff);
430 Read10Packet->Lba2 = (UINT8) (Lba32 >> 8);
431 Read10Packet->Lba1 = (UINT8) (Lba32 >> 16);
432 Read10Packet->Lba0 = (UINT8) (Lba32 >> 24);
433
434 //
435 // TranLen0 ~ TranLen1 specify the transfer length in block unit.
436 // TranLen0 is MSB, TranLen is LSB
437 //
438 Read10Packet->TranLen1 = (UINT8) (SectorCount & 0xff);
439 Read10Packet->TranLen0 = (UINT8) (SectorCount >> 8);
440
441 ByteCount = SectorCount * BlockSize;
442
443 TimeOut = (UINT16) (SectorCount * 2000);
444
445 //
446 // send command packet
447 //
448 Status = PeiAtapiCommand (
449 PeiServices,
450 PeiBotDevice,
451 &Packet,
452 (UINT8) sizeof (ATAPI_PACKET_COMMAND),
453 (VOID *) PtrBuffer,
454 ByteCount,
455 EfiUsbDataIn,
456 TimeOut
457 );
458
459 if (Status != EFI_SUCCESS) {
460 return Status;
461 }
462
463 Lba32 += SectorCount;
464 PtrBuffer = (UINT8 *) PtrBuffer + SectorCount * BlockSize;
465 BlocksRemaining = (UINT16) (BlocksRemaining - SectorCount);
466 }
467
468 return Status;
469 }
470
471 /**
472 Check if there is media according to sense data.
473
474 @param SenseData Pointer to sense data.
475 @param SenseCounts Count of sense data.
476
477 @retval TRUE No media
478 @retval FALSE Media exists
479
480 **/
481 BOOLEAN
482 IsNoMedia (
483 IN ATAPI_REQUEST_SENSE_DATA *SenseData,
484 IN UINTN SenseCounts
485 )
486 {
487 ATAPI_REQUEST_SENSE_DATA *SensePtr;
488 UINTN Index;
489 BOOLEAN NoMedia;
490
491 NoMedia = FALSE;
492 SensePtr = SenseData;
493
494 for (Index = 0; Index < SenseCounts; Index++) {
495
496 switch (SensePtr->sense_key) {
497
498 case ATA_SK_NOT_READY:
499 switch (SensePtr->addnl_sense_code) {
500 //
501 // if no media, fill IdeDev parameter with specific info.
502 //
503 case ATA_ASC_NO_MEDIA:
504 NoMedia = TRUE;
505 break;
506
507 default:
508 break;
509 }
510 break;
511
512 default:
513 break;
514 }
515
516 SensePtr++;
517 }
518
519 return NoMedia;
520 }
521
522 /**
523 Check if there is media error according to sense data.
524
525 @param SenseData Pointer to sense data.
526 @param SenseCounts Count of sense data.
527
528 @retval TRUE Media error
529 @retval FALSE No media error
530
531 **/
532 BOOLEAN
533 IsMediaError (
534 IN ATAPI_REQUEST_SENSE_DATA *SenseData,
535 IN UINTN SenseCounts
536 )
537 {
538 ATAPI_REQUEST_SENSE_DATA *SensePtr;
539 UINTN Index;
540 BOOLEAN Error;
541
542 SensePtr = SenseData;
543 Error = FALSE;
544
545 for (Index = 0; Index < SenseCounts; Index++) {
546
547 switch (SensePtr->sense_key) {
548 //
549 // Medium error case
550 //
551 case ATA_SK_MEDIUM_ERROR:
552 switch (SensePtr->addnl_sense_code) {
553 case ATA_ASC_MEDIA_ERR1:
554 //
555 // fall through
556 //
557 case ATA_ASC_MEDIA_ERR2:
558 //
559 // fall through
560 //
561 case ATA_ASC_MEDIA_ERR3:
562 //
563 // fall through
564 //
565 case ATA_ASC_MEDIA_ERR4:
566 Error = TRUE;
567 break;
568
569 default:
570 break;
571 }
572
573 break;
574
575 //
576 // Medium upside-down case
577 //
578 case ATA_SK_NOT_READY:
579 switch (SensePtr->addnl_sense_code) {
580 case ATA_ASC_MEDIA_UPSIDE_DOWN:
581 Error = TRUE;
582 break;
583
584 default:
585 break;
586 }
587 break;
588
589 default:
590 break;
591 }
592
593 SensePtr++;
594 }
595
596 return Error;
597 }
598
599 /**
600 Check if media is changed according to sense data.
601
602 @param SenseData Pointer to sense data.
603 @param SenseCounts Count of sense data.
604
605 @retval TRUE There is media change event.
606 @retval FALSE media is NOT changed.
607
608 **/
609 BOOLEAN
610 IsMediaChange (
611 IN ATAPI_REQUEST_SENSE_DATA *SenseData,
612 IN UINTN SenseCounts
613 )
614 {
615 ATAPI_REQUEST_SENSE_DATA *SensePtr;
616 UINTN Index;
617 BOOLEAN MediaChange;
618
619 MediaChange = FALSE;
620
621 SensePtr = SenseData;
622
623 for (Index = 0; Index < SenseCounts; Index++) {
624 //
625 // catch media change sense key and addition sense data
626 //
627 switch (SensePtr->sense_key) {
628 case ATA_SK_UNIT_ATTENTION:
629 switch (SensePtr->addnl_sense_code) {
630 case ATA_ASC_MEDIA_CHANGE:
631 MediaChange = TRUE;
632 break;
633
634 default:
635 break;
636 }
637 break;
638
639 default:
640 break;
641 }
642
643 SensePtr++;
644 }
645
646 return MediaChange;
647 }