From: Kristen Carlson Accardi <kristen.c.accardi@intel.com>
To: Kristen Carlson Accardi <kristen.c.accardi@intel.com>
Cc: jeff@garzik.org, akpm@linux-foundation.org,
linux-ide@vger.kernel.org, linux-kernel@vger.kernel.org
Subject: Re: [patch] ata: ahci: Enclosure Management via LED
Date: Thu, 29 Nov 2007 10:43:07 -0800 [thread overview]
Message-ID: <20071129104307.4966efc2@appleyard> (raw)
In-Reply-To: <20071129094802.49e729ed@appleyard>
On Thu, 29 Nov 2007 09:48:02 -0800
Kristen Carlson Accardi <kristen.c.accardi@intel.com> wrote:
> This patch implements Enclosure Management via the LED protocol. See
> the AHCI 1.1 spec for details.
Whoops, I totally messed up and sent the wrong version of this patch.
I'll send an updated one, ignore this.
Kristen
>
> Signed-off-by: Kristen Carlson Accardi <kristen.c.accardi@intel.com>
> ---
> Here's a new version of the Enclosure management patch I sent a few
> weeks ago. I tried to incorporate all the feedback, although I'm
> still checking on whether it's ok to use these capability bits on
> a 1.0 ahci device. Please let me know if there are additional
> changes needed.
>
> drivers/ata/ahci.c | 152
> ++++++++++++++++++++++++++++++++++++++++++++-
> drivers/ata/libata-scsi.c | 5 +- include/linux/libata.h | 2 +
> 3 files changed, 155 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
> index 2c686b4..5f22132 100644
> --- a/drivers/ata/ahci.c
> +++ b/drivers/ata/ahci.c
> @@ -44,6 +44,7 @@
> #include <linux/dmi.h>
> #include <scsi/scsi_host.h>
> #include <scsi/scsi_cmnd.h>
> +#include <scsi/scsi_device.h>
> #include <linux/libata.h>
>
> #define DRV_NAME "ahci"
> @@ -92,6 +93,8 @@ enum {
> HOST_IRQ_STAT = 0x08, /* interrupt status */
> HOST_PORTS_IMPL = 0x0c, /* bitmap of
> implemented ports */ HOST_VERSION = 0x10, /* AHCI
> spec. version compliancy */
> + HOST_EM_LOC = 0x1c, /* Enclosure Management
> location */
> + HOST_EM_CTL = 0x20, /* Enclosure Management
> Control */
> /* HOST_CTL bits */
> HOST_RESET = (1 << 0), /* reset controller;
> self-clear */ @@ -99,6 +102,7 @@ enum {
> HOST_AHCI_EN = (1 << 31), /* AHCI enabled */
>
> /* HOST_CAP bits */
> + HOST_CAP_EMS = (1 << 6), /* Enclosure
> Management support */ HOST_CAP_SSC = (1 << 14), /*
> Slumber capable */ HOST_CAP_PMP = (1 << 17), /* Port
> Multiplier support */ HOST_CAP_CLO = (1 << 24), /*
> Command List Override support */ @@ -193,6 +197,10 @@ enum {
> ATA_FLAG_ACPI_SATA |
> ATA_FLAG_AN | ATA_FLAG_IPM,
> AHCI_LFLAG_COMMON = ATA_LFLAG_SKIP_D2H_BSY,
> +
> + /* em_ctl bits */
> + EM_CTL_RST = (1 << 9), /* Reset */
> + EM_CTL_TM = (1 << 8), /* Transmit
> Message */ };
>
> struct ahci_cmd_hdr {
> @@ -216,6 +224,7 @@ struct ahci_host_priv {
> u32 port_map; /* port map to
> use */ u32 saved_cap; /* saved initial
> cap */ u32 saved_port_map; /* saved
> initial port_map */
> + u32 em_loc; /* enclosure management
> location */ };
>
> struct ahci_port_priv {
> @@ -231,6 +240,7 @@ struct ahci_port_priv {
> unsigned int ncq_saw_dmas:1;
> unsigned int ncq_saw_sdb:1;
> u32 intr_mask; /* interrupts
> to enable */
> + u16 led_state; /* saved
> current led state */ };
>
> static int ahci_scr_read(struct ata_port *ap, unsigned int sc_reg,
> u32 *val); @@ -572,6 +582,11 @@ static struct pci_driver
> ahci_pci_driver = { #endif
> };
>
> +static int ahci_em_messages = 1;
> +module_param(ahci_em_messages, int, 0444);
> +/* add other LED protocol types when they become supported */
> +MODULE_PARM_DESC(ahci_em_messages,
> + "Set AHCI Enclosure Management Message type (0 = disabled, 1
> = LED");
> static inline int ahci_nr_ports(u32 cap)
> {
> @@ -1082,6 +1097,116 @@ static int ahci_reset_controller(struct
> ata_host *host) return 0;
> }
>
> +/****** LED Enclosure Management routines ********/
> +static int ahci_reset_em(struct ata_host *host)
> +{
> + void __iomem *mmio = host->iomap[AHCI_PCI_BAR];
> + u32 em_ctl;
> +
> + em_ctl = readl(mmio + HOST_EM_CTL);
> + if ((em_ctl & EM_CTL_TM) || (em_ctl & EM_CTL_RST))
> + return -EINVAL;
> +
> + writel(em_ctl | EM_CTL_RST, mmio + HOST_EM_CTL);
> + return 0;
> +}
> +
> +static int ahci_transmit_led_message(struct ata_port *ap, int
> led_num,
> + int state)
> +{
> + struct ahci_host_priv *hpriv = ap->host->private_data;
> + void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR];
> + struct ahci_port_priv *pp = ap->private_data;
> + u32 em_ctl;
> + u32 message[] = {0, 0};
> + unsigned int flags;
> +
> + spin_lock_irqsave(ap->lock, flags);
> +
> + /*
> + * if we are still busy transmitting a previous message,
> + * do not allow
> + */
> + em_ctl = readl(mmio + HOST_EM_CTL);
> + if (em_ctl & EM_CTL_TM) {
> + spin_unlock_irqrestore(ap->lock, flags);
> + return -EINVAL;
> + }
> +
> + /*
> + * create message header - this is all zero except for
> + * the message size, which is 4 bytes.
> + */
> + message[0] |= (4 << 8);
> +
> + pp->led_state &= ~(9 << (3*led_num));
> +
> + /*
> + * create the actual message
> + * XXX will need Port Multiplier support
> + */
> + message[1] = (ap->port_no | (pp->led_state << 16));
> +
> + /* LED bit locations are determined by the led_num */
> + message[1] |= (state << (16 + (3*led_num)));
> +
> + /* write message to EM_LOC */
> + writel(message[0], mmio + hpriv->em_loc);
> + writel(message[1], mmio + hpriv->em_loc+4);
> +
> + /* save off new led state */
> + pp->led_state = ((message[1] >> 16) & 0x00ff);
> +
> + /*
> + * tell hardware to transmit the message
> + */
> + writel(em_ctl | EM_CTL_TM, mmio + HOST_EM_CTL);
> +
> + spin_unlock_irqrestore(ap->lock, flags);
> + return 0;
> +}
> +
> +static ssize_t ahci_led_store(struct device *dev, const char *buf,
> int num) +{
> + struct scsi_device *sdev = to_scsi_device(dev);
> + struct ata_port *ap = ata_shost_to_port(sdev->host);
> + struct ata_device *atadev = ata_scsi_find_dev(ap, sdev);
> + int state;
> + int rc;
> +
> + if (!atadev || !ata_dev_enabled(atadev))
> + return -EINVAL;
> +
> + state = simple_strtoul(buf, NULL, 0);
> + if (state != 0 && state != 1)
> + return -EINVAL;
> +
> + rc = ahci_transmit_led_message(ap, num, state);
> + if (!rc)
> + return count;
> + return rc;
> +}
> +
> +static ssize_t ahci_led_locate_store(struct device *dev,
> + struct device_attribute *attr, const char *buf, size_t count)
> +{
> + ahci_led_store(dev, buf, 1);
> +}
> +static DEVICE_ATTR(locate, S_IWUSR | S_IRUGO, NULL,
> ahci_led_locate_store); +
> +static ssize_t ahci_led_fault_store(struct device *dev,
> + struct device_attribute *attr, const char *buf, size_t count)
> +{
> + ahci_led_store(dev, buf, 2);
> +}
> +static DEVICE_ATTR(fault, S_IWUGO, NULL, ahci_led_fault_store);
> +
> +static struct device_attribute *ahci_em_led_attrs[] = {
> + &dev_attr_locate,
> + &dev_attr_fault,
> + NULL
> +};
> +
> static void ahci_port_init(struct pci_dev *pdev, struct ata_port *ap,
> int port_no, void __iomem *mmio,
> void __iomem *port_mmio)
> @@ -2178,7 +2303,8 @@ static void ahci_print_info(struct ata_host
> *host) dev_printk(KERN_INFO, &pdev->dev,
> "flags: "
> "%s%s%s%s%s%s%s"
> - "%s%s%s%s%s%s%s\n"
> + "%s%s%s%s%s%s%s"
> + "%s\n"
> ,
>
> cap & (1 << 31) ? "64bit " : "",
> @@ -2195,7 +2321,8 @@ static void ahci_print_info(struct ata_host
> *host) cap & (1 << 17) ? "pmp " : "",
> cap & (1 << 15) ? "pio " : "",
> cap & (1 << 14) ? "slum " : "",
> - cap & (1 << 13) ? "part " : ""
> + cap & (1 << 13) ? "part " : "",
> + cap & (1 << 6) ? "ems ": ""
> );
> }
>
> @@ -2331,6 +2458,27 @@ static int ahci_init_one(struct pci_dev *pdev,
> const struct pci_device_id *ent) ahci_init_controller(host);
> ahci_print_info(host);
>
> + if (ahci_em_messages && (hpriv->cap & HOST_CAP_EMS)) {
> + u8 messages;
> + void __iomem *mmio = host->iomap[AHCI_PCI_BAR];
> + u32 em_loc = readl(mmio + HOST_EM_LOC);
> + u32 em_ctl = readl(mmio + HOST_EM_CTL);
> +
> + messages = (em_ctl & 0x000f0000) >> 16;
> +
> + /* we only support LED message type right now */
> + if ((messages & 0x01) && (ahci_em_messages == 1)) {
> + /* store em_loc */
> + hpriv->em_loc = ((em_loc >> 16) * 4);
> +
> + /* reset the LEDs */
> + ahci_reset_em(host);
> +
> + /* modify sht to add led sysfs files */
> + ahci_sht.sdev_attrs = ahci_em_led_attrs;
> + }
> + }
> +
> pci_set_master(pdev);
> return ata_host_activate(host, pdev->irq, ahci_interrupt,
> IRQF_SHARED, &ahci_sht);
> diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c
> index fad236d..a49dc19 100644
> --- a/drivers/ata/libata-scsi.c
> +++ b/drivers/ata/libata-scsi.c
> @@ -55,7 +55,7 @@ typedef unsigned int (*ata_xlat_func_t)(struct
> ata_queued_cmd *qc);
> static struct ata_device *__ata_scsi_find_dev(struct ata_port *ap,
> const struct scsi_device
> *scsidev); -static struct ata_device *ata_scsi_find_dev(struct
> ata_port *ap, +struct ata_device *ata_scsi_find_dev(struct ata_port
> *ap, const struct scsi_device *scsidev);
> static int ata_scsi_user_scan(struct Scsi_Host *shost, unsigned int
> channel, unsigned int id, unsigned int lun);
> @@ -2593,7 +2593,7 @@ static int ata_scsi_dev_enabled(struct
> ata_device *dev)
> * RETURNS:
> * Associated ATA device, or %NULL if not found.
> */
> -static struct ata_device *
> +struct ata_device *
> ata_scsi_find_dev(struct ata_port *ap, const struct scsi_device
> *scsidev) {
> struct ata_device *dev = __ata_scsi_find_dev(ap, scsidev);
> @@ -2603,6 +2603,7 @@ ata_scsi_find_dev(struct ata_port *ap, const
> struct scsi_device *scsidev)
> return dev;
> }
> +EXPORT_SYMBOL_GPL(ata_scsi_find_dev);
>
> /*
> * ata_scsi_map_proto - Map pass-thru protocol value to
> taskfile value. diff --git a/include/linux/libata.h
> b/include/linux/libata.h index ef52a07..1ccbd83 100644
> --- a/include/linux/libata.h
> +++ b/include/linux/libata.h
> @@ -900,6 +900,8 @@ extern int ata_scsi_slave_config(struct
> scsi_device *sdev); extern void ata_scsi_slave_destroy(struct
> scsi_device *sdev); extern int ata_scsi_change_queue_depth(struct
> scsi_device *sdev, int queue_depth);
> +struct ata_device *ata_scsi_find_dev(struct ata_port *ap,
> + const struct scsi_device
> *scsidev); extern struct ata_device *ata_dev_pair(struct ata_device
> *adev); extern int ata_do_set_mode(struct ata_link *link, struct
> ata_device **r_failed_dev); extern u8 ata_irq_on(struct ata_port *ap);
next prev parent reply other threads:[~2007-11-29 18:47 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2007-11-29 17:48 [patch] ata: ahci: Enclosure Management via LED Kristen Carlson Accardi
2007-11-29 18:16 ` Mark Lord
2007-11-29 19:22 ` Kristen Carlson Accardi
2007-11-29 20:04 ` Mark Lord
2007-11-29 18:43 ` Kristen Carlson Accardi [this message]
2007-12-05 11:13 ` Pavel Machek
-- strict thread matches above, loose matches on Subject: below --
2007-11-29 20:19 Kristen Carlson Accardi
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=20071129104307.4966efc2@appleyard \
--to=kristen.c.accardi@intel.com \
--cc=akpm@linux-foundation.org \
--cc=jeff@garzik.org \
--cc=linux-ide@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
/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.