Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2c3dfe3f authored by Seokmann Ju's avatar Seokmann Ju Committed by James Bottomley
Browse files

[SCSI] qla2xxx: add support for NPIV



Following patch adds support for NPIV (N-Port ID Virtualization) to the
qla2xxx.

- supported within switched-fabric topologies only.
- supports up to 63 virtual ports on each physical port.

Signed-off-by: default avatarSeokmann Ju <seokmann.ju@qlogic.com>
Signed-off-by: default avatarJames Bottomley <James.Bottomley@SteelEye.com>
parent 968a5763
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
qla2xxx-y := qla_os.o qla_init.o qla_mbx.o qla_iocb.o qla_isr.o qla_gs.o \
		qla_dbg.o qla_sup.o qla_attr.o
		qla_dbg.o qla_sup.o qla_attr.o qla_mid.o

obj-$(CONFIG_SCSI_QLA_FC) += qla2xxx.o
+164 −0
Original line number Diff line number Diff line
@@ -6,8 +6,11 @@
 */
#include "qla_def.h"

#include <linux/kthread.h>
#include <linux/vmalloc.h>

int qla24xx_vport_disable(struct fc_vport *, bool);

/* SYSFS attributes --------------------------------------------------------- */

static ssize_t
@@ -959,6 +962,122 @@ qla2x00_get_host_port_state(struct Scsi_Host *shost)
		fc_host_port_state(shost) = FC_PORTSTATE_ONLINE;
}

static int
qla24xx_vport_create(struct fc_vport *fc_vport, bool disable)
{
	int	ret = 0;
	scsi_qla_host_t *ha = (scsi_qla_host_t *) fc_vport->shost->hostdata;
	scsi_qla_host_t *vha;

	ret = qla24xx_vport_create_req_sanity_check(fc_vport);
	if (ret) {
		DEBUG15(printk("qla24xx_vport_create_req_sanity_check failed, "
		    "status %x\n", ret));
		return (ret);
	}

	vha = qla24xx_create_vhost(fc_vport);
	if (vha == NULL) {
		DEBUG15(printk ("qla24xx_create_vhost failed, vha = %p\n",
		    vha));
		return FC_VPORT_FAILED;
	}
	if (disable) {
		atomic_set(&vha->vp_state, VP_OFFLINE);
		fc_vport_set_state(fc_vport, FC_VPORT_DISABLED);
	} else
		atomic_set(&vha->vp_state, VP_FAILED);

	/* ready to create vport */
	qla_printk(KERN_INFO, vha, "VP entry id %d assigned.\n", vha->vp_idx);

	/* initialized vport states */
	atomic_set(&vha->loop_state, LOOP_DOWN);
	vha->vp_err_state=  VP_ERR_PORTDWN;
	vha->vp_prev_err_state=  VP_ERR_UNKWN;
	/* Check if physical ha port is Up */
	if (atomic_read(&ha->loop_state) == LOOP_DOWN ||
	    atomic_read(&ha->loop_state) == LOOP_DEAD) {
		/* Don't retry or attempt login of this virtual port */
		DEBUG15(printk ("scsi(%ld): pport loop_state is not UP.\n",
		    vha->host_no));
		atomic_set(&vha->loop_state, LOOP_DEAD);
		if (!disable)
			fc_vport_set_state(fc_vport, FC_VPORT_LINKDOWN);
	}

	if (scsi_add_host(vha->host, &fc_vport->dev)) {
		DEBUG15(printk("scsi(%ld): scsi_add_host failure for VP[%d].\n",
			vha->host_no, vha->vp_idx));
		goto vport_create_failed_2;
	}

	/* initialize attributes */
	fc_host_node_name(vha->host) = wwn_to_u64(vha->node_name);
	fc_host_port_name(vha->host) = wwn_to_u64(vha->port_name);
	fc_host_supported_classes(vha->host) =
		fc_host_supported_classes(ha->host);
	fc_host_supported_speeds(vha->host) =
		fc_host_supported_speeds(ha->host);

	qla24xx_vport_disable(fc_vport, disable);

	return 0;
vport_create_failed_2:
	qla24xx_disable_vp(vha);
	qla24xx_deallocate_vp_id(vha);
	kfree(vha->port_name);
	kfree(vha->node_name);
	scsi_host_put(vha->host);
	return FC_VPORT_FAILED;
}

