From patchwork Tue Mar 9 10:37:55 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Harry Zhang X-Patchwork-Id: 47155 X-Patchwork-Delegate: davem@davemloft.net Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id B743FB7D41 for ; Tue, 9 Mar 2010 21:38:13 +1100 (EST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752743Ab0CIKiM (ORCPT ); Tue, 9 Mar 2010 05:38:12 -0500 Received: from tx2ehsobe001.messaging.microsoft.com ([65.55.88.11]:36269 "EHLO TX2EHSOBE001.bigfish.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751024Ab0CIKiK convert rfc822-to-8bit (ORCPT ); Tue, 9 Mar 2010 05:38:10 -0500 Received: from mail37-tx2-R.bigfish.com (10.9.14.248) by TX2EHSOBE001.bigfish.com (10.9.40.21) with Microsoft SMTP Server id 8.1.340.0; Tue, 9 Mar 2010 10:38:08 +0000 Received: from mail37-tx2 (localhost [127.0.0.1]) by mail37-tx2-R.bigfish.com (Postfix) with ESMTP id 5C21710F81AC; Tue, 9 Mar 2010 10:38:08 +0000 (UTC) X-SpamScore: 1 X-BigFish: VPS1(zzab9bhzz1202hzzz32i6bh367h2a8h61h) X-Spam-TCS-SCL: 0:0 X-FB-SS: 5, Received: from mail37-tx2 (localhost.localdomain [127.0.0.1]) by mail37-tx2 (MessageSwitch) id 1268131086278391_3995; Tue, 9 Mar 2010 10:38:06 +0000 (UTC) Received: from TX2EHSMHS033.bigfish.com (unknown [10.9.14.237]) by mail37-tx2.bigfish.com (Postfix) with ESMTP id 417851790053; Tue, 9 Mar 2010 10:38:06 +0000 (UTC) Received: from ausb3extmailp02.amd.com (163.181.251.22) by TX2EHSMHS033.bigfish.com (10.9.99.133) with Microsoft SMTP Server (TLS) id 14.0.482.39; Tue, 9 Mar 2010 10:38:06 +0000 Received: from ausb3twp02.amd.com ([163.181.250.38]) by ausb3extmailp02.amd.com (Switch-3.2.7/Switch-3.2.7) with SMTP id o29AfkTN001336; Tue, 9 Mar 2010 04:41:49 -0600 X-WSS-ID: 0KZ0G7B-02-EFS-02 X-M-MSG: Received: from sausexhtp01.amd.com (sausexhtp01.amd.com [163.181.3.165]) (using TLSv1 with cipher RC4-MD5 (128/128 bits)) (No client certificate requested) by ausb3twp02.amd.com (Tumbleweed MailGate 3.7.2) with ESMTP id 275C7FCC08D; Tue, 9 Mar 2010 04:37:58 -0600 (CST) Received: from storexhtp02.amd.com (172.24.4.4) by sausexhtp01.amd.com (163.181.3.165) with Microsoft SMTP Server (TLS) id 8.2.234.1; Tue, 9 Mar 2010 02:38:00 -0800 Received: from storexbh1.amd.com (10.1.1.17) by storexhtp02.amd.com (172.24.4.4) with Microsoft SMTP Server id 8.2.234.1; Tue, 9 Mar 2010 05:37:59 -0500 Received: from sshaexmb1.amd.com ([10.237.2.11]) by storexbh1.amd.com with Microsoft SMTPSVC(6.0.3790.3959); Tue, 9 Mar 2010 05:38:00 -0500 Received: from 10.237.82.16 ([10.237.82.16]) by sshaexmb1.amd.com ([10.237.2.11]) with Microsoft Exchange Server HTTP-DAV ; Tue, 9 Mar 2010 10:37:55 +0000 Received: from harry-desktop by sshaexmb1.amd.com; 09 Mar 2010 18:37:55 +0800 Subject: [PATCH] ahci: add "em_buffer" attribute for AHCI hosts From: Harry Zhang To: jgarzik@pobox.com CC: linux-ide@vger.kernel.org, tj@kernel.org, "Huang, Shane" , "Zhang, Harry" Date: Tue, 9 Mar 2010 18:37:55 +0800 Message-ID: <1268131075.2000.6.camel@harry-desktop> MIME-Version: 1.0 X-Mailer: Evolution 2.28.2 X-OriginalArrivalTime: 09 Mar 2010 10:38:00.0088 (UTC) FILETIME=[96D12180:01CABF74] X-Reverse-DNS: ausb3extmailp02.amd.com Sender: linux-ide-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-ide@vger.kernel.org Add "em_buffer" attribute for SATA AHCI hosts to enable user access AHCI EM (enclosure management) buffer in user space if the host support EM. AHCI driver should support SGPIO EM message. However the SATA/AHCI spec does no define the SGPIO message format filled in EM buffer. Different HW vendors may have different definitions. The mainly purpose of "em_buffer" attribute is to solve this issue by allowing HW vendors to provide user space SGPIO drivers and tools. Signed-off-by: Harry Zhang --- drivers/ata/ahci.c | 73 +++++++++++++++++++++++++++++++++++++++++--- drivers/ata/libata-scsi.c | 14 ++++++++ include/linux/libata.h | 3 ++ 3 files changed, 85 insertions(+), 5 deletions(-) -- To unsubscribe from this list: send the line "unsubscribe linux-ide" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 6bd930b..a6b9059 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -268,6 +268,10 @@ enum { EM_CTL_RST = (1 << 9), /* Reset */ EM_CTL_TM = (1 << 8), /* Transmit Message */ EM_CTL_ALHD = (1 << 26), /* Activity LED */ + + /* EM buffer message flags */ + EM_BUF_MSG_RST = 1, /* reset */ + EM_BUF_MSG_TM = (1 << 1), /* transmit message */ }; struct ahci_cmd_hdr { @@ -293,6 +297,13 @@ struct ahci_em_priv { unsigned long led_state; }; +struct ahci_em_buf_msg { + u32 flags; /* message flags */ + u16 offset; /* DWORD offset in EM buffer to r/w */ + u16 len; /* data length in DWORD */ + u32 buf[0]; /* message data buffer */ +}; + struct ahci_host_priv { unsigned int flags; /* AHCI_HFLAG_* */ u32 cap; /* cap to use */ @@ -302,6 +313,7 @@ struct ahci_host_priv { u32 saved_cap2; /* saved initial cap2 */ u32 saved_port_map; /* saved initial port_map */ u32 em_loc; /* enclosure management location */ + u32 em_buf_sz; /* EM buffer size*/ }; struct ahci_port_priv { @@ -365,6 +377,8 @@ static ssize_t ahci_activity_show(struct ata_device *dev, char *buf); static ssize_t ahci_activity_store(struct ata_device *dev, enum sw_activity val); static void ahci_init_sw_activity(struct ata_link *link); +static ssize_t ahci_em_buffer_store(struct ata_port *ap, + const char *buf, size_t size); static ssize_t ahci_show_host_caps(struct device *dev, struct device_attribute *attr, char *buf); @@ -384,6 +398,7 @@ static struct device_attribute *ahci_shost_attrs[] = { &dev_attr_link_power_management_policy, &dev_attr_em_message_type, &dev_attr_em_message, + &dev_attr_em_buffer, &dev_attr_ahci_host_caps, &dev_attr_ahci_host_cap2, &dev_attr_ahci_host_version, @@ -435,6 +450,7 @@ static struct ata_port_operations ahci_ops = { .em_store = ahci_led_store, .sw_activity_show = ahci_activity_show, .sw_activity_store = ahci_activity_store, + .em_buffer_store = ahci_em_buffer_store, #ifdef CONFIG_PM .port_suspend = ahci_port_suspend, .port_resume = ahci_port_resume, @@ -721,11 +737,13 @@ static struct pci_driver ahci_pci_driver = { #endif }; -static int ahci_em_messages = 1; +static int ahci_em_messages = 0x09; 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"); + "AHCI Enclosure Management Message type on-off bit mask. \ + bit 0 to 3 control LED, SAF-TE, SES-2, and SGPIO respectively \ + (0 to disable, 1 to enable)"); #if defined(CONFIG_PATA_MARVELL) || defined(CONFIG_PATA_MARVELL_MODULE) static int marvell_enable; @@ -1608,6 +1626,48 @@ static ssize_t ahci_activity_show(struct ata_device *dev, char *buf) return sprintf(buf, "%d\n", emp->blink_policy); } +static ssize_t ahci_em_buffer_store(struct ata_port *ap, + const char *buf, size_t size) +{ + struct ahci_host_priv *hpriv = ap->host->private_data; + void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR]; + void __iomem *em_mmio = mmio + hpriv->em_loc; + struct ahci_em_buf_msg *msg = (struct ahci_em_buf_msg *)buf; + u32 em_ctl; + unsigned long flags; + int i, tmp; + + /* check message validity */ + tmp = sizeof(struct ahci_em_buf_msg); + if (size % 4 || size < tmp || size > tmp + msg->len * 4 || + msg->offset + msg->len > hpriv->em_buf_sz / 4) { + return -EINVAL; + } + + if (msg->flags & EM_BUF_MSG_RST) + ahci_reset_em(ap->host); + + spin_lock_irqsave(ap->lock, flags); + + em_ctl = readl(mmio + HOST_EM_CTL); + if (em_ctl & EM_CTL_TM) { + spin_unlock_irqrestore(ap->lock, flags); + return -EBUSY; + } + + for (i = 0; i < msg->len; ++i) { + tmp = (msg->offset + i) * 4; + writel(msg->buf[i], em_mmio + tmp); + } + + if (msg->flags & EM_BUF_MSG_TM) + writel(em_ctl | EM_CTL_TM, mmio + HOST_EM_CTL); + + spin_unlock_irqrestore(ap->lock, flags); + + return size; +} + static void ahci_port_init(struct pci_dev *pdev, struct ata_port *ap, int port_no, void __iomem *mmio, void __iomem *port_mmio) @@ -3295,12 +3355,15 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) messages = (em_ctl & EM_CTRL_MSG_TYPE) >> 16; - /* we only support LED message type right now */ - if ((messages & 0x01) && (ahci_em_messages == 1)) { + /* only LED and SGPIO EM messages are enabled as default */ + ahci_em_messages &= messages; + if (ahci_em_messages) { /* store em_loc */ hpriv->em_loc = ((em_loc >> 16) * 4); + hpriv->em_buf_sz = ((em_loc & 0xff) * 4); pi.flags |= ATA_FLAG_EM; - if (!(em_ctl & EM_CTL_ALHD)) + if (!(em_ctl & EM_CTL_ALHD) && + (ahci_em_messages == 1)) pi.flags |= ATA_FLAG_SW_ACTIVITY; } } diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index bea003a..b1a2379 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -370,6 +370,20 @@ DEVICE_ATTR(sw_activity, S_IWUSR | S_IRUGO, ata_scsi_activity_show, ata_scsi_activity_store); EXPORT_SYMBOL_GPL(dev_attr_sw_activity); +static ssize_t +ata_scsi_em_buffer_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct Scsi_Host *shost = class_to_shost(dev); + struct ata_port *ap = ata_shost_to_port(shost); + + if (ap->ops->em_buffer_store && (ap->flags & ATA_FLAG_EM)) + return ap->ops->em_buffer_store(ap, buf, count); + return -EINVAL; +} +DEVICE_ATTR(em_buffer, S_IWUSR, NULL, ata_scsi_em_buffer_store); +EXPORT_SYMBOL_GPL(dev_attr_em_buffer); + struct device_attribute *ata_common_sdev_attrs[] = { &dev_attr_unload_heads, NULL diff --git a/include/linux/libata.h b/include/linux/libata.h index f8ea71e..a26fd0e 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -495,6 +495,7 @@ extern struct device_attribute dev_attr_unload_heads; extern struct device_attribute dev_attr_em_message_type; extern struct device_attribute dev_attr_em_message; extern struct device_attribute dev_attr_sw_activity; +extern struct device_attribute dev_attr_em_buffer; enum sw_activity { OFF, @@ -874,6 +875,8 @@ struct ata_port_operations { ssize_t (*sw_activity_show)(struct ata_device *dev, char *buf); ssize_t (*sw_activity_store)(struct ata_device *dev, enum sw_activity val); + ssize_t (*em_buffer_store)(struct ata_port *ap, + const char *buf, size_t size); /* * Obsolete */