/*
* libata-pmp.c - libata port multiplier support
*
* Copyright (c) 2007 SUSE Linux Products GmbH
* Copyright (c) 2007 Tejun Heo <teheo@suse.de>
*
* This file is released under the GPLv2.
*/
#include <linux/kernel.h>
#include <linux/libata.h>
#include "libata.h"
/**
* sata_pmp_read - read PMP register
* @link: link to read PMP register for
* @reg: register to read
* @r_val: resulting value
*
* Wrapper around ap->ops->pmp_read to make it easier to call and
* nomarlize error return value.
*
* LOCKING:
* Kernel thread context (may sleep).
*
* RETURNS:
* 0 on success, -errno on failure.
*/
static int sata_pmp_read(struct ata_link *link, int reg, u32 *r_val)
{
struct ata_port *ap = link->ap;
struct ata_device *pmp_dev = ap->link.device;
int rc;
might_sleep();
rc = ap->ops->pmp_read(pmp_dev, link->pmp, reg, r_val);
if (rc)
rc = -EIO;
return rc;
}
/**
* sata_pmp_write - write PMP register
* @link: link to write PMP register for
* @reg: register to write
* @r_val: value to write
*
* Wrapper around ap->ops->pmp_write to make it easier to call
* and nomarlize error return value.
*
* LOCKING:
* Kernel thread context (may sleep).
*
* RETURNS:
* 0 on success, -errno on failure.
*/
static int sata_pmp_write(struct ata_link *link, int reg, u32 val)
{
struct ata_port *ap = link->ap;
struct ata_device *pmp_dev = ap->link.device;
int rc;
might_sleep();
rc = ap->ops->pmp_write(pmp_dev, link->pmp, reg, val);
if (rc)
rc = -EIO;
return rc;
}
/**
* sata_pmp_read_init_tf - initialize TF for PMP read
* @tf: taskfile to initialize
* @dev: PMP dev
* @pmp: port multiplier port number
* @reg: register to read
*
* Initialize @tf for PMP read command.
*
* LOCKING:
* None.
*/
void sata_pmp_read_init_tf(struct ata_taskfile *tf,
struct ata_device *dev, int pmp, int reg)
{
ata_tf_init(dev, tf);
tf->command = ATA_CMD_PMP_READ;
tf->protocol = ATA_PROT_NODATA;
tf->flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
tf->feature = reg;
tf->device = pmp;
}
/**
* sata_pmp_read_val - extract PMP read result from TF
* @tf: target TF
*
* Determine PMP read result from @tf.
*
* LOCKING:
* None.
*/
u32 sata_pmp_read_val(const struct ata_taskfile *tf)
{
return tf->nsect | tf->lbal << 8 | tf->lbam << 16 | tf->lbah << 24;
}
/**
* sata_pmp_read_init_tf - initialize TF for PMP write
* @tf: taskfile to initialize
* @dev: PMP dev
* @pmp: port multiplier port number
* @reg: register to read
* @val: value to write
*
* Initialize @tf for PMP write command.
*
* LOCKING:
* None.
*/
void sata_pmp_write_init_tf(struct ata_taskfile *tf,
struct ata_device *dev, int pmp, int reg, u32 val)
{
ata_tf_init(dev, tf);
tf->command = ATA_CMD_PMP_WRITE;
tf->protocol = ATA_PROT_NODATA;
tf->flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
tf->feature = reg;
tf->device = pmp;
tf->nsect = val & 0xff;
tf->lbal = (val >> 8) & 0xff;
tf->lbam = (val >><