Patch from Dorit Halsadi <Dorit.Halsadi@dothill.com> and Uri Yanai <Uri.Yanai@ngsoft.com> adding NPIV support to the SCST Target driver for Qlogic 24xx/25xx Fibre Channel cards

with minor fixes.

Note: you need NPIV-supporting firmware as well as NPIV-supporting switches to use NPIV.



git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@2408 d57e44dd-8a1f-0410-8b47-8ef2f437770f
This commit is contained in:
Vladislav Bolkhovitin
2010-10-14 18:11:22 +00:00
parent a2dc603642
commit 1af1e674d4
12 changed files with 841 additions and 141 deletions

View File

@@ -1,8 +1,17 @@
Summary of changes between versions 2.0.0 and 2.1.0
---------------------------------------------------
- Complete NPIV support added. Particularly, now SCST core sees
all the virtual targets and provide separate target-oriented access
control for them. Thanks a lot to Uri Yanai and Dorit
Halsadi!
Summary of changes between versions 1.0.2 and 2.0.0
---------------------------------------------------
- Support for 24xx/25xx added
- Disable by default initiator mode if target mode enabled. It can be changed
using .config option CONFIG_SCSI_QLA2XXX_TARGET_DISABLE_INI_MODE.
@@ -17,7 +26,7 @@ Summary of changes between versions 1.0.1 and 1.0.2
module unload fixed
- Implemented abort on timeout of stuck in the firmware commands
Summary of changes between versions 1.0.0 and 1.0.1
---------------------------------------------------

View File

