[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-Id: <1238904131.4250.755.camel@haakon2.linux-iscsi.org>
Date: Sat, 04 Apr 2009 21:02:11 -0700
From: "Nicholas A. Bellinger" <nab@...ux-iscsi.org>
To: LKML <linux-kernel@...r.kernel.org>,
linux-scsi <linux-scsi@...r.kernel.org>
Cc: James Bottomley <James.Bottomley@...senPartnership.com>,
Andrew Morton <akpm@...ux-foundation.org>,
Hannes Reinecke <hare@...e.de>,
FUJITA Tomonori <fujita.tomonori@....ntt.co.jp>,
Mike Christie <michaelc@...wisc.edu>,
"Martin K. Petersen" <martin.petersen@...cle.com>,
Ming Zhang <blackmagic02881@...il.com>,
Philipp Reisner <philipp.reisner@...bit.com>,
Linus Torvalds <torvalds@...ux-foundation.org>
Subject: [RFC PATCH 14/19] Target_Core_Mod SCSI MIBs
This patch adds support for SCSI MIBs through /proc/scsi_target/mib following RFC-4455.
Signed-off-by: Nicholas A. Bellinger <nab@...ux-iscsi.org>
diff --git a/drivers/target/target_core_mib.c b/drivers/target/target_core_mib.c
new file mode 100644
index 0000000..a2f9349
--- /dev/null
+++ b/drivers/target/target_core_mib.c
@@ -0,0 +1,1188 @@
+/*******************************************************************************
+ * Filename: target_core_mib.c
+ *
+ * Copyright (c) 2006-2007 SBE, Inc. All Rights Reserved.
+ * Copyright (c) 2007-2009 Rising Tide Software, Inc.
+ * Copyright (c) 2008-2009 Linux-iSCSI.org
+ *
+ * Nicholas A. Bellinger <nab@...ux-iscsi.org>
+ *
+ * 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 of the License, 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; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ ******************************************************************************/
+
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/string.h>
+#include <linux/version.h>
+#include <linux/utsrelease.h>
+#include <linux/utsname.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+#include <linux/blkdev.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_host.h>
+
+#include <target/target_core_base.h>
+#include <target/target_core_hba.h>
+#include <target/target_core_transport.h>
+#include <target/target_core_mib.h>
+#include <target/target_core_plugin.h>
+#include <target/target_core_seobj.h>
+#include <target/target_core_fabric_ops.h>
+#include <target/target_core_configfs.h>
+
+/* SCSI mib table index */
+scsi_index_table_t scsi_index_table;
+
+#ifndef INITIAL_JIFFIES
+#define INITIAL_JIFFIES ((unsigned long)(unsigned int) (-300*HZ))
+#endif
+
+/* SCSI Instance Table */
+#define SCSI_INST_SW_INDEX 1
+#define SCSI_TRANSPORT_INDEX 1
+
+#define NONE "None"
+#define ISPRINT(a) ((a >= ' ') && (a <= '~'))
+
+/* Structure for table row iteration with seq_file */
+typedef struct table_iter_s {
+ int ti_skip_body;
+ u32 ti_offset;
+ void *ti_ptr;
+} table_iter_t;
+
+/****************************************************************************
+ * SCSI MIB Tables
+ ****************************************************************************/
+
+/*
+ * SCSI Instance Table
+ */
+static int scsi_inst_seq_show(struct seq_file *seq, void *v)
+{
+ se_hba_t *hba;
+ int i;
+
+ seq_puts(seq, "inst sw_indx\n");
+
+ spin_lock(&se_global->hba_lock);
+ for (i = 0; i < TRANSPORT_MAX_GLOBAL_HBAS; i++) {
+ hba = &se_global->hba_list[i];
+
+ if (!(hba->hba_status & HBA_STATUS_ACTIVE))
+ continue;
+
+ if (!hba->transport)
+ continue;
+
+ seq_printf(seq, "%u %u\n", hba->hba_index, SCSI_INST_SW_INDEX);
+ seq_printf(seq, "plugin: %s version: %s\n",
+ hba->transport->name,
+ TARGET_CORE_VERSION);
+ }
+ spin_unlock(&se_global->hba_lock);
+
+ return 0;
+}
+
+static int scsi_inst_seq_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, scsi_inst_seq_show, NULL);
+}
+
+static const struct file_operations scsi_inst_seq_fops = {
+ .owner = THIS_MODULE,
+ .open = scsi_inst_seq_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static void *locate_hba_start(
+ struct seq_file *seq,
+ loff_t *pos,
+ int (*do_check)(void *))
+{
+ se_device_t *dev;
+ se_hba_t *hba;
+ table_iter_t *tpg_iter;
+ int i;
+
+ if (*pos != 0)
+ return NULL;
+
+ tpg_iter = kzalloc(sizeof(table_iter_t), GFP_KERNEL);
+ if (!(tpg_iter))
+ return NULL;
+#if 0
+ printk(KERN_INFO "%s[%d] - Allocating iterp: %p\n", current->comm,
+ current->pid, tpg_iter);
+#endif
+ seq->private = (void *)tpg_iter;
+
+ spin_lock(&se_global->hba_lock);
+ for (i = 0; i < TRANSPORT_MAX_GLOBAL_HBAS; i++) {
+ hba = &se_global->hba_list[i];
+
+ if (!(hba->hba_status & HBA_STATUS_ACTIVE))
+ continue;
+ if (do_check((void *)hba) == 0)
+ continue;
+
+ spin_lock(&hba->device_lock);
+ list_for_each_entry(dev, &hba->hba_dev_list, dev_list) {
+ tpg_iter->ti_ptr = (void *)dev;
+ tpg_iter->ti_offset = hba->hba_id;
+ atomic_inc(&hba->dev_mib_access_count);
+#if 0
+ printk(KERN_INFO "[%d]: Incremented dev_mib_access"
+ "_count: %d\n", hba->hba_id,
+ atomic_read(&hba->dev_mib_access_count));
+#endif
+ spin_unlock(&hba->device_lock);
+ spin_unlock(&se_global->hba_lock);
+ return SEQ_START_TOKEN;
+ }
+ spin_unlock(&hba->device_lock);
+ }
+ spin_unlock(&se_global->hba_lock);
+
+ return SEQ_START_TOKEN;
+}
+
+static void *locate_hba_next(
+ struct seq_file *seq,
+ void *v,
+ loff_t *pos,
+ int (*do_check)(void *))
+{
+ table_iter_t *iterp = (table_iter_t *)seq->private;
+ se_device_t *dev, *dev_p, *dev_next = NULL;
+ se_hba_t *hba;
+ int i;
+
+ (*pos)++;
+
+ if (!(iterp))
+ return NULL;
+
+ dev = (se_device_t *)iterp->ti_ptr;
+ if (!(dev))
+ return NULL;
+
+ dev_p = dev;
+ spin_lock(&SE_HBA(dev)->device_lock);
+ list_for_each_entry_continue(dev_p, &dev->se_hba->hba_dev_list,
+ dev_list) {
+ dev_next = dev_p;
+ break;
+ }
+ if ((dev_next)) {
+ iterp->ti_ptr = dev_next;
+ spin_unlock(&SE_HBA(dev)->device_lock);
+ return (void *)iterp;
+ }
+ spin_unlock(&SE_HBA(dev)->device_lock);
+
+ spin_lock(&se_global->hba_lock);
+ hba = &se_global->hba_list[iterp->ti_offset];
+ atomic_dec(&hba->dev_mib_access_count);
+ iterp->ti_ptr = NULL;
+
+ for (i = (iterp->ti_offset + 1); i < TRANSPORT_MAX_GLOBAL_HBAS; i++) {
+ hba = &se_global->hba_list[i];
+
+ if (!(hba->hba_status & HBA_STATUS_ACTIVE))
+ continue;
+ if (do_check((void *)hba) == 0)
+ continue;
+
+ spin_lock(&hba->device_lock);
+ list_for_each_entry(dev, &hba->hba_dev_list, dev_list) {
+ iterp->ti_ptr = (void *)dev;
+ iterp->ti_offset = hba->hba_id;
+ atomic_inc(&hba->dev_mib_access_count);
+
+ spin_unlock(&hba->device_lock);
+ spin_unlock(&se_global->hba_lock);
+ return (void *)iterp;
+ }
+ spin_unlock(&hba->device_lock);
+ }
+ spin_unlock(&se_global->hba_lock);
+
+ return NULL;
+}
+
+static void locate_hba_stop(struct seq_file *seq, void *v)
+{
+ table_iter_t *iterp = (table_iter_t *)seq->private;
+
+ if (!(iterp))
+ return;
+
+ iterp->ti_ptr = NULL;
+ kfree(iterp);
+ seq->private = NULL;
+
+ return;
+}
+
+/*
+ * SCSI Device Table
+ */
+int do_hba_check(void *p)
+{
+ se_hba_t *hba = (se_hba_t *)p;
+
+ return hba->dev_count;
+}
+
+static void *scsi_dev_seq_start(struct seq_file *seq, loff_t *pos)
+{
+ return locate_hba_start(seq, pos, &do_hba_check);
+}
+
+static void *scsi_dev_seq_next(struct seq_file *seq, void *v, loff_t *pos)
+{
+ return locate_hba_next(seq, v, pos, &do_hba_check);
+}
+
+static void scsi_dev_seq_stop(struct seq_file *seq, void *v)
+{
+ locate_hba_stop(seq, v);
+}
+
+static int scsi_dev_seq_show(struct seq_file *seq, void *v)
+{
+ se_hba_t *hba;
+ se_device_t *dev;
+ table_iter_t *iterp = (table_iter_t *)seq->private;
+ int k;
+
+ if (v == SEQ_START_TOKEN)
+ seq_puts(seq, "inst indx role ports\n");
+
+ hba = core_get_hba_from_id(iterp->ti_offset, 0);
+ if (!(hba)) {
+ /* Log error ? */
+ return 0;
+ }
+
+ spin_lock(&hba->device_lock);
+ dev = (se_device_t *)iterp->ti_ptr;
+ if ((dev)) {
+ char str[28];
+
+ seq_printf(seq, "%u %u %s %u\n", hba->hba_index,
+ dev->dev_index, "Target", dev->dev_port_count);
+
+ memcpy(&str[0], (void *)DEV_T10_WWN(dev), 28);
+
+ /* vendor */
+ for (k = 0; k < 8; k++)
+ str[k] = ISPRINT(DEV_T10_WWN(dev)->vendor[k]) ?
+ DEV_T10_WWN(dev)->vendor[k] : 0x20;
+ str[k] = 0x20;
+
+ /* model */
+ for (k = 0; k < 16; k++)
+ str[k+9] = ISPRINT(DEV_T10_WWN(dev)->model[k]) ?
+ DEV_T10_WWN(dev)->model[k] : 0x20;
+ str[k + 9] = 0;
+
+ seq_printf(seq, "dev_alias: %s\n", str);
+ }
+ spin_unlock(&hba->device_lock);
+
+ /* Release the semaphore */
+ core_put_hba(hba);
+
+ return 0;
+}
+
+static const struct seq_operations scsi_dev_seq_ops = {
+ .start = scsi_dev_seq_start,
+ .next = scsi_dev_seq_next,
+ .stop = scsi_dev_seq_stop,
+ .show = scsi_dev_seq_show
+};
+
+static int scsi_dev_seq_open(struct inode *inode, struct file *file)
+{
+ return seq_open(file, &scsi_dev_seq_ops);
+}
+
+static const struct file_operations scsi_dev_seq_fops = {
+ .owner = THIS_MODULE,
+ .open = scsi_dev_seq_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release,
+};
+
+/*
+ * SCSI Port Table
+ */
+static void *scsi_port_seq_start(struct seq_file *seq, loff_t *pos)
+{
+ return locate_hba_start(seq, pos, &do_hba_check);
+}
+
+static void *scsi_port_seq_next(struct seq_file *seq, void *v, loff_t *pos)
+{
+ return locate_hba_next(seq, v, pos, &do_hba_check);
+}
+
+static void scsi_port_seq_stop(struct seq_file *seq, void *v)
+{
+ locate_hba_stop(seq, v);
+}
+
+static int scsi_port_seq_show(struct seq_file *seq, void *v)
+{
+ se_hba_t *hba;
+ se_device_t *dev;
+ se_port_t *sep, *sep_tmp;
+ table_iter_t *iterp = (table_iter_t *)seq->private;
+
+ if (v == SEQ_START_TOKEN)
+ seq_puts(seq, "inst device indx role busy_count\n");
+
+ hba = core_get_hba_from_id(iterp->ti_offset, 0);
+ if (!(hba)) {
+ /* Log error ? */
+ return 0;
+ }
+
+ /* FIXME: scsiPortBusyStatuses count */
+ spin_lock(&hba->device_lock);
+ dev = (se_device_t *)iterp->ti_ptr;
+ if ((dev)) {
+ spin_lock(&dev->se_port_lock);
+ list_for_each_entry_safe(sep, sep_tmp, &dev->dev_sep_list,
+ sep_list) {
+ seq_printf(seq, "%u %u %u %s%u %u\n", hba->hba_index,
+ dev->dev_index, sep->sep_index, "Device",
+ dev->dev_index, 0);
+ }
+ spin_unlock(&dev->se_port_lock);
+ }
+ spin_unlock(&hba->device_lock);
+
+ /* Release the semaphore */
+ core_put_hba(hba);
+
+ return 0;
+}
+
+static const struct seq_operations scsi_port_seq_ops = {
+ .start = scsi_port_seq_start,
+ .next = scsi_port_seq_next,
+ .stop = scsi_port_seq_stop,
+ .show = scsi_port_seq_show
+};
+
+static int scsi_port_seq_open(struct inode *inode, struct file *file)
+{
+ return seq_open(file, &scsi_port_seq_ops);
+}
+
+static const struct file_operations scsi_port_seq_fops = {
+ .owner = THIS_MODULE,
+ .open = scsi_port_seq_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release,
+};
+
+/*
+ * SCSI Transport Table
+ */
+static void *scsi_transport_seq_start(struct seq_file *seq, loff_t *pos)
+{
+ return locate_hba_start(seq, pos, &do_hba_check);
+}
+
+static void *scsi_transport_seq_next(struct seq_file *seq, void *v, loff_t *pos)
+{
+ return locate_hba_next(seq, v, pos, &do_hba_check);
+}
+
+static void scsi_transport_seq_stop(struct seq_file *seq, void *v)
+{
+ locate_hba_stop(seq, v);
+}
+
+static int scsi_transport_seq_show(struct seq_file *seq, void *v)
+{
+ se_hba_t *hba;
+ se_device_t *dev;
+ table_iter_t *iterp = (table_iter_t *)seq->private;
+ se_port_t *se, *se_tmp;
+ se_portal_group_t *tpg;
+ t10_wwn_t *wwn;
+ char buf[64];
+
+ if (v == SEQ_START_TOKEN)
+ seq_puts(seq, "inst device indx dev_name\n");
+
+ hba = core_get_hba_from_id(iterp->ti_offset, 0);
+ if (!(hba)) {
+ /* Log error ? */
+ return 0;
+ }
+
+ spin_lock(&hba->device_lock);
+ dev = (se_device_t *)iterp->ti_ptr;
+ if ((dev)) {
+ wwn = DEV_T10_WWN(dev);
+
+ spin_lock(&dev->se_port_lock);
+ list_for_each_entry_safe(se, se_tmp, &dev->dev_sep_list,
+ sep_list) {
+ tpg = se->sep_tpg;
+ sprintf(buf, "scsiTransport%s",
+ TPG_TFO(tpg)->get_fabric_name());
+
+ seq_printf(seq, "%u %s %u %s+%s\n",
+ hba->hba_index, /* scsiTransportIndex */
+ buf, /* scsiTransportType */
+ TPG_TFO(tpg)->tpg_get_inst_index(tpg),
+ TPG_TFO(tpg)->tpg_get_wwn(tpg),
+ (strlen(wwn->unit_serial)) ?
+ /* scsiTransportDevName */
+ wwn->unit_serial : wwn->vendor);
+ }
+ spin_unlock(&dev->se_port_lock);
+ }
+ spin_unlock(&hba->device_lock);
+
+ /* Release the semaphore */
+ core_put_hba(hba);
+
+ return 0;
+}
+
+static const struct seq_operations scsi_transport_seq_ops = {
+ .start = scsi_transport_seq_start,
+ .next = scsi_transport_seq_next,
+ .stop = scsi_transport_seq_stop,
+ .show = scsi_transport_seq_show
+};
+
+static int scsi_transport_seq_open(struct inode *inode, struct file *file)
+{
+ return seq_open(file, &scsi_transport_seq_ops);
+}
+
+static const struct file_operations scsi_transport_seq_fops = {
+ .owner = THIS_MODULE,
+ .open = scsi_transport_seq_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release,
+};
+
+/*
+ * SCSI Target Device Table
+ */
+static void *scsi_tgt_dev_seq_start(struct seq_file *seq, loff_t *pos)
+{
+ return locate_hba_start(seq, pos, &do_hba_check);
+}
+
+static void *scsi_tgt_dev_seq_next(struct seq_file *seq, void *v, loff_t *pos)
+{
+ return locate_hba_next(seq, v, pos, &do_hba_check);
+}
+
+static void scsi_tgt_dev_seq_stop(struct seq_file *seq, void *v)
+{
+ locate_hba_stop(seq, v);
+}
+
+
+#define LU_COUNT 1 /* for now */
+static int scsi_tgt_dev_seq_show(struct seq_file *seq, void *v)
+{
+ se_hba_t *hba;
+ se_device_t *dev;
+ table_iter_t *iterp = (table_iter_t *)seq->private;
+ int non_accessible_lus = 0;
+ char status[16];
+
+ if (v == SEQ_START_TOKEN)
+ seq_puts(seq, "inst indx num_LUs status non_access_LUs"
+ " resets\n");
+
+ hba = core_get_hba_from_id(iterp->ti_offset, 0);
+ if (!(hba)) {
+ /* Log error ? */
+ return 0;
+ }
+
+ spin_lock(&hba->device_lock);
+ dev = (se_device_t *)iterp->ti_ptr;
+ if ((dev)) {
+ switch (dev->dev_status) {
+ case TRANSPORT_DEVICE_ACTIVATED:
+ strcpy(status, "activated");
+ break;
+ case TRANSPORT_DEVICE_DEACTIVATED:
+ strcpy(status, "deactivated");
+ non_accessible_lus = 1;
+ break;
+ case TRANSPORT_DEVICE_SHUTDOWN:
+ strcpy(status, "shutdown");
+ non_accessible_lus = 1;
+ break;
+ case TRANSPORT_DEVICE_OFFLINE_ACTIVATED:
+ case TRANSPORT_DEVICE_OFFLINE_DEACTIVATED:
+ strcpy(status, "offline");
+ non_accessible_lus = 1;
+ break;
+ default:
+ sprintf(status, "unknown(%d)", dev->dev_status);
+ non_accessible_lus = 1;
+ }
+
+ seq_printf(seq, "%u %u %u %s %u %u\n",
+ hba->hba_index, dev->dev_index, LU_COUNT,
+ status, non_accessible_lus, dev->num_resets);
+ }
+ spin_unlock(&hba->device_lock);
+
+ /* Release the semaphore */
+ core_put_hba(hba);
+
+ return 0;
+}
+
+static const struct seq_operations scsi_tgt_dev_seq_ops = {
+ .start = scsi_tgt_dev_seq_start,
+ .next = scsi_tgt_dev_seq_next,
+ .stop = scsi_tgt_dev_seq_stop,
+ .show = scsi_tgt_dev_seq_show
+};
+
+static int scsi_tgt_dev_seq_open(struct inode *inode, struct file *file)
+{
+ return seq_open(file, &scsi_tgt_dev_seq_ops);
+}
+
+static const struct file_operations scsi_tgt_dev_seq_fops = {
+ .owner = THIS_MODULE,
+ .open = scsi_tgt_dev_seq_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release,
+};
+
+/*
+ * SCSI Target Port Table
+ */
+static void *scsi_tgt_port_seq_start(struct seq_file *seq, loff_t *pos)
+{
+ return locate_hba_start(seq, pos, &do_hba_check);
+}
+
+static void *scsi_tgt_port_seq_next(struct seq_file *seq, void *v, loff_t *pos)
+{
+ return locate_hba_next(seq, v, pos, &do_hba_check);
+}
+
+static void scsi_tgt_port_seq_stop(struct seq_file *seq, void *v)
+{
+ locate_hba_stop(seq, v);
+}
+
+static int scsi_tgt_port_seq_show(struct seq_file *seq, void *v)
+{
+ se_hba_t *hba;
+ se_device_t *dev;
+ se_port_t *sep, *sep_tmp;
+ se_portal_group_t *tpg;
+ table_iter_t *iterp = (table_iter_t *)seq->private;
+ u32 rx_mbytes, tx_mbytes;
+ unsigned long long num_cmds;
+ char buf[64];
+
+ if (v == SEQ_START_TOKEN)
+ seq_puts(seq, "inst device indx name port_index in_cmds"
+ " write_mbytes read_mbytes hs_in_cmds\n");
+
+ hba = core_get_hba_from_id(iterp->ti_offset, 0);
+ if (!(hba)) {
+ /* Log error ? */
+ return 0;
+ }
+
+ spin_lock(&hba->device_lock);
+ dev = (se_device_t *)iterp->ti_ptr;
+ if ((dev)) {
+ spin_lock(&dev->se_port_lock);
+ list_for_each_entry_safe(sep, sep_tmp, &dev->dev_sep_list,
+ sep_list) {
+ tpg = sep->sep_tpg;
+ sprintf(buf, "%sPort#",
+ TPG_TFO(tpg)->get_fabric_name());
+
+ seq_printf(seq, "%u %u %u %s%d %s%s%d ",
+ hba->hba_index,
+ dev->dev_index,
+ sep->sep_index,
+ buf, sep->sep_index,
+ TPG_TFO(tpg)->tpg_get_wwn(tpg), "+t+",
+ TPG_TFO(tpg)->tpg_get_tag(tpg));
+
+ spin_lock(&sep->sep_lun->lun_sep_lock);
+ num_cmds = sep->sep_stats.cmd_pdus;
+ rx_mbytes = (sep->sep_stats.rx_data_octets >> 20);
+ tx_mbytes = (sep->sep_stats.tx_data_octets >> 20);
+ spin_unlock(&sep->sep_lun->lun_sep_lock);
+
+ seq_printf(seq, "%llu %u %u %u\n", num_cmds,
+ rx_mbytes, tx_mbytes, 0);
+ }
+ spin_unlock(&dev->se_port_lock);
+ }
+ spin_unlock(&hba->device_lock);
+
+ /* Release the semaphore */
+ core_put_hba(hba);
+
+ return 0;
+}
+
+static const struct seq_operations scsi_tgt_port_seq_ops = {
+ .start = scsi_tgt_port_seq_start,
+ .next = scsi_tgt_port_seq_next,
+ .stop = scsi_tgt_port_seq_stop,
+ .show = scsi_tgt_port_seq_show
+};
+
+static int scsi_tgt_port_seq_open(struct inode *inode, struct file *file)
+{
+ return seq_open(file, &scsi_tgt_port_seq_ops);
+}
+
+static const struct file_operations scsi_tgt_port_seq_fops = {
+ .owner = THIS_MODULE,
+ .open = scsi_tgt_port_seq_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release,
+};
+
+/*
+ * SCSI Authorized Initiator Table:
+ * It contains the SCSI Initiators authorized to be attached to one of the
+ * local Target ports.
+ * Iterates through all active TPGs and extracts the info from the ACLs
+ */
+static void *scsi_auth_intr_seq_start(struct seq_file *seq, loff_t *pos)
+{
+ spin_lock_bh(&se_global->se_tpg_lock);
+ return seq_list_start(&se_global->g_se_tpg_list, *pos);
+}
+
+static void *scsi_auth_intr_seq_next(struct seq_file *seq, void *v,
+ loff_t *pos)
+{
+ return seq_list_next(v, &se_global->g_se_tpg_list, pos);
+}
+
+static void scsi_auth_intr_seq_stop(struct seq_file *seq, void *v)
+{
+ spin_unlock_bh(&se_global->se_tpg_lock);
+}
+
+static inline int list_is_first(const struct list_head *list,
+ const struct list_head *head)
+{
+ return list->prev == head;
+}
+
+static int scsi_auth_intr_seq_show(struct seq_file *seq, void *v)
+{
+ se_portal_group_t *se_tpg = list_entry(v, se_portal_group_t,
+ se_tpg_list);
+ se_dev_entry_t *deve;
+ se_lun_t *lun;
+ se_node_acl_t *se_nacl;
+ int j;
+
+ if (list_is_first(&se_tpg->se_tpg_list,
+ &se_global->g_se_tpg_list))
+ seq_puts(seq, "inst dev port indx dev_or_port intr_name "
+ "map_indx att_count num_cmds read_mbytes "
+ "write_mbytes hs_num_cmds creation_time row_status\n");
+
+ if (!(se_tpg))
+ return 0;
+
+ spin_lock(&se_tpg->acl_node_lock);
+ list_for_each_entry(se_nacl, &se_tpg->acl_node_list, acl_list) {
+ spin_lock(&se_nacl->device_list_lock);
+ for (j = 0; j < TRANSPORT_MAX_LUNS_PER_TPG; j++) {
+ deve = &se_nacl->device_list[j];
+ if (!(deve->lun_flags &
+ TRANSPORT_LUNFLAGS_INITIATOR_ACCESS) ||
+ (!deve->se_lun))
+ continue;
+ lun = deve->se_lun;
+ if ((lun->lun_type != TRANSPORT_LUN_TYPE_DEVICE) ||
+ (!lun->se_dev))
+ continue;
+
+ seq_printf(seq,"%u %u %u %u %u %s %u %u %u %u %u %u"
+ " %u %s\n",
+ /* scsiInstIndex */
+ TPG_TFO(se_tpg)->tpg_get_inst_index(se_tpg),
+ /* scsiDeviceIndex */
+ lun->se_dev->dev_index,
+ /* scsiAuthIntrTgtPortIndex */
+ TPG_TFO(se_tpg)->tpg_get_tag(se_tpg),
+ /* scsiAuthIntrIndex */
+ se_nacl->acl_index,
+ /* scsiAuthIntrDevOrPort */
+ 1,
+ /* scsiAuthIntrName */
+ se_nacl->initiatorname[0] ?
+ se_nacl->initiatorname : NONE,
+ /* FIXME: scsiAuthIntrLunMapIndex */
+ 0,
+ /* scsiAuthIntrAttachedTimes */
+ deve->attach_count,
+ /* scsiAuthIntrOutCommands */
+ deve->total_cmds,
+ /* scsiAuthIntrReadMegaBytes */
+ (u32)(deve->read_bytes >> 20),
+ /* scsiAuthIntrWrittenMegaBytes */
+ (u32)(deve->write_bytes >> 20),
+ /* FIXME: scsiAuthIntrHSOutCommands */
+ 0,
+ /* scsiAuthIntrLastCreation */
+ (u32)(((u32)deve->creation_time -
+ INITIAL_JIFFIES) * 100 / HZ),
+ /* FIXME: scsiAuthIntrRowStatus */
+ "Ready");
+ }
+ spin_unlock(&se_nacl->device_list_lock);
+ }
+ spin_unlock(&se_tpg->acl_node_lock);
+
+ return 0;
+}
+
+static const struct seq_operations scsi_auth_intr_seq_ops = {
+ .start = scsi_auth_intr_seq_start,
+ .next = scsi_auth_intr_seq_next,
+ .stop = scsi_auth_intr_seq_stop,
+ .show = scsi_auth_intr_seq_show
+};
+
+static int scsi_auth_intr_seq_open(struct inode *inode, struct file *file)
+{
+ return seq_open(file, &scsi_auth_intr_seq_ops);
+}
+
+static const struct file_operations scsi_auth_intr_seq_fops = {
+ .owner = THIS_MODULE,
+ .open = scsi_auth_intr_seq_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release,
+};
+
+/*
+ * SCSI Attached Initiator Port Table:
+ * It lists the SCSI Initiators attached to one of the local Target ports.
+ * Iterates through all active TPGs and use active sessions from each TPG
+ * to list the info fo this table.
+ */
+static void *scsi_att_intr_port_seq_start(struct seq_file *seq, loff_t *pos)
+{
+ spin_lock_bh(&se_global->se_tpg_lock);
+ return seq_list_start(&se_global->g_se_tpg_list, *pos);
+}
+
+static void *scsi_att_intr_port_seq_next(struct seq_file *seq, void *v,
+ loff_t *pos)
+{
+ return seq_list_next(v, &se_global->g_se_tpg_list, pos);
+}
+
+static void scsi_att_intr_port_seq_stop(struct seq_file *seq, void *v)
+{
+ spin_unlock_bh(&se_global->se_tpg_lock);
+}
+
+static int scsi_att_intr_port_seq_show(struct seq_file *seq, void *v)
+{
+ se_portal_group_t *se_tpg = list_entry(v, se_portal_group_t,
+ se_tpg_list);
+ se_dev_entry_t *deve;
+ se_lun_t *lun;
+ se_node_acl_t *se_nacl;
+ se_session_t *se_sess;
+ unsigned char buf[64];
+ int j;
+
+ if (list_is_first(&se_tpg->se_tpg_list,
+ &se_global->g_se_tpg_list))
+ seq_puts(seq, "inst dev port indx port_auth_indx port_name"
+ " port_ident\n");
+
+ if (!(se_tpg))
+ return 0;
+
+ spin_lock(&se_tpg->session_lock);
+ list_for_each_entry(se_sess, &se_tpg->tpg_sess_list, sess_list) {
+ if ((TPG_TFO(se_tpg)->sess_logged_in(se_sess)) ||
+ (!se_sess->se_node_acl) ||
+ (!se_sess->se_node_acl->device_list))
+ continue;
+
+ se_nacl = se_sess->se_node_acl;
+
+ spin_lock(&se_nacl->device_list_lock);
+ for (j = 0; j < TRANSPORT_MAX_LUNS_PER_TPG; j++) {
+ deve = &se_nacl->device_list[j];
+ if (!(deve->lun_flags &
+ TRANSPORT_LUNFLAGS_INITIATOR_ACCESS) ||
+ (!deve->se_lun))
+ continue;
+
+ lun = deve->se_lun;
+ if ((lun->lun_type != TRANSPORT_LUN_TYPE_DEVICE) ||
+ (!lun->se_dev))
+ continue;
+
+ memset(buf, 0, 64);
+ TPG_TFO(se_tpg)->sess_get_initiator_wwn(se_sess,
+ (unsigned char *)&buf[0], 64);
+
+ seq_printf(seq,"%u %u %u %u %u %s+i+%s\n",
+ /* scsiInstIndex */
+ TPG_TFO(se_tpg)->tpg_get_inst_index(se_tpg),
+ /* scsiDeviceIndex */
+ lun->se_dev->dev_index,
+ /* scsiPortIndex */
+ TPG_TFO(se_tpg)->tpg_get_tag(se_tpg),
+ /* scsiAttIntrPortIndex */
+ TPG_TFO(se_tpg)->sess_get_index(se_sess),
+ /* scsiAttIntrPortAuthIntrIdx */
+ se_nacl->acl_index,
+ /* scsiAttIntrPortName */
+ se_nacl->initiatorname[0] ?
+ se_nacl->initiatorname : NONE,
+ /* scsiAttIntrPortIdentifier */
+ buf);
+ }
+ spin_unlock(&se_nacl->device_list_lock);
+ }
+ spin_unlock(&se_tpg->session_lock);
+
+ return 0;
+}
+
+static const struct seq_operations scsi_att_intr_port_seq_ops = {
+ .start = scsi_att_intr_port_seq_start,
+ .next = scsi_att_intr_port_seq_next,
+ .stop = scsi_att_intr_port_seq_stop,
+ .show = scsi_att_intr_port_seq_show
+};
+
+static int scsi_att_intr_port_seq_open(struct inode *inode, struct file *file)
+{
+ return seq_open(file, &scsi_att_intr_port_seq_ops);
+}
+
+static const struct file_operations scsi_att_intr_port_seq_fops = {
+ .owner = THIS_MODULE,
+ .open = scsi_att_intr_port_seq_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release,
+};
+
+/*
+ * SCSI Logical Unit Table
+ */
+static void *scsi_lu_seq_start(struct seq_file *seq, loff_t *pos)
+{
+ return locate_hba_start(seq, pos, &do_hba_check);
+}
+
+static void *scsi_lu_seq_next(struct seq_file *seq, void *v, loff_t *pos)
+{
+ return locate_hba_next(seq, v, pos, &do_hba_check);
+}
+
+static void scsi_lu_seq_stop(struct seq_file *seq, void *v)
+{
+ locate_hba_stop(seq, v);
+}
+
+#define SCSI_LU_INDEX 1
+static int scsi_lu_seq_show(struct seq_file *seq, void *v)
+{
+ se_hba_t *hba;
+ se_device_t *dev;
+ table_iter_t *iterp = (table_iter_t *)seq->private;
+ int j;
+ char str[28];
+
+ if (v == SEQ_START_TOKEN)
+ seq_puts(seq, "inst dev indx LUN lu_name vend prod rev"
+ " dev_type status state-bit num_cmds read_mbytes"
+ " write_mbytes resets full_stat hs_num_cmds creation_time\n");
+
+ hba = core_get_hba_from_id(iterp->ti_offset, 0);
+ if (!(hba)) {
+ /* Log error ? */
+ return 0;
+ }
+
+ spin_lock(&hba->device_lock);
+ dev = (se_device_t *)iterp->ti_ptr;
+ if ((dev)) {
+ /* Fix LU state, if we can read it from the device */
+ seq_printf(seq, "%u %u %u %llu %s", hba->hba_index,
+ dev->dev_index, SCSI_LU_INDEX,
+ (unsigned long long)0, /* FIXME: scsiLuDefaultLun */
+ (strlen(DEV_T10_WWN(dev)->unit_serial)) ?
+ /* scsiLuWwnName */
+ (char *)&DEV_T10_WWN(dev)->unit_serial[0] :
+ "None");
+
+ memcpy(&str[0], (void *)DEV_T10_WWN(dev), 28);
+ /* scsiLuVendorId */
+ for (j = 0; j < 8; j++)
+ str[j] = ISPRINT(DEV_T10_WWN(dev)->vendor[j]) ?
+ DEV_T10_WWN(dev)->vendor[j] : 0x20;
+ str[8] = 0;
+ seq_printf(seq, " %s", str);
+
+ /* scsiLuProductId */
+ for (j = 0; j < 16; j++)
+ str[j] = ISPRINT(DEV_T10_WWN(dev)->model[j]) ?
+ DEV_T10_WWN(dev)->model[j] : 0x20;
+ str[16] = 0;
+ seq_printf(seq, " %s", str);
+
+ /* scsiLuRevisionId */
+ for (j = 0; j < 4; j++)
+ str[j] = ISPRINT(DEV_T10_WWN(dev)->revision[j]) ?
+ DEV_T10_WWN(dev)->revision[j] : 0x20;
+ str[4] = 0;
+ seq_printf(seq, " %s", str);
+
+ seq_printf(seq, " %u %s %s %llu %u %u %u %u %u %u\n",
+ /* scsiLuPeripheralType */
+ dev->dev_obj_api->get_device_type((void *)dev),
+ (dev->dev_status == TRANSPORT_DEVICE_ACTIVATED) ?
+ "available" : "notavailable", /* scsiLuStatus */
+ "exposed", /* scsiLuState */
+ (unsigned long long)dev->num_cmds,
+ /* scsiLuReadMegaBytes */
+ (u32)(dev->read_bytes >> 20),
+ /* scsiLuWrittenMegaBytes */
+ (u32)(dev->write_bytes >> 20),
+ dev->num_resets, /* scsiLuInResets */
+ 0, /* scsiLuOutTaskSetFullStatus */
+ 0, /* scsiLuHSInCommands */
+ (u32)(((u32)dev->creation_time - INITIAL_JIFFIES) *
+ 100 / HZ));
+ }
+ spin_unlock(&hba->device_lock);
+
+ /* Release the semaphore */
+ core_put_hba(hba);
+
+ return 0;
+}
+
+static const struct seq_operations scsi_lu_seq_ops = {
+ .start = scsi_lu_seq_start,
+ .next = scsi_lu_seq_next,
+ .stop = scsi_lu_seq_stop,
+ .show = scsi_lu_seq_show
+};
+
+static int scsi_lu_seq_open(struct inode *inode, struct file *file)
+{
+ return seq_open(file, &scsi_lu_seq_ops);
+}
+
+static const struct file_operations scsi_lu_seq_fops = {
+ .owner = THIS_MODULE,
+ .open = scsi_lu_seq_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release,
+};
+
+/****************************************************************************/
+
+/*
+ * Remove proc fs entries
+ */
+void remove_scsi_target_mib(void)
+{
+ remove_proc_entry("scsi_target/mib/scsi_inst", NULL);
+ remove_proc_entry("scsi_target/mib/scsi_dev", NULL);
+ remove_proc_entry("scsi_target/mib/scsi_port", NULL);
+ remove_proc_entry("scsi_target/mib/scsi_transport", NULL);
+ remove_proc_entry("scsi_target/mib/scsi_tgt_dev", NULL);
+ remove_proc_entry("scsi_target/mib/scsi_tgt_port", NULL);
+ remove_proc_entry("scsi_target/mib/scsi_auth_intr", NULL);
+ remove_proc_entry("scsi_target/mib/scsi_att_intr_port", NULL);
+ remove_proc_entry("scsi_target/mib/scsi_lu", NULL);
+ remove_proc_entry("scsi_target/mib", NULL);
+}
+
+/*
+ * Create proc fs entries for the mib tables
+ */
+int init_scsi_target_mib(void)
+{
+ struct proc_dir_entry *dir_entry;
+ struct proc_dir_entry *scsi_inst_entry;
+ struct proc_dir_entry *scsi_dev_entry;
+ struct proc_dir_entry *scsi_port_entry;
+ struct proc_dir_entry *scsi_transport_entry;
+ struct proc_dir_entry *scsi_tgt_dev_entry;
+ struct proc_dir_entry *scsi_tgt_port_entry;
+ struct proc_dir_entry *scsi_auth_intr_entry;
+ struct proc_dir_entry *scsi_att_intr_port_entry;
+ struct proc_dir_entry *scsi_lu_entry;
+
+ dir_entry = proc_mkdir("scsi_target/mib", NULL);
+ if (!(dir_entry)) {
+ printk("proc_mkdir() failed.\n");
+ return -1;
+ }
+
+ scsi_inst_entry =
+ create_proc_entry("scsi_target/mib/scsi_inst", 0, NULL);
+ if (scsi_inst_entry)
+ scsi_inst_entry->proc_fops = &scsi_inst_seq_fops;
+ else
+ goto error;
+
+ scsi_dev_entry =
+ create_proc_entry("scsi_target/mib/scsi_dev", 0, NULL);
+ if (scsi_dev_entry)
+ scsi_dev_entry->proc_fops = &scsi_dev_seq_fops;
+ else
+ goto error;
+
+ scsi_port_entry =
+ create_proc_entry("scsi_target/mib/scsi_port", 0, NULL);
+ if (scsi_port_entry)
+ scsi_port_entry->proc_fops = &scsi_port_seq_fops;
+ else
+ goto error;
+
+ scsi_transport_entry =
+ create_proc_entry("scsi_target/mib/scsi_transport", 0, NULL);
+ if (scsi_transport_entry)
+ scsi_transport_entry->proc_fops = &scsi_transport_seq_fops;
+ else
+ goto error;
+
+ scsi_tgt_dev_entry =
+ create_proc_entry("scsi_target/mib/scsi_tgt_dev", 0, NULL);
+ if (scsi_tgt_dev_entry)
+ scsi_tgt_dev_entry->proc_fops = &scsi_tgt_dev_seq_fops;
+ else
+ goto error;
+
+ scsi_tgt_port_entry =
+ create_proc_entry("scsi_target/mib/scsi_tgt_port", 0, NULL);
+ if (scsi_tgt_port_entry)
+ scsi_tgt_port_entry->proc_fops = &scsi_tgt_port_seq_fops;
+ else
+ goto error;
+
+ scsi_auth_intr_entry =
+ create_proc_entry("scsi_target/mib/scsi_auth_intr", 0, NULL);
+ if (scsi_auth_intr_entry)
+ scsi_auth_intr_entry->proc_fops = &scsi_auth_intr_seq_fops;
+ else
+ goto error;
+
+ scsi_att_intr_port_entry =
+ create_proc_entry("scsi_target/mib/scsi_att_intr_port", 0, NULL);
+ if (scsi_att_intr_port_entry)
+ scsi_att_intr_port_entry->proc_fops =
+ &scsi_att_intr_port_seq_fops;
+ else
+ goto error;
+
+ scsi_lu_entry = create_proc_entry("scsi_target/mib/scsi_lu", 0, NULL);
+ if (scsi_lu_entry)
+ scsi_lu_entry->proc_fops = &scsi_lu_seq_fops;
+ else
+ goto error;
+
+ return 0;
+
+error:
+ printk(KERN_ERR "create_proc_entry() failed.\n");
+ remove_scsi_target_mib();
+ return -1;
+}
+
+/*
+ * Initialize the index table for allocating unique row indexes to various mib
+ * tables
+ */
+void init_scsi_index_table(void)
+{
+ memset(&scsi_index_table, 0, sizeof(scsi_index_table));
+ spin_lock_init(&scsi_index_table.lock);
+}
+
+/*
+ * Allocate a new row index for the entry type specified
+ */
+u32 scsi_get_new_index(scsi_index_t type)
+{
+ u32 new_index;
+
+ if ((type < 0) || (type >= SCSI_INDEX_TYPE_MAX)) {
+ printk(KERN_ERR "Invalid index type %d\n", type);
+ return -1;
+ }
+
+ spin_lock(&scsi_index_table.lock);
+ new_index = ++scsi_index_table.scsi_mib_index[type];
+ if (new_index == 0)
+ new_index = ++scsi_index_table.scsi_mib_index[type];
+ spin_unlock(&scsi_index_table.lock);
+
+ return new_index;
+}
+EXPORT_SYMBOL(scsi_get_new_index);
diff --git a/include/target/target_core_mib.h b/include/target/target_core_mib.h
new file mode 100644
index 0000000..36cacd5
--- /dev/null
+++ b/include/target/target_core_mib.h
@@ -0,0 +1,57 @@
+/*******************************************************************************
+ * Filename: target_core_mib.h
+ *
+ * Copyright (c) 2006 SBE, Inc. All Rights Reserved.
+ * Copyright (c) 2007-2009 Rising Tide Software, Inc.
+ * Copyright (c) 2008-2009 Linux-iSCSI.org
+ *
+ * Nicholas A. Bellinger <nab@...ux-iscsi.org>
+ *
+ * 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 of the License, 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; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ ******************************************************************************/
+
+
+#ifndef TARGET_CORE_MIB_H
+#define TARGET_CORE_MIB_H
+
+extern struct se_global_s *se_global;
+
+typedef enum {
+ SCSI_INST_INDEX,
+ SCSI_DEVICE_INDEX,
+ SCSI_AUTH_INTR_INDEX,
+ SCSI_INDEX_TYPE_MAX
+} scsi_index_t;
+
+typedef struct scsi_index_table_s {
+ spinlock_t lock;
+ u32 scsi_mib_index[SCSI_INDEX_TYPE_MAX];
+} scsi_index_table_t;
+
+/* SCSI Port stats */
+typedef struct scsi_port_stats_s {
+ u64 cmd_pdus;
+ u64 tx_data_octets;
+ u64 rx_data_octets;
+} scsi_port_stats_t;
+
+extern int init_scsi_target_mib(void);
+extern void remove_scsi_target_mib(void);
+extern void init_scsi_index_table(void);
+extern u32 scsi_get_new_index(scsi_index_t);
+
+#endif /*** TARGET_CORE_MIB_H ***/
+
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
Powered by blists - more mailing lists