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