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

[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
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
......@@ -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;
}
......@@ -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
*/
......
......@@ -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;
......
......@@ -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
......@@ -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 *);
......
......@@ -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;
}
......
......@@ -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;
}
/* Bypass if same domain and area of adapter. */
if (((new_fcport->d_id.b24 & 0xffff00) ==
(ha->d_id.b24 & 0xffff00)) && ha->current_topology ==
......@@ -2537,7 +2618,9 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *ha, struct list_head *new_fcports)
/* Locate matching device in database. */
found = 0;
list_for_each_entry(fcport, &ha->fcports, list) {
list_for_each_entry(fcport, &pha->fcports, list) {
if (new_fcport->vp_idx != fcport->vp_idx)
continue;
if (memcmp(new_fcport->port_name, fcport->port_name,
WWN_SIZE))
continue;
......@@ -2605,6 +2688,7 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *ha, struct list_head *new_fcports)
}
new_fcport->flags |= (FCF_FABRIC_DEVICE | FCF_LOGIN_NEEDED);
new_fcport->d_id.b24 = nxt_d_id.b24;
new_fcport->vp_idx = ha->vp_idx;
}
kfree(swl);
......@@ -2637,6 +2721,7 @@ qla2x00_find_new_loop_id(scsi_qla_host_t *ha, fc_port_t *dev)
int found;
fc_port_t *fcport;
uint16_t first_loop_id;
scsi_qla_host_t *pha = to_qla_parent(ha);
rval = QLA_SUCCESS;
......@@ -2663,7 +2748,7 @@ qla2x00_find_new_loop_id(scsi_qla_host_t *ha, fc_port_t *dev)
/* Check for loop ID being already in use. */
found = 0;
fcport = NULL;
list_for_each_entry(fcport, &ha->fcports, list) {
list_for_each_entry(fcport, &pha->fcports, list) {
if (fcport->loop_id == dev->loop_id && fcport != dev) {
/* ID possibly in use */
found++;
......@@ -2710,6 +2795,7 @@ qla2x00_device_resync(scsi_qla_host_t *ha)
uint8_t rscn_out_iter;
uint8_t format;
port_id_t d_id;
scsi_qla_host_t *pha = to_qla_parent(ha);
rval = QLA_RSCNS_HANDLED;
......@@ -2776,7 +2862,10 @@ qla2x00_device_resync(scsi_qla_host_t *ha)
rval = QLA_SUCCESS;
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 ((fcport->flags & FCF_FABRIC_DEVICE) == 0 ||
(fcport->d_id.b24 & mask) != d_id.b24 ||
fcport->port_type == FCT_BROADCAST)
......@@ -3940,3 +4029,40 @@ qla2x00_try_to_stop_firmware(scsi_qla_host_t *ha)
ret = qla2x00_stop_firmware(ha);
}
}
int
qla24xx_configure_vhba(scsi_qla_host_t *ha)
{
int rval = QLA_SUCCESS;
uint16_t mb[MAILBOX_REGISTER_COUNT];
if (!ha->parent)
return -EINVAL;
rval = qla2x00_fw_ready(ha);
if (rval == QLA_SUCCESS) {
clear_bit(RESET_MARKER_NEEDED, &ha->dpc_flags);
qla2x00_marker(ha, 0, 0, MK_SYNC_ALL);
}
ha->flags.management_server_logged_in = 0;
/* Login to SNS first */
qla24xx_login_fabric(ha, NPH_SNS, 0xff, 0xff, 0xfc,
mb, BIT_1);
if (mb[0] != MBS_COMMAND_COMPLETE) {
DEBUG15(qla_printk(KERN_INFO, ha,
"Failed SNS login: loop_id=%x mb[0]=%x mb[1]=%x "
"mb[2]=%x mb[6]=%x mb[7]=%x\n", NPH_SNS,
mb[0], mb[1], mb[2], mb[6], mb[7]));
return (QLA_FUNCTION_FAILED);
}
atomic_set(&ha->loop_down_timer, 0);
atomic_set(&ha->loop_state, LOOP_UP);
set_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags);
set_bit(LOCAL_LOOP_UPDATE, &ha->dpc_flags);
rval = qla2x00_loop_resync(ha);
return rval;
}
......@@ -179,7 +179,6 @@ void qla2x00_build_scsi_iocbs_32(srb_t *sp, cmd_entry_t *cmd_pkt,
cur_dsd = (uint32_t *)&cmd_pkt->dseg_0_address;
/* Load data segments */
scsi_for_each_sg(cmd, sg, tot_dsds, i) {
cont_entry_t *cont_pkt;
......@@ -316,9 +315,14 @@ qla2x00_start_scsi(srb_t *sp)
goto queuing_error;
/* Map the sg table so we have an accurate count of sg entries needed */
nseg = scsi_dma_map(cmd);
if (nseg < 0)
goto queuing_error;
if (scsi_sg_count(cmd)) {
nseg = dma_map_sg(&ha->pdev->dev, scsi_sglist(cmd),
scsi_sg_count(cmd), cmd->sc_data_direction);
if (unlikely(!nseg))
goto queuing_error;
} else
nseg = 0;
tot_dsds = nseg;
/* Calculate the number of request entries needed. */
......@@ -414,9 +418,10 @@ __qla2x00_marker(scsi_qla_host_t *ha, uint16_t loop_id, uint16_t lun,
{
mrk_entry_t *mrk;
struct mrk_entry_24xx *mrk24;
scsi_qla_host_t *pha = to_qla_parent(ha);
mrk24 = NULL;
mrk = (mrk_entry_t *)qla2x00_req_pkt(ha);
mrk = (mrk_entry_t *)qla2x00_req_pkt(pha);
if (mrk == NULL) {
DEBUG2_3(printk("%s(%ld): failed to allocate Marker IOCB.\n",
__func__, ha->host_no));
......@@ -433,6 +438,7 @@ __qla2x00_marker(scsi_qla_host_t *ha, uint16_t loop_id, uint16_t lun,
mrk24->lun[1] = LSB(lun);
mrk24->lun[2] = MSB(lun);
host_to_fcp_swap(mrk24->lun, sizeof(mrk24->lun));
mrk24->vp_index = ha->vp_idx;
} else {
SET_TARGET_ID(ha, mrk->target, loop_id);
mrk->lun = cpu_to_le16(lun);
......@@ -440,7 +446,7 @@ __qla2x00_marker(scsi_qla_host_t *ha, uint16_t loop_id, uint16_t lun,
}
wmb();
qla2x00_isp_cmd(ha);
qla2x00_isp_cmd(pha);
return (QLA_SUCCESS);
}
......@@ -712,9 +718,14 @@ qla24xx_start_scsi(srb_t *sp)
goto queuing_error;
/* Map the sg table so we have an accurate count of sg entries needed */
nseg = scsi_dma_map(cmd);
if (nseg < 0)
if (scsi_sg_count(cmd)) {
nseg = dma_map_sg(&ha->pdev->dev, scsi_sglist(cmd),
scsi_sg_count(cmd), cmd->sc_data_direction);
if (unlikely(!nseg))
goto queuing_error;
} else
nseg = 0;
tot_dsds = nseg;
req_cnt = qla24xx_calc_iocbs(tot_dsds);
......@@ -750,6 +761,7 @@ qla24xx_start_scsi(srb_t *sp)
cmd_pkt->port_id[0] = sp->fcport->d_id.b.al_pa;
cmd_pkt->port_id[1] = sp->fcport->d_id.b.area;
cmd_pkt->port_id[2] = sp->fcport->d_id.b.domain;
cmd_pkt->vp_index = sp->fcport->vp_idx;
int_to_scsilun(sp->cmd->device->lun, &cmd_pkt->lun);
host_to_fcp_swap((uint8_t *)&cmd_pkt->lun, sizeof(cmd_pkt->lun));
......
......@@ -9,7 +9,6 @@
#include <scsi/scsi_tcq.h>
static void qla2x00_mbx_completion(scsi_qla_host_t *, uint16_t);
static void qla2x00_async_event(scsi_qla_host_t *, uint16_t *);
static void qla2x00_process_completed_request(struct scsi_qla_host *, uint32_t);
static void qla2x00_status_entry(scsi_qla_host_t *, void *);
static void qla2x00_status_cont_entry(scsi_qla_host_t *, sts_cont_entry_t *);
......@@ -244,7 +243,7 @@ qla2x00_mbx_completion(scsi_qla_host_t *ha, uint16_t mb0)
* @ha: SCSI driver HA context
* @mb: Mailbox registers (0 - 3)
*/
static void
void
qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb)
{
#define LS_UNKNOWN 2
......@@ -386,6 +385,11 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb)
qla2x00_mark_all_devices_lost(ha, 1);
}
if (ha->parent) {
atomic_set(&ha->vp_state, VP_FAILED);
fc_vport_set_state(ha->fc_vport, FC_VPORT_FAILED);
}
set_bit(REGISTER_FC4_NEEDED, &ha->dpc_flags);
ha->flags.management_server_logged_in = 0;
......@@ -422,6 +426,11 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb)
qla2x00_mark_all_devices_lost(ha, 1);
}
if (ha->parent) {
atomic_set(&ha->vp_state, VP_FAILED);
fc_vport_set_state(ha->fc_vport, FC_VPORT_FAILED);
}
ha->flags.management_server_logged_in = 0;
ha->link_data_rate = PORT_SPEED_UNKNOWN;
if (ql2xfdmienable)
......@@ -440,6 +449,11 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb)
qla2x00_mark_all_devices_lost(ha, 1);
}
if (ha->parent) {
atomic_set(&ha->vp_state, VP_FAILED);
fc_vport_set_state(ha->fc_vport, FC_VPORT_FAILED);
}
set_bit(RESET_MARKER_NEEDED, &ha->dpc_flags);
ha->operating_mode = LOOP;
......@@ -465,6 +479,11 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb)
qla2x00_mark_all_devices_lost(ha, 1);
}
if (ha->parent) {
atomic_set(&ha->vp_state, VP_FAILED);
fc_vport_set_state(ha->fc_vport, FC_VPORT_FAILED);
}
if (!(test_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags))) {
set_bit(RESET_MARKER_NEEDED, &ha->dpc_flags);
}
......@@ -491,6 +510,11 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb)
qla2x00_mark_all_devices_lost(ha, 1);
}
if (ha->parent) {
atomic_set(&ha->vp_state, VP_FAILED);
fc_vport_set_state(ha->fc_vport, FC_VPORT_FAILED);
}
set_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags);
set_bit(LOCAL_LOOP_UPDATE, &ha->dpc_flags);
break;
......@@ -530,6 +554,10 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb)
break;
case MBA_RSCN_UPDATE: /* State Change Registration */
/* Check if the Vport has issued a SCR */
if (ha->parent && test_bit(VP_SCR_NEEDED, &ha->vp_flags))
break;
DEBUG2(printk("scsi(%ld): Asynchronous RSCR UPDATE.\n",
ha->host_no));
DEBUG(printk(KERN_INFO
......@@ -589,6 +617,9 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb)
ha->host_no, mb[1], mb[2]));
break;
}
if (!ha->parent && ha->num_vhosts)
qla2x00_alert_all_vps(ha, mb);
}
static void
......@@ -1393,6 +1424,10 @@ qla24xx_process_response_queue(struct scsi_qla_host *ha)
case MS_IOCB_TYPE:
qla24xx_ms_entry(ha, (struct ct_entry_24xx *)pkt);
break;
case VP_RPT_ID_IOCB_TYPE:
qla24xx_report_id_acquisition(ha,
(struct vp_rpt_id_entry_24xx *)pkt);
break;
default:
/* Type Not Supported. */
DEBUG4(printk(KERN_WARNING
......
......@@ -42,25 +42,29 @@ qla2x00_mbx_sem_timeout(unsigned long data)
* Kernel context.
*/
static int
qla2x00_mailbox_command(scsi_qla_host_t *ha, mbx_cmd_t *mcp)
qla2x00_mailbox_command(scsi_qla_host_t *pvha, mbx_cmd_t *mcp)
{
int rval;
unsigned long flags = 0;
device_reg_t __iomem *reg = ha->iobase;
device_reg_t __iomem *reg;
struct timer_list tmp_intr_timer;
uint8_t abort_active;
uint8_t io_lock_on = ha->flags.init_done;
uint8_t io_lock_on;
uint16_t command;
uint16_t *iptr;
uint16_t __iomem *optr;
uint32_t cnt;
uint32_t mboxes;
unsigned long wait_time;
scsi_qla_host_t *ha = to_qla_parent(pvha);
reg = ha->iobase;
io_lock_on = ha->flags.init_done;
rval = QLA_SUCCESS;
abort_active = test_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags);
DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no));
DEBUG11(printk("%s(%ld): entered.\n", __func__, pvha->host_no));
/*
* Wait for active mailbox commands to finish by waiting at most tov
......@@ -889,7 +893,7 @@ qla2x00_abort_target(fc_port_t *fcport)
*/
int
qla2x00_get_adapter_id(scsi_qla_host_t *ha, uint16_t *id, uint8_t *al_pa,
uint8_t *area, uint8_t *domain, uint16_t *top)
uint8_t *area, uint8_t *domain, uint16_t *top, uint16_t *sw_cap)
{
int rval;
mbx_cmd_t mc;
......@@ -899,8 +903,9 @@ qla2x00_get_adapter_id(scsi_qla_host_t *ha, uint16_t *id, uint8_t *al_pa,
ha->host_no));
mcp->mb[0] = MBC_GET_ADAPTER_LOOP_ID;
mcp->mb[9] = ha->vp_idx;
mcp->out_mb = MBX_0;
mcp->in_mb = MBX_7|MBX_6|MBX_3|MBX_2|MBX_1|MBX_0;
mcp->in_mb = MBX_9|MBX_7|MBX_6|MBX_3|MBX_2|MBX_1|MBX_0;
mcp->tov = 30;
mcp->flags = 0;
rval = qla2x00_mailbox_command(ha, mcp);
......@@ -913,6 +918,7 @@ qla2x00_get_adapter_id(scsi_qla_host_t *ha, uint16_t *id, uint8_t *al_pa,
*area = MSB(mcp->mb[2]);
*domain = LSB(mcp->mb[3]);
*top = mcp->mb[6];
*sw_cap = mcp->mb[7];
if (rval != QLA_SUCCESS) {
/*EMPTY*/
......@@ -1009,7 +1015,11 @@ qla2x00_init_firmware(scsi_qla_host_t *ha, uint16_t size)
DEBUG11(printk("qla2x00_init_firmware(%ld): entered.\n",
ha->host_no));
mcp->mb[0] = MBC_INITIALIZE_FIRMWARE;
if (ha->flags.npiv_supported)
mcp->mb[0] = MBC_MID_INITIALIZE_FIRMWARE;
else
mcp->mb[0] = MBC_INITIALIZE_FIRMWARE;
mcp->mb[2] = MSW(ha->init_cb_dma);
mcp->mb[3] = LSW(ha->init_cb_dma);
mcp->mb[4] = 0;
......@@ -1081,7 +1091,8 @@ qla2x00_get_port_database(scsi_qla_host_t *ha, fc_port_t *fcport, uint8_t opt)
mcp->mb[3] = LSW(pd_dma);
mcp->mb[6] = MSW(MSD(pd_dma));
mcp->mb[7] = LSW(MSD(pd_dma));
mcp->out_mb = MBX_7|MBX_6|MBX_3|MBX_2|MBX_0;
mcp->mb[9] = ha->vp_idx;
mcp->out_mb = MBX_9|MBX_7|MBX_6|MBX_3|MBX_2|MBX_0;
mcp->in_mb = MBX_0;
if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) {
mcp->mb[1] = fcport->loop_id;
......@@ -1259,7 +1270,8 @@ qla2x00_get_port_name(scsi_qla_host_t *ha, uint16_t loop_id, uint8_t *name,
ha->host_no));
mcp->mb[0] = MBC_GET_PORT_NAME;
mcp->out_mb = MBX_1|MBX_0;
mcp->mb[9] = ha->vp_idx;
mcp->out_mb = MBX_9|MBX_1|MBX_0;
if (HAS_EXTENDED_IDS(ha)) {
mcp->mb[1] = loop_id;
mcp->mb[10] = opt;
......@@ -1447,6 +1459,7 @@ qla24xx_login_fabric(scsi_qla_host_t *ha, uint16_t loop_id, uint8_t domain,
lg->port_id[0] = al_pa;
lg->port_id[1] = area;
lg->port_id[2] = domain;
lg->vp_index = cpu_to_le16(ha->vp_idx);
rval = qla2x00_issue_iocb(ha, lg, lg_dma, 0);
if (rval != QLA_SUCCESS) {
DEBUG2_3_11(printk("%s(%ld): failed to issue Login IOCB "
......@@ -1701,6 +1714,7 @@ qla24xx_fabric_logout(scsi_qla_host_t *ha, uint16_t loop_id, uint8_t domain,
lg->port_id[0] = al_pa;
lg->port_id[1] = area;
lg->port_id[2] = domain;
lg->vp_index = cpu_to_le16(ha->vp_idx);
rval = qla2x00_issue_iocb(ha, lg, lg_dma, 0);
if (rval != QLA_SUCCESS) {
DEBUG2_3_11(printk("%s(%ld): failed to issue Logout IOCB "
......@@ -1863,7 +1877,8 @@ qla2x00_get_id_list(scsi_qla_host_t *ha, void *id_list, dma_addr_t id_list_dma,
mcp->mb[6] = MSW(MSD(id_list_dma));
mcp->mb[7] = LSW(MSD(id_list_dma));
mcp->mb[8] = 0;
mcp->out_mb |= MBX_8|MBX_7|MBX_6|MBX_3|MBX_2;
mcp->mb[9] = ha->vp_idx;
mcp->out_mb |= MBX_9|MBX_8|MBX_7|MBX_6|MBX_3|MBX_2;
} else {
mcp->mb[1] = MSW(id_list_dma);
mcp->mb[2] = LSW(id_list_dma);
......@@ -2212,6 +2227,7 @@ qla24xx_abort_command(scsi_qla_host_t *ha, srb_t *sp)
abt->port_id[0] = fcport->d_id.b.al_pa;
abt->port_id[1] = fcport->d_id.b.area;
abt->port_id[2] = fcport->d_id.b.domain;
abt->vp_index = fcport->vp_idx;
rval = qla2x00_issue_iocb(ha, abt, abt_dma, 0);
if (rval != QLA_SUCCESS) {
DEBUG2_3_11(printk("%s(%ld): failed to issue IOCB (%x).\n",
......@@ -2249,7 +2265,7 @@ qla24xx_abort_target(fc_port_t *fcport)
int rval;
struct tsk_mgmt_cmd *tsk;
dma_addr_t tsk_dma;
scsi_qla_host_t *ha;
scsi_qla_host_t *ha, *pha;
if (fcport == NULL)
return 0;
......@@ -2257,7 +2273,8 @@ qla24xx_abort_target(fc_port_t *fcport)
DEBUG11(printk("%s(%ld): entered.\n", __func__, fcport->ha->host_no));
ha = fcport->ha;
tsk = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &tsk_dma);
pha = to_qla_parent(ha);
tsk = dma_pool_alloc(pha->s_dma_pool, GFP_KERNEL, &tsk_dma);
if (tsk == NULL) {
DEBUG2_3(printk("%s(%ld): failed to allocate Task Management "
"IOCB.\n", __func__, ha->host_no));
......@@ -2273,6 +2290,8 @@ qla24xx_abort_target(fc_port_t *fcport)
tsk->p.tsk.port_id[0] = fcport->d_id.b.al_pa;
tsk->p.tsk.port_id[1] = fcport->d_id.b.area;
tsk->p.tsk.port_id[2] = fcport->d_id.b.domain;
tsk->p.tsk.vp_index = fcport->vp_idx;
rval = qla2x00_issue_iocb(ha, tsk, tsk_dma, 0);
if (rval != QLA_SUCCESS) {
DEBUG2_3_11(printk("%s(%ld): failed to issue Target Reset IOCB "
......@@ -2303,7 +2322,7 @@ qla24xx_abort_target(fc_port_t *fcport)
}
atarget_done:
dma_pool_free(ha->s_dma_pool, tsk, tsk_dma);
dma_pool_free(pha->s_dma_pool, tsk, tsk_dma);
return rval;
}
......@@ -2610,3 +2629,354 @@ qla2x00_set_idma_speed(scsi_qla_host_t *ha, uint16_t loop_id,
return rval;
}
/*
* qla24xx_get_vp_database
* Get the VP's database for all configured ports.
*
* Input:
* ha = adapter block pointer.
* size = size of initialization control block.
*
* Returns:
* qla2x00 local function return status code.
*
* Context:
* Kernel context.
*/
int
qla24xx_get_vp_database(scsi_qla_host_t *ha, uint16_t size)
{
int rval;
mbx_cmd_t mc;
mbx_cmd_t *mcp = &mc;
DEBUG11(printk("scsi(%ld):%s - entered.\n",
ha->host_no, __func__));
mcp->mb[0] = MBC_MID_GET_VP_DATABASE;
mcp->mb[2] = MSW(ha->init_cb_dma);
mcp->mb[3] = LSW(ha->init_cb_dma);
mcp->mb[4] = 0;
mcp->mb[5] = 0;
mcp->mb[6] = MSW(MSD(ha->init_cb_dma));
mcp->mb[7] = LSW(MSD(ha->init_cb_dma));
mcp->out_mb = MBX_7|MBX_6|MBX_3|MBX_2|MBX_0;
mcp->in_mb = MBX_1|MBX_0;
mcp->buf_size = size;
mcp->flags = MBX_DMA_OUT;
mcp->tov = MBX_TOV_SECONDS;
rval = qla2x00_mailbox_command(ha, mcp);
if (rval != QLA_SUCCESS) {
/*EMPTY*/
DEBUG2_3_11(printk("%s(%ld): failed=%x "
"mb0=%x.\n",
__func__, ha->host_no, rval, mcp->mb[0]));
} else {
/*EMPTY*/
DEBUG11(printk("%s(%ld): done.\n",
__func__, ha->host_no));
}
return rval;
}
int
qla24xx_get_vp_entry(scsi_qla_host_t *ha, uint16_t size, int vp_id)
{
int rval;
mbx_cmd_t mc;
mbx_cmd_t *mcp = &mc;
DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no));
mcp->mb[0] = MBC_MID_GET_VP_ENTRY;
mcp->mb[2] = MSW(ha->init_cb_dma);
mcp->mb[3] = LSW(ha->init_cb_dma);
mcp->mb[4] = 0;
mcp->mb[5] = 0;
mcp->mb[6] = MSW(MSD(ha->init_cb_dma));
mcp->mb[7] = LSW(MSD(ha->init_cb_dma));
mcp->mb[9] = vp_id;
mcp->out_mb = MBX_9|MBX_7|MBX_6|MBX_3|MBX_2|MBX_0;
mcp->in_mb = MBX_0;
mcp->buf_size = size;
mcp->flags = MBX_DMA_OUT;
mcp->tov = 30;
rval = qla2x00_mailbox_command(ha, mcp);
if (rval != QLA_SUCCESS) {
/*EMPTY*/
DEBUG2_3_11(printk("qla24xx_get_vp_entry(%ld): failed=%x "
"mb0=%x.\n",
ha->host_no, rval, mcp->mb[0]));
} else {
/*EMPTY*/
DEBUG11(printk("qla24xx_get_vp_entry(%ld): done.\n",
ha->host_no));
}
return rval;
}
void
qla24xx_report_id_acquisition(scsi_qla_host_t *ha,
struct vp_rpt_id_entry_24xx *rptid_entry)
{
uint8_t vp_idx;
scsi_qla_host_t *vha;
if (rptid_entry->entry_status != 0)
return;
if (rptid_entry->entry_status != __constant_cpu_to_le16(CS_COMPLETE))
return;
if (rptid_entry->format == 0) {
DEBUG15(printk("%s:format 0 : scsi(%ld) number of VPs setup %d,"
" number of VPs acquired %d\n", __func__, ha->host_no,
MSB(rptid_entry->vp_count), LSB(rptid_entry->vp_count)));
DEBUG15(printk("%s primary port id %02x%02x%02x\n", __func__,
rptid_entry->port_id[2], rptid_entry->port_id[1],
rptid_entry->port_id[0]));
} else if (rptid_entry->format == 1) {
vp_idx = LSB(rptid_entry->vp_idx);
DEBUG15(printk("%s:format 1: scsi(%ld): VP[%d] enabled "
"- status %d - "
"with port id %02x%02x%02x\n",__func__,ha->host_no,
vp_idx, MSB(rptid_entry->vp_idx),
rptid_entry->port_id[2], rptid_entry->port_id[1],
rptid_entry->port_id[0]));
if (vp_idx == 0)
return;
if (MSB(rptid_entry->vp_idx) == 1)
return;
list_for_each_entry(vha, &ha->vp_list, vp_list)
if (vp_idx == vha->vp_idx)
break;
if (!vha)
return;
vha->d_id.b.domain = rptid_entry->port_id[2];
vha->d_id.b.area = rptid_entry->port_id[1];
vha->d_id.b.al_pa = rptid_entry->port_id[0];
/*
* Cannot configure here as we are still sitting on the
* response queue. Handle it in dpc context.
*/
set_bit(VP_IDX_ACQUIRED, &vha->vp_flags);
set_bit(VP_DPC_NEEDED, &ha->dpc_flags);
wake_up_process(ha->dpc_thread);
}
}
/*
* qla24xx_modify_vp_config
* Change VP configuration for vha
*
* Input:
* vha = adapter block pointer.
*
* Returns:
* qla2xxx local function return status code.
*
* Context:
* Kernel context.
*/
int
qla24xx_modify_vp_config(scsi_qla_host_t *vha)
{
int rval;
struct vp_config_entry_24xx *vpmod;
dma_addr_t vpmod_dma;
scsi_qla_host_t *pha;
/* This can be called by the parent */
pha = to_qla_parent(vha);
vpmod = dma_pool_alloc(pha->s_dma_pool, GFP_KERNEL, &vpmod_dma);
if (!vpmod) {
DEBUG2_3(printk("%s(%ld): failed to allocate Modify VP "
"IOCB.\n", __func__, pha->host_no));
return QLA_MEMORY_ALLOC_FAILED;
}
memset(vpmod, 0, sizeof(struct vp_config_entry_24xx));
vpmod->entry_type = VP_CONFIG_IOCB_TYPE;
vpmod->entry_count = 1;
vpmod->command = VCT_COMMAND_MOD_ENABLE_VPS;
vpmod->vp_count = 1;
vpmod->vp_index1 = vha->vp_idx;
vpmod->options_idx1 = BIT_3|BIT_4|BIT_5;
memcpy(vpmod->node_name_idx1, vha->node_name, WWN_SIZE);
memcpy(vpmod->port_name_idx1, vha->port_name, WWN_SIZE);
vpmod->entry_count = 1;
rval = qla2x00_issue_iocb(pha, vpmod, vpmod_dma, 0);
if (rval != QLA_SUCCESS) {
DEBUG2_3_11(printk("%s(%ld): failed to issue VP config IOCB"
"(%x).\n", __func__, pha->host_no, rval));
} else if (vpmod->comp_status != 0) {
DEBUG2_3_11(printk("%s(%ld): failed to complete IOCB "
"-- error status (%x).\n", __func__, pha->host_no,
vpmod->comp_status));
rval = QLA_FUNCTION_FAILED;
} else if (vpmod->comp_status != __constant_cpu_to_le16(CS_COMPLETE)) {
DEBUG2_3_11(printk("%s(%ld): failed to complete IOCB "
"-- completion status (%x).\n", __func__, pha->host_no,
le16_to_cpu(vpmod->comp_status)));
rval = QLA_FUNCTION_FAILED;
} else {
/* EMPTY */
DEBUG11(printk("%s(%ld): done.\n", __func__, pha->host_no));
fc_vport_set_state(vha->fc_vport, FC_VPORT_INITIALIZING);
}
dma_pool_free(pha->s_dma_pool, vpmod, vpmod_dma);
return rval;
}
/*
* qla24xx_control_vp
* Enable a virtual port for given host
*
* Input:
* ha = adapter block pointer.
* vhba = virtual adapter (unused)
* index = index number for enabled VP
*
* Returns:
* qla2xxx local function return status code.
*
* Context:
* Kernel context.
*/
int
qla24xx_control_vp(scsi_qla_host_t *vha, int cmd)
{
int rval;
int map, pos;
struct vp_ctrl_entry_24xx *vce;
dma_addr_t vce_dma;
scsi_qla_host_t *ha = vha->parent;
int vp_index = vha->vp_idx;
DEBUG11(printk("%s(%ld): entered. Enabling index %d\n", __func__,
ha->host_no, vp_index));
if (vp_index == 0 || vp_index >= MAX_MULTI_ID_LOOP)
return QLA_PARAMETER_ERROR;
vce = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &vce_dma);
if (!vce) {
DEBUG2_3(printk("%s(%ld): "
"failed to allocate VP Control IOCB.\n", __func__,
ha->host_no));
return QLA_MEMORY_ALLOC_FAILED;
}
memset(vce, 0, sizeof(struct vp_ctrl_entry_24xx));
vce->entry_type = VP_CTRL_IOCB_TYPE;
vce->entry_count = 1;
vce->command = cpu_to_le16(cmd);
vce->vp_count = __constant_cpu_to_le16(1);
/* index map in firmware starts with 1; decrement index
* this is ok as we never use index 0
*/
map = (vp_index - 1) / 8;
pos = (vp_index - 1) & 7;
down(&ha->vport_sem);
vce->vp_idx_map[map] |= 1 << pos;
up(&ha->vport_sem);
rval = qla2x00_issue_iocb(ha, vce, vce_dma, 0);
if (rval != QLA_SUCCESS) {
DEBUG2_3_11(printk("%s(%ld): failed to issue VP control IOCB"
"(%x).\n", __func__, ha->host_no, rval));
printk("%s(%ld): failed to issue VP control IOCB"
"(%x).\n", __func__, ha->host_no, rval);
} else if (vce->entry_status != 0) {
DEBUG2_3_11(printk("%s(%ld): failed to complete IOCB "
"-- error status (%x).\n", __func__, ha->host_no,
vce->entry_status));
printk("%s(%ld): failed to complete IOCB "
"-- error status (%x).\n", __func__, ha->host_no,
vce->entry_status);
rval = QLA_FUNCTION_FAILED;
} else if (vce->comp_status != __constant_cpu_to_le16(CS_COMPLETE)) {
DEBUG2_3_11(printk("%s(%ld): failed to complete IOCB "
"-- completion status (%x).\n", __func__, ha->host_no,
le16_to_cpu(vce->comp_status)));
printk("%s(%ld): failed to complete IOCB "
"-- completion status (%x).\n", __func__, ha->host_no,
le16_to_cpu(vce->comp_status));
rval = QLA_FUNCTION_FAILED;
} else {
DEBUG2(printk("%s(%ld): done.\n", __func__, ha->host_no));
}
dma_pool_free(ha->s_dma_pool, vce, vce_dma);
return rval;
}
/*
* qla2x00_send_change_request
* Receive or disable RSCN request from fabric controller
*
* Input:
* ha = adapter block pointer
* format = registration format:
* 0 - Reserved
* 1 - Fabric detected registration
* 2 - N_port detected registration
* 3 - Full registration
* FF - clear registration
* vp_idx = Virtual port index
*
* Returns:
* qla2x00 local function return status code.
*
* Context:
* Kernel Context
*/
int
qla2x00_send_change_request(scsi_qla_host_t *ha, uint16_t format,
uint16_t vp_idx)
{
int rval;
mbx_cmd_t mc;
mbx_cmd_t *mcp = &mc;
/*
* This command is implicitly executed by firmware during login for the
* physical hosts
*/
if (vp_idx == 0)
return QLA_FUNCTION_FAILED;
mcp->mb[0] = MBC_SEND_CHANGE_REQUEST;
mcp->mb[1] = format;
mcp->mb[9] = vp_idx;
mcp->out_mb = MBX_9|MBX_1|MBX_0;
mcp->in_mb = MBX_0|MBX_1;
mcp->tov = MBX_TOV_SECONDS;
mcp->flags = 0;
rval = qla2x00_mailbox_command(ha, mcp);
if (rval == QLA_SUCCESS) {
if (mcp->mb[0] != MBS_COMMAND_COMPLETE) {
rval = BIT_1;
}
} else
rval = BIT_1;
return rval;
}
/*
* QLOGIC LINUX SOFTWARE
*
* QLogic ISP2x00 device driver for Linux 2.6.x
* Copyright (C) 2003-2005 QLogic Corporation
* (www.qlogic.com)
*
* 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, 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.
*
*/
#include "qla_def.h"
#include <linux/version.h>
#include <linux/moduleparam.h>
#include <linux/vmalloc.h>
#include <linux/smp_lock.h>
#include <linux/list.h>
#include <scsi/scsi_tcq.h>
#include <scsi/scsicam.h>
#include <linux/delay.h>
void qla2x00_vp_stop_timer(scsi_qla_host_t *);
void
qla2x00_vp_stop_timer(scsi_qla_host_t *vha)
{
if (vha->parent && vha->timer_active) {
del_timer_sync(&vha->timer);
vha->timer_active = 0;
}
}
uint32_t
qla24xx_allocate_vp_id(scsi_qla_host_t *vha)
{
uint32_t vp_id;
scsi_qla_host_t *ha = vha->parent;
/* Find an empty slot and assign an vp_id */
down(&ha->vport_sem);
vp_id = find_first_zero_bit((unsigned long *)ha->vp_idx_map,
MAX_MULTI_ID_FABRIC);
if (vp_id > MAX_MULTI_ID_FABRIC) {
DEBUG15(printk ("vp_id %d is bigger than MAX_MULTI_ID_FABRID\n",
vp_id));
up(&ha->vport_sem);
return vp_id;
}
set_bit(vp_id, (unsigned long *)ha->vp_idx_map);
ha->num_vhosts++;
vha->vp_idx = vp_id;
list_add_tail(&vha->vp_list, &ha->vp_list);
up(&ha->vport_sem);
return vp_id;
}
void
qla24xx_deallocate_vp_id(scsi_qla_host_t *vha)
{
uint16_t vp_id;
scsi_qla_host_t *ha = vha->parent;
down(&ha->vport_sem);
vp_id = vha->vp_idx;
ha->num_vhosts--;
clear_bit(vp_id, (unsigned long *)ha->vp_idx_map);
list_del(&vha->vp_list);
up(&ha->vport_sem);
}
scsi_qla_host_t *
qla24xx_find_vhost_by_name(scsi_qla_host_t *ha, uint8_t *port_name)
{
scsi_qla_host_t *vha;
/* Locate matching device in database. */
list_for_each_entry(vha, &ha->vp_list, vp_list) {
if (!memcmp(port_name, vha->port_name, WWN_SIZE))
return vha;
}
return NULL;
}
/*
* qla2x00_mark_vp_devices_dead
* Updates fcport state when device goes offline.
*
* Input:
* ha = adapter block pointer.
* fcport = port structure pointer.
*
* Return:
* None.
*
* Context:
*/
void
qla2x00_mark_vp_devices_dead(scsi_qla_host_t *vha)
{
fc_port_t *fcport;
scsi_qla_host_t *pha = to_qla_parent(vha);
list_for_each_entry(fcport, &pha->fcports, list) {
if (fcport->vp_idx != vha->vp_idx)
continue;
DEBUG15(printk("scsi(%ld): Marking port dead, "
"loop_id=0x%04x :%x\n",
vha->host_no, fcport->loop_id, fcport->vp_idx));
atomic_set(&fcport->state, FCS_DEVICE_DEAD);
qla2x00_mark_device_lost(vha, fcport, 0, 0);
}
}
int
qla24xx_disable_vp(scsi_qla_host_t *vha)
{
int ret;
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);
/* Delete all vp's fcports from parent's list */
qla2x00_mark_vp_devices_dead(vha);
atomic_set(&vha->vp_state, VP_FAILED);
vha->flags.management_server_logged_in = 0;
if (ret == QLA_SUCCESS) {
fc_vport_set_state(vha->fc_vport, FC_VPORT_DISABLED);
} else {
fc_vport_set_state(vha->fc_vport, FC_VPORT_FAILED);
return -1;
}
return 0;
}
int
qla24xx_enable_vp(scsi_qla_host_t *vha)
{
int ret;
scsi_qla_host_t *ha = vha->parent;
/* Check if physical ha port is Up */
if (atomic_read(&ha->loop_state) == LOOP_DOWN ||
atomic_read(&ha->loop_state) == LOOP_DEAD ) {
vha->vp_err_state = VP_ERR_PORTDWN;
fc_vport_set_state(vha->fc_vport, FC_VPORT_LINKDOWN);
goto enable_failed;
}
/* Initialize the new vport unless it is a persistent port */
down(&ha->vport_sem);
ret = qla24xx_modify_vp_config(vha);
up(&ha->vport_sem);
if (ret != QLA_SUCCESS) {
fc_vport_set_state(vha->fc_vport, FC_VPORT_FAILED);
goto enable_failed;
}
DEBUG15(qla_printk(KERN_INFO, ha,
"Virtual port with id: %d - Enabled\n", vha->vp_idx));
return 0;
enable_failed:
DEBUG15(qla_printk(KERN_INFO, ha,
"Virtual port with id: %d - Disabled\n", vha->vp_idx));
return 1;
}
/**
* qla24xx_modify_vport() - Modifies the virtual fabric port's configuration
* @ha: HA context
* @vp: pointer to buffer of virtual port parameters.
* @ret_code: return error code:
*
* Returns the virtual port id, or MAX_VSAN_ID, if couldn't create.
*/
uint32_t
qla24xx_modify_vhba(scsi_qla_host_t *ha, vport_params_t *vp, uint32_t *vp_id)
{
scsi_qla_host_t *vha;
vha = qla24xx_find_vhost_by_name(ha, vp->port_name);
if (!vha) {
*vp_id = MAX_NUM_VPORT_LOOP;
return VP_RET_CODE_WWPN;
}
if (qla24xx_enable_vp(vha)) {
scsi_host_put(vha->host);
qla2x00_mem_free(vha);
*vp_id = MAX_NUM_VPORT_LOOP;
return VP_RET_CODE_RESOURCES;
}
*vp_id = vha->vp_idx;
return VP_RET_CODE_OK;
}
void
qla24xx_configure_vp(scsi_qla_host_t *vha)
{
struct fc_vport *fc_vport;
int ret;
fc_vport = vha->fc_vport;
DEBUG15(printk("scsi(%ld): %s: change request #3 for this host.\n",
vha->host_no, __func__));
ret = qla2x00_send_change_request(vha, 0x3, vha->vp_idx);
if (ret != QLA_SUCCESS) {
DEBUG15(qla_printk(KERN_ERR, vha, "Failed to enable receiving"
" of RSCN requests: 0x%x\n", ret));
return;
} else {
/* Corresponds to SCR enabled */
clear_bit(VP_SCR_NEEDED, &vha->vp_flags);
}
vha->flags.online = 1;
if (qla24xx_configure_vhba(vha))
return;
atomic_set(&vha->vp_state, VP_ACTIVE);
fc_vport_set_state(fc_vport, FC_VPORT_ACTIVE);
}
void
qla2x00_alert_all_vps(scsi_qla_host_t *ha, uint16_t *mb)
{
int i, vp_idx_matched;
scsi_qla_host_t *vha;
if (ha->parent)
return;
i = find_next_bit((unsigned long *)ha->vp_idx_map,
MAX_MULTI_ID_FABRIC + 1, 1);
for (;i <= MAX_MULTI_ID_FABRIC;
i = find_next_bit((unsigned long *)ha->vp_idx_map,
MAX_MULTI_ID_FABRIC + 1, i + 1)) {
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) {
switch (mb[0]) {
case MBA_LIP_OCCURRED:
case MBA_LOOP_UP:
case MBA_LOOP_DOWN:
case MBA_LIP_RESET:
case MBA_POINT_TO_POINT:
case MBA_CHG_IN_CONNECTION:
case MBA_PORT_UPDATE:
case MBA_RSCN_UPDATE:
DEBUG15(printk("scsi(%ld)%s: Async_event for"
" VP[%d], mb = 0x%x, vha=%p\n",
vha->host_no, __func__,i, *mb, vha));
qla2x00_async_event(vha, mb);
break;
}
}
}
}
void
qla2x00_vp_abort_isp(scsi_qla_host_t *vha)
{
/*
* Physical port will do most of the abort and recovery work. We can
* just treat it as a loop down
*/
if (atomic_read(&vha->loop_state) != LOOP_DOWN) {
atomic_set(&vha->loop_state, LOOP_DOWN);
qla2x00_mark_all_devices_lost(vha, 0);
} else {
if (!atomic_read(&vha->loop_down_timer))
atomic_set(&vha->loop_down_timer, LOOP_DOWN_TIME);
}
DEBUG15(printk("scsi(%ld): Scheduling enable of Vport %d...\n",
vha->host_no, vha->vp_idx));
qla24xx_enable_vp(vha);
}
int
qla2x00_do_dpc_vp(scsi_qla_host_t *vha)
{
if (test_and_clear_bit(VP_IDX_ACQUIRED, &vha->vp_flags)) {
/* VP acquired. complete port configuration */
qla24xx_configure_vp(vha);
return 0;
}
if (test_and_clear_bit(ISP_ABORT_NEEDED, &vha->dpc_flags))
qla2x00_vp_abort_isp(vha);
if (test_and_clear_bit(RESET_MARKER_NEEDED, &vha->dpc_flags) &&
(!(test_and_set_bit(RESET_ACTIVE, &vha->dpc_flags)))) {
clear_bit(RESET_ACTIVE, &vha->dpc_flags);
}
if (test_and_clear_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags)) {
if (!(test_and_set_bit(LOOP_RESYNC_ACTIVE, &vha->dpc_flags))) {
qla2x00_loop_resync(vha);
clear_bit(LOOP_RESYNC_ACTIVE, &vha->dpc_flags);
}
}
return 0;
}
void
qla2x00_do_dpc_all_vps(scsi_qla_host_t *ha)
{
int ret;
int i, vp_idx_matched;
scsi_qla_host_t *vha;
if (ha->parent)
return;
if (list_empty(&ha->vp_list))
return;
clear_bit(VP_DPC_NEEDED, &ha->dpc_flags);
i = find_next_bit((unsigned long *)ha->vp_idx_map,
MAX_MULTI_ID_FABRIC + 1, 1);
for (;i <= MAX_MULTI_ID_FABRIC;
i = find_next_bit((unsigned long *)ha->vp_idx_map,
MAX_MULTI_ID_FABRIC + 1, i + 1)) {
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)
ret = qla2x00_do_dpc_vp(vha);
}
}
int
qla24xx_vport_create_req_sanity_check(struct fc_vport *fc_vport)
{
scsi_qla_host_t *ha = (scsi_qla_host_t *) fc_vport->shost->hostdata;
scsi_qla_host_t *vha;
uint8_t port_name[WWN_SIZE];
if (fc_vport->roles != FC_PORT_ROLE_FCP_INITIATOR)
return VPCERR_UNSUPPORTED;
/* Check up the F/W and H/W support NPIV */
if (!ha->flags.npiv_supported)
return VPCERR_UNSUPPORTED;
/* Check up whether npiv supported switch presented */
if (!(ha->switch_cap & FLOGI_MID_SUPPORT))
return VPCERR_NO_FABRIC_SUPP;
/* Check up unique WWPN */
u64_to_wwn(fc_vport->port_name, port_name);
vha = qla24xx_find_vhost_by_name(ha, port_name);
if (vha)
return VPCERR_BAD_WWN;
/* Check up max-npiv-supports */
if (ha->num_vhosts > ha->max_npiv_vports) {
DEBUG15(printk("scsi(%ld): num_vhosts %d is bigger than "
"max_npv_vports %d.\n", ha->host_no,
(uint16_t) ha->num_vhosts, (int) ha->max_npiv_vports));
return VPCERR_UNSUPPORTED;
}
return 0;
}
scsi_qla_host_t *
qla24xx_create_vhost(struct fc_vport *fc_vport)
{
scsi_qla_host_t *ha = (scsi_qla_host_t *) fc_vport->shost->hostdata;
scsi_qla_host_t *vha;
struct Scsi_Host *host;
host = scsi_host_alloc(&qla24xx_driver_template,
sizeof(scsi_qla_host_t));
if (!host) {
printk(KERN_WARNING
"qla2xxx: scsi_host_alloc() failed for vport\n");
return(NULL);
}
vha = (scsi_qla_host_t *)host->hostdata;
/* clone the parent hba */
memcpy(vha, ha, sizeof (scsi_qla_host_t));
fc_vport->dd_data = vha;
vha->node_name = kmalloc(WWN_SIZE * sizeof(char), GFP_KERNEL);
if (!vha->node_name)
goto create_vhost_failed_1;
vha->port_name = kmalloc(WWN_SIZE * sizeof(char), GFP_KERNEL);
if (!vha->port_name)
goto create_vhost_failed_2;
/* New host info */
u64_to_wwn(fc_vport->node_name, vha->node_name);
u64_to_wwn(fc_vport->port_name, vha->port_name);
vha->host = host;
vha->host_no = host->host_no;
vha->parent = ha;
vha->fc_vport = fc_vport;
vha->device_flags = 0;
vha->instance = num_hosts;
vha->vp_idx = 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));
goto create_vhost_failed_3;
}
vha->mgmt_svr_loop_id = 10 + vha->vp_idx;
init_MUTEX(&vha->mbx_cmd_sem);
init_MUTEX_LOCKED(&vha->mbx_intr_sem);
INIT_LIST_HEAD(&vha->list);
INIT_LIST_HEAD(&vha->fcports);
INIT_LIST_HEAD(&vha->vp_fcports);
vha->dpc_flags = 0L;
set_bit(REGISTER_FDMI_NEEDED, &vha->dpc_flags);
set_bit(REGISTER_FC4_NEEDED, &vha->dpc_flags);
/*
* To fix the issue of processing a parent's RSCN for the vport before
* its SCR is complete.
*/
set_bit(VP_SCR_NEEDED, &vha->vp_flags);
atomic_set(&vha->loop_state, LOOP_DOWN);
atomic_set(&vha->loop_down_timer, LOOP_DOWN_TIME);
qla2x00_start_timer(vha, qla2x00_timer, WATCH_INTERVAL);
host->can_queue = vha->request_q_length + 128;
host->this_id = 255;
host->cmd_per_lun = 3;
host->max_cmd_len = MAX_CMDSZ;
host->max_channel = MAX_BUSES - 1;
host->max_lun = MAX_LUNS;
host->unique_id = vha->instance;
host->max_id = MAX_TARGETS_2200;
host->transportt = qla2xxx_transport_vport_template;
DEBUG15(printk("DEBUG: detect vport hba %ld at address = %p\n",
vha->host_no, vha));
vha->flags.init_done = 1;
num_hosts++;
down(&ha->vport_sem);
set_bit(vha->vp_idx, (unsigned long *)ha->vp_idx_map);
ha->cur_vport_count++;
up(&ha->vport_sem);
return vha;
create_vhost_failed_3:
kfree(vha->port_name);
create_vhost_failed_2:
kfree(vha->node_name);
create_vhost_failed_1:
return NULL;
}
......@@ -29,8 +29,7 @@ static struct kmem_cache *srb_cachep;
/*
* Ioctl related information.
*/
static int num_hosts;
int num_hosts;
int ql2xlogintimeout = 20;
module_param(ql2xlogintimeout, int, S_IRUGO|S_IRUSR);
MODULE_PARM_DESC(ql2xlogintimeout,
......@@ -112,7 +111,7 @@ static int qla2x00_device_reset(scsi_qla_host_t *, fc_port_t *);
static int qla2x00_change_queue_depth(struct scsi_device *, int);
static int qla2x00_change_queue_type(struct scsi_device *, int);
static struct scsi_host_template qla2x00_driver_template = {
struct scsi_host_template qla2x00_driver_template = {
.module = THIS_MODULE,
.name = QLA2XXX_DRIVER_NAME,
.queuecommand = qla2x00_queuecommand,
......@@ -143,7 +142,7 @@ static struct scsi_host_template qla2x00_driver_template = {
.shost_attrs = qla2x00_host_attrs,
};
static struct scsi_host_template qla24xx_driver_template = {
struct scsi_host_template qla24xx_driver_template = {
.module = THIS_MODULE,
.name = QLA2XXX_DRIVER_NAME,
.queuecommand = qla24xx_queuecommand,
......@@ -171,21 +170,21 @@ static struct scsi_host_template qla24xx_driver_template = {
};
static struct scsi_transport_template *qla2xxx_transport_template = NULL;
struct scsi_transport_template *qla2xxx_transport_vport_template = NULL;
/* TODO Convert to inlines
*
* Timer routines
*/
#define WATCH_INTERVAL 1 /* number of seconds */
static void qla2x00_timer(scsi_qla_host_t *);
void qla2x00_timer(scsi_qla_host_t *);
static __inline__ void qla2x00_start_timer(scsi_qla_host_t *,
__inline__ void qla2x00_start_timer(scsi_qla_host_t *,
void *, unsigned long);
static __inline__ void qla2x00_restart_timer(scsi_qla_host_t *, unsigned long);
static __inline__ void qla2x00_stop_timer(scsi_qla_host_t *);
__inline__ void qla2x00_stop_timer(scsi_qla_host_t *);
static inline void
__inline__ void
qla2x00_start_timer(scsi_qla_host_t *ha, void *func, unsigned long interval)
{
init_timer(&ha->timer);
......@@ -202,7 +201,7 @@ qla2x00_restart_timer(scsi_qla_host_t *ha, unsigned long interval)
mod_timer(&ha->timer, jiffies + interval * HZ);
}
static __inline__ void
__inline__ void
qla2x00_stop_timer(scsi_qla_host_t *ha)
{
del_timer_sync(&ha->timer);
......@@ -213,8 +212,8 @@ static int qla2x00_do_dpc(void *data);
static void qla2x00_rst_aen(scsi_qla_host_t *);
static uint8_t qla2x00_mem_alloc(scsi_qla_host_t *);
static void qla2x00_mem_free(scsi_qla_host_t *ha);
uint8_t qla2x00_mem_alloc(scsi_qla_host_t *);
void qla2x00_mem_free(scsi_qla_host_t *ha);
static int qla2x00_allocate_sp_pool( scsi_qla_host_t *ha);
static void qla2x00_free_sp_pool(scsi_qla_host_t *ha);
static void qla2x00_sp_free_dma(scsi_qla_host_t *, srb_t *);
......@@ -438,6 +437,7 @@ qla24xx_queuecommand(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
struct fc_rport *rport = starget_to_rport(scsi_target(cmd->device));
srb_t *sp;
int rval;
scsi_qla_host_t *pha = to_qla_parent(ha);
rval = fc_remote_port_chkready(rport);
if (rval) {
......@@ -453,7 +453,7 @@ qla24xx_queuecommand(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
if (atomic_read(&fcport->state) != FCS_ONLINE) {
if (atomic_read(&fcport->state) == FCS_DEVICE_DEAD ||
atomic_read(&ha->loop_state) == LOOP_DEAD) {
atomic_read(&pha->loop_state) == LOOP_DEAD) {
cmd->result = DID_NO_CONNECT << 16;
goto qc24_fail_command;
}
......@@ -462,7 +462,7 @@ qla24xx_queuecommand(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
spin_unlock_irq(ha->host->host_lock);
sp = qla2x00_get_new_sp(ha, fcport, cmd, done);
sp = qla2x00_get_new_sp(pha, fcport, cmd, done);
if (!sp)
goto qc24_host_busy_lock;
......@@ -475,8 +475,8 @@ qla24xx_queuecommand(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
return 0;
qc24_host_busy_free_sp:
qla2x00_sp_free_dma(ha, sp);
mempool_free(sp, ha->srb_mempool);
qla2x00_sp_free_dma(pha, sp);
mempool_free(sp, pha->srb_mempool);
qc24_host_busy_lock:
spin_lock_irq(ha->host->host_lock);
......@@ -548,16 +548,17 @@ qla2x00_wait_for_hba_online(scsi_qla_host_t *ha)
{
int return_status;
unsigned long wait_online;
scsi_qla_host_t *pha = to_qla_parent(ha);
wait_online = jiffies + (MAX_LOOP_TIMEOUT * HZ);
while (((test_bit(ISP_ABORT_NEEDED, &ha->dpc_flags)) ||
test_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags) ||
test_bit(ISP_ABORT_RETRY, &ha->dpc_flags) ||
ha->dpc_active) && time_before(jiffies, wait_online)) {
while (((test_bit(ISP_ABORT_NEEDED, &pha->dpc_flags)) ||
test_bit(ABORT_ISP_ACTIVE, &pha->dpc_flags) ||
test_bit(ISP_ABORT_RETRY, &pha->dpc_flags) ||
pha->dpc_active) && time_before(jiffies, wait_online)) {
msleep(1000);
}
if (ha->flags.online)
if (pha->flags.online)
return_status = QLA_SUCCESS;
else
return_status = QLA_FUNCTION_FAILED;
......@@ -588,14 +589,15 @@ qla2x00_wait_for_loop_ready(scsi_qla_host_t *ha)
{
int return_status = QLA_SUCCESS;
unsigned long loop_timeout ;
scsi_qla_host_t *pha = to_qla_parent(ha);
/* wait for 5 min at the max for loop to be ready */
loop_timeout = jiffies + (MAX_LOOP_TIMEOUT * HZ);
while ((!atomic_read(&ha->loop_down_timer) &&
atomic_read(&ha->loop_state) == LOOP_DOWN) ||
atomic_read(&ha->loop_state) != LOOP_READY) {
if (atomic_read(&ha->loop_state) == LOOP_DEAD) {
while ((!atomic_read(&pha->loop_down_timer) &&
atomic_read(&pha->loop_state) == LOOP_DOWN) ||
atomic_read(&pha->loop_state) != LOOP_READY) {
if (atomic_read(&pha->loop_state) == LOOP_DEAD) {
return_status = QLA_FUNCTION_FAILED;
break;
}
......@@ -650,6 +652,7 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd)
unsigned long serial;
unsigned long flags;
int wait = 0;
scsi_qla_host_t *pha = to_qla_parent(ha);
qla2x00_block_error_handler(cmd);
......@@ -663,9 +666,9 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd)
serial = cmd->serial_number;
/* Check active list for command command. */
spin_lock_irqsave(&ha->hardware_lock, flags);
spin_lock_irqsave(&pha->hardware_lock, flags);
for (i = 1; i < MAX_OUTSTANDING_COMMANDS; i++) {
sp = ha->outstanding_cmds[i];
sp = pha->outstanding_cmds[i];
if (sp == NULL)
continue;
......@@ -677,7 +680,7 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd)
__func__, ha->host_no, sp, serial));
DEBUG3(qla2x00_print_scsi_cmd(cmd));
spin_unlock_irqrestore(&ha->hardware_lock, flags);
spin_unlock_irqrestore(&pha->hardware_lock, flags);
if (ha->isp_ops.abort_command(ha, sp)) {
DEBUG2(printk("%s(%ld): abort_command "
"mbx failed.\n", __func__, ha->host_no));
......@@ -686,11 +689,11 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd)
"mbx success.\n", __func__, ha->host_no));
wait = 1;
}
spin_lock_irqsave(&ha->hardware_lock, flags);
spin_lock_irqsave(&pha->hardware_lock, flags);
break;
}
spin_unlock_irqrestore(&ha->hardware_lock, flags);
spin_unlock_irqrestore(&pha->hardware_lock, flags);
/* Wait for the command to be returned. */
if (wait) {
......@@ -731,6 +734,7 @@ qla2x00_eh_wait_for_pending_target_commands(scsi_qla_host_t *ha, unsigned int t)
srb_t *sp;
struct scsi_cmnd *cmd;
unsigned long flags;
scsi_qla_host_t *pha = to_qla_parent(ha);
status = 0;
......@@ -739,19 +743,20 @@ qla2x00_eh_wait_for_pending_target_commands(scsi_qla_host_t *ha, unsigned int t)
* array
*/
for (cnt = 1; cnt < MAX_OUTSTANDING_COMMANDS; cnt++) {
spin_lock_irqsave(&ha->hardware_lock, flags);
sp = ha->outstanding_cmds[cnt];
spin_lock_irqsave(&pha->hardware_lock, flags);
sp = pha->outstanding_cmds[cnt];
if (sp) {
cmd = sp->cmd;
spin_unlock_irqrestore(&ha->hardware_lock, flags);
if (cmd->device->id == t) {
spin_unlock_irqrestore(&pha->hardware_lock, flags);
if (cmd->device->id == t &&
ha->vp_idx == sp->ha->vp_idx) {
if (!qla2x00_eh_wait_on_command(ha, cmd)) {
status = 1;
break;
}
}
} else {
spin_unlock_irqrestore(&ha->hardware_lock, flags);
spin_unlock_irqrestore(&pha->hardware_lock, flags);
}
}
return (status);
......@@ -782,14 +787,12 @@ qla2xxx_eh_device_reset(struct scsi_cmnd *cmd)
{
scsi_qla_host_t *ha = to_qla_host(cmd->device->host);
fc_port_t *fcport = (struct fc_port *) cmd->device->hostdata;
int ret;
int ret = FAILED;
unsigned int id, lun;
unsigned long serial;
qla2x00_block_error_handler(cmd);
ret = FAILED;
id = cmd->device->id;
lun = cmd->device->lun;
serial = cmd->serial_number;
......@@ -912,15 +915,14 @@ static int
qla2xxx_eh_bus_reset(struct scsi_cmnd *cmd)
{
scsi_qla_host_t *ha = to_qla_host(cmd->device->host);
scsi_qla_host_t *pha = to_qla_parent(ha);
fc_port_t *fcport = (struct fc_port *) cmd->device->hostdata;
int ret;
int ret = FAILED;
unsigned int id, lun;
unsigned long serial;
qla2x00_block_error_handler(cmd);
ret = FAILED;
id = cmd->device->id;
lun = cmd->device->lun;
serial = cmd->serial_number;
......@@ -944,7 +946,7 @@ qla2xxx_eh_bus_reset(struct scsi_cmnd *cmd)
goto eh_bus_reset_done;
/* Flush outstanding commands. */
if (!qla2x00_eh_wait_for_pending_commands(ha))
if (!qla2x00_eh_wait_for_pending_commands(pha))
ret = FAILED;
eh_bus_reset_done:
......@@ -974,14 +976,13 @@ qla2xxx_eh_host_reset(struct scsi_cmnd *cmd)
{
scsi_qla_host_t *ha = to_qla_host(cmd->device->host);
fc_port_t *fcport = (struct fc_port *) cmd->device->hostdata;
int ret;
int ret = FAILED;
unsigned int id, lun;
unsigned long serial;
scsi_qla_host_t *pha = to_qla_parent(ha);
qla2x00_block_error_handler(cmd);
ret = FAILED;
id = cmd->device->id;
lun = cmd->device->lun;
serial = cmd->serial_number;
......@@ -1004,21 +1005,24 @@ qla2xxx_eh_host_reset(struct scsi_cmnd *cmd)
* while dpc is stuck for the mailbox to complete.
*/
qla2x00_wait_for_loop_ready(ha);
set_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags);
if (qla2x00_abort_isp(ha)) {
clear_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags);
set_bit(ABORT_ISP_ACTIVE, &pha->dpc_flags);
if (qla2x00_abort_isp(pha)) {
clear_bit(ABORT_ISP_ACTIVE, &pha->dpc_flags);
/* failed. schedule dpc to try */
set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags);
set_bit(ISP_ABORT_NEEDED, &pha->dpc_flags);
if (qla2x00_wait_for_hba_online(ha) != QLA_SUCCESS)
goto eh_host_reset_lock;
}
clear_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags);
clear_bit(ABORT_ISP_ACTIVE, &pha->dpc_flags);
/* Waiting for our command in done_queue to be returned to OS.*/
if (qla2x00_eh_wait_for_pending_commands(ha))
if (qla2x00_eh_wait_for_pending_commands(pha))
ret = SUCCESS;
if (ha->parent)
qla2x00_vp_abort_isp(ha);
eh_host_reset_lock:
qla_printk(KERN_INFO, ha, "%s: reset %s\n", __func__,
(ret == FAILED) ? "failed" : "succeded");
......@@ -1435,6 +1439,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
ha->host = host;
ha->host_no = host->host_no;
sprintf(ha->host_str, "%s_%ld", QLA2XXX_DRIVER_NAME, ha->host_no);
ha->parent = NULL;
/* Set ISP-type information. */
qla2x00_set_isp_flags(ha);
......@@ -1452,7 +1457,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
ha->prev_topology = 0;
ha->init_cb_size = sizeof(init_cb_t);
ha->mgmt_svr_loop_id = MANAGEMENT_SERVER;
ha->mgmt_svr_loop_id = MANAGEMENT_SERVER + ha->vp_idx;
ha->link_data_rate = PORT_SPEED_UNKNOWN;
ha->optrom_size = OPTROM_SIZE_2300;
......@@ -1524,8 +1529,8 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
ha->request_q_length = REQUEST_ENTRY_CNT_24XX;
ha->response_q_length = RESPONSE_ENTRY_CNT_2300;
ha->last_loop_id = SNS_LAST_LOOP_ID_2300;
ha->init_cb_size = sizeof(struct init_cb_24xx);
ha->mgmt_svr_loop_id = 10;
ha->init_cb_size = sizeof(struct mid_init_cb_24xx);
ha->mgmt_svr_loop_id = 10 + ha->vp_idx;
ha->isp_ops.pci_config = qla24xx_pci_config;
ha->isp_ops.reset_chip = qla24xx_reset_chip;
ha->isp_ops.chip_diag = qla24xx_chip_diag;
......@@ -1563,10 +1568,14 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
ha->instance = num_hosts;
init_MUTEX(&ha->mbx_cmd_sem);
init_MUTEX(&ha->vport_sem);
init_MUTEX_LOCKED(&ha->mbx_intr_sem);
INIT_LIST_HEAD(&ha->list);
INIT_LIST_HEAD(&ha->fcports);
INIT_LIST_HEAD(&ha->vp_list);
set_bit(0, (unsigned long *) ha->vp_idx_map);
qla2x00_config_dma_addressing(ha);
if (qla2x00_mem_alloc(ha)) {
......@@ -1789,7 +1798,8 @@ qla2x00_schedule_rport_del(struct scsi_qla_host *ha, fc_port_t *fcport,
void qla2x00_mark_device_lost(scsi_qla_host_t *ha, fc_port_t *fcport,
int do_login, int defer)
{
if (atomic_read(&fcport->state) == FCS_ONLINE)
if (atomic_read(&fcport->state) == FCS_ONLINE &&
ha->vp_idx == fcport->vp_idx)
qla2x00_schedule_rport_del(ha, fcport, defer);
/*
......@@ -1840,19 +1850,23 @@ void
qla2x00_mark_all_devices_lost(scsi_qla_host_t *ha, int defer)
{
fc_port_t *fcport;
scsi_qla_host_t *pha = to_qla_parent(ha);
list_for_each_entry(fcport, &ha->fcports, list) {
if (fcport->port_type != FCT_TARGET)
list_for_each_entry(fcport, &pha->fcports, list) {
if (ha->vp_idx != 0 && ha->vp_idx != fcport->vp_idx)
continue;
/*
* No point in marking the device as lost, if the device is
* already DEAD.
*/
if (atomic_read(&fcport->state) == FCS_DEVICE_DEAD)
continue;
if (atomic_read(&fcport->state) == FCS_ONLINE)
qla2x00_schedule_rport_del(ha, fcport, defer);
if (atomic_read(&fcport->state) == FCS_ONLINE) {
if (defer)
qla2x00_schedule_rport_del(ha, fcport, defer);
else if (ha->vp_idx == fcport->vp_idx)
qla2x00_schedule_rport_del(ha, fcport, defer);
}
atomic_set(&fcport->state, FCS_DEVICE_LOST);
}
......@@ -1868,7 +1882,7 @@ qla2x00_mark_all_devices_lost(scsi_qla_host_t *ha, int defer)
* 0 = success.
* 1 = failure.
*/
static uint8_t
uint8_t
qla2x00_mem_alloc(scsi_qla_host_t *ha)
{
char name[16];
......@@ -1920,33 +1934,33 @@ qla2x00_mem_alloc(scsi_qla_host_t *ha)
continue;
}
snprintf(name, sizeof(name), "%s_%ld", QLA2XXX_DRIVER_NAME,
ha->host_no);
ha->s_dma_pool = dma_pool_create(name, &ha->pdev->dev,
DMA_POOL_SIZE, 8, 0);
if (ha->s_dma_pool == NULL) {
/* get consistent memory allocated for init control block */
ha->init_cb = dma_alloc_coherent(&ha->pdev->dev,
ha->init_cb_size, &ha->init_cb_dma, GFP_KERNEL);
if (ha->init_cb == NULL) {
qla_printk(KERN_WARNING, ha,
"Memory Allocation failed - s_dma_pool\n");
"Memory Allocation failed - init_cb\n");
qla2x00_mem_free(ha);
msleep(100);
continue;
}
memset(ha->init_cb, 0, ha->init_cb_size);
/* get consistent memory allocated for init control block */
ha->init_cb = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL,
&ha->init_cb_dma);
if (ha->init_cb == NULL) {
snprintf(name, sizeof(name), "%s_%ld", QLA2XXX_DRIVER_NAME,
ha->host_no);
ha->s_dma_pool = dma_pool_create(name, &ha->pdev->dev,
DMA_POOL_SIZE, 8, 0);
if (ha->s_dma_pool == NULL) {
qla_printk(KERN_WARNING, ha,
"Memory Allocation failed - init_cb\n");
"Memory Allocation failed - s_dma_pool\n");
qla2x00_mem_free(ha);
msleep(100);
continue;
}
memset(ha->init_cb, 0, ha->init_cb_size);
if (qla2x00_allocate_sp_pool(ha)) {
qla_printk(KERN_WARNING, ha,
......@@ -2052,7 +2066,7 @@ qla2x00_mem_alloc(scsi_qla_host_t *ha)
* Input:
* ha = adapter block pointer.
*/
static void
void
qla2x00_mem_free(scsi_qla_host_t *ha)
{
struct list_head *fcpl, *fcptemp;
......@@ -2088,12 +2102,13 @@ qla2x00_mem_free(scsi_qla_host_t *ha)
if (ha->ms_iocb)
dma_pool_free(ha->s_dma_pool, ha->ms_iocb, ha->ms_iocb_dma);
if (ha->init_cb)
dma_pool_free(ha->s_dma_pool, ha->init_cb, ha->init_cb_dma);
if (ha->s_dma_pool)
dma_pool_destroy(ha->s_dma_pool);
if (ha->init_cb)
dma_free_coherent(&ha->pdev->dev, ha->init_cb_size,
ha->init_cb, ha->init_cb_dma);
if (ha->gid_list)
dma_free_coherent(&ha->pdev->dev, GID_LIST_SIZE, ha->gid_list,
ha->gid_list_dma);
......@@ -2199,6 +2214,7 @@ qla2x00_free_sp_pool( scsi_qla_host_t *ha)
static int
qla2x00_do_dpc(void *data)
{
int rval;
scsi_qla_host_t *ha;
fc_port_t *fcport;
uint8_t status;
......@@ -2347,7 +2363,7 @@ qla2x00_do_dpc(void *data)
if (!(test_and_set_bit(LOOP_RESYNC_ACTIVE,
&ha->dpc_flags))) {
qla2x00_loop_resync(ha);
rval = qla2x00_loop_resync(ha);
clear_bit(LOOP_RESYNC_ACTIVE, &ha->dpc_flags);
}
......@@ -2374,6 +2390,8 @@ qla2x00_do_dpc(void *data)
if (test_and_clear_bit(BEACON_BLINK_NEEDED, &ha->dpc_flags))
ha->isp_ops.beacon_blink(ha);
qla2x00_do_dpc_all_vps(ha);
ha->dpc_active = 0;
} /* End of while(1) */
......@@ -2452,7 +2470,7 @@ qla2x00_sp_compl(scsi_qla_host_t *ha, srb_t *sp)
*
* Context: Interrupt
***************************************************************************/
static void
void
qla2x00_timer(scsi_qla_host_t *ha)
{
unsigned long cpu_flags = 0;
......@@ -2461,6 +2479,7 @@ qla2x00_timer(scsi_qla_host_t *ha)
int index;
srb_t *sp;
int t;
scsi_qla_host_t *pha = to_qla_parent(ha);
/*
* Ports - Port down timer.
......@@ -2506,23 +2525,29 @@ qla2x00_timer(scsi_qla_host_t *ha)
atomic_set(&ha->loop_state, LOOP_DEAD);
/* Schedule an ISP abort to return any tape commands. */
spin_lock_irqsave(&ha->hardware_lock, cpu_flags);
for (index = 1; index < MAX_OUTSTANDING_COMMANDS;
index++) {
fc_port_t *sfcp;
/* NPIV - scan physical port only */
if (!ha->parent) {
spin_lock_irqsave(&ha->hardware_lock,
cpu_flags);
for (index = 1;
index < MAX_OUTSTANDING_COMMANDS;
index++) {
fc_port_t *sfcp;
sp = ha->outstanding_cmds[index];
if (!sp)
continue;
sfcp = sp->fcport;
if (!(sfcp->flags & FCF_TAPE_PRESENT))
continue;
sp = ha->outstanding_cmds[index];
if (!sp)
continue;
sfcp = sp->fcport;
if (!(sfcp->flags & FCF_TAPE_PRESENT))
continue;
set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags);
break;
set_bit(ISP_ABORT_NEEDED,
&ha->dpc_flags);
break;
}
spin_unlock_irqrestore(&ha->hardware_lock,
cpu_flags);
}
spin_unlock_irqrestore(&ha->hardware_lock, cpu_flags);
set_bit(ABORT_QUEUES_NEEDED, &ha->dpc_flags);
start_dpc++;
}
......@@ -2566,8 +2591,9 @@ qla2x00_timer(scsi_qla_host_t *ha)
test_bit(LOGIN_RETRY_NEEDED, &ha->dpc_flags) ||
test_bit(RESET_MARKER_NEEDED, &ha->dpc_flags) ||
test_bit(BEACON_BLINK_NEEDED, &ha->dpc_flags) ||
test_bit(VP_DPC_NEEDED, &ha->dpc_flags) ||
test_bit(RELOGIN_NEEDED, &ha->dpc_flags)))
qla2xxx_wake_dpc(ha);
qla2xxx_wake_dpc(pha);
qla2x00_restart_timer(ha, WATCH_INTERVAL);
}
......@@ -2711,14 +2737,24 @@ qla2x00_module_init(void)
qla2xxx_transport_template =
fc_attach_transport(&qla2xxx_transport_functions);
if (!qla2xxx_transport_template)
if (!qla2xxx_transport_template) {
kmem_cache_destroy(srb_cachep);
return -ENODEV;
}
qla2xxx_transport_vport_template =
fc_attach_transport(&qla2xxx_transport_vport_functions);
if (!qla2xxx_transport_vport_template) {
kmem_cache_destroy(srb_cachep);
fc_release_transport(qla2xxx_transport_template);
return -ENODEV;
}
printk(KERN_INFO "QLogic Fibre Channel HBA Driver\n");
ret = pci_register_driver(&qla2xxx_pci_driver);
if (ret) {
kmem_cache_destroy(srb_cachep);
fc_release_transport(qla2xxx_transport_template);
fc_release_transport(qla2xxx_transport_vport_template);
}
return ret;
}
......@@ -2733,6 +2769,7 @@ qla2x00_module_exit(void)
qla2x00_release_firmware();
kmem_cache_destroy(srb_cachep);
fc_release_transport(qla2xxx_transport_template);
fc_release_transport(qla2xxx_transport_vport_template);
}
module_init(qla2x00_module_init);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment