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

Commit c19f8366 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
* 'upstream-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jgarzik/libata-dev:
  ata: Report 16/32bit PIO as best we can
  libata: use ATA_ID_CFA_*
  pata_legacy: fix no device fail path
  pata_hpt37x: fix HPT370 DMA timeouts
  libata: handle SEMB signature better
parents 05fa199d e3cf95dd
Loading
Loading
Loading
Loading
+20 −5
Original line number Diff line number Diff line
@@ -1231,6 +1231,9 @@ unsigned int ata_dev_classify(const struct ata_taskfile *tf)
	 *
	 * We follow the current spec and consider that 0x69/0x96
	 * identifies a port multiplier and 0x3c/0xc3 a SEMB device.
	 * Unfortunately, WDC WD1600JS-62MHB5 (a hard drive) reports
	 * SEMB signature.  This is worked around in
	 * ata_dev_read_id().
	 */
	if ((tf->lbam == 0) && (tf->lbah == 0)) {
		DPRINTK("found ATA device by sig\n");
@@ -1248,8 +1251,8 @@ unsigned int ata_dev_classify(const struct ata_taskfile *tf)
	}

	if ((tf->lbam == 0x3c) && (tf->lbah == 0xc3)) {
		printk(KERN_INFO "ata: SEMB device ignored\n");
		return ATA_DEV_SEMB_UNSUP; /* not yet */
		DPRINTK("found SEMB device by sig (could be ATA device)\n");
		return ATA_DEV_SEMB;
	}

	DPRINTK("unknown device\n");
@@ -1653,8 +1656,8 @@ unsigned long ata_id_xfermask(const u16 *id)
		/*
		 *	Process compact flash extended modes
		 */
		int pio = id[163] & 0x7;
		int dma = (id[163] >> 3) & 7;
		int pio = (id[ATA_ID_CFA_MODES] >> 0) & 0x7;
		int dma = (id[ATA_ID_CFA_MODES] >> 3) & 0x7;

		if (pio)
			pio_mask |= (1 << 5);
@@ -2080,6 +2083,7 @@ int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class,
	struct ata_taskfile tf;
	unsigned int err_mask = 0;
	const char *reason;
	bool is_semb = class == ATA_DEV_SEMB;
	int may_fallback = 1, tried_spinup = 0;
	int rc;