int
qla24xx_vport_delete(struct fc_vport *fc_vport)
{
	scsi_qla_host_t *ha = (scsi_qla_host_t *) fc_vport->shost->hostdata;
	scsi_qla_host_t *vha = fc_vport->dd_data;

	qla24xx_disable_vp(vha);
	qla24xx_deallocate_vp_id(vha);

	down(&ha->vport_sem);
	ha->cur_vport_count--;
	clear_bit(vha->vp_idx, (unsigned long *)ha->vp_idx_map);
	up(&ha->vport_sem);

	kfree(vha->node_name);
	kfree(vha->port_name);

	if (vha->timer_active) {
		qla2x00_vp_stop_timer(vha);
		DEBUG15(printk ("scsi(%ld): timer for the vport[%d] = %p "
		    "has stopped\n",
		    vha->host_no, vha->vp_idx, vha));
        }

	fc_remove_host(vha->host);

	scsi_remove_host(vha->host);

	scsi_host_put(vha->host);

	return 0;
}

int
qla24xx_vport_disable(struct fc_vport *fc_vport, bool disable)
{
	scsi_qla_host_t *vha = fc_vport->dd_data;

	if (disable)
		qla24xx_disable_vp(vha);
	else
		qla24xx_enable_vp(vha);

	return 0;
}

struct fc_function_template qla2xxx_transport_functions = {

	.show_host_node_name = 1,
@@ -996,6 +1115,49 @@ struct fc_function_template qla2xxx_transport_functions = {

	.issue_fc_host_lip = qla2x00_issue_lip,
	.get_fc_host_stats = qla2x00_get_fc_host_stats,

	.vport_create = qla24xx_vport_create,
	.vport_disable = qla24xx_vport_disable,
	.vport_delete = qla24xx_vport_delete,
};

struct fc_function_template qla2xxx_transport_vport_functions = {

	.show_host_node_name = 1,
	.show_host_port_name = 1,
	.show_host_supported_classes = 1,

	.get_host_port_id = qla2x00_get_host_port_id,
	.show_host_port_id = 1,
	.get_host_speed = qla2x00_get_host_speed,
	.show_host_speed = 1,
	.get_host_port_type = qla2x00_get_host_port_type,
	.show_host_port_type = 1,
	.get_host_symbolic_name = qla2x00_get_host_symbolic_name,
	.show_host_symbolic_name = 1,
	.set_host_system_hostname = qla2x00_set_host_system_hostname,
	.show_host_system_hostname = 1,
	.get_host_fabric_name = qla2x00_get_host_fabric_name,
	.show_host_fabric_name = 1,
	.get_host_port_state = qla2x00_get_host_port_state,
	.show_host_port_state = 1,

	.dd_fcrport_size = sizeof(struct fc_port *),
	.show_rport_supported_classes = 1,

	.get_starget_node_name = qla2x00_get_starget_node_name,
	.show_starget_node_name = 1,
	.get_starget_port_name = qla2x00_get_starget_port_name,
	.show_starget_port_name = 1,
	.get_starget_port_id  = qla2x00_get_starget_port_id,
	.show_starget_port_id = 1,

	.get_rport_dev_loss_tmo = qla2x00_get_rport_loss_tmo,
	.set_rport_dev_loss_tmo = qla2x00_set_rport_loss_tmo,
	.show_rport_dev_loss_tmo = 1,

	.issue_fc_host_lip = qla2x00_issue_lip,
	.get_fc_host_stats = qla2x00_get_fc_host_stats,
};

void
@@ -1004,4 +1166,6 @@ qla2x00_init_host_attr(scsi_qla_host_t *ha)
	fc_host_node_name(ha->host) = wwn_to_u64(ha->node_name);
	fc_host_port_name(ha->host) = wwn_to_u64(ha->port_name);
	fc_host_supported_classes(ha->host) = FC_COS_CLASS3;
	fc_host_max_npiv_vports(ha->host) = MAX_NUM_VPORT_FABRIC;
	fc_host_npiv_vports_inuse(ha->host) = ha->cur_vport_count;
}
+9 −1
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@
/* #define QL_DEBUG_LEVEL_12 */ /* Output IP trace msgs */
/* #define QL_DEBUG_LEVEL_13 */ /* Output fdmi function trace msgs */
/* #define QL_DEBUG_LEVEL_14 */ /* Output RSCN trace msgs */
/* #define QL_DEBUG_LEVEL_15 */ /* Output NPIV trace msgs */
/*
 *  Local Macro Definitions.
 */
