]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Bus/Usb/UsbBotPei/PeiAtapi.c
MdeModulePkg: Add PEI USB drivers and related PPIs
[mirror_edk2.git] / MdeModulePkg / Bus / Usb / UsbBotPei / PeiAtapi.c
1 /** @file
2 Pei USB ATATPI command implementations.
3
4 Copyright (c) 1999 - 2010, 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
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 } else {
77 PeiBotDevice->DeviceType = USBFLOPPY;
78 PeiBotDevice->Media.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
205 Ptr += sizeof (ATAPI_REQUEST_SENSE_DATA);
206 //
207 // Ptr is byte based pointer
208 //
209 (*SenseCounts)++;
210
211 if (*SenseCounts == MAXSENSEKEY) {
212 break;
213 }
214
215 } else {
216 //
217 // when no sense key, skip out the loop
218 //
219 SenseReq = FALSE;
220 }
221 }
222
223 return EFI_SUCCESS;
224 }
225
226 /**
227 Sends out ATAPI Read Capacity Packet Command to the specified device.
228 This command will return the information regarding the capacity of the
229 media in the device.
230
231 @param PeiServices The pointer of EFI_PEI_SERVICES.
232 @param PeiBotDevice The pointer to PEI_BOT_DEVICE instance.
233
234 @retval EFI_SUCCESS Command executed successfully.
235 @retval EFI_DEVICE_ERROR Some device errors happen.
236
237 **/
238 EFI_STATUS
239 PeiUsbReadCapacity (
240 IN EFI_PEI_SERVICES **PeiServices,
241 IN PEI_BOT_DEVICE *PeiBotDevice
242 )
243 {
244 EFI_STATUS Status;
245 ATAPI_PACKET_COMMAND Packet;
246 ATAPI_READ_CAPACITY_DATA Data;
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
271 PeiBotDevice->Media.LastBlock = (Data.LastLba3 << 24) | (Data.LastLba2 << 16) | (Data.LastLba1 << 8) | Data.LastLba0;
272
273 PeiBotDevice->Media.MediaPresent = TRUE;
274
275 return EFI_SUCCESS;
276 }
277
278 /**
279 Sends out ATAPI Read Format Capacity Data Command to the specified device.
280 This command will return the information regarding the capacity of the
281 media in the device.
282
283 @param PeiServices The pointer of EFI_PEI_SERVICES.
284 @param PeiBotDevice The pointer to PEI_BOT_DEVICE instance.
285
286 @retval EFI_SUCCESS Command executed successfully.
287 @retval EFI_DEVICE_ERROR Some device errors happen.
288
289 **/
290 EFI_STATUS
291 PeiUsbReadFormattedCapacity (
292 IN EFI_PEI_SERVICES **PeiServices,
293 IN PEI_BOT_DEVICE *PeiBotDevice
294 )
295 {
296 EFI_STATUS Status;
297 ATAPI_PACKET_COMMAND Packet;
298 ATAPI_READ_FORMAT_CAPACITY_DATA FormatData;
299
300 ZeroMem (&FormatData, sizeof (ATAPI_READ_FORMAT_CAPACITY_DATA));
301 ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));
302
303 Packet.ReadFormatCapacity.opcode = ATA_CMD_READ_FORMAT_CAPACITY;
304 Packet.ReadFormatCapacity.allocation_length_lo = 12;
305
306 //
307 // send command packet
308 //
309 Status = PeiAtapiCommand (
310 PeiServices,
311 PeiBotDevice,
312 &Packet,
313 (UINT8) sizeof (ATAPI_PACKET_COMMAND),
314 (VOID *) &FormatData,
315 sizeof (ATAPI_READ_FORMAT_CAPACITY_DATA),
316 EfiUsbDataIn,
317 2000
318 );
319
320 if (EFI_ERROR (Status)) {
321 return EFI_DEVICE_ERROR;
322 }
323
324 if (FormatData.DesCode == 3) {
325 //
326 // Media is not present
327 //
328 PeiBotDevice->Media.MediaPresent = FALSE;
329 PeiBotDevice->Media.LastBlock = 0;
330
331 } else {
332
333 PeiBotDevice->Media.LastBlock = (FormatData.LastLba3 << 24) | (FormatData.LastLba2 << 16) | (FormatData.LastLba1 << 8) | FormatData.LastLba0;
334
335 PeiBotDevice->Media.LastBlock--;
336
337 PeiBotDevice->Media.MediaPresent = TRUE;
338 }
339
340 return EFI_SUCCESS;
341 }
342
343 /**
344 Execute Read(10) ATAPI command on a specific SCSI target.
345
346 Executes the ATAPI Read(10) command on the ATAPI target specified by PeiBotDevice.
347
348 @param PeiServices The pointer of EFI_PEI_SERVICES.
349 @param PeiBotDevice The pointer to PEI_BOT_DEVICE instance.
350 @param Buffer The pointer to data buffer.
351 @param Lba The start logic block address of reading.
352 @param NumberOfBlocks The block number of reading.
353
354 @retval EFI_SUCCESS Command executed successfully.
355 @retval EFI_DEVICE_ERROR Some device errors happen.
356
357 **/
358 EFI_STATUS
359 PeiUsbRead10 (
360 IN EFI_PEI_SERVICES **PeiServices,
361 IN PEI_BOT_DEVICE *PeiBotDevice,
362 IN VOID *Buffer,
363 IN EFI_PEI_LBA Lba,
364 IN UINTN NumberOfBlocks
365 )
366 {
367 ATAPI_PACKET_COMMAND Packet;
368 ATAPI_READ10_CMD *Read10Packet;
369 UINT16 MaxBlock;
370 UINT16 BlocksRemaining;
371 UINT16 SectorCount;
372 UINT32 Lba32;
373 UINT32 BlockSize;
374 UINT32 ByteCount;
375 VOID *PtrBuffer;
376 EFI_STATUS Status;
377 UINT16 TimeOut;
378
379 //
380 // prepare command packet for the Inquiry Packet Command.
381 //
382 ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));
383 Read10Packet = &Packet.Read10;
384 Lba32 = (UINT32) Lba;
385 PtrBuffer = Buffer;
386
387 BlockSize = (UINT32) PeiBotDevice->Media.BlockSize;
388
389 MaxBlock = (UINT16) (65535 / BlockSize);
390 BlocksRemaining = (UINT16) NumberOfBlocks;
391
392 Status = EFI_SUCCESS;
393 while (BlocksRemaining > 0) {
394
395 if (BlocksRemaining <= MaxBlock) {
396
397 SectorCount = BlocksRemaining;
398
399 } else {
400
401 SectorCount = MaxBlock;
402 }
403 //
404 // fill the Packet data structure
405 //
406 Read10Packet->opcode = ATA_CMD_READ_10;
407
408 //
409 // Lba0 ~ Lba3 specify the start logical block address of the data transfer.
410 // Lba0 is MSB, Lba3 is LSB
411 //
412 Read10Packet->Lba3 = (UINT8) (Lba32 & 0xff);
413 Read10Packet->Lba2 = (UINT8) (Lba32 >> 8);
414 Read10Packet->Lba1 = (UINT8) (Lba32 >> 16);
415 Read10Packet->Lba0 = (UINT8) (Lba32 >> 24);
416
417 //
418 // TranLen0 ~ TranLen1 specify the transfer length in block unit.
419 // TranLen0 is MSB, TranLen is LSB
420 //
421 Read10Packet->TranLen1 = (UINT8) (SectorCount & 0xff);
422 Read10Packet->TranLen0 = (UINT8) (SectorCount >> 8);
423
424 ByteCount = SectorCount * BlockSize;
425
426 TimeOut = (UINT16) (SectorCount * 2000);
427
428 //
429 // send command packet
430 //
431 Status = PeiAtapiCommand (
432 PeiServices,
433 PeiBotDevice,
434 &Packet,
435 (UINT8) sizeof (ATAPI_PACKET_COMMAND),
436 (VOID *) PtrBuffer,
437 ByteCount,
438 EfiUsbDataIn,
439 TimeOut
440 );
441
442 if (Status != EFI_SUCCESS) {
443 return Status;
444 }
445
446 Lba32 += SectorCount;
447 PtrBuffer = (UINT8 *) PtrBuffer + SectorCount * BlockSize;
448 BlocksRemaining = (UINT16) (BlocksRemaining - SectorCount);
449 }
450
451 return Status;
452 }
453
454 /**
455 Check if there is media according to sense data.
456
457 @param SenseData Pointer to sense data.
458 @param SenseCounts Count of sense data.
459
460 @retval TRUE No media
461 @retval FALSE Media exists
462
463 **/
464 BOOLEAN
465 IsNoMedia (
466 IN ATAPI_REQUEST_SENSE_DATA *SenseData,
467 IN UINTN SenseCounts
468 )
469 {
470 ATAPI_REQUEST_SENSE_DATA *SensePtr;
471 UINTN Index;
472 BOOLEAN NoMedia;
473
474 NoMedia = FALSE;
475 SensePtr = SenseData;
476
477 for (Index = 0; Index < SenseCounts; Index++) {
478
479 switch (SensePtr->sense_key) {
480
481 case ATA_SK_NOT_READY:
482 switch (SensePtr->addnl_sense_code) {
483 //
484 // if no media, fill IdeDev parameter with specific info.
485 //
486 case ATA_ASC_NO_MEDIA:
487 NoMedia = TRUE;
488 break;
489
490 default:
491 break;
492 }
493 break;
494
495 default:
496 break;
497 }
498
499 SensePtr++;
500 }
501
502 return NoMedia;
503 }
504
505 /**
506 Check if there is media error according to sense data.
507
508 @param SenseData Pointer to sense data.
509 @param SenseCounts Count of sense data.
510
511 @retval TRUE Media error
512 @retval FALSE No media error
513
514 **/
515 BOOLEAN
516 IsMediaError (
517 IN ATAPI_REQUEST_SENSE_DATA *SenseData,
518 IN UINTN SenseCounts
519 )
520 {
521 ATAPI_REQUEST_SENSE_DATA *SensePtr;
522 UINTN Index;
523 BOOLEAN Error;
524
525 SensePtr = SenseData;
526 Error = FALSE;
527
528 for (Index = 0; Index < SenseCounts; Index++) {
529
530 switch (SensePtr->sense_key) {
531 //
532 // Medium error case
533 //
534 case ATA_SK_MEDIUM_ERROR:
535 switch (SensePtr->addnl_sense_code) {
536 case ATA_ASC_MEDIA_ERR1:
537 //
538 // fall through
539 //
540 case ATA_ASC_MEDIA_ERR2:
541 //
542 // fall through
543 //
544 case ATA_ASC_MEDIA_ERR3:
545 //
546 // fall through
547 //
548 case ATA_ASC_MEDIA_ERR4:
549 Error = TRUE;
550 break;
551
552 default:
553 break;
554 }
555
556 break;
557
558 //
559 // Medium upside-down case
560 //
561 case ATA_SK_NOT_READY:
562 switch (SensePtr->addnl_sense_code) {
563 case ATA_ASC_MEDIA_UPSIDE_DOWN:
564 Error = TRUE;
565 break;
566
567 default:
568 break;
569 }
570 break;
571
572 default:
573 break;
574 }
575
576 SensePtr++;
577 }
578
579 return Error;
580 }
581
582 /**
583 Check if media is changed according to sense data.
584
585 @param SenseData Pointer to sense data.
586 @param SenseCounts Count of sense data.
587
588 @retval TRUE There is media change event.
589 @retval FALSE media is NOT changed.
590
591 **/
592 BOOLEAN
593 IsMediaChange (
594 IN ATAPI_REQUEST_SENSE_DATA *SenseData,
595 IN UINTN SenseCounts
596 )
597 {
598 ATAPI_REQUEST_SENSE_DATA *SensePtr;
599 UINTN Index;
600 BOOLEAN MediaChange;
601
602 MediaChange = FALSE;
603
604 SensePtr = SenseData;
605
606 for (Index = 0; Index < SenseCounts; Index++) {
607 //
608 // catch media change sense key and addition sense data
609 //
610 switch (SensePtr->sense_key) {
611 case ATA_SK_UNIT_ATTENTION:
612 switch (SensePtr->addnl_sense_code) {
613 case ATA_ASC_MEDIA_CHANGE:
614 MediaChange = TRUE;
615 break;
616
617 default:
618 break;
619 }
620 break;
621
622 default:
623 break;
624 }
625
626 SensePtr++;
627 }
628
629 return MediaChange;
630 }