@@ -17,14 +17,6 @@ Linux kernel 2.6.26 and higher. Sorry, kernels below 2.6.26 are not
supported, because it's too hard to backport used initiator driver to
older kernels.
NPIV is partially supported by this driver. You can create virtual
targets using standard Linux interface by echoing wwpn:wwnn into
/sys/class/fc_host/hostX/vport_create and work with them, but SCST core
will not see those virtual targets and, hence, provide the
target-oriented access control for them. However, the initiator-oriented
access control will still work very well. Note, you need NPIV-supporting
firmware as well as NPIV-supporting switches to use NPIV.
The original initiator driver was taken from the kernel 2.6.26. Also the
following 2.6.26.x commits have been applied to it (upstream ID):
048feec5548c0582ee96148c61b87cccbcb5f9be,
@@ -167,6 +159,34 @@ option needs a special firmware with class 2 support. Disabled by
default.
N_Port ID Virtualization
------------------------
N_Port ID Virtualization(NPIV) is a Fibre Channel facility allowing
multiple N_Port IDs to share a single physical N_Port. NPIV is fully
supported by this driver. You must have 24xx+ ISPs with NPIV-supporting
and NPIV-switches switch(es) to use this facility.
You can add NPIV targets by echoing
add_target target_name node_name=node_name_value; parent_host=parent_host_value
in /sys/kernel/scst_tgt/targets/qla2x00t/mgmt.
Removing NPIV targets is done by echoing
del_target target_name
in/sys/kernel/scst_tgt/targets/qla2x00t/mgmt.
Also, you can create and remove NPIV targets using the standard Linux
interface (i.e. echoing wwpn:wwnn into /sys/class/fc_host/hostX/vport_create
and /sys/class/fc_host/hostX/vport_delete).
It is recommended to use scstadmin utility and its config file to
configure virtual NPIV targets instead of the above direct interface.
Compilation options
-------------------
@@ -211,6 +231,12 @@ entries:
- version - read-only attribute, which allows to see version of
this driver and enabled optional features.
- mgmt - main management entry, which allows to configure NPIV targets.
See content of this file for help how to use it.
- hw_target (hardware target only) - read-only attribute with value 1.
It allows to distinguish hardware and virtual targets.
Each target subdirectory contains the following entries:
- host - link pointing on the corresponding scsi_host of the initiator
@@ -241,6 +267,12 @@ Each target subdirectory contains the following entries:
until rel_tgt_id becomes unique. This attribute initialized unique by
SCST by default.
- node_name (NPIV targets only) - read-only attribute, which allows to see
the target World Wide Node Name.
- parent_host (NPIV target only) - read-only attribute, which allows to see
the parent HBA World Wide Port Name (WWPN).
Subdirectory "sessions" contains one subdirectory for each connected
session with name equal to port name of the connected initiator.
@@ -253,9 +285,10 @@ Each session subdirectory contains the following entries:
- commands - contains overall number of SCSI commands in this session.
Below is a sample script, which configures 1 virtual disk "disk1" using
/disk1 image for usage with 25:00:00:f0:98:87:92:f3 target. All
initiators connected to this target will see this device.
Below is a sample script, which configures 2 virtual disk "disk1" using
/disk1 image for usage with 25:00:00:f0:98:87:92:f3 hardware target, and
"disk2" using /disk2 image for usage with 50:50:00:00:00:00:00:11 NPIV
target. All initiators connected to this targets will see those devices.
#!/bin/bash
@@ -263,11 +296,17 @@ modprobe scst
modprobe scst_vdisk
echo "add_device disk1 filename=/disk1; nv_cache=1" >/sys/kernel/scst_tgt/handlers/vdisk_fileio/mgmt
echo "add_device disk2 filename=/disk2; nv_cache=1" >/sys/kernel/scst_tgt/handlers/vdisk_fileio/mgmt
modprobe qla2x00tgt
echo "add_target 50:50:00:00:00:00:00:11 node_name=50:50:00:00:00:00:00:00;parent_host=25:00:00:f0:98:87:92:f3" >\
/sys/kernel/scst_tgt/targets/qla2x00t/mgmt
echo "add disk1 0" >/sys/kernel/scst_tgt/targets/qla2x00t/25:00:00:f0:98:87:92:f3/luns/mgmt
echo "add disk2 0" >/sys/kernel/scst_tgt/targets/qla2x00t/50:50:00:00:00:00:00:11/luns/mgmt
echo 1 >/sys/kernel/scst_tgt/targets/qla2x00t/25:00:00:f0:98:87:92:f3/enabled
echo 1 >/sys/kernel/scst_tgt/targets/qla2x00t/50:50:00:00:00:00:00:11/enabled
Below is another sample script, which configures 1 real local SCSI disk
0:0:1:0 for usage with 25:00:00:f0:98:87:92:f3 target:
@@ -456,6 +495,7 @@ The resulting overall SCST sysfs hierarchy with initiator
| | | | `-- read_only
| | | `-- mgmt
| | |-- rel_tgt_id
| | |-- hw_target
| | `-- sessions
| | `-- 25:00:00:f0:99:87:94:a3
| | |-- active_commands
@@ -463,7 +503,8 @@ The resulting overall SCST sysfs hierarchy with initiator
| | |-- initiator_name
| | `-- luns -> ../../ini_groups/25:00:00:f0:99:87:94:a3/luns
| |-- trace_level
| `-- version
| |-- version
| `-- mgmt
|-- threads
|-- trace_level
`-- version
@@ -503,4 +544,7 @@ help in debugging.
* Ming Zhang <mingz@ele.uri.edu> for fixes.
* Uri Yanai <Uri.Yanai@ngsoft.com> and Dorit Halsadi
<Dorit.Halsadi@dothill.com> for adding full NPIV support.
Vladislav Bolkhovitin <vst@vlnb.net>, http://scst.sourceforge.net

View File

@@ -3,9 +3,6 @@ Known issues and unimplemented features
- Allow to set port and node names through sysfs.
- Complete NPIV support. Particularly, SCST core should see all the virtual
targets and provide separate target-oriented access control for them.
- Minor "ToDo"'s spread in the code.
- If a Linux initiator asks for devices using INQUIRY command too soon

File diff suppressed because it is too large Load Diff

View File

@@ -126,7 +126,9 @@ qla2x00_send_enable_lun(scsi_qla_host_t *ha, bool enable)
}
extern void qla2xxx_add_targets(void);
extern size_t
qla2xxx_add_vtarget(u64 *port_name, u64 *node_name, u64 *parent_host);
extern size_t qla2xxx_del_vtarget(u64 *port_name);
#endif /* CONFIG_SCSI_QLA2XXX_TARGET */
#endif /* __QLA2X_TGT_H */

