From patchwork Wed Apr 22 09:24:01 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Narsimhulu Musini X-Patchwork-Id: 6255371 Return-Path: X-Original-To: patchwork-linux-scsi@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork2.web.kernel.org (Postfix) with ESMTP id 7095ABF4A6 for ; Wed, 22 Apr 2015 09:28:24 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 4425E20303 for ; Wed, 22 Apr 2015 09:28:23 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id CD5B2202F8 for ; Wed, 22 Apr 2015 09:28:21 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S965923AbbDVJ2N (ORCPT ); Wed, 22 Apr 2015 05:28:13 -0400 Received: from alln-iport-1.cisco.com ([173.37.142.88]:8114 "EHLO alln-iport-1.cisco.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S934463AbbDVJ2A (ORCPT ); Wed, 22 Apr 2015 05:28:00 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=cisco.com; i=@cisco.com; l=9195; q=dns/txt; s=iport; t=1429694881; x=1430904481; h=from:to:cc:subject:date:message-id:in-reply-to: references; bh=EOy644iNgjdEC65YitUpDCY5mAnSNlrZMyCXrVvEsaY=; b=ef6A5JIBSxSBKPlQoYiDkqP1xtLWa3cEhD4pUylMDXFxfaJ8whW5Bbpm mhvokyyMkaS3Xo6DyHx/IyFueaid+LM9r3KFKmnJAs6SrRmFBq+HSdBa9 VUY8UU9/hb8Li7hO20+lT4Q1ZSWv13R1NY+8it6qQqxRzHXb8yv4TnZvj k=; X-IronPort-AV: E=Sophos;i="5.11,623,1422921600"; d="scan'208";a="143398840" Received: from rcdn-core-6.cisco.com ([173.37.93.157]) by alln-iport-1.cisco.com with ESMTP/TLS/DHE-RSA-AES256-SHA; 22 Apr 2015 09:27:50 +0000 Received: from hishah-lnx.cisco.com (dhcp-171-71-13-47.cisco.com [171.71.13.47]) (authenticated bits=0) by rcdn-core-6.cisco.com (8.14.5/8.14.5) with ESMTP id t3M9Rebl001558 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO); Wed, 22 Apr 2015 09:27:49 GMT From: Narsimhulu Musini To: JBottomley@Parallels.com, linux-scsi@vger.kernel.org, hare@suse.de Cc: Narsimhulu Musini , Sesidhar Baddela Subject: [PATCH v5 8/9] snic:Add event tracing to capture IO events. Date: Wed, 22 Apr 2015 02:24:01 -0700 Message-Id: <1429694642-22309-9-git-send-email-nmusini@cisco.com> X-Mailer: git-send-email 1.8.5.4 In-Reply-To: <1429694642-22309-1-git-send-email-nmusini@cisco.com> References: <1429694642-22309-1-git-send-email-nmusini@cisco.com> X-Authenticated-User: nmusini@cisco.com Sender: linux-scsi-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-scsi@vger.kernel.org X-Spam-Status: No, score=-14.5 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, RCVD_IN_DNSWL_HI, T_RP_MATCHES_RCVD, UNPARSEABLE_RELAY, USER_IN_DEF_DKIM_WL autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP snic_trc.h contains global trace structure definitions for snic driver snic_trc.c adds tracing functionality to capture various IO events. It maintains global trace buffer to maintain recent history of IO events. It helps to understand the sequence of events prior to particular IO event, or hung, panic, etc,. Signed-off-by: Narsimhulu Musini Signed-off-by: Sesidhar Baddela Reviewed-by: Hannes Reinecke --- * v2 - Added compile time macro SNIC_DEBUG_FS to handle debugfs dependent functionality. drivers/scsi/snic/snic_trc.c | 182 +++++++++++++++++++++++++++++++++++++++++++ drivers/scsi/snic/snic_trc.h | 121 ++++++++++++++++++++++++++++ 2 files changed, 303 insertions(+) create mode 100644 drivers/scsi/snic/snic_trc.c create mode 100644 drivers/scsi/snic/snic_trc.h diff --git a/drivers/scsi/snic/snic_trc.c b/drivers/scsi/snic/snic_trc.c new file mode 100644 index 0000000..c9e6f96 --- /dev/null +++ b/drivers/scsi/snic/snic_trc.c @@ -0,0 +1,182 @@ +/* + * Copyright 2014 Cisco Systems, Inc. All rights reserved. + * + * This program is free software; you may redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include + +#include "snic_io.h" +#include "snic.h" + +/* + * snic_get_trc_buf : Allocates a trace record and returns. + */ +struct snic_trc_data * +snic_get_trc_buf(void) +{ + struct snic_trc *trc = &snic_glob->trc; + struct snic_trc_data *td = NULL; + unsigned long flags; + + spin_lock_irqsave(&trc->lock, flags); + td = &trc->buf[trc->wr_idx]; + trc->wr_idx++; + + if (trc->wr_idx == trc->max_idx) + trc->wr_idx = 0; + + if (trc->wr_idx != trc->rd_idx) { + spin_unlock_irqrestore(&trc->lock, flags); + + goto end; + } + + trc->rd_idx++; + if (trc->rd_idx == trc->max_idx) + trc->rd_idx = 0; + + td->ts = 0; /* Marker for checking the record, for complete data*/ + spin_unlock_irqrestore(&trc->lock, flags); + +end: + + return td; +} /* end of snic_get_trc_buf */ + +/* + * snic_fmt_trc_data : Formats trace data for printing. + */ +static int +snic_fmt_trc_data(struct snic_trc_data *td, char *buf, int buf_sz) +{ + int len = 0; + struct timespec tmspec; + + jiffies_to_timespec(td->ts, &tmspec); + + len += snprintf(buf, buf_sz, + "%lu.%10lu %-25s %3d %4x %16llx %16llx %16llx %16llx %16llx\n", + tmspec.tv_sec, + tmspec.tv_nsec, + td->fn, + td->hno, + td->tag, + td->data[0], td->data[1], td->data[2], td->data[3], + td->data[4]); + + return len; +} /* end of snic_fmt_trc_data */ + +/* + * snic_get_trc_data : Returns a formatted trace buffer. + */ +int +snic_get_trc_data(char *buf, int buf_sz) +{ + struct snic_trc_data *td = NULL; + struct snic_trc *trc = &snic_glob->trc; + unsigned long flags; + + spin_lock_irqsave(&trc->lock, flags); + if (trc->rd_idx == trc->wr_idx) { + spin_unlock_irqrestore(&trc->lock, flags); + + return -1; + } + td = &trc->buf[trc->rd_idx]; + + if (td->ts == 0) { + /* write in progress. */ + spin_unlock_irqrestore(&trc->lock, flags); + + return -1; + } + + trc->rd_idx++; + if (trc->rd_idx == trc->max_idx) + trc->rd_idx = 0; + spin_unlock_irqrestore(&trc->lock, flags); + + return snic_fmt_trc_data(td, buf, buf_sz); +} /* end of snic_get_trc_data */ + +/* + * snic_trc_init() : Configures Trace Functionality for snic. + */ +int +snic_trc_init(void) +{ + struct snic_trc *trc = &snic_glob->trc; + void *tbuf = NULL; + int tbuf_sz = 0, ret; + + BUILD_BUG_ON(sizeof(struct snic_trc_data) != 64); + + tbuf_sz = (snic_trace_max_pages * PAGE_SIZE); + tbuf = vmalloc(tbuf_sz); + if (!tbuf) { + SNIC_ERR("Failed to Allocate Trace Buffer Size. %d\n", tbuf_sz); + SNIC_ERR("Trace Facility not enabled.\n"); + ret = -ENOMEM; + + return ret; + } + + memset(tbuf, 0, tbuf_sz); + trc->buf = (struct snic_trc_data *) tbuf; + spin_lock_init(&trc->lock); + + ret = snic_trc_debugfs_init(); + if (ret) { + SNIC_ERR("Failed to create Debugfs Files.\n"); + + goto error; + } + + trc->max_idx = (tbuf_sz / SNIC_TRC_ENTRY_SZ); + trc->rd_idx = trc->wr_idx = 0; + trc->enable = 1; + SNIC_INFO("Trace Facility Enabled.\n Trace Buffer SZ %lu Pages.\n", + tbuf_sz / PAGE_SIZE); + ret = 0; + + return ret; + +error: + snic_trc_free(); + + return ret; +} /* end of snic_trc_init */ + +/* + * snic_trc_free : Releases the trace buffer and disables the tracing. + */ +void +snic_trc_free(void) +{ + struct snic_trc *trc = &snic_glob->trc; + + trc->enable = 0; + snic_trc_debugfs_term(); + + if (trc->buf) { + vfree(trc->buf); + trc->buf = NULL; + } + + SNIC_INFO("Trace Facility Disabled.\n"); +} /* end of snic_trc_free */ diff --git a/drivers/scsi/snic/snic_trc.h b/drivers/scsi/snic/snic_trc.h new file mode 100644 index 0000000..99de384 --- /dev/null +++ b/drivers/scsi/snic/snic_trc.h @@ -0,0 +1,121 @@ +/* + * Copyright 2014 Cisco Systems, Inc. All rights reserved. + * + * This program is free software; you may redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef __SNIC_TRC_H +#define __SNIC_TRC_H + +#ifdef SNIC_DEBUG_FS + +extern ssize_t simple_read_from_buffer(void __user *to, + size_t count, + loff_t *ppos, + const void *from, + size_t available); + +extern unsigned int snic_trace_max_pages; + +/* Global Data structure for trace to manage trace functionality */ +struct snic_trc_data { + u64 ts; /* Time Stamp */ + char *fn; /* Ptr to Function Name */ + u32 hno; /* SCSI Host ID */ + u32 tag; /* Command Tag */ + u64 data[5]; +} __attribute__((__packed__)); + +#define SNIC_TRC_ENTRY_SZ 64 /* in Bytes */ + +struct snic_trc { + spinlock_t lock; + struct snic_trc_data *buf; /* Trace Buffer */ + u32 max_idx; /* Max Index into trace buffer */ + u32 rd_idx; + u32 wr_idx; + u32 enable; /* Control Variable for Tracing */ + + struct dentry *trc_enable; /* debugfs file object */ + struct dentry *trc_file; +}; + +int snic_trc_init(void); +void snic_trc_free(void); +int snic_trc_debugfs_init(void); +void snic_trc_debugfs_term(void); +struct snic_trc_data *snic_get_trc_buf(void); +int snic_get_trc_data(char *buf, int buf_sz); + +int snic_debugfs_init(void); +void snic_debugfs_term(void); + +static inline void +snic_trace(char *fn, u16 hno, u32 tag, u64 d1, u64 d2, u64 d3, u64 d4, u64 d5) +{ + struct snic_trc_data *tr_rec = snic_get_trc_buf(); + + if (!tr_rec) + return; + + tr_rec->fn = (char *)fn; + tr_rec->hno = hno; + tr_rec->tag = tag; + tr_rec->data[0] = d1; + tr_rec->data[1] = d2; + tr_rec->data[2] = d3; + tr_rec->data[3] = d4; + tr_rec->data[4] = d5; + tr_rec->ts = jiffies; /* Update time stamp at last */ +} + +#define SNIC_TRC(_hno, _tag, d1, d2, d3, d4, d5) \ + do { \ + if (unlikely(snic_glob->trc.enable)) \ + snic_trace((char *)__func__, \ + (u16)(_hno), \ + (u32)(_tag), \ + (u64)(d1), \ + (u64)(d2), \ + (u64)(d3), \ + (u64)(d4), \ + (u64)(d5)); \ + } while (0) +#else + +#define SNIC_TRC(_hno, _tag, d1, d2, d3, d4, d5) \ + do { \ + if (unlikely(snic_log_level & 0x2)) \ + SNIC_DBG("SnicTrace: %s %2u %2u %llx %llx %llx %llx %llx", \ + (char *)__func__, \ + (u16)(_hno), \ + (u32)(_tag), \ + (u64)(d1), \ + (u64)(d2), \ + (u64)(d3), \ + (u64)(d4), \ + (u64)(d5)); \ + } while (0); +#endif /* end of SNIC_DEBUG_FS */ + +#define SNIC_TRC_CMD(sc) \ + ((u64)sc->cmnd[0] << 56 | (u64)sc->cmnd[7] << 40 | \ + (u64)sc->cmnd[8] << 32 | (u64)sc->cmnd[2] << 24 | \ + (u64)sc->cmnd[3] << 16 | (u64)sc->cmnd[4] << 8 | \ + (u64)sc->cmnd[5]) + +#define SNIC_TRC_CMD_STATE_FLAGS(sc) \ + ((u64) CMD_FLAGS(sc) << 32 | CMD_STATE(sc)) + +#endif /* end of __SNIC_TRC_H */