@@ -2090,6 +2094,8 @@ int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class,
	ata_tf_init(dev, &tf);

	switch (class) {
	case ATA_DEV_SEMB:
		class = ATA_DEV_ATA;	/* some hard drives report SEMB sig */
	case ATA_DEV_ATA:
		tf.command = ATA_CMD_ID_ATA;
		break;
@@ -2126,6 +2132,14 @@ int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class,
			return -ENOENT;
		}

		if (is_semb) {
			ata_dev_printk(dev, KERN_INFO, "IDENTIFY failed on "
				       "device w/ SEMB sig, disabled\n");
			/* SEMB is not supported yet */
			*p_class = ATA_DEV_SEMB_UNSUP;
			return 0;
		}

		if ((err_mask == AC_ERR_DEV) && (tf.feature & ATA_ABORTED)) {
			/* Device or controller might have reported
			 * the wrong device class.  Give a shot at the
@@ -2412,7 +2426,8 @@ int ata_dev_configure(struct ata_device *dev)
	/* ATA-specific feature tests */
	if (dev->class == ATA_DEV_ATA) {
		if (ata_id_is_cfa(id)) {
			if (id[162] & 1) /* CPRM may make this media unusable */
			/* CPRM may make this media unusable */
			if (id[ATA_ID_CFA_KEY_MGMT] & 1)
				ata_dev_printk(dev, KERN_WARNING,
					       "supports DRM functions and may "
					       "not be fully accessable.\n");
+26 −4
Original line number Diff line number Diff line
@@ -647,23 +647,45 @@ int ata_task_ioctl(struct scsi_device *scsidev, void __user *arg)
	return rc;
}

static int ata_ioc32(struct ata_port *ap)
{
	if (ap->flags & ATA_FLAG_PIO_DMA)
		return 1;
	if (ap->pflags & ATA_PFLAG_PIO32)
		return 1;
	return 0;
}

int ata_sas_scsi_ioctl(struct ata_port *ap, struct scsi_device *scsidev,
		     int cmd, void __user *arg)
{
	int val = -EINVAL, rc = -EINVAL;
	unsigned long flags;

	switch (cmd) {
	case ATA_IOC_GET_IO32:
		val = 0;
		spin_lock_irqsave(ap->lock, flags);
		val = ata_ioc32(ap);
		spin_unlock_irqrestore(ap->lock, flags);
		if (copy_to_user(arg, &val, 1))
			return -EFAULT;
		return 0;

	case ATA_IOC_SET_IO32:
		val = (unsigned long) arg;
		if (val != 0)
			return -EINVAL;
		return 0;
		rc = 0;
		spin_lock_irqsave(ap->lock, flags);
		if (ap->pflags & ATA_PFLAG_PIO32CHANGE) {
			if (val)
				ap->pflags |= ATA_PFLAG_PIO32;
			else
				ap->pflags &= ~ATA_PFLAG_PIO32;
		} else {
			if (val != ata_ioc32(ap))
				rc = -EINVAL;
		}
		spin_unlock_irqrestore(ap->lock, flags);
		return rc;

	case HDIO_GET_IDENTITY:
		return ata_get_identity(ap, scsidev, arg);
+27 −0
Original line number Diff line number Diff line
@@ -87,6 +87,7 @@ const struct ata_port_operations ata_bmdma32_port_ops = {
	.inherits		= &ata_bmdma_port_ops,

	.sff_data_xfer		= ata_sff_data_xfer32,
	.port_start		= ata_sff_port_start32,
};
EXPORT_SYMBOL_GPL(ata_bmdma32_port_ops);

@@ -770,6 +771,9 @@ unsigned int ata_sff_data_xfer32(struct ata_device *dev, unsigned char *buf,
	unsigned int words = buflen >> 2;
	int slop = buflen & 3;
	
	if (!(ap->pflags & ATA_PFLAG_PIO32))
		return ata_sff_data_xfer(dev, buf, buflen, rw);

	/* Transfer multiple of 4 bytes */
	if (rw == READ)
		ioread32_rep(data_addr, buf, words);
@@ -2401,6 +2405,29 @@ int ata_sff_port_start(struct ata_port *ap)
}
EXPORT_SYMBOL_GPL(ata_sff_port_start);

/**
 *	ata_sff_port_start32 - Set port up for dma.
 *	@ap: Port to initialize
 *
 *	Called just after data structures for each port are
 *	initialized.  Allocates space for PRD table if the device
 *	is DMA capable SFF.
 *
 *	May be used as the port_start() entry in ata_port_operations for
 *	devices that are capable of 32bit PIO.
 *
 *	LOCKING:
 *	Inherited from caller.
 */
int ata_sff_port_start32(struct ata_port *ap)
{
	ap->pflags |= ATA_PFLAG_PIO32 | ATA_PFLAG_PIO32CHANGE;
	if (ap->ioaddr.bmdma_addr)
		return ata_port_start(ap);
	return 0;
}
EXPORT_SYMBOL_GPL(ata_sff_port_start32);

/**
 *	ata_sff_std_ports - initialize ioaddr with standard port offsets.
 *	@ioaddr: IO address structure to be initialized
+2 −20
Original line number Diff line number Diff line
@@ -8,7 +8,7 @@
 * Copyright (C) 1999-2003		Andre Hedrick <andre@linux-ide.org>
 * Portions Copyright (C) 2001	        Sun Microsystems, Inc.
 * Portions Copyright (C) 2003		Red Hat Inc
 * Portions Copyright (C) 2005-2007	MontaVista Software, Inc.
 * Portions Copyright (C) 2005-2009	MontaVista Software, Inc.
 *
 * TODO
 *	Look into engine reset on timeout errors. Should not be	required.
@@ -24,7 +24,7 @@
#include <linux/libata.h>

#define DRV_NAME	"pata_hpt37x"
#define DRV_VERSION	"0.6.11"
#define DRV_VERSION	"0.6.12"

struct hpt_clock {
	u8	xfer_speed;
@@ -444,23 +444,6 @@ static void hpt370_set_dmamode(struct ata_port *ap, struct ata_device *adev)
	pci_write_config_dword(pdev, addr1, reg | mode);
}

/**
 *	hpt370_bmdma_start		-	DMA engine begin
 *	@qc: ATA command
 *
 *	The 370 and 370A want us to reset the DMA engine each time we
 *	use it. The 372 and later are fine.
 */

static void hpt370_bmdma_start(struct ata_queued_cmd *qc)
{
	struct ata_port *ap = qc->ap;
	struct pci_dev *pdev = to_pci_dev(ap->host->dev);
	pci_write_config_byte(pdev, 0x50 + 4 * ap->port_no, 0x37);
	udelay(10);
	ata_bmdma_start(qc);
}

/**
 *	hpt370_bmdma_end		-	DMA engine stop
 *	@qc: ATA command
@@ -598,7 +581,6 @@ static struct scsi_host_template hpt37x_sht = {
static struct ata_port_operations hpt370_port_ops = {
	.inherits	= &ata_bmdma_port_ops,

	.bmdma_start 	= hpt370_bmdma_start,
	.bmdma_stop	= hpt370_bmdma_stop,

	.mode_filter	= hpt370_filter,
+21 −13
Original line number Diff line number Diff line
@@ -108,6 +108,7 @@ struct legacy_controller {
	struct ata_port_operations *ops;
	unsigned int pio_mask;
	unsigned int flags;
	unsigned int pflags;
	int (*setup)(struct platform_device *, struct legacy_probe *probe,
		struct legacy_data *data);
};
@@ -285,7 +286,8 @@ static unsigned int pdc_data_xfer_vlb(struct ata_device *dev,
{
	int slop = buflen & 3;
	/* 32bit I/O capable *and* we need to write a whole number of dwords */
	if (ata_id_has_dword_io(dev->id) && (slop == 0 || slop == 3)) {
	if (ata_id_has_dword_io(dev->id) && (slop == 0 || slop == 3)
					&& (ap->pflags & ATA_PFLAG_PIO32)) {
		struct ata_port *ap = dev->link->ap;
		unsigned long flags;

@@ -736,7 +738,8 @@ static unsigned int vlb32_data_xfer(struct ata_device *adev, unsigned char *buf,
	struct ata_port *ap = adev->link->ap;
	int slop = buflen & 3;

	if (ata_id_has_dword_io(adev->id) && (slop == 0 || slop == 3)) {
	if (ata_id_has_dword_io(adev->id) && (slop == 0 || slop == 3)
					&& (ap->pflags & ATA_PFLAG_PIO32)) {
		if (rw == WRITE)
			iowrite32_rep(ap->ioaddr.data_addr, buf, buflen >> 2);
		else
@@ -858,27 +861,30 @@ static struct ata_port_operations winbond_port_ops = {

static struct legacy_controller controllers[] = {
	{"BIOS",	&legacy_port_ops, 	0x1F,
						ATA_FLAG_NO_IORDY,	NULL },
			ATA_FLAG_NO_IORDY,	0,			NULL },
	{"Snooping", 	&simple_port_ops, 	0x1F,
						0	       ,	NULL },
			0,			0,			NULL },
	{"PDC20230",	&pdc20230_port_ops,	0x7,
						ATA_FLAG_NO_IORDY,	NULL },
			ATA_FLAG_NO_IORDY,
			ATA_PFLAG_PIO32 | ATA_PFLAG_PIO32_CHANGE,	NULL },
	{"HT6560A",	&ht6560a_port_ops,	0x07,
						ATA_FLAG_NO_IORDY,	NULL },
			ATA_FLAG_NO_IORDY,	0,			NULL },
	{"HT6560B",	&ht6560b_port_ops,	0x1F,
						ATA_FLAG_NO_IORDY,	NULL },
			ATA_FLAG_NO_IORDY,	0,			NULL },
	{"OPTI82C611A",	&opti82c611a_port_ops,	0x0F,
						0	       ,	NULL },
			0,			0,			NULL },
	{"OPTI82C46X",	&opti82c46x_port_ops,	0x0F,
						0	       ,	NULL },
			0,			0,			NULL },
	{"QDI6500",	&qdi6500_port_ops,	0x07,
					ATA_FLAG_NO_IORDY,	qdi_port },
			ATA_FLAG_NO_IORDY,
			ATA_PFLAG_PIO32 | ATA_PFLAG_PIO32_CHANGE,    qdi_port },
	{"QDI6580",	&qdi6580_port_ops,	0x1F,
					0	       ,	qdi_port },
			0, ATA_PFLAG_PIO32 | ATA_PFLAG_PIO32_CHANGE, qdi_port },
	{"QDI6580DP",	&qdi6580dp_port_ops,	0x1F,
					0	       ,	qdi_port },
			0, ATA_PFLAG_PIO32 | ATA_PFLAG_PIO32_CHANGE, qdi_port },
	{"W83759A",	&winbond_port_ops,	0x1F,
					0	       ,	winbond_port }
			0, ATA_PFLAG_PIO32 | ATA_PFLAG_PIO32_CHANGE,
								winbond_port }
};

/**
@@ -1008,6 +1014,7 @@ static __init int legacy_init_one(struct legacy_probe *probe)
	ap->ops = ops;
	ap->pio_mask = pio_modes;
	ap->flags |= ATA_FLAG_SLAVE_POSS | iordy;
	ap->pflags |= controller->pflags;
	ap->ioaddr.cmd_addr = io_addr;
	ap->ioaddr.altstatus_addr = ctrl_addr;
	ap->ioaddr.ctl_addr = ctrl_addr;
@@ -1032,6 +1039,7 @@ static __init int legacy_init_one(struct legacy_probe *probe)
			return 0;
		}
	}
	ata_host_detach(host);
fail:
	platform_device_unregister(pdev);
	return ret;
Loading