View File

@@ -44,13 +44,13 @@
* Must be changed on any change in any initiator visible interfaces or
* data in the target add-on
*/
#define QLA2X_TARGET_MAGIC 267
#define QLA2X_TARGET_MAGIC 268
/*
* Must be changed on any change in any target visible interfaces or
* data in the initiator
*/
#define QLA2X_INITIATOR_MAGIC 57219
#define QLA2X_INITIATOR_MAGIC 57220
#define QLA2X_INI_MODE_STR_EXCLUSIVE "exclusive"
#define QLA2X_INI_MODE_STR_DISABLED "disabled"
@@ -508,7 +508,8 @@ typedef struct {
uint16_t status;
uint16_t timeout;
uint16_t dseg_count; /* Data segment count. */
uint8_t reserved1[6];
uint8_t vp_index;
uint8_t reserved1[5];
uint32_t exchange_address;
uint16_t reserved2;
uint16_t flags;
@@ -614,7 +615,8 @@ typedef struct {
uint8_t entry_status; /* Entry Status. */
uint8_t reserved_1[6];
uint16_t nport_handle;
uint8_t reserved_2[3];
uint8_t reserved_2[2];
uint8_t vp_index;
uint8_t reserved_3:4;
uint8_t sof_type:4;
uint32_t exchange_address;
@@ -656,7 +658,7 @@ typedef struct {
uint16_t nport_handle;
uint16_t control_flags;
#define ABTS_CONTR_FLG_TERM_EXCHG BIT_0
uint8_t reserved_2;
uint8_t vp_index;
uint8_t reserved_3:4;
uint8_t sof_type:4;
uint32_t exchange_address;

View File

@@ -1783,6 +1783,26 @@ qla24xx_vport_create(struct fc_vport *fc_vport, bool disable)
fc_host_supported_speeds(vha->host) =
fc_host_supported_speeds(ha->host);
#ifdef CONFIG_SCSI_QLA2XXX_TARGET
vha->tgt = NULL;
vha->q2t_tgt = NULL;
mutex_init(&vha->tgt_mutex);
mutex_init(&vha->tgt_host_action_mutex);
qla_clear_tgt_mode(vha);
qla2x00_send_enable_lun(vha, false);
if (IS_QLA24XX_TYPE(vha))
vha->atio_q_length = ATIO_ENTRY_CNT_24XX;
else if (IS_QLA25XX(vha))
vha->atio_q_length = ATIO_ENTRY_CNT_24XX;
if (qla_target.tgt_host_action != NULL)
qla_target.tgt_host_action(vha, ADD_TARGET);
/*
* Must be after tgt_host_action() to not race with
* qla2xxx_add_targets().
*/
#endif
qla24xx_vport_disable(fc_vport, disable);
return 0;
@@ -1801,6 +1821,11 @@ qla24xx_vport_delete(struct fc_vport *fc_vport)
scsi_qla_host_t *ha = shost_priv(fc_vport->shost);
scsi_qla_host_t *vha = fc_vport->dd_data;
#ifdef CONFIG_SCSI_QLA2XXX_TARGET
if (qla_target.tgt_host_action != NULL)
qla_target.tgt_host_action(vha, REMOVE_TARGET);
#endif
qla24xx_disable_vp(vha);
qla24xx_deallocate_vp_id(vha);

View File

@@ -2626,6 +2626,7 @@ typedef struct scsi_qla_host {
uint16_t vp_idx; /* vport ID */
#ifdef CONFIG_SCSI_QLA2XXX_TARGET
struct qla_tgt_vp_map *tgt_vp_map;
struct mutex tgt_mutex;
struct mutex tgt_host_action_mutex;
@@ -2671,6 +2672,12 @@ typedef struct scsi_qla_host {
struct qla_chip_state_84xx *cs84xx;
} scsi_qla_host_t;
#ifdef CONFIG_SCSI_QLA2XXX_TARGET
struct qla_tgt_vp_map {
uint8_t idx;
scsi_qla_host_t *vha;
};
#endif
/*
* Macros to help code, maintain, etc.

View File

@@ -1460,7 +1460,9 @@ qla2x00_configure_hba(scsi_qla_host_t *ha)
uint8_t area;
uint8_t domain;
char connect_type[22];
#ifdef CONFIG_SCSI_QLA2XXX_TARGET
scsi_qla_host_t *pha = ha->parent;
#endif
/* Get host addresses. */
rval = qla2x00_get_adapter_id(ha,
&loop_id, &al_pa, &area, &domain, &topo, &sw_cap);
@@ -1537,7 +1539,10 @@ qla2x00_configure_hba(scsi_qla_host_t *ha)
ha->d_id.b.domain = domain;
ha->d_id.b.area = area;
ha->d_id.b.al_pa = al_pa;
#ifdef CONFIG_SCSI_QLA2XXX_TARGET
if (pha)
pha->tgt_vp_map[al_pa].idx = ha->vp_idx;
#endif
if (!ha->flags.init_done)
qla_printk(KERN_INFO, ha,
"Topology - %s, Host Loop address 0x%x\n",
@@ -4139,6 +4144,9 @@ qla2x00_enable_tgt_mode(scsi_qla_host_t *ha)
qla_set_tgt_mode(ha);
spin_unlock_irqrestore(&ha->hardware_lock, flags);
if (ha->parent)
ha = ha->parent;
set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags);
qla2xxx_wake_dpc(ha);
qla2x00_wait_for_hba_online(ha);
@@ -4154,14 +4162,15 @@ void
qla2x00_disable_tgt_mode(scsi_qla_host_t *ha)
{
unsigned long flags;
scsi_qla_host_t *vha = to_qla_parent(ha);
spin_lock_irqsave(&ha->hardware_lock, flags);
spin_lock_irqsave(&vha->hardware_lock, flags);
qla_clear_tgt_mode(ha);
spin_unlock_irqrestore(&ha->hardware_lock, flags);
spin_unlock_irqrestore(&vha->hardware_lock, flags);
set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags);
qla2xxx_wake_dpc(ha);
qla2x00_wait_for_hba_online(ha);
set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
qla2xxx_wake_dpc(vha);
qla2x00_wait_for_hba_online(vha);
}
EXPORT_SYMBOL(qla2x00_disable_tgt_mode);

View File

@@ -6,6 +6,8 @@
*/
#include "qla_def.h"
#include "qla2x_tgt.h"
#include <linux/delay.h>
@@ -2765,6 +2767,14 @@ qla24xx_modify_vp_config(scsi_qla_host_t *vha)
vpmod->vp_count = 1;
vpmod->vp_index1 = vha->vp_idx;
vpmod->options_idx1 = BIT_3|BIT_4|BIT_5;
#ifdef CONFIG_SCSI_QLA2XXX_TARGET
/* Enable target mode */
if (qla_tgt_mode_enabled(vha))
vpmod->options_idx1 &= ~BIT_5;
/* Disable ini mode, if requested */
if (!qla_ini_mode_enabled(vha))
vpmod->options_idx1 &= ~BIT_4;
#endif
memcpy(vpmod->node_name_idx1, vha->node_name, WWN_SIZE);
memcpy(vpmod->port_name_idx1, vha->port_name, WWN_SIZE);
vpmod->entry_count = 1;

View File

@@ -16,6 +16,8 @@
#include <scsi/scsicam.h>
#include <linux/delay.h>
#include "qla2x_tgt.h"
void
qla2x00_vp_stop_timer(scsi_qla_host_t *vha)
{
@@ -25,7 +27,7 @@ qla2x00_vp_stop_timer(scsi_qla_host_t *vha)
}
}
static uint32_t
static void
qla24xx_allocate_vp_id(scsi_qla_host_t *vha)
{
uint32_t vp_id;
@@ -38,15 +40,16 @@ qla24xx_allocate_vp_id(scsi_qla_host_t *vha)
DEBUG15(printk ("vp_id %d is bigger than max-supported %d.\n",
vp_id, ha->max_npiv_vports));
mutex_unlock(&ha->vport_lock);
return vp_id;
} else {
set_bit(vp_id, ha->vp_idx_map);
ha->num_vhosts++;
vha->vp_idx = vp_id;
list_add_tail(&vha->vp_list, &ha->vp_list);
#ifdef CONFIG_SCSI_QLA2XXX_TARGET
ha->tgt_vp_map[vp_id].vha = vha;
#endif
mutex_unlock(&ha->vport_lock);
}
set_bit(vp_id, ha->vp_idx_map);
ha->num_vhosts++;
vha->vp_idx = vp_id;
list_add_tail(&vha->vp_list, &ha->vp_list);
mutex_unlock(&ha->vport_lock);
return vp_id;
}
void
@@ -60,6 +63,9 @@ qla24xx_deallocate_vp_id(scsi_qla_host_t *vha)
ha->num_vhosts--;
clear_bit(vp_id, ha->vp_idx_map);
list_del(&vha->vp_list);
#ifdef CONFIG_SCSI_QLA2XXX_TARGET
ha->tgt_vp_map[vp_id].vha = NULL;
#endif
mutex_unlock(&ha->vport_lock);
}
@@ -116,6 +122,10 @@ qla24xx_disable_vp(scsi_qla_host_t *vha)
ret = qla24xx_control_vp(vha, VCE_COMMAND_DISABLE_VPS_LOGO_ALL);
atomic_set(&vha->loop_state, LOOP_DOWN);
atomic_set(&vha->loop_down_timer, LOOP_DOWN_TIME);
#ifdef CONFIG_SCSI_QLA2XXX_TARGET
/* Remove port id from vp target map */
vha->parent->tgt_vp_map[vha->d_id.b.al_pa].idx = 0;
#endif
/* Delete all vp's fcports from parent's list */
qla2x00_mark_vp_devices_dead(vha);
@@ -249,6 +259,11 @@ qla2x00_vp_abort_isp(scsi_qla_host_t *vha)
DEBUG15(printk("scsi(%ld): Scheduling enable of Vport %d...\n",
vha->host_no, vha->vp_idx));
qla24xx_enable_vp(vha);
#ifdef CONFIG_SCSI_QLA2XXX_TARGET
/* Enable target response to SCSI bus. */
if (qla_tgt_mode_enabled(vha))
qla2x00_send_enable_lun(vha, true);
#endif
}
static int
@@ -391,7 +406,7 @@ qla24xx_create_vhost(struct fc_vport *fc_vport)
vha->fc_vport = fc_vport;
vha->device_flags = 0;
vha->instance = num_hosts;
vha->vp_idx = qla24xx_allocate_vp_id(vha);
qla24xx_allocate_vp_id(vha);
if (vha->vp_idx > ha->max_npiv_vports) {
DEBUG15(printk("scsi(%ld): Couldn't allocate vp_id.\n",
vha->host_no));

View File

@@ -1649,13 +1649,104 @@ qla2xxx_add_targets(void)
mutex_lock(&qla_ha_list_mutex);
list_for_each_entry(ha, &qla_ha_list, ha_list_entry) {
if (qla_target.tgt_host_action != NULL)
if (qla_target.tgt_host_action != NULL) {
int i, vp_idx_matched;
qla_target.tgt_host_action(ha, ADD_TARGET);
for_each_mapped_vp_idx(ha, i) {
scsi_qla_host_t *vha;
vp_idx_matched = 0;
list_for_each_entry(vha, &ha->vp_list,
vp_list) {
if (i == vha->vp_idx) {
vp_idx_matched = 1;
break;
}
}
if (vp_idx_matched)
qla_target.tgt_host_action(vha, ADD_TARGET);
}
}
}
mutex_unlock(&qla_ha_list_mutex);
return;
}
EXPORT_SYMBOL(qla2xxx_add_targets);
size_t qla2xxx_add_vtarget(u64 *port_name, u64 *node_name, u64 *parent_host)
{
struct Scsi_Host *shost = NULL;
scsi_qla_host_t *ha;
struct fc_vport_identifiers vid;
uint8_t parent_wwn[WWN_SIZE];
memset(&vid, 0, sizeof(vid));
u64_to_wwn(*parent_host, parent_wwn);
mutex_lock(&qla_ha_list_mutex);
list_for_each_entry(ha, &qla_ha_list, ha_list_entry) {
if (!memcmp(parent_wwn, ha->port_name, WWN_SIZE)) {
shost = ha->host;
break;
}
}
mutex_unlock(&qla_ha_list_mutex);
if (!ha || !shost)
return -ENODEV;
vid.port_name = *port_name;
vid.node_name = *node_name;
vid.roles = FC_PORT_ROLE_FCP_INITIATOR;
vid.vport_type = FC_PORTTYPE_NPIV;
/* vid.symbolic_name is already zero/NULL's */
vid.disable = false; /* always enabled */
/* We only allow support on Channel 0 !!! */
if (!fc_vport_create(shost, 0, &vid))
return -EINVAL;
return 0;
}
EXPORT_SYMBOL(qla2xxx_add_vtarget);
size_t qla2xxx_del_vtarget(u64 *port_name)
{
scsi_qla_host_t *ha;
struct Scsi_Host *shost;
struct fc_host_attrs *fc_host;
struct fc_vport *vport;
unsigned long flags;
int match = 0;
mutex_lock(&qla_ha_list_mutex);
list_for_each_entry(ha, &qla_ha_list, ha_list_entry) {
shost = ha->host;
fc_host = shost_to_fc_host(shost);
spin_lock_irqsave(shost->host_lock, flags);
/* We only allow support on Channel 0 !!! */
list_for_each_entry(vport, &fc_host->vports, peers) {
if ((vport->channel == 0) &&
(vport->port_name == *port_name)) {
match = 1;
break;
}
}
spin_unlock_irqrestore(shost->host_lock, flags);
if (match)
break;
}
mutex_unlock(&qla_ha_list_mutex);
if (!match)
return -ENODEV;
return fc_vport_terminate(vport);
}
EXPORT_SYMBOL(qla2xxx_del_vtarget);
#endif /* CONFIG_SCSI_QLA2XXX_TARGET */
/*
@@ -1729,6 +1820,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
mutex_init(&ha->tgt_mutex);
mutex_init(&ha->tgt_host_action_mutex);
qla_clear_tgt_mode(ha);
ha->tgt_vp_map = NULL;
#endif
/* Set ISP-type information. */
@@ -2184,11 +2276,16 @@ qla2x00_mem_alloc(scsi_qla_host_t *ha)
#ifdef CONFIG_SCSI_QLA2XXX_TARGET
if (IS_FWI2_CAPABLE(ha)) {
ha->tgt_vp_map = kzalloc(sizeof(struct qla_tgt_vp_map) *
MAX_MULTI_ID_FABRIC, GFP_KERNEL);
if (!ha->tgt_vp_map)
goto fail_free_response_ring;
ha->atio_ring = dma_alloc_coherent(&ha->pdev->dev,
(ha->atio_q_length + 1) * sizeof(atio_t),
&ha->atio_dma, GFP_KERNEL);
if (ha->atio_ring == NULL)
goto fail_free_response_ring;
goto fail_free_vp_map;
}
#endif
@@ -2270,6 +2367,9 @@ fail_free_atio_ring:
sizeof(response_t), ha->atio_ring, ha->atio_dma);
ha->atio_ring = NULL;
ha->atio_dma = 0;
fail_free_vp_map:
kfree(ha->tgt_vp_map);
ha->tgt_vp_map = NULL;
fail_free_response_ring:
#endif
dma_free_coherent(&ha->pdev->dev, (ha->response_q_length + 1) *
@@ -2342,6 +2442,7 @@ qla2x00_mem_free(scsi_qla_host_t *ha)
dma_free_coherent(&ha->pdev->dev,
(ha->atio_q_length + 1) * sizeof(atio_t),
ha->atio_ring, ha->atio_dma);
kfree(ha->tgt_vp_map);
#endif
if (ha->response_ring)
@@ -2378,6 +2479,7 @@ qla2x00_mem_free(scsi_qla_host_t *ha)
#ifdef CONFIG_SCSI_QLA2XXX_TARGET
ha->atio_ring = NULL;
ha->atio_dma = 0;
ha->tgt_vp_map = NULL;
#endif
list_for_each_safe(fcpl, fcptemp, &ha->fcports) {