Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9a3dccc4 authored by Tejun Heo's avatar Tejun Heo Committed by Jens Axboe
Browse files

[BLOCK] add FUA support to libata



Signed-off-by: default avatarTejun Heo <htejun@gmail.com>
Signed-off-by: default avatarJens Axboe <axboe@suse.de>
parent 93c93387
Loading
Loading
Loading
Loading
+25 −6
Original line number Diff line number Diff line
@@ -562,16 +562,28 @@ static const u8 ata_rw_cmds[] = {
	ATA_CMD_WRITE_MULTI,
	ATA_CMD_READ_MULTI_EXT,
	ATA_CMD_WRITE_MULTI_EXT,
	0,
	0,
	0,
	ATA_CMD_WRITE_MULTI_FUA_EXT,
	/* pio */
	ATA_CMD_PIO_READ,
	ATA_CMD_PIO_WRITE,
	ATA_CMD_PIO_READ_EXT,
	ATA_CMD_PIO_WRITE_EXT,
	0,
	0,
	0,
	0,
	/* dma */
	ATA_CMD_READ,
	ATA_CMD_WRITE,
	ATA_CMD_READ_EXT,
	ATA_CMD_WRITE_EXT
	ATA_CMD_WRITE_EXT,
	0,
	0,
	0,
	ATA_CMD_WRITE_FUA_EXT
};

/**
@@ -584,25 +596,32 @@ static const u8 ata_rw_cmds[] = {
 *	LOCKING:
 *	caller.
 */
void ata_rwcmd_protocol(struct ata_queued_cmd *qc)
int ata_rwcmd_protocol(struct ata_queued_cmd *qc)
{
	struct ata_taskfile *tf = &qc->tf;
	struct ata_device *dev = qc->dev;
	u8 cmd;

	int index, lba48, write;
	int index, fua, lba48, write;
 
	fua = (tf->flags & ATA_TFLAG_FUA) ? 4 : 0;
	lba48 = (tf->flags & ATA_TFLAG_LBA48) ? 2 : 0;
	write = (tf->flags & ATA_TFLAG_WRITE) ? 1 : 0;

	if (dev->flags & ATA_DFLAG_PIO) {
		tf->protocol = ATA_PROT_PIO;
		index = dev->multi_count ? 0 : 4;
		index = dev->multi_count ? 0 : 8;
	} else {
		tf->protocol = ATA_PROT_DMA;
		index = 8;
		index = 16;
	}

	tf->command = ata_rw_cmds[index + lba48 + write];
	cmd = ata_rw_cmds[index + fua + lba48 + write];
	if (cmd) {
		tf->command = cmd;
		return 0;
	}
	return -1;
}

static const char * const xfer_mode_str[] = {
+26 −6
Original line number Diff line number Diff line
@@ -1080,11 +1080,13 @@ static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc, const u8 *scsicm
	    scsicmd[0] == WRITE_16)
		tf->flags |= ATA_TFLAG_WRITE;

	/* Calculate the SCSI LBA and transfer length. */
	/* Calculate the SCSI LBA, transfer length and FUA. */
	switch (scsicmd[0]) {
	case READ_10:
	case WRITE_10:
		scsi_10_lba_len(scsicmd, &block, &n_block);
		if (unlikely(scsicmd[1] & (1 << 3)))
			tf->flags |= ATA_TFLAG_FUA;
		break;
	case READ_6:
	case WRITE_6:
@@ -1099,6 +1101,8 @@ static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc, const u8 *scsicm
	case READ_16:
	case WRITE_16:
		scsi_16_lba_len(scsicmd, &block, &n_block);
		if (unlikely(scsicmd[1] & (1 << 3)))
			tf->flags |= ATA_TFLAG_FUA;
		break;
	default:
		DPRINTK("no-byte command\n");
@@ -1142,7 +1146,8 @@ static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc, const u8 *scsicm
			tf->device |= (block >> 24) & 0xf;
		}

		ata_rwcmd_protocol(qc);
		if (unlikely(ata_rwcmd_protocol(qc) < 0))
			goto invalid_fld;

		qc->nsect = n_block;
		tf->nsect = n_block & 0xff;
@@ -1160,7 +1165,8 @@ static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc, const u8 *scsicm
		if ((block >> 28) || (n_block > 256))
			goto out_of_range;

		ata_rwcmd_protocol(qc);
		if (unlikely(ata_rwcmd_protocol(qc) < 0))
			goto invalid_fld;

		/* Convert LBA to CHS */
		track = (u32)block / dev->sectors;
@@ -1695,6 +1701,7 @@ static unsigned int ata_msense_rw_recovery(u8 **ptr_io, const u8 *last)
unsigned int ata_scsiop_mode_sense(struct ata_scsi_args *args, u8 *rbuf,
				  unsigned int buflen)
{
	struct ata_device *dev = args->dev;
	u8 *scsicmd = args->cmd->cmnd, *p, *last;
	const u8 sat_blk_desc[] = {
		0, 0, 0, 0,	/* number of blocks: sat unspecified */
@@ -1703,6 +1710,7 @@ unsigned int ata_scsiop_mode_sense(struct ata_scsi_args *args, u8 *rbuf,
	};
	u8 pg, spg;
	unsigned int ebd, page_control, six_byte, output_len, alloc_len, minlen;
	u8 dpofua;

	VPRINTK("ENTER\n");

@@ -1771,9 +1779,17 @@ unsigned int ata_scsiop_mode_sense(struct ata_scsi_args *args, u8 *rbuf,

	if (minlen < 1)
		return 0;

	dpofua = 0;
	if (ata_id_has_fua(args->id) && dev->flags & ATA_DFLAG_LBA48 &&
	    (!(dev->flags & ATA_DFLAG_PIO) || dev->multi_count))
		dpofua = 1 << 4;

	if (six_byte) {
		output_len--;
		rbuf[0] = output_len;
		if (minlen > 2)
			rbuf[2] |= dpofua;
		if (ebd) {
			if (minlen > 3)
				rbuf[3] = sizeof(sat_blk_desc);
@@ -1786,6 +1802,8 @@ unsigned int ata_scsiop_mode_sense(struct ata_scsi_args *args, u8 *rbuf,
		rbuf[0] = output_len >> 8;
		if (minlen > 1)
			rbuf[1] = output_len;
		if (minlen > 3)
			rbuf[3] |= dpofua;
		if (ebd) {
			if (minlen > 7)
				rbuf[7] = sizeof(sat_blk_desc);
@@ -2446,7 +2464,7 @@ int ata_scsi_queuecmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
		if (xlat_func)
			ata_scsi_translate(ap, dev, cmd, done, xlat_func);
		else
			ata_scsi_simulate(dev->id, cmd, done);
			ata_scsi_simulate(ap, dev, cmd, done);
	} else
		ata_scsi_translate(ap, dev, cmd, done, atapi_xlat);

@@ -2469,14 +2487,16 @@ out_unlock:
 *	spin_lock_irqsave(host_set lock)
 */

void ata_scsi_simulate(u16 *id,
void ata_scsi_simulate(struct ata_port *ap, struct ata_device *dev,
		      struct scsi_cmnd *cmd,
		      void (*done)(struct scsi_cmnd *))
{
	struct ata_scsi_args args;
	const u8 *scsicmd = cmd->cmnd;

	args.id = id;
	args.ap = ap;
	args.dev = dev;
	args.id = dev->id;
	args.cmd = cmd;
	args.done = done;

+3 −1
Original line number Diff line number Diff line
@@ -32,6 +32,8 @@
#define DRV_VERSION	"1.20"	/* must be exactly four chars */

struct ata_scsi_args {
	struct ata_port		*ap;
	struct ata_device	*dev;
	u16			*id;
	struct scsi_cmnd	*cmd;
	void			(*done)(struct scsi_cmnd *);
@@ -41,7 +43,7 @@ struct ata_scsi_args {
extern int atapi_enabled;
extern struct ata_queued_cmd *ata_qc_new_init(struct ata_port *ap,
				      struct ata_device *dev);
extern void ata_rwcmd_protocol(struct ata_queued_cmd *qc);
extern int ata_rwcmd_protocol(struct ata_queued_cmd *qc);
extern void ata_qc_free(struct ata_queued_cmd *qc);
extern int ata_qc_issue(struct ata_queued_cmd *qc);
extern int ata_check_atapi_dma(struct ata_queued_cmd *qc);
+5 −1
Original line number Diff line number Diff line
@@ -129,6 +129,7 @@ enum {
	ATA_CMD_READ_EXT	= 0x25,
	ATA_CMD_WRITE		= 0xCA,
	ATA_CMD_WRITE_EXT	= 0x35,
	ATA_CMD_WRITE_FUA_EXT	= 0x3D,
	ATA_CMD_PIO_READ	= 0x20,
	ATA_CMD_PIO_READ_EXT	= 0x24,
	ATA_CMD_PIO_WRITE	= 0x30,
@@ -137,6 +138,7 @@ enum {
	ATA_CMD_READ_MULTI_EXT	= 0x29,
	ATA_CMD_WRITE_MULTI	= 0xC5,
	ATA_CMD_WRITE_MULTI_EXT	= 0x39,
	ATA_CMD_WRITE_MULTI_FUA_EXT = 0xCE,
	ATA_CMD_SET_FEATURES	= 0xEF,
	ATA_CMD_PACKET		= 0xA0,
	ATA_CMD_VERIFY		= 0x40,
@@ -192,6 +194,7 @@ enum {
	ATA_TFLAG_DEVICE	= (1 << 2), /* enable r/w to device reg */
	ATA_TFLAG_WRITE		= (1 << 3), /* data dir: host->dev==1 (write) */
	ATA_TFLAG_LBA		= (1 << 4), /* enable LBA */
	ATA_TFLAG_FUA		= (1 << 5), /* enable FUA */
};

enum ata_tf_protocols {
@@ -245,6 +248,7 @@ struct ata_taskfile {
#define ata_id_is_sata(id)	((id)[93] == 0)
#define ata_id_rahead_enabled(id) ((id)[85] & (1 << 6))
#define ata_id_wcache_enabled(id) ((id)[85] & (1 << 5))
#define ata_id_has_fua(id)	((id)[84] & (1 << 6))
#define ata_id_has_flush(id)	((id)[83] & (1 << 12))
#define ata_id_has_flush_ext(id) ((id)[83] & (1 << 13))
#define ata_id_has_lba48(id)	((id)[83] & (1 << 10))
+2 −1
Original line number Diff line number Diff line
@@ -480,7 +480,8 @@ extern u8 ata_bmdma_status(struct ata_port *ap);
extern void ata_bmdma_irq_clear(struct ata_port *ap);
extern void ata_qc_complete(struct ata_queued_cmd *qc);
extern void ata_eng_timeout(struct ata_port *ap);
extern void ata_scsi_simulate(u16 *id, struct scsi_cmnd *cmd,
extern void ata_scsi_simulate(struct ata_port *ap, struct ata_device *dev,
			      struct scsi_cmnd *cmd,
			      void (*done)(struct scsi_cmnd *));
extern int ata_std_bios_param(struct scsi_device *sdev,
			      struct block_device *bdev,