xref: /kernel/linux/linux-5.10/drivers/ide/ide-lib.c (revision 8c2ecf20)
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