diff options
author | Seokmann Ju <seokmann.ju@qlogic.com> | 2007-07-05 13:16:51 -0700 |
---|---|---|
committer | James Bottomley <jejb@mulgrave.localdomain> | 2007-07-14 19:08:05 -0500 |
commit | 2c3dfe3f6ad8daff5acdb01713e4f2b116e78136 (patch) | |
tree | 8d95e2356c0f5121ceab48ab564d2796b6530d29 /drivers/scsi | |
parent | 968a5763fb7247feb0e69573a2975a7a0c094267 (diff) |
[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: Seokmann Ju <seokmann.ju@qlogic.com>
Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
Diffstat (limited to 'drivers/scsi')
-rw-r--r-- | drivers/scsi/qla2xxx/Makefile | 2 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_attr.c | 164 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_dbg.h | 10 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_def.h | 83 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_fw.h | 91 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_gbl.h | 39 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_gs.c | 3 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_init.c | 166 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_iocb.c | 28 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_isr.c | 39 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_mbx.c | 396 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_mid.c | 497 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_os.c | 229 |
13 files changed, 1593 insertions, 154 deletions
diff --git a/drivers/scsi/qla2xxx/Makefile b/drivers/scsi/qla2xxx/Makefile index 411663af7bb..71ddb5db494 100644 --- a/drivers/scsi/qla2xxx/Makefile +++ b/drivers/scsi/qla2xxx/Makefile @@ -1,4 +1,4 @@ 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 diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c index 8081b637d97..b79c4dfc2a9 100644 --- a/drivers/scsi/qla2xxx/qla_attr.c +++ b/drivers/scsi/qla2xxx/qla_attr.c @@ -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; } diff --git a/drivers/scsi/qla2xxx/qla_dbg.h b/drivers/scsi/qla2xxx/qla_dbg.h index 5b12278968e..49dffeb7851 100644 --- a/drivers/scsi/qla2xxx/qla_dbg.h +++ b/drivers/scsi/qla2xxx/qla_dbg.h @@ -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 */ diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index e8948b679f5..a1ca590ba44 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h @@ -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; diff --git a/drivers/scsi/qla2xxx/qla_fw.h b/drivers/scsi/qla2xxx/qla_fw.h index a0a722cf423..63a11fef5d1 100644 --- a/drivers/scsi/qla2xxx/qla_fw.h +++ b/drivers/scsi/qla2xxx/qla_fw.h @@ -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 diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h index 74544ae4b0e..b44eff2803c 100644 --- a/drivers/scsi/qla2xxx/qla_gbl.h +++ b/drivers/scsi/qla2xxx/qla_gbl.h @@ -62,6 +62,38 @@ extern int ql2xfdmienable; extern int ql2xallocfwdump; extern int ql2xextended_error_logging; extern int ql2xqfullrampup; +extern int num_hosts; + +/* + * Global Functions in qla_mid.c source file. + */ +extern struct scsi_host_template qla2x00_driver_template; +extern struct scsi_host_template qla24xx_driver_template; +extern struct scsi_transport_template *qla2xxx_transport_vport_template; +extern uint8_t qla2x00_mem_alloc(scsi_qla_host_t *); +extern void qla2x00_timer(scsi_qla_host_t *); +extern void qla2x00_start_timer(scsi_qla_host_t *, void *, unsigned long); +extern void qla2x00_stop_timer(scsi_qla_host_t *); +extern uint32_t qla24xx_allocate_vp_id(scsi_qla_host_t *); +extern void qla24xx_deallocate_vp_id(scsi_qla_host_t *); +extern int qla24xx_disable_vp (scsi_qla_host_t *); +extern int qla24xx_enable_vp (scsi_qla_host_t *); +extern void qla2x00_mem_free(scsi_qla_host_t *); +extern int qla24xx_control_vp(scsi_qla_host_t *, int ); +extern int qla24xx_modify_vp_config(scsi_qla_host_t *); +extern int qla2x00_send_change_request(scsi_qla_host_t *, uint16_t, uint16_t); +extern void qla2x00_vp_stop_timer(scsi_qla_host_t *); +extern int qla24xx_configure_vhba (scsi_qla_host_t *); +extern int qla24xx_get_vp_entry(scsi_qla_host_t *, uint16_t, int); +extern int qla24xx_get_vp_database(scsi_qla_host_t *, uint16_t); +extern int qla2x00_do_dpc_vp(scsi_qla_host_t *); +extern void qla24xx_report_id_acquisition(scsi_qla_host_t *, + struct vp_rpt_id_entry_24xx *); +extern scsi_qla_host_t * qla24xx_find_vhost_by_name(scsi_qla_host_t *, + uint8_t *); +extern void qla2x00_do_dpc_all_vps(scsi_qla_host_t *); +extern int qla24xx_vport_create_req_sanity_check(struct fc_vport *); +extern scsi_qla_host_t * qla24xx_create_vhost(struct fc_vport *); extern void qla2x00_sp_compl(scsi_qla_host_t *, srb_t *); @@ -77,6 +109,10 @@ extern struct fw_blob *qla2x00_request_firmware(scsi_qla_host_t *); extern int qla2x00_wait_for_hba_online(scsi_qla_host_t *); extern void qla2xxx_wake_dpc(scsi_qla_host_t *); +extern void qla2x00_alert_all_vps(scsi_qla_host_t *, uint16_t *); +extern void qla2x00_async_event(scsi_qla_host_t *, uint16_t *); +extern void qla2x00_vp_abort_isp(scsi_qla_host_t *); +extern int qla24xx_vport_delete(struct fc_vport *); /* * Global Function Prototypes in qla_iocb.c source file. @@ -128,7 +164,7 @@ qla2x00_abort_target(fc_port_t *); extern int qla2x00_get_adapter_id(scsi_qla_host_t *, uint16_t *, uint8_t *, uint8_t *, - uint8_t *, uint16_t *); + uint8_t *, uint16_t *, uint16_t *); extern int qla2x00_get_retry_cnt(scsi_qla_host_t *, uint8_t *, uint8_t *, uint16_t *); @@ -303,6 +339,7 @@ struct class_device_attribute; extern struct class_device_attribute *qla2x00_host_attrs[]; struct fc_function_template; extern struct fc_function_template qla2xxx_transport_functions; +extern struct fc_function_template qla2xxx_transport_vport_functions; extern void qla2x00_alloc_sysfs_attr(scsi_qla_host_t *); extern void qla2x00_free_sysfs_attr(scsi_qla_host_t *); extern void qla2x00_init_host_attr(scsi_qla_host_t *); diff --git a/drivers/scsi/qla2xxx/qla_gs.c b/drivers/scsi/qla2xxx/qla_gs.c index ec5b2dd90d6..a086b3f0df6 100644 --- a/drivers/scsi/qla2xxx/qla_gs.c +++ b/drivers/scsi/qla2xxx/qla_gs.c @@ -88,6 +88,7 @@ qla24xx_prep_ms_iocb(scsi_qla_host_t *ha, uint32_t req_size, uint32_t rsp_size) ct_pkt->dseg_1_address[0] = cpu_to_le32(LSD(ha->ct_sns_dma)); ct_pkt->dseg_1_address[1] = cpu_to_le32(MSD(ha->ct_sns_dma)); ct_pkt->dseg_1_len = ct_pkt->rsp_byte_count; + ct_pkt->vp_index = ha->vp_idx; return (ct_pkt); } @@ -1186,6 +1187,7 @@ qla24xx_prep_ms_fdmi_iocb(scsi_qla_host_t *ha, uint32_t req_size, ct_pkt->dseg_1_address[0] = cpu_to_le32(LSD(ha->ct_sns_dma)); ct_pkt->dseg_1_address[1] = cpu_to_le32(MSD(ha->ct_sns_dma)); ct_pkt->dseg_1_len = ct_pkt->rsp_byte_count; + ct_pkt->vp_index = ha->vp_idx; return ct_pkt; } @@ -1746,6 +1748,7 @@ qla24xx_prep_ms_fm_iocb(scsi_qla_host_t *ha, uint32_t req_size, ct_pkt->dseg_1_address[0] = cpu_to_le32(LSD(ha->ct_sns_dma)); ct_pkt->dseg_1_address[1] = cpu_to_le32(MSD(ha->ct_sns_dma)); ct_pkt->dseg_1_len = ct_pkt->rsp_byte_count; + ct_pkt->vp_index = ha->vp_idx; return ct_pkt; } diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index 2a45aec4ff2..bd95f7dc5cf 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -899,6 +899,10 @@ qla2x00_setup_chip(scsi_qla_host_t *ha) &ha->fw_subminor_version, &ha->fw_attributes, &ha->fw_memory_size); qla2x00_resize_request_q(ha); + ha->flags.npiv_supported = 0; + if (IS_QLA24XX(ha) && + (ha->fw_attributes & BIT_2)) + ha->flags.npiv_supported = 1; if (ql2xallocfwdump) qla2x00_alloc_fw_dump(ha); @@ -1101,6 +1105,8 @@ qla2x00_init_rings(scsi_qla_host_t *ha) int rval; unsigned long flags = 0; int cnt; + struct mid_init_cb_24xx *mid_init_cb = + (struct mid_init_cb_24xx *) ha->init_cb; spin_lock_irqsave(&ha->hardware_lock, flags); @@ -1132,6 +1138,10 @@ qla2x00_init_rings(scsi_qla_host_t *ha) ha->isp_ops.update_fw_options(ha); DEBUG(printk("scsi(%ld): Issue init firmware.\n", ha->host_no)); + + mid_init_cb->count = MAX_NUM_VPORT_FABRIC; + ha->max_npiv_vports = MAX_NUM_VPORT_FABRIC; + rval = qla2x00_init_firmware(ha, ha->init_cb_size); if (rval) { DEBUG2_3(printk("scsi(%ld): Init firmware **** FAILED ****.\n", @@ -1263,6 +1273,7 @@ qla2x00_configure_hba(scsi_qla_host_t *ha) int rval; uint16_t loop_id; uint16_t topo; + uint16_t sw_cap; uint8_t al_pa; uint8_t area; uint8_t domain; @@ -1270,7 +1281,7 @@ qla2x00_configure_hba(scsi_qla_host_t *ha) /* Get host addresses. */ rval = qla2x00_get_adapter_id(ha, - &loop_id, &al_pa, &area, &domain, &topo); + &loop_id, &al_pa, &area, &domain, &topo, &sw_cap); if (rval != QLA_SUCCESS) { if (LOOP_TRANSITION(ha) || atomic_read(&ha->loop_down_timer) || (rval == QLA_COMMAND_ERROR && loop_id == 0x7)) { @@ -1295,6 +1306,7 @@ qla2x00_configure_hba(scsi_qla_host_t *ha) /* initialize */ ha->min_external_loopid = SNS_FIRST_LOOP_ID; ha->operating_mode = LOOP; + ha->switch_cap = 0; switch (topo) { case 0: @@ -1307,6 +1319,7 @@ qla2x00_configure_hba(scsi_qla_host_t *ha) case 1: DEBUG3(printk("scsi(%ld): HBA in FL topology.\n", ha->host_no)); + ha->switch_cap = sw_cap; ha->current_topology = ISP_CFG_FL; strcpy(connect_type, "(FL_Port)"); break; @@ -1322,6 +1335,7 @@ qla2x00_configure_hba(scsi_qla_host_t *ha) case 3: DEBUG3(printk("scsi(%ld): HBA in F P2P topology.\n", ha->host_no)); + ha->switch_cap = sw_cap; ha->operating_mode = P2P; ha->current_topology = ISP_CFG_F; strcpy(connect_type, "(F_Port)"); @@ -1743,7 +1757,6 @@ qla2x00_rport_del(void *data) spin_unlock_irqrestore(&fcport->rport_lock, flags); if (rport) fc_remote_port_delete(rport); - } /** @@ -1765,6 +1778,7 @@ qla2x00_alloc_fcport(scsi_qla_host_t *ha, gfp_t flags) /* Setup fcport template structure. */ memset(fcport, 0, sizeof (fc_port_t)); fcport->ha = ha; + fcport->vp_idx = ha->vp_idx; fcport->port_type = FCT_UNKNOWN; fcport->loop_id = FC_NO_LOOP_ID; atomic_set(&fcport->state, FCS_UNCONFIGURED); @@ -1911,6 +1925,7 @@ qla2x00_configure_local_loop(scsi_qla_host_t *ha) char *id_iter; uint16_t loop_id; uint8_t domain, area, al_pa; + scsi_qla_host_t *pha = to_qla_parent(ha); found_devs = 0; new_fcport = NULL; @@ -1942,7 +1957,10 @@ qla2x00_configure_local_loop(scsi_qla_host_t *ha) /* * Mark local devices that were present with FCF_DEVICE_LOST for now. */ - list_for_each_entry(fcport, &ha->fcports, list) { + list_for_each_entry(fcport, &pha->fcports, list) { + if (fcport->vp_idx != ha->vp_idx) + continue; + if (atomic_read(&fcport->state) == FCS_ONLINE && fcport->port_type != FCT_BROADCAST && (fcport->flags & FCF_FABRIC_DEVICE) == 0) { @@ -1988,6 +2006,7 @@ qla2x00_configure_local_loop(scsi_qla_host_t *ha) new_fcport->d_id.b.area = area; new_fcport->d_id.b.al_pa = al_pa; new_fcport->loop_id = loop_id; + new_fcport->vp_idx = ha->vp_idx; rval2 = qla2x00_get_port_database(ha, new_fcport, 0); if (rval2 != QLA_SUCCESS) { DEBUG2(printk("scsi(%ld): Failed to retrieve fcport " @@ -2003,7 +2022,10 @@ qla2x00_configure_local_loop(scsi_qla_host_t *ha) /* Check for matching device in port list. */ found = 0; fcport = NULL; - list_for_each_entry(fcport, &ha->fcports, list) { + list_for_each_entry(fcport, &pha->fcports, list) { + if (fcport->vp_idx != ha->vp_idx) + continue; + if (memcmp(new_fcport->port_name, fcport->port_name, WWN_SIZE)) continue; @@ -2023,7 +2045,13 @@ qla2x00_configure_local_loop(scsi_qla_host_t *ha) if (!found) { /* New device, add to fcports list. */ new_fcport->flags &= ~FCF_PERSISTENT_BOUND; - list_add_tail(&new_fcport->list, &ha->fcports); + if (ha->parent) { + new_fcport->ha = ha; + new_fcport->vp_idx = ha->vp_idx; + list_add_tail(&new_fcport->vp_fcport, + &ha->vp_fcports); + } + list_add_tail(&new_fcport->list, &pha->fcports); /* Allocate a new replacement fcport. */ fcport = new_fcport; @@ -2199,11 +2227,13 @@ qla2x00_reg_remote_port(scsi_qla_host_t *ha, fc_port_t *fcport) void qla2x00_update_fcport(scsi_qla_host_t *ha, fc_port_t *fcport) { + scsi_qla_host_t *pha = to_qla_parent(ha); + fcport->ha = ha; fcport->login_retry = 0; - fcport->port_login_retry_count = ha->port_down_retry_count * + fcport->port_login_retry_count = pha->port_down_retry_count * PORT_RETRY_TIME; - atomic_set(&fcport->port_down_timer, ha->port_down_retry_count * + atomic_set(&fcport->port_down_timer, pha->port_down_retry_count * PORT_RETRY_TIME); fcport->flags &= ~FCF_LOGIN_NEEDED; @@ -2234,6 +2264,7 @@ qla2x00_configure_fabric(scsi_qla_host_t *ha) uint16_t mb[MAILBOX_REGISTER_COUNT]; uint16_t loop_id; LIST_HEAD(new_fcports); + scsi_qla_host_t *pha = to_qla_parent(ha); /* If FL port exists, then SNS is present */ if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) @@ -2307,7 +2338,10 @@ qla2x00_configure_fabric(scsi_qla_host_t *ha) * Logout all previous fabric devices marked lost, except * tape devices. */ - list_for_each_entry(fcport, &ha->fcports, list) { + list_for_each_entry(fcport, &pha->fcports, list) { + if (fcport->vp_idx !=ha->vp_idx) + continue; + if (test_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags)) break; @@ -2332,13 +2366,16 @@ qla2x00_configure_fabric(scsi_qla_host_t *ha) } /* Starting free loop ID. */ - next_loopid = ha->min_external_loopid; + next_loopid = pha->min_external_loopid; /* * Scan through our port list and login entries that need to be * logged in. */ - list_for_each_entry(fcport, &ha->fcports, list) { + list_for_each_entry(fcport, &pha->fcports, list) { + if (fcport->vp_idx != ha->vp_idx) + continue; + if (atomic_read(&ha->loop_down_timer) || test_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags)) break; @@ -2380,11 +2417,18 @@ qla2x00_configure_fabric(scsi_qla_host_t *ha) break; } - /* Remove device from the new list and add it to DB */ - list_move_tail(&fcport->list, &ha->fcports); - /* Login and update database */ qla2x00_fabric_dev_login(ha, fcport, &next_loopid); + + if (ha->parent) { + fcport->ha = ha; + fcport->vp_idx = ha->vp_idx; + list_add_tail(&fcport->vp_fcport, + &ha->vp_fcports); + list_move_tail(&fcport->list, + &ha->parent->fcports); + } else + list_move_tail(&fcport->list, &ha->fcports); } } while (0); @@ -2428,6 +2472,11 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *ha, struct list_head *new_fcports) int swl_idx; int first_dev, last_dev; port_id_t wrap, nxt_d_id; + int vp_index; + int empty_vp_index; + int found_vp; + scsi_qla_host_t *vha; + scsi_qla_host_t *pha = to_qla_parent(ha); rval = QLA_SUCCESS; @@ -2461,13 +2510,13 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *ha, struct list_head *new_fcports) return (QLA_MEMORY_ALLOC_FAILED); } new_fcport->flags |= (FCF_FABRIC_DEVICE | FCF_LOGIN_NEEDED); - + new_fcport->vp_idx = ha->vp_idx; /* Set start port ID scan at adapter ID. */ first_dev = 1; last_dev = 0; /* Starting free loop ID. */ - loop_id = ha->min_external_loopid; + loop_id = pha->min_external_loopid; for (; loop_id <= ha->last_loop_id; loop_id++) { if (qla2x00_is_reserved_id(ha, loop_id)) continue; @@ -2521,10 +2570,42 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *ha, struct list_head *new_fcports) break; } - /* Bypass if host adapter. */ - if (new_fcport->d_id.b24 == ha->d_id.b24) + /* Bypass if same physical adapter. */ + if (new_fcport->d_id.b24 == pha->d_id.b24) continue; + /* Bypass virtual ports of the same host. */ + if (pha->num_vhosts) { + vp_index = find_next_bit( + (unsigned long *)pha->vp_idx_map, + MAX_MULTI_ID_FABRIC + 1, 1); + + for (;vp_index <= MAX_MULTI_ID_FABRIC; + vp_index = find_next_bit( + (unsigned long *)pha->vp_idx_map, + MAX_MULTI_ID_FABRIC + 1, vp_index + 1)) { + empty_vp_index = 1; + found_vp = 0; + list_for_each_entry(vha, &pha->vp_list, + vp_list) { + if (vp_index == vha->vp_idx) { + empty_vp_index = 0; + found_vp = 1; + break; + } + } + + if (empty_vp_index) + continue; + + if (found_vp && + new_fcport->d_id.b24 == vha->d_id.b24) + break; + } + if (vp_index <= MAX_MULTI_ID_FABRIC) + continue; + } |