18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci#include <linux/types.h> 38c2ecf20Sopenharmony_ci#include <linux/string.h> 48c2ecf20Sopenharmony_ci#include <linux/kernel.h> 58c2ecf20Sopenharmony_ci#include <linux/export.h> 68c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 78c2ecf20Sopenharmony_ci#include <linux/ide.h> 88c2ecf20Sopenharmony_ci#include <linux/bitops.h> 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ciu64 ide_get_lba_addr(struct ide_cmd *cmd, int lba48) 118c2ecf20Sopenharmony_ci{ 128c2ecf20Sopenharmony_ci struct ide_taskfile *tf = &cmd->tf; 138c2ecf20Sopenharmony_ci u32 high, low; 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci low = (tf->lbah << 16) | (tf->lbam << 8) | tf->lbal; 168c2ecf20Sopenharmony_ci if (lba48) { 178c2ecf20Sopenharmony_ci tf = &cmd->hob; 188c2ecf20Sopenharmony_ci high = (tf->lbah << 16) | (tf->lbam << 8) | tf->lbal; 198c2ecf20Sopenharmony_ci } else 208c2ecf20Sopenharmony_ci high = tf->device & 0xf; 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci return ((u64)high << 24) | low; 238c2ecf20Sopenharmony_ci} 248c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(ide_get_lba_addr); 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_cistatic void ide_dump_sector(ide_drive_t *drive) 278c2ecf20Sopenharmony_ci{ 288c2ecf20Sopenharmony_ci struct ide_cmd cmd; 298c2ecf20Sopenharmony_ci struct ide_taskfile *tf = &cmd.tf; 308c2ecf20Sopenharmony_ci u8 lba48 = !!(drive->dev_flags & IDE_DFLAG_LBA48); 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci memset(&cmd, 0, sizeof(cmd)); 338c2ecf20Sopenharmony_ci if (lba48) { 348c2ecf20Sopenharmony_ci cmd.valid.in.tf = IDE_VALID_LBA; 358c2ecf20Sopenharmony_ci cmd.valid.in.hob = IDE_VALID_LBA; 368c2ecf20Sopenharmony_ci cmd.tf_flags = IDE_TFLAG_LBA48; 378c2ecf20Sopenharmony_ci } else 388c2ecf20Sopenharmony_ci cmd.valid.in.tf = IDE_VALID_LBA | IDE_VALID_DEVICE; 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci ide_tf_readback(drive, &cmd); 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci if (lba48 || (tf->device & ATA_LBA)) 438c2ecf20Sopenharmony_ci printk(KERN_CONT ", LBAsect=%llu", 448c2ecf20Sopenharmony_ci (unsigned long long)ide_get_lba_addr(&cmd, lba48)); 458c2ecf20Sopenharmony_ci else 468c2ecf20Sopenharmony_ci printk(KERN_CONT ", CHS=%d/%d/%d", (tf->lbah << 8) + tf->lbam, 478c2ecf20Sopenharmony_ci tf->device & 0xf, tf->lbal); 488c2ecf20Sopenharmony_ci} 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_cistatic void ide_dump_ata_error(ide_drive_t *drive, u8 err) 518c2ecf20Sopenharmony_ci{ 528c2ecf20Sopenharmony_ci printk(KERN_CONT "{ "); 538c2ecf20Sopenharmony_ci if (err & ATA_ABORTED) 548c2ecf20Sopenharmony_ci printk(KERN_CONT "DriveStatusError "); 558c2ecf20Sopenharmony_ci if (err & ATA_ICRC) 568c2ecf20Sopenharmony_ci printk(KERN_CONT "%s", 578c2ecf20Sopenharmony_ci (err & ATA_ABORTED) ? "BadCRC " : "BadSector "); 588c2ecf20Sopenharmony_ci if (err & ATA_UNC) 598c2ecf20Sopenharmony_ci printk(KERN_CONT "UncorrectableError "); 608c2ecf20Sopenharmony_ci if (err & ATA_IDNF) 618c2ecf20Sopenharmony_ci printk(KERN_CONT "SectorIdNotFound "); 628c2ecf20Sopenharmony_ci if (err & ATA_TRK0NF) 638c2ecf20Sopenharmony_ci printk(KERN_CONT "TrackZeroNotFound "); 648c2ecf20Sopenharmony_ci if (err & ATA_AMNF) 658c2ecf20Sopenharmony_ci printk(KERN_CONT "AddrMarkNotFound "); 668c2ecf20Sopenharmony_ci printk(KERN_CONT "}"); 678c2ecf20Sopenharmony_ci if ((err & (ATA_BBK | ATA_ABORTED)) == ATA_BBK || 688c2ecf20Sopenharmony_ci (err & (ATA_UNC | ATA_IDNF | ATA_AMNF))) { 698c2ecf20Sopenharmony_ci struct request *rq = drive->hwif->rq; 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci ide_dump_sector(drive); 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci if (rq) 748c2ecf20Sopenharmony_ci printk(KERN_CONT ", sector=%llu", 758c2ecf20Sopenharmony_ci (unsigned long long)blk_rq_pos(rq)); 768c2ecf20Sopenharmony_ci } 778c2ecf20Sopenharmony_ci printk(KERN_CONT "\n"); 788c2ecf20Sopenharmony_ci} 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_cistatic void ide_dump_atapi_error(ide_drive_t *drive, u8 err) 818c2ecf20Sopenharmony_ci{ 828c2ecf20Sopenharmony_ci printk(KERN_CONT "{ "); 838c2ecf20Sopenharmony_ci if (err & ATAPI_ILI) 848c2ecf20Sopenharmony_ci printk(KERN_CONT "IllegalLengthIndication "); 858c2ecf20Sopenharmony_ci if (err & ATAPI_EOM) 868c2ecf20Sopenharmony_ci printk(KERN_CONT "EndOfMedia "); 878c2ecf20Sopenharmony_ci if (err & ATA_ABORTED) 888c2ecf20Sopenharmony_ci printk(KERN_CONT "AbortedCommand "); 898c2ecf20Sopenharmony_ci if (err & ATA_MCR) 908c2ecf20Sopenharmony_ci printk(KERN_CONT "MediaChangeRequested "); 918c2ecf20Sopenharmony_ci if (err & ATAPI_LFS) 928c2ecf20Sopenharmony_ci printk(KERN_CONT "LastFailedSense=0x%02x ", 938c2ecf20Sopenharmony_ci (err & ATAPI_LFS) >> 4); 948c2ecf20Sopenharmony_ci printk(KERN_CONT "}\n"); 958c2ecf20Sopenharmony_ci} 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci/** 988c2ecf20Sopenharmony_ci * ide_dump_status - translate ATA/ATAPI error 998c2ecf20Sopenharmony_ci * @drive: drive that status applies to 1008c2ecf20Sopenharmony_ci * @msg: text message to print 1018c2ecf20Sopenharmony_ci * @stat: status byte to decode 1028c2ecf20Sopenharmony_ci * 1038c2ecf20Sopenharmony_ci * Error reporting, in human readable form (luxurious, but a memory hog). 1048c2ecf20Sopenharmony_ci * Combines the drive name, message and status byte to provide a 1058c2ecf20Sopenharmony_ci * user understandable explanation of the device error. 1068c2ecf20Sopenharmony_ci */ 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ciu8 ide_dump_status(ide_drive_t *drive, const char *msg, u8 stat) 1098c2ecf20Sopenharmony_ci{ 1108c2ecf20Sopenharmony_ci u8 err = 0; 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci printk(KERN_ERR "%s: %s: status=0x%02x { ", drive->name, msg, stat); 1138c2ecf20Sopenharmony_ci if (stat & ATA_BUSY) 1148c2ecf20Sopenharmony_ci printk(KERN_CONT "Busy "); 1158c2ecf20Sopenharmony_ci else { 1168c2ecf20Sopenharmony_ci if (stat & ATA_DRDY) 1178c2ecf20Sopenharmony_ci printk(KERN_CONT "DriveReady "); 1188c2ecf20Sopenharmony_ci if (stat & ATA_DF) 1198c2ecf20Sopenharmony_ci printk(KERN_CONT "DeviceFault "); 1208c2ecf20Sopenharmony_ci if (stat & ATA_DSC) 1218c2ecf20Sopenharmony_ci printk(KERN_CONT "SeekComplete "); 1228c2ecf20Sopenharmony_ci if (stat & ATA_DRQ) 1238c2ecf20Sopenharmony_ci printk(KERN_CONT "DataRequest "); 1248c2ecf20Sopenharmony_ci if (stat & ATA_CORR) 1258c2ecf20Sopenharmony_ci printk(KERN_CONT "CorrectedError "); 1268c2ecf20Sopenharmony_ci if (stat & ATA_SENSE) 1278c2ecf20Sopenharmony_ci printk(KERN_CONT "Sense "); 1288c2ecf20Sopenharmony_ci if (stat & ATA_ERR) 1298c2ecf20Sopenharmony_ci printk(KERN_CONT "Error "); 1308c2ecf20Sopenharmony_ci } 1318c2ecf20Sopenharmony_ci printk(KERN_CONT "}\n"); 1328c2ecf20Sopenharmony_ci if ((stat & (ATA_BUSY | ATA_ERR)) == ATA_ERR) { 1338c2ecf20Sopenharmony_ci err = ide_read_error(drive); 1348c2ecf20Sopenharmony_ci printk(KERN_ERR "%s: %s: error=0x%02x ", drive->name, msg, err); 1358c2ecf20Sopenharmony_ci if (drive->media == ide_disk) 1368c2ecf20Sopenharmony_ci ide_dump_ata_error(drive, err); 1378c2ecf20Sopenharmony_ci else 1388c2ecf20Sopenharmony_ci ide_dump_atapi_error(drive, err); 1398c2ecf20Sopenharmony_ci } 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci printk(KERN_ERR "%s: possibly failed opcode: 0x%02x\n", 1428c2ecf20Sopenharmony_ci drive->name, drive->hwif->cmd.tf.command); 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci return err; 1458c2ecf20Sopenharmony_ci} 1468c2ecf20Sopenharmony_ciEXPORT_SYMBOL(ide_dump_status); 147