@@ -30,7 +31,8 @@
    defined(QL_DEBUG_LEVEL_7)  || defined(QL_DEBUG_LEVEL_8) || \
    defined(QL_DEBUG_LEVEL_9)  || defined(QL_DEBUG_LEVEL_10) || \
    defined(QL_DEBUG_LEVEL_11) || defined(QL_DEBUG_LEVEL_12) || \
    defined(QL_DEBUG_LEVEL_13) || defined(QL_DEBUG_LEVEL_14)
    defined(QL_DEBUG_LEVEL_13) || defined(QL_DEBUG_LEVEL_14) || \
    defined(QL_DEBUG_LEVEL_15)
    #define QL_DEBUG_ROUTINES
#endif

@@ -125,6 +127,12 @@
#define DEBUG14(x)	do {} while (0)
#endif

#if defined(QL_DEBUG_LEVEL_15)
#define DEBUG15(x)      do {x;} while (0)
#else
#define DEBUG15(x)	do {} while (0)
#endif

/*
 * Firmware Dump structure definition
 */
+83 −0
Original line number Diff line number Diff line
@@ -1551,6 +1551,9 @@ typedef struct fc_port {

	unsigned long last_queue_full;
	unsigned long last_ramp_up;

	struct list_head vp_fcport;
	uint16_t vp_idx;
} fc_port_t;

/*
@@ -1999,6 +2002,36 @@ struct gid_list_info {
};
#define GID_LIST_SIZE (sizeof(struct gid_list_info) * MAX_FIBRE_DEVICES)

/* NPIV */
typedef struct vport_info {
	uint8_t		port_name[WWN_SIZE];
	uint8_t		node_name[WWN_SIZE];
	int		vp_id;
	uint16_t	loop_id;
	unsigned long	host_no;
	uint8_t		port_id[3];
	int		loop_state;
} vport_info_t;

typedef struct vport_params {
	uint8_t 	port_name[WWN_SIZE];
	uint8_t 	node_name[WWN_SIZE];
	uint32_t 	options;
#define	VP_OPTS_RETRY_ENABLE	BIT_0
#define	VP_OPTS_VP_DISABLE	BIT_1
} vport_params_t;

/* NPIV - return codes of VP create and modify */
#define VP_RET_CODE_OK			0
#define VP_RET_CODE_FATAL		1
#define VP_RET_CODE_WRONG_ID		2
#define VP_RET_CODE_WWPN		3
#define VP_RET_CODE_RESOURCES		4
#define VP_RET_CODE_NO_MEM		5
#define VP_RET_CODE_NOT_FOUND		6

#define to_qla_parent(x) (((x)->parent) ? (x)->parent : (x))

/*
 * ISP operations
 */
@@ -2073,6 +2106,16 @@ struct qla_msix_entry {
	uint16_t msix_entry;
};

#define	WATCH_INTERVAL		1       /* number of seconds */

/* NPIV */
#define MAX_MULTI_ID_LOOP                     126
#define MAX_MULTI_ID_FABRIC                    64
#define MAX_NUM_VPORT_LOOP                      (MAX_MULTI_ID_LOOP - 1)
#define MAX_NUM_VPORT_FABRIC                    (MAX_MULTI_ID_FABRIC - 1)
#define MAX_NUM_VHBA_LOOP                       (MAX_MULTI_ID_LOOP - 1)
#define MAX_NUM_VHBA_FABRIC                     (MAX_MULTI_ID_FABRIC - 1)

/*
 * Linux Host Adapter structure
 */
@@ -2108,6 +2151,8 @@ typedef struct scsi_qla_host {
		uint32_t	msix_enabled		:1;
		uint32_t	disable_serdes		:1;
		uint32_t	gpsc_supported		:1;
		uint32_t        vsan_enabled            :1;
		uint32_t	npiv_supported		:1;
	} flags;

	atomic_t	loop_state;
