From: Tejun Heo <htejun@gmail.com>
To: jgarzik@pobox.com, alan@lxorguk.ukuu.org.uk, mlord@pobox.com,
albertcc@tw.ibm.com, uchang@tw.ibm.com, forrest.zhao@intel.com,
brking@us.ibm.com, linux-ide@vger.kernel.org
Cc: Tejun Heo <htejun@gmail.com>
Subject: [PATCH 6/20] libata: implement legacy ATA init helpers
Date: Sat, 19 Aug 2006 17:59:31 +0900 [thread overview]
Message-ID: <1155977971677-git-send-email-htejun@gmail.com> (raw)
In-Reply-To: <11559778241753-git-send-email-htejun@gmail.com>
Implement the following legacy ATA init helpers.
* ata_legacy_acquire_resources() : acquire legacy ATA resources
* ata_legacy_release_resources() : release legacy ATA resources
* ata_legacy_init_ports() : init legacy port addresses
* ata_legacy_request_irqs() : request legacy ATA IRQs
* ata_legacy_free_irqs() : free legacy ATA IRQs
These helpers can be used independently or called implictly from other
bus helpers which has support for legacy ATA device for compatibility
(e.g. PCI).
Signed-off-by: Tejun Heo <htejun@gmail.com>
---
drivers/ata/Kconfig | 5 +
drivers/ata/Makefile | 3 +
drivers/ata/libata-legacy.c | 241 +++++++++++++++++++++++++++++++++++++++++++
drivers/ata/libata.h | 11 ++
include/linux/libata.h | 15 ++-
5 files changed, 273 insertions(+), 2 deletions(-)
diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig
index 2109d75..1a98559 100644
--- a/drivers/ata/Kconfig
+++ b/drivers/ata/Kconfig
@@ -15,6 +15,11 @@ config ATA
that "speaks" the ATA protocol, also called ATA controller),
because you will be asked for it.
+config ATA_LEGACY
+ bool
+ depends on ATA
+ default n
+
config SATA_AHCI
tristate "AHCI SATA support"
depends on ATA && PCI
diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile
index c17ae9c..61d3e76 100644
--- a/drivers/ata/Makefile
+++ b/drivers/ata/Makefile
@@ -19,3 +19,6 @@ obj-$(CONFIG_PDC_ADMA) += pdc_adma.o
libata-objs := libata-core.o libata-scsi.o libata-bmdma.o libata-eh.o
+ifeq ($(CONFIG_ATA_LEGACY),y)
+libata-objs += libata-legacy.o
+endif
diff --git a/drivers/ata/libata-legacy.c b/drivers/ata/libata-legacy.c
new file mode 100644
index 0000000..00b70b0
--- /dev/null
+++ b/drivers/ata/libata-legacy.c
@@ -0,0 +1,241 @@
+/*
+ * libata-legacy.c - helper library for legacy ATA
+ *
+ * Maintained by: Jeff Garzik <jgarzik@pobox.com>
+ * Please ALWAYS copy linux-ide@vger.kernel.org
+ * on emails.
+ *
+ * Copyright 2006 Tejun Heo <htejun@gmail.com>
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139,
+ * USA.
+ *
+ *
+ * libata documentation is available via 'make {ps|pdf}docs',
+ * as Documentation/DocBook/libata.*
+ *
+ * Hardware documentation available from http://www.t13.org/ and
+ * http://www.sata-io.org/
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/libata.h>
+
+#include "libata.h"
+
+static unsigned long ata_legacy_addr(int port, int sel)
+{
+ if (port == 0) {
+ if (sel == 0)
+ return ATA_PRIMARY_CMD;
+ else
+ return ATA_PRIMARY_CTL;
+ } else {
+ if (sel == 0)
+ return ATA_SECONDARY_CMD;
+ else
+ return ATA_SECONDARY_CTL;
+ }
+}
+
+static int ata_legacy_acquire_port(struct ata_port *ap)
+{
+ struct ata_host *host = ap->host;
+ unsigned long cmd_addr = ata_legacy_addr(ap->port_no, 0);
+
+ if (request_region(cmd_addr, 8, "libata") != NULL)
+ host->legacy_flags |= ATA_LEGACY_RES_PRI << ap->port_no;
+ else {
+ struct resource *conflict, res;
+
+ res.start = cmd_addr;
+ res.end = cmd_addr + 8 - 1;
+ conflict = ____request_resource(&ioport_resource, &res);
+
+ if (strcmp(conflict->name, "libata")) {
+ printk(KERN_WARNING "ata: 0x%0lX IDE port busy\n",
+ cmd_addr);
+ host->flags |= ATA_HOST_DEV_BUSY;
+ return -EBUSY;
+ }
+ printk("ata: 0x%0lX IDE port preallocated\n", cmd_addr);
+ }
+
+ return 0;
+}
+
+/**
+ * ata_legacy_acquire_resources - acquire legacy ATA resources
+ * @host: target ATA host
+ * @p_reason: out arg for error message (can be NULL)
+ *
+ * Acquire legacy ATA resources for ports specified by
+ * ATA_PORT_PRIMARY/SECONDARY mask in host->legacy_flags. If the
+ * port is busy, this function makes the port dummy instead of
+ * failing. This is to allow legacy ports to be driven by other
+ * drivers.
+ *
+ * LOCKING:
+ * Inherited from calling layer (may sleep).
+ *
+ * RETURNS:
+ * 0 on success, -errno otherwise.
+ */
+int ata_legacy_acquire_resources(struct ata_host *host, const char **p_reason)
+{
+ int i;
+
+ for (i = 0; i < 2; i++) {
+ if (!(host->legacy_flags & (ATA_PORT_PRIMARY << i)))
+ continue;
+ BUG_ON(i >= host->n_ports);
+
+ if (ata_legacy_acquire_port(host->ports[i]))
+ host->ports[i]->ops = &ata_dummy_port_ops;
+ }
+
+ return 0;
+}
+
+/**
+ * ata_legacy_release_resources - release legacy ATA resources
+ * @host: target ATA host
+ *
+ * Free all legacy ATA resources @host is holding.
+ *
+ * LOCKING:
+ * Inherited from calling layer (may sleep).
+ */
+void ata_legacy_release_resources(struct ata_host *host)
+{
+ int i;
+
+ for (i = 0; i < 2; i++) {
+ if (host->legacy_flags & (ATA_LEGACY_RES_PRI << i)) {
+ release_region(ata_legacy_addr(i, 0), 8);
+ host->legacy_flags &= ~(ATA_LEGACY_RES_PRI << i);
+ }
+ }
+}
+
+/**
+ * ata_legacy_init_ports - initialize legacy ATA port addresses
+ * @host: target ATA host
+ *
+ * Initialize legacy ATA port addresses for non-dummy legacy
+ * ports in @host.
+ *
+ * LOCKING:
+ * Inherited from calling layer.
+ */
+void ata_legacy_init_ports(struct ata_host *host)
+{
+ int i;
+
+ for (i = 0; i < 2; i++) {
+ struct ata_port *ap = host->ports[i];
+
+ if (host->legacy_flags & (ATA_PORT_PRIMARY << i) &&
+ !ata_port_is_dummy(ap)) {
+ struct ata_ioports *ioaddr = &ap->ioaddr;
+ unsigned long cmd_addr = ata_legacy_addr(i, 0);
+ unsigned long ctl_addr = ata_legacy_addr(i, 1);
+
+ ioaddr->cmd_addr = cmd_addr;
+ ioaddr->altstatus_addr = ctl_addr;
+ ioaddr->ctl_addr = ctl_addr;
+ ata_std_ports(ioaddr);
+ }
+ }
+}
+
+/**
+ * ata_legacy_request_irqs - request legacy ATA IRQs
+ * @host: target ATA host
+ * @handler: array of IRQ handlers
+ * @irq_flags: array of IRQ flags
+ * @dev_id: array of IRQ dev_ids
+ * @p_reason: out arg for error message (can be NULL)
+ *
+ * Request legacy IRQs for non-dummy legacy ports in @host. All
+ * IRQ parameters are passed as array to allow ports to have
+ * separate IRQ handlers.
+ *
+ * LOCKING:
+ * Inherited from calling layer (may sleep).
+ *
+ * RETURNS:
+ * 0 on success, -errno otherwise.
+ */
+int ata_legacy_request_irqs(struct ata_host *host,
+ irqreturn_t (* const * handler)(int, void *, struct pt_regs *),
+ const unsigned int *irq_flags, void * const *dev_id,
+ const char **p_reason)
+{
+ const unsigned int legacy_irq[] = { 14, 15 };
+ const char *reason;
+ int i, rc;
+
+ for (i = 0; i < 2; i++) {
+ struct ata_port *ap = host->ports[i];
+ unsigned int irq = legacy_irq[i];
+
+ if (!(host->legacy_flags & (ATA_PORT_PRIMARY << i)) ||
+ ata_port_is_dummy(ap))
+ continue;
+
+ if (!handler[i]) {
+ reason = "NULL handler";
+ rc = -EINVAL;
+ goto err;
+ }
+
+ rc = ata_host_request_irq_marker(host, irq,
+ handler[i], irq_flags[i], dev_id[i],
+ ata_legacy_request_irqs, &reason);
+ if (rc)
+ goto err;
+
+ /* only for info printing */
+ if (i == 0)
+ host->irq = irq;
+ else
+ host->irq2 = irq;
+ }
+
+ return 0;
+
+ err:
+ ata_legacy_free_irqs(host);
+ if (p_reason)
+ *p_reason = reason;
+ return rc;
+}
+
+/**
+ * ata_legacy_free_irqs - free legacy ATA IRQs
+ * @host: target ATA host
+ *
+ * Free all legacy ATA IRQs of @host.
+ *
+ * LOCKING:
+ * Inherited from calling layer (may sleep).
+ */
+void ata_legacy_free_irqs(struct ata_host *host)
+{
+ ata_host_free_irqs_marker(host, ata_legacy_request_irqs);
+}
diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h
index 1d24254..0601c4a 100644
--- a/drivers/ata/libata.h
+++ b/drivers/ata/libata.h
@@ -117,6 +117,17 @@ extern void ata_schedule_scsi_eh(struct
extern void ata_scsi_dev_rescan(void *data);
extern int ata_bus_probe(struct ata_port *ap);
+/* libata-legacy.c */
+extern int ata_legacy_acquire_resources(struct ata_host *host,
+ const char **p_reason);
+extern void ata_legacy_release_resources(struct ata_host *host);
+extern void ata_legacy_init_ports(struct ata_host *host);
+extern int ata_legacy_request_irqs(struct ata_host *host,
+ irqreturn_t (* const * handler)(int, void *, struct pt_regs *),
+ const unsigned int *irq_flags, void * const *dev_id,
+ const char **p_reason);
+extern void ata_legacy_free_irqs(struct ata_host *host);
+
/* libata-eh.c */
extern enum scsi_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd);
extern void ata_scsi_error(struct Scsi_Host *host);
diff --git a/include/linux/libata.h b/include/linux/libata.h
index b050517..9535f54 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -200,8 +200,16 @@ enum {
ATA_QCFLAG_EH_SCHEDULED = (1 << 18), /* EH scheduled (obsolete) */
/* host set flags */
- ATA_HOST_SIMPLEX = (1 << 0), /* Host is simplex, one DMA channel per host only */
-
+ ATA_HOST_SIMPLEX = (1 << 0), /* host is simplex, one DMA channel per host only */
+ ATA_HOST_DEV_BUSY = (1 << 1), /* host device was busy on init */
+
+ /* legacy flags */
+ /* BIT 0 and 1 are reserved for ATA_PORT_PRIMARY and SECONDARY */
+ ATA_LEGACY_MASK = (1 << 0) | (1 << 1),
+
+ ATA_LEGACY_RES_PRI = (1 << 8),
+ ATA_LEGACY_RES_SEC = (1 << 9),
+
/* various lengths of time */
ATA_TMOUT_BOOT = 30 * HZ, /* heuristic */
ATA_TMOUT_BOOT_QUICK = 7 * HZ, /* heuristic */
@@ -376,8 +384,11 @@ struct ata_host {
void *private_data;
const struct ata_port_operations *ops;
unsigned long flags;
+
int simplex_claimed; /* Keep seperate in case we
ever need to do this locked */
+ unsigned int legacy_flags;
+
struct list_head irq_list; /* list of acquired irqs */
struct ata_port *ports[0];
};
--
1.4.1.1
next prev parent reply other threads:[~2006-08-19 9:27 UTC|newest]
Thread overview: 50+ messages / expand[flat|nested] mbox.gz Atom feed top
2006-08-19 8:57 [PATCHSET] libata: implement new initialization model w/ iomap support, take 2 Tejun Heo
2006-08-19 8:59 ` [PATCH 2/20] libata: implement ata_host_start/stop() Tejun Heo
2006-08-19 8:59 ` [PATCH 1/20] libata: kill ata_host_stop() Tejun Heo
2006-08-19 14:51 ` Jeff Garzik
2006-08-19 15:29 ` Tejun Heo
2006-09-19 4:46 ` Jeff Garzik
2006-09-19 4:50 ` Tejun Heo
2006-08-19 8:59 ` [PATCH 3/20] libata: implement ata_host_detach() and ata_host_free() Tejun Heo
2006-09-19 4:59 ` Jeff Garzik
2006-08-19 8:59 ` [PATCH 5/20] libata: implement several LLD init helpers Tejun Heo
2006-08-22 22:11 ` Brian King
2006-08-27 9:52 ` Tejun Heo
2006-08-30 21:16 ` Brian King
2006-09-19 5:16 ` Jeff Garzik
2006-09-19 5:57 ` Tejun Heo
2006-08-19 8:59 ` [PATCH 4/20] libata: separate out ata_host_alloc() and ata_host_attach() Tejun Heo
2006-09-19 5:08 ` Jeff Garzik
2006-09-19 5:48 ` Tejun Heo
2006-08-19 8:59 ` Tejun Heo [this message]
2006-09-19 5:26 ` [PATCH 6/20] libata: implement legacy ATA init helpers Jeff Garzik
2006-08-19 8:59 ` [PATCH 7/20] libata: implement PCI " Tejun Heo
2006-09-19 5:29 ` Jeff Garzik
2006-08-19 8:59 ` [PATCH 8/20] libata: reimplement ata_pci_init_one() using new " Tejun Heo
2006-09-19 5:32 ` Jeff Garzik
2006-09-19 6:04 ` Tejun Heo
2006-09-19 6:09 ` Jeff Garzik
2006-08-19 8:59 ` [PATCH 10/20] libata: reimplement ata_pci_remove_one() using new PCI " Tejun Heo
2006-08-19 8:59 ` [PATCH 12/20] libata: kill old " Tejun Heo
2006-08-19 8:59 ` [PATCH 13/20] libata: kill unused ->host_stop() operation and related functions Tejun Heo
2006-09-19 5:42 ` Jeff Garzik
2006-08-19 8:59 ` [PATCH 11/20] libata: use remove_one() for deinit instead of ->host_stop() Tejun Heo
2006-09-19 5:42 ` Jeff Garzik
2006-08-19 8:59 ` [PATCH 19/20] libata: kill unused ATA_FLAG_MMIO Tejun Heo
2006-08-19 8:59 ` [PATCH 17/20] libata: make ata_pci_acquire_resources() handle iomap Tejun Heo
2006-09-19 5:47 ` Jeff Garzik
2006-09-19 6:27 ` Tejun Heo
2006-09-19 6:32 ` Jeff Garzik
2006-08-19 8:59 ` [PATCH 14/20] libata: use LLD name where possible Tejun Heo
2006-09-19 5:43 ` Jeff Garzik
2006-08-19 8:59 ` [PATCH 16/20] libata: make ata_host_alloc() take care of hpriv alloc/free Tejun Heo
2006-09-19 5:45 ` Jeff Garzik
2006-08-19 8:59 ` [PATCH 15/20] libata: move ->irq_handler from port_ops to port_info Tejun Heo
2006-09-19 5:43 ` Jeff Garzik
2006-08-19 8:59 ` [PATCH 20/20] libata: move scattered PCI ATA functions into liata-pci.c Tejun Heo
2006-09-19 5:50 ` Jeff Garzik
2006-08-22 22:10 ` [PATCHSET] libata: implement new initialization model w/ iomap support, take 2 Brian King
2006-08-27 10:12 ` Tejun Heo
2006-08-30 20:58 ` Brian King
2006-09-01 13:45 ` Tejun Heo
2006-09-07 13:22 ` Brian King
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1155977971677-git-send-email-htejun@gmail.com \
--to=htejun@gmail.com \
--cc=alan@lxorguk.ukuu.org.uk \
--cc=albertcc@tw.ibm.com \
--cc=brking@us.ibm.com \
--cc=forrest.zhao@intel.com \
--cc=jgarzik@pobox.com \
--cc=linux-ide@vger.kernel.org \
--cc=mlord@pobox.com \
--cc=uchang@tw.ibm.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.