From patchwork Fri Apr 23 09:28:38 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Harry Zhang X-Patchwork-Id: 50801 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 6285BB7D1C for ; Fri, 23 Apr 2010 19:28:55 +1000 (EST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1756809Ab0DWJ2x (ORCPT ); Fri, 23 Apr 2010 05:28:53 -0400 Received: from tx2ehsobe003.messaging.microsoft.com ([65.55.88.13]:36501 "EHLO TX2EHSOBE005.bigfish.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1756806Ab0DWJ2v (ORCPT ); Fri, 23 Apr 2010 05:28:51 -0400 Received: from mail62-tx2-R.bigfish.com (10.9.14.248) by TX2EHSOBE005.bigfish.com (10.9.40.25) with Microsoft SMTP Server id 8.1.340.0; Fri, 23 Apr 2010 09:28:50 +0000 Received: from mail62-tx2 (localhost.localdomain [127.0.0.1]) by mail62-tx2-R.bigfish.com (Postfix) with ESMTP id D577BB683BC; Fri, 23 Apr 2010 09:28:50 +0000 (UTC) X-SpamScore: 1 X-BigFish: VPS1(zzab9bhzz1202hzz6ff19hz32i367h2a8h62h) X-Spam-TCS-SCL: 1:0 Received: from mail62-tx2 (localhost.localdomain [127.0.0.1]) by mail62-tx2 (MessageSwitch) id 12720149306448_444; Fri, 23 Apr 2010 09:28:50 +0000 (UTC) Received: from TX2EHSMHS019.bigfish.com (unknown [10.9.14.240]) by mail62-tx2.bigfish.com (Postfix) with ESMTP id E8A2F194804E; Fri, 23 Apr 2010 09:28:49 +0000 (UTC) Received: from ausb3extmailp02.amd.com (163.181.251.22) by TX2EHSMHS019.bigfish.com (10.9.99.119) with Microsoft SMTP Server (TLS) id 14.0.482.44; Fri, 23 Apr 2010 09:28:48 +0000 Received: from ausb3twp01.amd.com (ausb3twp01.amd.com [163.181.250.37]) by ausb3extmailp02.amd.com (Switch-3.2.7/Switch-3.2.7) with SMTP id o3N9Z3Vc006949; Fri, 23 Apr 2010 04:35:06 -0500 X-WSS-ID: 0L1BOZT-01-A6B-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 ausb3twp01.amd.com (Tumbleweed MailGate 3.7.2) with ESMTP id 25EDC102801D; Fri, 23 Apr 2010 04:28:41 -0500 (CDT) 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; Fri, 23 Apr 2010 02:28:43 -0700 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; Fri, 23 Apr 2010 04:28:43 -0500 Received: from sshaexmb1.amd.com ([10.237.2.11]) by storexbh1.amd.com with Microsoft SMTPSVC(6.0.3790.4675); Fri, 23 Apr 2010 05:28:42 -0400 Received: from 10.237.82.16 ([10.237.82.16]) by sshaexmb1.amd.com ([10.237.2.11]) with Microsoft Exchange Server HTTP-DAV ; Fri, 23 Apr 2010 09:28:39 +0000 Received: from zm-desktop by sshaexmb1.amd.com; 23 Apr 2010 17:28:39 +0800 Subject: [PATCH 2/2 v5] ahci: add "em_buffer" attribute for AHCI hosts From: Harry Zhang To: jgarzik@pobox.com CC: linux-ide@vger.kernel.org, tj@kernel.org, "Zhang, Harry" , shane.huang@amd.com Date: Fri, 23 Apr 2010 17:28:38 +0800 Message-ID: <1272014918.3594.43.camel@zm-desktop> MIME-Version: 1.0 X-Mailer: Evolution 2.26.1 X-OriginalArrivalTime: 23 Apr 2010 09:28:42.0891 (UTC) FILETIME=[5D85F5B0:01CAE2C7] 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 provide a way for userland to access AHCI EM (enclosure management) buffer directly if the host supports EM. AHCI driver should support SGPIO EM messages. However the SATA/AHCI specs did not define the SGPIO message format filled in EM buffer. Different HW vendors may have different definitions. The mainly purpose of this attribute is to solve this issue by allowing HW vendors to provide userland drivers and tools for their SGPIO initiators. Signed-off-by: Harry Zhang Acked-by: Tejun Heo --- v2: rebase this patch on the new upstream branch of linux-next.git v3: do not use "ahci_em_messages" module parameter as EM message type control, instead by detecting supported types at initialization. Remove EM message structure shared with userland, instead by simply writing the raw message into the buffer. Move write function for this attribute from libata-scsi.c to libahci.c. Add read function. Add necessary definitions for EM in ahci.h. v4: remove changes for EM message types. Add PAGE_SIZE check for em_buffer read function. Report EAGAIN for read function when no message in the buffer. v5: move this patch to second one. Exam EM message type for SGPIO when enter r/w method. Use ata_port_printk to report warning for large read buffer. drivers/ata/ahci.h | 10 +++- drivers/ata/libahci.c | 104 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 111 insertions(+), 3 deletions(-) diff --git a/drivers/ata/ahci.h b/drivers/ata/ahci.h index 5edce44..7113c57 100644 --- a/drivers/ata/ahci.h +++ b/drivers/ata/ahci.h @@ -224,9 +224,12 @@ enum { EM_MAX_RETRY = 5, /* em_ctl bits */ - EM_CTL_RST = (1 << 9), /* Reset */ - EM_CTL_TM = (1 << 8), /* Transmit Message */ - EM_CTL_ALHD = (1 << 26), /* Activity LED */ + EM_CTL_RST = (1 << 9), /* Reset */ + EM_CTL_TM = (1 << 8), /* Transmit Message */ + EM_CTL_MR = (1 << 0), /* Message Recieved */ + EM_CTL_ALHD = (1 << 26), /* Activity LED */ + EM_CTL_XMT = (1 << 25), /* Transmit Only */ + EM_CTL_SMB = (1 << 24), /* Single Message Buffer */ /* em message type */ EM_MSG_TYPE_LED = (1 << 0), /* LED */ @@ -288,6 +291,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 in byte */ u32 em_msg_type; /* EM message type */ }; diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c index 817bcd0..1984a6e 100644 --- a/drivers/ata/libahci.c +++ b/drivers/ata/libahci.c @@ -108,11 +108,18 @@ static ssize_t ahci_show_host_version(struct device *dev, struct device_attribute *attr, char *buf); static ssize_t ahci_show_port_cmd(struct device *dev, struct device_attribute *attr, char *buf); +static ssize_t ahci_read_em_buffer(struct device *dev, + struct device_attribute *attr, char *buf); +static ssize_t ahci_store_em_buffer(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size); static DEVICE_ATTR(ahci_host_caps, S_IRUGO, ahci_show_host_caps, NULL); static DEVICE_ATTR(ahci_host_cap2, S_IRUGO, ahci_show_host_cap2, NULL); static DEVICE_ATTR(ahci_host_version, S_IRUGO, ahci_show_host_version, NULL); static DEVICE_ATTR(ahci_port_cmd, S_IRUGO, ahci_show_port_cmd, NULL); +static DEVICE_ATTR(em_buffer, S_IWUSR | S_IRUGO, + ahci_read_em_buffer, ahci_store_em_buffer); static struct device_attribute *ahci_shost_attrs[] = { &dev_attr_link_power_management_policy, @@ -122,6 +129,7 @@ static struct device_attribute *ahci_shost_attrs[] = { &dev_attr_ahci_host_cap2, &dev_attr_ahci_host_version, &dev_attr_ahci_port_cmd, + &dev_attr_em_buffer, NULL }; @@ -252,6 +260,101 @@ static ssize_t ahci_show_port_cmd(struct device *dev, return sprintf(buf, "%x\n", readl(port_mmio + PORT_CMD)); } +static ssize_t ahci_read_em_buffer(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct Scsi_Host *shost = class_to_shost(dev); + struct ata_port *ap = ata_shost_to_port(shost); + struct ahci_host_priv *hpriv = ap->host->private_data; + void __iomem *mmio = hpriv->mmio; + void __iomem *em_mmio = mmio + hpriv->em_loc; + u32 em_ctl, msg; + unsigned long flags; + size_t count; + int i; + + spin_lock_irqsave(ap->lock, flags); + + em_ctl = readl(mmio + HOST_EM_CTL); + if (!(ap->flags & ATA_FLAG_EM) || em_ctl & EM_CTL_XMT || + !(hpriv->em_msg_type & EM_MSG_TYPE_SGPIO)) { + spin_unlock_irqrestore(ap->lock, flags); + return -EINVAL; + } + + if (!(em_ctl & EM_CTL_MR)) { + spin_unlock_irqrestore(ap->lock, flags); + return -EAGAIN; + } + + if (!(em_ctl & EM_CTL_SMB)) + em_mmio += hpriv->em_buf_sz; + + count = hpriv->em_buf_sz; + + /* the count should not be larger than PAGE_SIZE */ + if (count > PAGE_SIZE) { + if (printk_ratelimit()) + ata_port_printk(ap, KERN_WARNING, + "EM read buffer size too large: " + "buffer size %u, page size %lu\n", + hpriv->em_buf_sz, PAGE_SIZE); + count = PAGE_SIZE; + } + + for (i = 0; i < count; i += 4) { + msg = readl(em_mmio + i); + buf[i] = msg & 0xff; + buf[i + 1] = (msg >> 8) & 0xff; + buf[i + 2] = (msg >> 16) & 0xff; + buf[i + 3] = (msg >> 24) & 0xff; + } + + spin_unlock_irqrestore(ap->lock, flags); + + return i; +} + +static ssize_t ahci_store_em_buffer(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + struct Scsi_Host *shost = class_to_shost(dev); + struct ata_port *ap = ata_shost_to_port(shost); + struct ahci_host_priv *hpriv = ap->host->private_data; + void __iomem *mmio = hpriv->mmio; + void __iomem *em_mmio = mmio + hpriv->em_loc; + u32 em_ctl, msg; + unsigned long flags; + int i; + + /* check size validity */ + if (!(ap->flags & ATA_FLAG_EM) || + !(hpriv->em_msg_type & EM_MSG_TYPE_SGPIO) || + size % 4 || size > hpriv->em_buf_sz) + return -EINVAL; + + 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 < size; i += 4) { + msg = buf[i] | buf[i + 1] << 8 | + buf[i + 2] << 16 | buf[i + 3] << 24; + writel(msg, em_mmio + i); + } + + writel(em_ctl | EM_CTL_TM, mmio + HOST_EM_CTL); + + spin_unlock_irqrestore(ap->lock, flags); + + return size; +} + /** * ahci_save_initial_config - Save and fixup initial config values * @dev: target AHCI device @@ -2099,6 +2202,7 @@ void ahci_set_em_messages(struct ahci_host_priv *hpriv, if (messages) { /* store em_loc */ hpriv->em_loc = ((em_loc >> 16) * 4); + hpriv->em_buf_sz = ((em_loc & 0xff) * 4); hpriv->em_msg_type = messages; pi->flags |= ATA_FLAG_EM; if (!(em_ctl & EM_CTL_ALHD))