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 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 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 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 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 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 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 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 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 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