From 70370760fb68cef9c7004b48fcdc6c7b4ac0cf42 Mon Sep 17 00:00:00 2001 From: Nicholas Bellinger Date: Mon, 30 Aug 2010 08:00:28 +0000 Subject: [RFC 08/22] tcm: Add HBA core infrastructure This patch adds the core struct se_hba functionality that is used internally by target_core_mod to group the same subsystem storage objects types until a single /sys/kernel/config/target/core/$HBA directory. The HBA code supports boths physical storage objects (from Linux/SCSI) and virtual storage objects (from Linux/BLOCK, Linux/VFS, RAMDISK) Signed-off-by: Nicholas A. Bellinger --- drivers/target/target_core_hba.c | 211 ++++++++++++++++++++++++++++++++++++++ drivers/target/target_core_hba.h | 14 +++ 2 files changed, 225 insertions(+), 0 deletions(-) create mode 100644 drivers/target/target_core_hba.c create mode 100644 drivers/target/target_core_hba.h diff --git a/drivers/target/target_core_hba.c b/drivers/target/target_core_hba.c new file mode 100644 index 0000000..d9e286c --- /dev/null +++ b/drivers/target/target_core_hba.c @@ -0,0 +1,211 @@ +/******************************************************************************* + * Filename: target_core_hba.c + * + * This file copntains the iSCSI HBA Transport related functions. + * + * Copyright (c) 2003, 2004, 2005 PyX Technologies, Inc. + * Copyright (c) 2005, 2006, 2007 SBE, Inc. + * Copyright (c) 2007-2010 Rising Tide Systems + * Copyright (c) 2008-2010 Linux-iSCSI.org + * + * Nicholas A. Bellinger + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "target_core_hba.h" + +int core_get_hba(struct se_hba *hba) +{ + return ((mutex_lock_interruptible(&hba->hba_access_mutex) != 0) ? + -1 : 0); +} + +struct se_hba *core_alloc_hba(void) +{ + struct se_hba *hba; + + hba = kmem_cache_zalloc(se_hba_cache, GFP_KERNEL); + if (!(hba)) { + printk(KERN_ERR "Unable to allocate struct se_hba\n"); + return NULL; + } + + hba->hba_status |= HBA_STATUS_FREE; + INIT_LIST_HEAD(&hba->hba_dev_list); + spin_lock_init(&hba->device_lock); + spin_lock_init(&hba->hba_queue_lock); + mutex_init(&hba->hba_access_mutex); + hba->hba_index = scsi_get_new_index(SCSI_INST_INDEX); + + return hba; +} +EXPORT_SYMBOL(core_alloc_hba); + +void core_put_hba(struct se_hba *hba) +{ + mutex_unlock(&hba->hba_access_mutex); +} +EXPORT_SYMBOL(core_put_hba); + +/* se_core_add_hba(): + * + * + */ +int se_core_add_hba( + struct se_hba *hba, + const char *plugin_name, + u32 plugin_dep_id) +{ + struct se_subsystem_api *t; + int ret = 0; + + if (hba->hba_status & HBA_STATUS_ACTIVE) + return -EEXIST; + + atomic_set(&hba->max_queue_depth, 0); + atomic_set(&hba->left_queue_depth, 0); + + t = transport_core_get_sub_by_name(plugin_name); + if (!(t)) + return -EINVAL; + + hba->transport = t; + /* + * Get TCM subsystem api struct module reference to struct se_hba + */ + if (t->external_submod) { + if (!(t->sub_owner)) { + printk(KERN_ERR "Pointer to struct module does not" + " exist for %s\n", t->name); + hba->transport = NULL; + transport_core_put_sub(t); + return -EINVAL; + } + /* + * Grab a struct module reference count for subsystem plugin + */ + if (!(try_module_get(t->sub_owner))) { + printk(KERN_ERR "try_module_get() failed for" + " t->sub_owner\n"); + hba->transport = NULL; + transport_core_put_sub(t); + return -EINVAL; + } + } + + ret = t->attach_hba(hba, plugin_dep_id); + if (ret < 0) { + hba->transport = NULL; + if (t->external_submod) + module_put(t->sub_owner); + transport_core_put_sub(t); + return ret; + } + + hba->hba_status &= ~HBA_STATUS_FREE; + hba->hba_status |= HBA_STATUS_ACTIVE; + + spin_lock(&se_global->hba_lock); + hba->hba_id = se_global->g_hba_id_counter++; + list_add_tail(&hba->hba_list, &se_global->g_hba_list); + spin_unlock(&se_global->hba_lock); + + printk(KERN_INFO "CORE_HBA[%d] - Attached HBA to Generic Target" + " Core\n", hba->hba_id); + + return 0; +} +EXPORT_SYMBOL(se_core_add_hba); + +static int se_core_shutdown_hba( + struct se_hba *hba) +{ + struct se_subsystem_api *t = hba->transport;; + + if (t->detach_hba(hba) < 0) + return -1; + /* + * Release TCM subsystem api struct module reference from struct se_hba + */ + if (t->external_submod) + module_put(t->sub_owner); + + return 0; +} + +/* se_core_del_hba(): + * + * + */ +int se_core_del_hba( + struct se_hba *hba) +{ + struct se_device *dev, *dev_tmp; + + if (!(hba->hba_status & HBA_STATUS_ACTIVE)) { + printk(KERN_ERR "HBA ID: %d Status: INACTIVE, ignoring" + " delhbafromtarget request\n", hba->hba_id); + return -EINVAL; + } + + spin_lock(&hba->device_lock); + list_for_each_entry_safe(dev, dev_tmp, &hba->hba_dev_list, dev_list) { + + se_clear_dev_ports(dev); + spin_unlock(&hba->device_lock); + + se_release_device_for_hba(dev); + + spin_lock(&hba->device_lock); + } + spin_unlock(&hba->device_lock); + + se_core_shutdown_hba(hba); + if (!(hba->hba_flags & HBA_FLAGS_INTERNAL_USE)) + transport_core_put_sub(hba->transport); + + spin_lock(&se_global->hba_lock); + list_del(&hba->hba_list); + spin_unlock(&se_global->hba_lock); + + hba->transport = NULL; + hba->hba_status &= ~HBA_STATUS_ACTIVE; + hba->hba_status |= HBA_STATUS_FREE; + + printk(KERN_INFO "CORE_HBA[%d] - Detached HBA from Generic Target" + " Core\n", hba->hba_id); + + kmem_cache_free(se_hba_cache, hba); + return 0; +} +EXPORT_SYMBOL(se_core_del_hba); diff --git a/drivers/target/target_core_hba.h b/drivers/target/target_core_hba.h new file mode 100644 index 0000000..01cf4fe --- /dev/null +++ b/drivers/target/target_core_hba.h @@ -0,0 +1,14 @@ +#ifndef TARGET_CORE_HBA_H +#define TARGET_CORE_HBA_H + +extern struct se_global *se_global; + +extern struct kmem_cache *se_hba_cache; + +extern int core_get_hba(struct se_hba *); +extern struct se_hba *core_alloc_hba(void); +extern void core_put_hba(struct se_hba *); +extern int se_core_add_hba(struct se_hba *, const char *, u32); +extern int se_core_del_hba(struct se_hba *); + +#endif /* TARGET_CORE_HBA_H */ -- 1.7.2.2