@@ -2147,6 +2192,7 @@ typedef struct scsi_qla_host {
#define BEACON_BLINK_NEEDED	25
#define REGISTER_FDMI_NEEDED	26
#define FCPORT_UPDATE_NEEDED	27
#define VP_DPC_NEEDED		28	/* wake up for VP dpc handling */

	uint32_t	device_flags;
#define DFLG_LOCAL_DEVICES		BIT_0
@@ -2237,6 +2283,11 @@ typedef struct scsi_qla_host {

	/* ISP configuration data. */
	uint16_t	loop_id;		/* Host adapter loop id */
	uint16_t	switch_cap;
#define FLOGI_SEQ_DEL		BIT_8
#define FLOGI_MID_SUPPORT	BIT_10
#define FLOGI_VSAN_SUPPORT	BIT_12
#define FLOGI_SP_SUPPORT	BIT_13
	uint16_t	fb_rev;

	port_id_t	d_id;			/* Host adapter port id */
@@ -2344,6 +2395,7 @@ typedef struct scsi_qla_host {
#define MBX_UPDATE_FLASH_ACTIVE	3

	struct semaphore mbx_cmd_sem;	/* Serialialize mbx access */
	struct semaphore vport_sem;	/* Virtual port synchronization */
	struct semaphore mbx_intr_sem;  /* Used for completion notification */

	uint32_t	mbx_flags;
@@ -2428,6 +2480,37 @@ typedef struct scsi_qla_host {
	struct fc_host_statistics fc_host_stat;

	struct qla_msix_entry msix_entries[QLA_MSIX_ENTRIES];

	struct list_head	vp_list;	/* list of VP */
	struct fc_vport	*fc_vport;	/* holds fc_vport * for each vport */
	uint8_t		vp_idx_map[16];
	uint16_t        num_vhosts;	/* number of vports created */
	uint16_t        num_vsans;	/* number of vsan created */
	uint16_t        vp_idx;		/* vport ID */

	struct scsi_qla_host	*parent;	/* holds pport */
	unsigned long		vp_flags;
	struct list_head	vp_fcports;	/* list of fcports */
#define VP_IDX_ACQUIRED		0	/* bit no 0 */
#define VP_CREATE_NEEDED	1
#define VP_BIND_NEEDED		2
#define VP_DELETE_NEEDED	3
#define VP_SCR_NEEDED		4	/* State Change Request registration */
	atomic_t 		vp_state;
#define VP_OFFLINE		0
#define VP_ACTIVE		1
#define VP_FAILED		2
// #define VP_DISABLE		3
	uint16_t 	vp_err_state;
	uint16_t	vp_prev_err_state;
#define VP_ERR_UNKWN		0
#define VP_ERR_PORTDWN		1
#define VP_ERR_FAB_UNSUPPORTED	2
#define VP_ERR_FAB_NORESOURCES	3
#define VP_ERR_FAB_LOGOUT	4
#define VP_ERR_ADAP_NORESOURCES	5
	int		max_npiv_vports;	/* 63 or 125 per topoloty */
	int		cur_vport_count;
} scsi_qla_host_t;


+79 −12
Original line number Diff line number Diff line
@@ -69,6 +69,16 @@ struct port_database_24xx {
	uint8_t reserved_3[24];
};

struct vp_database_24xx {
	uint16_t vp_status;
	uint8_t  options;
	uint8_t  id;
	uint8_t  port_name[WWN_SIZE];
	uint8_t  node_name[WWN_SIZE];
	uint16_t port_id_low;
	uint16_t port_id_high;
};

struct nvram_24xx {
	/* NVRAM header. */
	uint8_t id[4];
@@ -962,6 +972,25 @@ struct mid_db_24xx {
	struct mid_db_entry_24xx entries[MAX_MID_VPS];
};

 /*
 * Virtual Fabric ID type definition.
 */
typedef struct vf_id {
        uint16_t id : 12;
        uint16_t priority : 4;
} vf_id_t;

/*
 * Virtual Fabric HopCt type definition.
 */
typedef struct vf_hopct {
        uint16_t reserved : 8;
        uint16_t hopct : 8;
} vf_hopct_t;

/*
 * Virtual Port Control IOCB
 */
#define VP_CTRL_IOCB_TYPE	0x30	/* Vitual Port Control entry. */
struct vp_ctrl_entry_24xx {
	uint8_t entry_type;		/* Entry type. */
@@ -974,6 +1003,7 @@ struct vp_ctrl_entry_24xx {
	uint16_t vp_idx_failed;

	uint16_t comp_status;		/* Completion status. */
#define CS_VCE_IOCB_ERROR       0x01    /* Error processing IOCB */
#define CS_VCE_ACQ_ID_ERROR	0x02	/* Error while acquireing ID. */
#define CS_VCE_BUSY		0x05	/* Firmware not ready to accept cmd. */

@@ -982,24 +1012,34 @@ struct vp_ctrl_entry_24xx {
#define VCE_COMMAND_DISABLE_VPS	0x08	/* Disable VPs. */
#define VCE_COMMAND_DISABLE_VPS_REINIT	0x09 /* Disable VPs and reinit link. */
#define VCE_COMMAND_DISABLE_VPS_LOGO	0x0a /* Disable VPs and LOGO ports. */
#define VCE_COMMAND_DISABLE_VPS_LOGO_ALL        0x0b /* Disable VPs and LOGO ports. */

	uint16_t vp_count;

	uint8_t vp_idx_map[16];

	uint8_t reserved_4[32];
	uint16_t flags;
	struct vf_id    id;
	uint16_t reserved_4;
	struct vf_hopct  hopct;
	uint8_t reserved_5[8];
};

/*
 * Modify Virtual Port Configuration IOCB
 */
#define VP_CONFIG_IOCB_TYPE	0x31	/* Vitual Port Config entry. */
struct vp_config_entry_24xx {
	uint8_t entry_type;		/* Entry type. */
	uint8_t entry_count;		/* Entry count. */
	uint8_t sys_define;		/* System defined. */
	uint8_t handle_count;
	uint8_t entry_status;		/* Entry Status. */

	uint32_t handle;		/* System handle. */

	uint16_t reserved_1;
	uint16_t flags;
#define CS_VF_BIND_VPORTS_TO_VF         BIT_0
#define CS_VF_SET_QOS_OF_VPORTS         BIT_1
#define CS_VF_SET_HOPS_OF_VPORTS        BIT_2

	uint16_t comp_status;		/* Completion status. */
#define CS_VCT_STS_ERROR	0x01	/* Specified VPs were not disabled. */
@@ -1009,27 +1049,29 @@ struct vp_config_entry_24xx {
#define CS_VCT_BUSY		0x05	/* Firmware not ready to accept cmd. */

	uint8_t command;
#define VCT_COMMAND_MOD_VPS	0x00	/* Enable VPs. */
#define VCT_COMMAND_MOD_ENABLE_VPS 0x08	/* Disable VPs. */
#define VCT_COMMAND_MOD_VPS     0x00    /* Modify VP configurations. */
#define VCT_COMMAND_MOD_ENABLE_VPS 0x01 /* Modify configuration & enable VPs. */

	uint8_t vp_count;

	uint8_t vp_idx1;
	uint8_t vp_idx2;
	uint8_t vp_index1;
	uint8_t vp_index2;

	uint8_t options_idx1;
	uint8_t hard_address_idx1;
	uint16_t reserved_2;
	uint16_t reserved_vp1;
	uint8_t port_name_idx1[WWN_SIZE];
	uint8_t node_name_idx1[WWN_SIZE];

	uint8_t options_idx2;
	uint8_t hard_address_idx2;
	uint16_t reserved_3;
	uint16_t reserved_vp2;
	uint8_t port_name_idx2[WWN_SIZE];
	uint8_t node_name_idx2[WWN_SIZE];

	uint8_t reserved_4[8];
	struct vf_id    id;
	uint16_t reserved_4;
	struct vf_hopct  hopct;
	uint8_t reserved_5;
};

#define VP_RPT_ID_IOCB_TYPE	0x32	/* Report ID Acquisition entry. */
@@ -1054,5 +1096,30 @@ struct vp_rpt_id_entry_24xx {
	uint8_t reserved_4[32];
};

#define VF_EVFP_IOCB_TYPE       0x26    /* Exchange Virtual Fabric Parameters entry. */
struct vf_evfp_entry_24xx {
        uint8_t entry_type;             /* Entry type. */
        uint8_t entry_count;            /* Entry count. */
        uint8_t sys_define;             /* System defined. */
        uint8_t entry_status;           /* Entry Status. */

        uint32_t handle;                /* System handle. */
        uint16_t comp_status;           /* Completion status. */
        uint16_t timeout;               /* timeout */
        uint16_t adim_tagging_mode;

        uint16_t vfport_id;
        uint32_t exch_addr;

        uint16_t nport_handle;          /* N_PORT handle. */
        uint16_t control_flags;
        uint32_t io_parameter_0;
        uint32_t io_parameter_1;
        uint32_t tx_address[2];         /* Data segment 0 address. */
        uint32_t tx_len;                /* Data segment 0 length. */
        uint32_t rx_address[2];         /* Data segment 1 address. */
        uint32_t rx_len;                /* Data segment 1 length. */
};

/* END MID Support ***********************************************************/
#endif
Loading