162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * QLogic iSCSI HBA Driver
462306a36Sopenharmony_ci * Copyright (c)  2003-2013 QLogic Corporation
562306a36Sopenharmony_ci */
662306a36Sopenharmony_ci#include <linux/moduleparam.h>
762306a36Sopenharmony_ci#include <linux/slab.h>
862306a36Sopenharmony_ci#include <linux/blkdev.h>
962306a36Sopenharmony_ci#include <linux/iscsi_boot_sysfs.h>
1062306a36Sopenharmony_ci#include <linux/inet.h>
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci#include <scsi/scsi_tcq.h>
1362306a36Sopenharmony_ci#include <scsi/scsicam.h>
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci#include "ql4_def.h"
1662306a36Sopenharmony_ci#include "ql4_version.h"
1762306a36Sopenharmony_ci#include "ql4_glbl.h"
1862306a36Sopenharmony_ci#include "ql4_dbg.h"
1962306a36Sopenharmony_ci#include "ql4_inline.h"
2062306a36Sopenharmony_ci#include "ql4_83xx.h"
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ci/*
2362306a36Sopenharmony_ci * Driver version
2462306a36Sopenharmony_ci */
2562306a36Sopenharmony_cistatic char qla4xxx_version_str[40];
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci/*
2862306a36Sopenharmony_ci * SRB allocation cache
2962306a36Sopenharmony_ci */
3062306a36Sopenharmony_cistatic struct kmem_cache *srb_cachep;
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci/*
3362306a36Sopenharmony_ci * Module parameter information and variables
3462306a36Sopenharmony_ci */
3562306a36Sopenharmony_cistatic int ql4xdisablesysfsboot = 1;
3662306a36Sopenharmony_cimodule_param(ql4xdisablesysfsboot, int, S_IRUGO | S_IWUSR);
3762306a36Sopenharmony_ciMODULE_PARM_DESC(ql4xdisablesysfsboot,
3862306a36Sopenharmony_ci		 " Set to disable exporting boot targets to sysfs.\n"
3962306a36Sopenharmony_ci		 "\t\t  0 - Export boot targets\n"
4062306a36Sopenharmony_ci		 "\t\t  1 - Do not export boot targets (Default)");
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ciint ql4xdontresethba;
4362306a36Sopenharmony_cimodule_param(ql4xdontresethba, int, S_IRUGO | S_IWUSR);
4462306a36Sopenharmony_ciMODULE_PARM_DESC(ql4xdontresethba,
4562306a36Sopenharmony_ci		 " Don't reset the HBA for driver recovery.\n"
4662306a36Sopenharmony_ci		 "\t\t  0 - It will reset HBA (Default)\n"
4762306a36Sopenharmony_ci		 "\t\t  1 - It will NOT reset HBA");
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ciint ql4xextended_error_logging;
5062306a36Sopenharmony_cimodule_param(ql4xextended_error_logging, int, S_IRUGO | S_IWUSR);
5162306a36Sopenharmony_ciMODULE_PARM_DESC(ql4xextended_error_logging,
5262306a36Sopenharmony_ci		 " Option to enable extended error logging.\n"
5362306a36Sopenharmony_ci		 "\t\t  0 - no logging (Default)\n"
5462306a36Sopenharmony_ci		 "\t\t  2 - debug logging");
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ciint ql4xenablemsix = 1;
5762306a36Sopenharmony_cimodule_param(ql4xenablemsix, int, S_IRUGO|S_IWUSR);
5862306a36Sopenharmony_ciMODULE_PARM_DESC(ql4xenablemsix,
5962306a36Sopenharmony_ci		 " Set to enable MSI or MSI-X interrupt mechanism.\n"
6062306a36Sopenharmony_ci		 "\t\t  0 = enable INTx interrupt mechanism.\n"
6162306a36Sopenharmony_ci		 "\t\t  1 = enable MSI-X interrupt mechanism (Default).\n"
6262306a36Sopenharmony_ci		 "\t\t  2 = enable MSI interrupt mechanism.");
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci#define QL4_DEF_QDEPTH 32
6562306a36Sopenharmony_cistatic int ql4xmaxqdepth = QL4_DEF_QDEPTH;
6662306a36Sopenharmony_cimodule_param(ql4xmaxqdepth, int, S_IRUGO | S_IWUSR);
6762306a36Sopenharmony_ciMODULE_PARM_DESC(ql4xmaxqdepth,
6862306a36Sopenharmony_ci		 " Maximum queue depth to report for target devices.\n"
6962306a36Sopenharmony_ci		 "\t\t  Default: 32.");
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_cistatic int ql4xqfulltracking = 1;
7262306a36Sopenharmony_cimodule_param(ql4xqfulltracking, int, S_IRUGO | S_IWUSR);
7362306a36Sopenharmony_ciMODULE_PARM_DESC(ql4xqfulltracking,
7462306a36Sopenharmony_ci		 " Enable or disable dynamic tracking and adjustment of\n"
7562306a36Sopenharmony_ci		 "\t\t scsi device queue depth.\n"
7662306a36Sopenharmony_ci		 "\t\t  0 - Disable.\n"
7762306a36Sopenharmony_ci		 "\t\t  1 - Enable. (Default)");
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_cistatic int ql4xsess_recovery_tmo = QL4_SESS_RECOVERY_TMO;
8062306a36Sopenharmony_cimodule_param(ql4xsess_recovery_tmo, int, S_IRUGO);
8162306a36Sopenharmony_ciMODULE_PARM_DESC(ql4xsess_recovery_tmo,
8262306a36Sopenharmony_ci		" Target Session Recovery Timeout.\n"
8362306a36Sopenharmony_ci		"\t\t  Default: 120 sec.");
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ciint ql4xmdcapmask = 0;
8662306a36Sopenharmony_cimodule_param(ql4xmdcapmask, int, S_IRUGO);
8762306a36Sopenharmony_ciMODULE_PARM_DESC(ql4xmdcapmask,
8862306a36Sopenharmony_ci		 " Set the Minidump driver capture mask level.\n"
8962306a36Sopenharmony_ci		 "\t\t  Default is 0 (firmware default capture mask)\n"
9062306a36Sopenharmony_ci		 "\t\t  Can be set to 0x3, 0x7, 0xF, 0x1F, 0x3F, 0x7F, 0xFF");
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ciint ql4xenablemd = 1;
9362306a36Sopenharmony_cimodule_param(ql4xenablemd, int, S_IRUGO | S_IWUSR);
9462306a36Sopenharmony_ciMODULE_PARM_DESC(ql4xenablemd,
9562306a36Sopenharmony_ci		 " Set to enable minidump.\n"
9662306a36Sopenharmony_ci		 "\t\t  0 - disable minidump\n"
9762306a36Sopenharmony_ci		 "\t\t  1 - enable minidump (Default)");
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_cistatic int qla4xxx_wait_for_hba_online(struct scsi_qla_host *ha);
10062306a36Sopenharmony_ci/*
10162306a36Sopenharmony_ci * SCSI host template entry points
10262306a36Sopenharmony_ci */
10362306a36Sopenharmony_cistatic void qla4xxx_config_dma_addressing(struct scsi_qla_host *ha);
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci/*
10662306a36Sopenharmony_ci * iSCSI template entry points
10762306a36Sopenharmony_ci */
10862306a36Sopenharmony_cistatic int qla4xxx_session_get_param(struct iscsi_cls_session *cls_sess,
10962306a36Sopenharmony_ci				     enum iscsi_param param, char *buf);
11062306a36Sopenharmony_cistatic int qla4xxx_conn_get_param(struct iscsi_cls_conn *conn,
11162306a36Sopenharmony_ci				  enum iscsi_param param, char *buf);
11262306a36Sopenharmony_cistatic int qla4xxx_host_get_param(struct Scsi_Host *shost,
11362306a36Sopenharmony_ci				  enum iscsi_host_param param, char *buf);
11462306a36Sopenharmony_cistatic int qla4xxx_iface_set_param(struct Scsi_Host *shost, void *data,
11562306a36Sopenharmony_ci				   uint32_t len);
11662306a36Sopenharmony_cistatic int qla4xxx_get_iface_param(struct iscsi_iface *iface,
11762306a36Sopenharmony_ci				   enum iscsi_param_type param_type,
11862306a36Sopenharmony_ci				   int param, char *buf);
11962306a36Sopenharmony_cistatic enum scsi_timeout_action qla4xxx_eh_cmd_timed_out(struct scsi_cmnd *sc);
12062306a36Sopenharmony_cistatic struct iscsi_endpoint *qla4xxx_ep_connect(struct Scsi_Host *shost,
12162306a36Sopenharmony_ci						 struct sockaddr *dst_addr,
12262306a36Sopenharmony_ci						 int non_blocking);
12362306a36Sopenharmony_cistatic int qla4xxx_ep_poll(struct iscsi_endpoint *ep, int timeout_ms);
12462306a36Sopenharmony_cistatic void qla4xxx_ep_disconnect(struct iscsi_endpoint *ep);
12562306a36Sopenharmony_cistatic int qla4xxx_get_ep_param(struct iscsi_endpoint *ep,
12662306a36Sopenharmony_ci				enum iscsi_param param, char *buf);
12762306a36Sopenharmony_cistatic int qla4xxx_conn_start(struct iscsi_cls_conn *conn);
12862306a36Sopenharmony_cistatic struct iscsi_cls_conn *
12962306a36Sopenharmony_ciqla4xxx_conn_create(struct iscsi_cls_session *cls_sess, uint32_t conn_idx);
13062306a36Sopenharmony_cistatic int qla4xxx_conn_bind(struct iscsi_cls_session *cls_session,
13162306a36Sopenharmony_ci			     struct iscsi_cls_conn *cls_conn,
13262306a36Sopenharmony_ci			     uint64_t transport_fd, int is_leading);
13362306a36Sopenharmony_cistatic void qla4xxx_conn_destroy(struct iscsi_cls_conn *conn);
13462306a36Sopenharmony_cistatic struct iscsi_cls_session *
13562306a36Sopenharmony_ciqla4xxx_session_create(struct iscsi_endpoint *ep, uint16_t cmds_max,
13662306a36Sopenharmony_ci			uint16_t qdepth, uint32_t initial_cmdsn);
13762306a36Sopenharmony_cistatic void qla4xxx_session_destroy(struct iscsi_cls_session *sess);
13862306a36Sopenharmony_cistatic void qla4xxx_task_work(struct work_struct *wdata);
13962306a36Sopenharmony_cistatic int qla4xxx_alloc_pdu(struct iscsi_task *, uint8_t);
14062306a36Sopenharmony_cistatic int qla4xxx_task_xmit(struct iscsi_task *);
14162306a36Sopenharmony_cistatic void qla4xxx_task_cleanup(struct iscsi_task *);
14262306a36Sopenharmony_cistatic void qla4xxx_fail_session(struct iscsi_cls_session *cls_session);
14362306a36Sopenharmony_cistatic void qla4xxx_conn_get_stats(struct iscsi_cls_conn *cls_conn,
14462306a36Sopenharmony_ci				   struct iscsi_stats *stats);
14562306a36Sopenharmony_cistatic int qla4xxx_send_ping(struct Scsi_Host *shost, uint32_t iface_num,
14662306a36Sopenharmony_ci			     uint32_t iface_type, uint32_t payload_size,
14762306a36Sopenharmony_ci			     uint32_t pid, struct sockaddr *dst_addr);
14862306a36Sopenharmony_cistatic int qla4xxx_get_chap_list(struct Scsi_Host *shost, uint16_t chap_tbl_idx,
14962306a36Sopenharmony_ci				 uint32_t *num_entries, char *buf);
15062306a36Sopenharmony_cistatic int qla4xxx_delete_chap(struct Scsi_Host *shost, uint16_t chap_tbl_idx);
15162306a36Sopenharmony_cistatic int qla4xxx_set_chap_entry(struct Scsi_Host *shost, void  *data,
15262306a36Sopenharmony_ci				  int len);
15362306a36Sopenharmony_cistatic int qla4xxx_get_host_stats(struct Scsi_Host *shost, char *buf, int len);
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ci/*
15662306a36Sopenharmony_ci * SCSI host template entry points
15762306a36Sopenharmony_ci */
15862306a36Sopenharmony_cistatic int qla4xxx_queuecommand(struct Scsi_Host *h, struct scsi_cmnd *cmd);
15962306a36Sopenharmony_cistatic int qla4xxx_eh_abort(struct scsi_cmnd *cmd);
16062306a36Sopenharmony_cistatic int qla4xxx_eh_device_reset(struct scsi_cmnd *cmd);
16162306a36Sopenharmony_cistatic int qla4xxx_eh_target_reset(struct scsi_cmnd *cmd);
16262306a36Sopenharmony_cistatic int qla4xxx_eh_host_reset(struct scsi_cmnd *cmd);
16362306a36Sopenharmony_cistatic int qla4xxx_slave_alloc(struct scsi_device *device);
16462306a36Sopenharmony_cistatic umode_t qla4_attr_is_visible(int param_type, int param);
16562306a36Sopenharmony_cistatic int qla4xxx_host_reset(struct Scsi_Host *shost, int reset_type);
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci/*
16862306a36Sopenharmony_ci * iSCSI Flash DDB sysfs entry points
16962306a36Sopenharmony_ci */
17062306a36Sopenharmony_cistatic int
17162306a36Sopenharmony_ciqla4xxx_sysfs_ddb_set_param(struct iscsi_bus_flash_session *fnode_sess,
17262306a36Sopenharmony_ci			    struct iscsi_bus_flash_conn *fnode_conn,
17362306a36Sopenharmony_ci			    void *data, int len);
17462306a36Sopenharmony_cistatic int
17562306a36Sopenharmony_ciqla4xxx_sysfs_ddb_get_param(struct iscsi_bus_flash_session *fnode_sess,
17662306a36Sopenharmony_ci			    int param, char *buf);
17762306a36Sopenharmony_cistatic int qla4xxx_sysfs_ddb_add(struct Scsi_Host *shost, const char *buf,
17862306a36Sopenharmony_ci				 int len);
17962306a36Sopenharmony_cistatic int
18062306a36Sopenharmony_ciqla4xxx_sysfs_ddb_delete(struct iscsi_bus_flash_session *fnode_sess);
18162306a36Sopenharmony_cistatic int qla4xxx_sysfs_ddb_login(struct iscsi_bus_flash_session *fnode_sess,
18262306a36Sopenharmony_ci				   struct iscsi_bus_flash_conn *fnode_conn);
18362306a36Sopenharmony_cistatic int qla4xxx_sysfs_ddb_logout(struct iscsi_bus_flash_session *fnode_sess,
18462306a36Sopenharmony_ci				    struct iscsi_bus_flash_conn *fnode_conn);
18562306a36Sopenharmony_cistatic int qla4xxx_sysfs_ddb_logout_sid(struct iscsi_cls_session *cls_sess);
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_cistatic struct qla4_8xxx_legacy_intr_set legacy_intr[] =
18862306a36Sopenharmony_ci    QLA82XX_LEGACY_INTR_CONFIG;
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_cistatic const uint32_t qla4_82xx_reg_tbl[] = {
19162306a36Sopenharmony_ci	QLA82XX_PEG_HALT_STATUS1,
19262306a36Sopenharmony_ci	QLA82XX_PEG_HALT_STATUS2,
19362306a36Sopenharmony_ci	QLA82XX_PEG_ALIVE_COUNTER,
19462306a36Sopenharmony_ci	QLA82XX_CRB_DRV_ACTIVE,
19562306a36Sopenharmony_ci	QLA82XX_CRB_DEV_STATE,
19662306a36Sopenharmony_ci	QLA82XX_CRB_DRV_STATE,
19762306a36Sopenharmony_ci	QLA82XX_CRB_DRV_SCRATCH,
19862306a36Sopenharmony_ci	QLA82XX_CRB_DEV_PART_INFO,
19962306a36Sopenharmony_ci	QLA82XX_CRB_DRV_IDC_VERSION,
20062306a36Sopenharmony_ci	QLA82XX_FW_VERSION_MAJOR,
20162306a36Sopenharmony_ci	QLA82XX_FW_VERSION_MINOR,
20262306a36Sopenharmony_ci	QLA82XX_FW_VERSION_SUB,
20362306a36Sopenharmony_ci	CRB_CMDPEG_STATE,
20462306a36Sopenharmony_ci	CRB_TEMP_STATE,
20562306a36Sopenharmony_ci};
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_cistatic const uint32_t qla4_83xx_reg_tbl[] = {
20862306a36Sopenharmony_ci	QLA83XX_PEG_HALT_STATUS1,
20962306a36Sopenharmony_ci	QLA83XX_PEG_HALT_STATUS2,
21062306a36Sopenharmony_ci	QLA83XX_PEG_ALIVE_COUNTER,
21162306a36Sopenharmony_ci	QLA83XX_CRB_DRV_ACTIVE,
21262306a36Sopenharmony_ci	QLA83XX_CRB_DEV_STATE,
21362306a36Sopenharmony_ci	QLA83XX_CRB_DRV_STATE,
21462306a36Sopenharmony_ci	QLA83XX_CRB_DRV_SCRATCH,
21562306a36Sopenharmony_ci	QLA83XX_CRB_DEV_PART_INFO1,
21662306a36Sopenharmony_ci	QLA83XX_CRB_IDC_VER_MAJOR,
21762306a36Sopenharmony_ci	QLA83XX_FW_VER_MAJOR,
21862306a36Sopenharmony_ci	QLA83XX_FW_VER_MINOR,
21962306a36Sopenharmony_ci	QLA83XX_FW_VER_SUB,
22062306a36Sopenharmony_ci	QLA83XX_CMDPEG_STATE,
22162306a36Sopenharmony_ci	QLA83XX_ASIC_TEMP,
22262306a36Sopenharmony_ci};
22362306a36Sopenharmony_ci
22462306a36Sopenharmony_cistatic struct scsi_host_template qla4xxx_driver_template = {
22562306a36Sopenharmony_ci	.module			= THIS_MODULE,
22662306a36Sopenharmony_ci	.name			= DRIVER_NAME,
22762306a36Sopenharmony_ci	.proc_name		= DRIVER_NAME,
22862306a36Sopenharmony_ci	.queuecommand		= qla4xxx_queuecommand,
22962306a36Sopenharmony_ci	.cmd_size		= sizeof(struct qla4xxx_cmd_priv),
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_ci	.eh_abort_handler	= qla4xxx_eh_abort,
23262306a36Sopenharmony_ci	.eh_device_reset_handler = qla4xxx_eh_device_reset,
23362306a36Sopenharmony_ci	.eh_target_reset_handler = qla4xxx_eh_target_reset,
23462306a36Sopenharmony_ci	.eh_host_reset_handler	= qla4xxx_eh_host_reset,
23562306a36Sopenharmony_ci	.eh_timed_out		= qla4xxx_eh_cmd_timed_out,
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ci	.slave_alloc		= qla4xxx_slave_alloc,
23862306a36Sopenharmony_ci	.change_queue_depth	= scsi_change_queue_depth,
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_ci	.this_id		= -1,
24162306a36Sopenharmony_ci	.cmd_per_lun		= 3,
24262306a36Sopenharmony_ci	.sg_tablesize		= SG_ALL,
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_ci	.max_sectors		= 0xFFFF,
24562306a36Sopenharmony_ci	.shost_groups		= qla4xxx_host_groups,
24662306a36Sopenharmony_ci	.host_reset		= qla4xxx_host_reset,
24762306a36Sopenharmony_ci	.vendor_id		= SCSI_NL_VID_TYPE_PCI | PCI_VENDOR_ID_QLOGIC,
24862306a36Sopenharmony_ci};
24962306a36Sopenharmony_ci
25062306a36Sopenharmony_cistatic struct iscsi_transport qla4xxx_iscsi_transport = {
25162306a36Sopenharmony_ci	.owner			= THIS_MODULE,
25262306a36Sopenharmony_ci	.name			= DRIVER_NAME,
25362306a36Sopenharmony_ci	.caps			= CAP_TEXT_NEGO |
25462306a36Sopenharmony_ci				  CAP_DATA_PATH_OFFLOAD | CAP_HDRDGST |
25562306a36Sopenharmony_ci				  CAP_DATADGST | CAP_LOGIN_OFFLOAD |
25662306a36Sopenharmony_ci				  CAP_MULTI_R2T,
25762306a36Sopenharmony_ci	.attr_is_visible	= qla4_attr_is_visible,
25862306a36Sopenharmony_ci	.create_session         = qla4xxx_session_create,
25962306a36Sopenharmony_ci	.destroy_session        = qla4xxx_session_destroy,
26062306a36Sopenharmony_ci	.start_conn             = qla4xxx_conn_start,
26162306a36Sopenharmony_ci	.create_conn            = qla4xxx_conn_create,
26262306a36Sopenharmony_ci	.bind_conn              = qla4xxx_conn_bind,
26362306a36Sopenharmony_ci	.unbind_conn		= iscsi_conn_unbind,
26462306a36Sopenharmony_ci	.stop_conn              = iscsi_conn_stop,
26562306a36Sopenharmony_ci	.destroy_conn           = qla4xxx_conn_destroy,
26662306a36Sopenharmony_ci	.set_param              = iscsi_set_param,
26762306a36Sopenharmony_ci	.get_conn_param		= qla4xxx_conn_get_param,
26862306a36Sopenharmony_ci	.get_session_param	= qla4xxx_session_get_param,
26962306a36Sopenharmony_ci	.get_ep_param           = qla4xxx_get_ep_param,
27062306a36Sopenharmony_ci	.ep_connect		= qla4xxx_ep_connect,
27162306a36Sopenharmony_ci	.ep_poll		= qla4xxx_ep_poll,
27262306a36Sopenharmony_ci	.ep_disconnect		= qla4xxx_ep_disconnect,
27362306a36Sopenharmony_ci	.get_stats		= qla4xxx_conn_get_stats,
27462306a36Sopenharmony_ci	.send_pdu		= iscsi_conn_send_pdu,
27562306a36Sopenharmony_ci	.xmit_task		= qla4xxx_task_xmit,
27662306a36Sopenharmony_ci	.cleanup_task		= qla4xxx_task_cleanup,
27762306a36Sopenharmony_ci	.alloc_pdu		= qla4xxx_alloc_pdu,
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_ci	.get_host_param		= qla4xxx_host_get_param,
28062306a36Sopenharmony_ci	.set_iface_param	= qla4xxx_iface_set_param,
28162306a36Sopenharmony_ci	.get_iface_param	= qla4xxx_get_iface_param,
28262306a36Sopenharmony_ci	.bsg_request		= qla4xxx_bsg_request,
28362306a36Sopenharmony_ci	.send_ping		= qla4xxx_send_ping,
28462306a36Sopenharmony_ci	.get_chap		= qla4xxx_get_chap_list,
28562306a36Sopenharmony_ci	.delete_chap		= qla4xxx_delete_chap,
28662306a36Sopenharmony_ci	.set_chap		= qla4xxx_set_chap_entry,
28762306a36Sopenharmony_ci	.get_flashnode_param	= qla4xxx_sysfs_ddb_get_param,
28862306a36Sopenharmony_ci	.set_flashnode_param	= qla4xxx_sysfs_ddb_set_param,
28962306a36Sopenharmony_ci	.new_flashnode		= qla4xxx_sysfs_ddb_add,
29062306a36Sopenharmony_ci	.del_flashnode		= qla4xxx_sysfs_ddb_delete,
29162306a36Sopenharmony_ci	.login_flashnode	= qla4xxx_sysfs_ddb_login,
29262306a36Sopenharmony_ci	.logout_flashnode	= qla4xxx_sysfs_ddb_logout,
29362306a36Sopenharmony_ci	.logout_flashnode_sid	= qla4xxx_sysfs_ddb_logout_sid,
29462306a36Sopenharmony_ci	.get_host_stats		= qla4xxx_get_host_stats,
29562306a36Sopenharmony_ci};
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_cistatic struct scsi_transport_template *qla4xxx_scsi_transport;
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_cistatic int qla4xxx_isp_check_reg(struct scsi_qla_host *ha)
30062306a36Sopenharmony_ci{
30162306a36Sopenharmony_ci	u32 reg_val = 0;
30262306a36Sopenharmony_ci	int rval = QLA_SUCCESS;
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_ci	if (is_qla8022(ha))
30562306a36Sopenharmony_ci		reg_val = readl(&ha->qla4_82xx_reg->host_status);
30662306a36Sopenharmony_ci	else if (is_qla8032(ha) || is_qla8042(ha))
30762306a36Sopenharmony_ci		reg_val = qla4_8xxx_rd_direct(ha, QLA8XXX_PEG_ALIVE_COUNTER);
30862306a36Sopenharmony_ci	else
30962306a36Sopenharmony_ci		reg_val = readw(&ha->reg->ctrl_status);
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_ci	if (reg_val == QL4_ISP_REG_DISCONNECT)
31262306a36Sopenharmony_ci		rval = QLA_ERROR;
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ci	return rval;
31562306a36Sopenharmony_ci}
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_cistatic int qla4xxx_send_ping(struct Scsi_Host *shost, uint32_t iface_num,
31862306a36Sopenharmony_ci			     uint32_t iface_type, uint32_t payload_size,
31962306a36Sopenharmony_ci			     uint32_t pid, struct sockaddr *dst_addr)
32062306a36Sopenharmony_ci{
32162306a36Sopenharmony_ci	struct scsi_qla_host *ha = to_qla_host(shost);
32262306a36Sopenharmony_ci	struct sockaddr_in *addr;
32362306a36Sopenharmony_ci	struct sockaddr_in6 *addr6;
32462306a36Sopenharmony_ci	uint32_t options = 0;
32562306a36Sopenharmony_ci	uint8_t ipaddr[IPv6_ADDR_LEN];
32662306a36Sopenharmony_ci	int rval;
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_ci	memset(ipaddr, 0, IPv6_ADDR_LEN);
32962306a36Sopenharmony_ci	/* IPv4 to IPv4 */
33062306a36Sopenharmony_ci	if ((iface_type == ISCSI_IFACE_TYPE_IPV4) &&
33162306a36Sopenharmony_ci	    (dst_addr->sa_family == AF_INET)) {
33262306a36Sopenharmony_ci		addr = (struct sockaddr_in *)dst_addr;
33362306a36Sopenharmony_ci		memcpy(ipaddr, &addr->sin_addr.s_addr, IP_ADDR_LEN);
33462306a36Sopenharmony_ci		DEBUG2(ql4_printk(KERN_INFO, ha, "%s: IPv4 Ping src: %pI4 "
33562306a36Sopenharmony_ci				  "dest: %pI4\n", __func__,
33662306a36Sopenharmony_ci				  &ha->ip_config.ip_address, ipaddr));
33762306a36Sopenharmony_ci		rval = qla4xxx_ping_iocb(ha, options, payload_size, pid,
33862306a36Sopenharmony_ci					 ipaddr);
33962306a36Sopenharmony_ci		if (rval)
34062306a36Sopenharmony_ci			rval = -EINVAL;
34162306a36Sopenharmony_ci	} else if ((iface_type == ISCSI_IFACE_TYPE_IPV6) &&
34262306a36Sopenharmony_ci		   (dst_addr->sa_family == AF_INET6)) {
34362306a36Sopenharmony_ci		/* IPv6 to IPv6 */
34462306a36Sopenharmony_ci		addr6 = (struct sockaddr_in6 *)dst_addr;
34562306a36Sopenharmony_ci		memcpy(ipaddr, &addr6->sin6_addr.in6_u.u6_addr8, IPv6_ADDR_LEN);
34662306a36Sopenharmony_ci
34762306a36Sopenharmony_ci		options |= PING_IPV6_PROTOCOL_ENABLE;
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_ci		/* Ping using LinkLocal address */
35062306a36Sopenharmony_ci		if ((iface_num == 0) || (iface_num == 1)) {
35162306a36Sopenharmony_ci			DEBUG2(ql4_printk(KERN_INFO, ha, "%s: LinkLocal Ping "
35262306a36Sopenharmony_ci					  "src: %pI6 dest: %pI6\n", __func__,
35362306a36Sopenharmony_ci					  &ha->ip_config.ipv6_link_local_addr,
35462306a36Sopenharmony_ci					  ipaddr));
35562306a36Sopenharmony_ci			options |= PING_IPV6_LINKLOCAL_ADDR;
35662306a36Sopenharmony_ci			rval = qla4xxx_ping_iocb(ha, options, payload_size,
35762306a36Sopenharmony_ci						 pid, ipaddr);
35862306a36Sopenharmony_ci		} else {
35962306a36Sopenharmony_ci			ql4_printk(KERN_WARNING, ha, "%s: iface num = %d "
36062306a36Sopenharmony_ci				   "not supported\n", __func__, iface_num);
36162306a36Sopenharmony_ci			rval = -ENOSYS;
36262306a36Sopenharmony_ci			goto exit_send_ping;
36362306a36Sopenharmony_ci		}
36462306a36Sopenharmony_ci
36562306a36Sopenharmony_ci		/*
36662306a36Sopenharmony_ci		 * If ping using LinkLocal address fails, try ping using
36762306a36Sopenharmony_ci		 * IPv6 address
36862306a36Sopenharmony_ci		 */
36962306a36Sopenharmony_ci		if (rval != QLA_SUCCESS) {
37062306a36Sopenharmony_ci			options &= ~PING_IPV6_LINKLOCAL_ADDR;
37162306a36Sopenharmony_ci			if (iface_num == 0) {
37262306a36Sopenharmony_ci				options |= PING_IPV6_ADDR0;
37362306a36Sopenharmony_ci				DEBUG2(ql4_printk(KERN_INFO, ha, "%s: IPv6 "
37462306a36Sopenharmony_ci						  "Ping src: %pI6 "
37562306a36Sopenharmony_ci						  "dest: %pI6\n", __func__,
37662306a36Sopenharmony_ci						  &ha->ip_config.ipv6_addr0,
37762306a36Sopenharmony_ci						  ipaddr));
37862306a36Sopenharmony_ci			} else if (iface_num == 1) {
37962306a36Sopenharmony_ci				options |= PING_IPV6_ADDR1;
38062306a36Sopenharmony_ci				DEBUG2(ql4_printk(KERN_INFO, ha, "%s: IPv6 "
38162306a36Sopenharmony_ci						  "Ping src: %pI6 "
38262306a36Sopenharmony_ci						  "dest: %pI6\n", __func__,
38362306a36Sopenharmony_ci						  &ha->ip_config.ipv6_addr1,
38462306a36Sopenharmony_ci						  ipaddr));
38562306a36Sopenharmony_ci			}
38662306a36Sopenharmony_ci			rval = qla4xxx_ping_iocb(ha, options, payload_size,
38762306a36Sopenharmony_ci						 pid, ipaddr);
38862306a36Sopenharmony_ci			if (rval)
38962306a36Sopenharmony_ci				rval = -EINVAL;
39062306a36Sopenharmony_ci		}
39162306a36Sopenharmony_ci	} else
39262306a36Sopenharmony_ci		rval = -ENOSYS;
39362306a36Sopenharmony_ciexit_send_ping:
39462306a36Sopenharmony_ci	return rval;
39562306a36Sopenharmony_ci}
39662306a36Sopenharmony_ci
39762306a36Sopenharmony_cistatic umode_t qla4_attr_is_visible(int param_type, int param)
39862306a36Sopenharmony_ci{
39962306a36Sopenharmony_ci	switch (param_type) {
40062306a36Sopenharmony_ci	case ISCSI_HOST_PARAM:
40162306a36Sopenharmony_ci		switch (param) {
40262306a36Sopenharmony_ci		case ISCSI_HOST_PARAM_HWADDRESS:
40362306a36Sopenharmony_ci		case ISCSI_HOST_PARAM_IPADDRESS:
40462306a36Sopenharmony_ci		case ISCSI_HOST_PARAM_INITIATOR_NAME:
40562306a36Sopenharmony_ci		case ISCSI_HOST_PARAM_PORT_STATE:
40662306a36Sopenharmony_ci		case ISCSI_HOST_PARAM_PORT_SPEED:
40762306a36Sopenharmony_ci			return S_IRUGO;
40862306a36Sopenharmony_ci		default:
40962306a36Sopenharmony_ci			return 0;
41062306a36Sopenharmony_ci		}
41162306a36Sopenharmony_ci	case ISCSI_PARAM:
41262306a36Sopenharmony_ci		switch (param) {
41362306a36Sopenharmony_ci		case ISCSI_PARAM_PERSISTENT_ADDRESS:
41462306a36Sopenharmony_ci		case ISCSI_PARAM_PERSISTENT_PORT:
41562306a36Sopenharmony_ci		case ISCSI_PARAM_CONN_ADDRESS:
41662306a36Sopenharmony_ci		case ISCSI_PARAM_CONN_PORT:
41762306a36Sopenharmony_ci		case ISCSI_PARAM_TARGET_NAME:
41862306a36Sopenharmony_ci		case ISCSI_PARAM_TPGT:
41962306a36Sopenharmony_ci		case ISCSI_PARAM_TARGET_ALIAS:
42062306a36Sopenharmony_ci		case ISCSI_PARAM_MAX_BURST:
42162306a36Sopenharmony_ci		case ISCSI_PARAM_MAX_R2T:
42262306a36Sopenharmony_ci		case ISCSI_PARAM_FIRST_BURST:
42362306a36Sopenharmony_ci		case ISCSI_PARAM_MAX_RECV_DLENGTH:
42462306a36Sopenharmony_ci		case ISCSI_PARAM_MAX_XMIT_DLENGTH:
42562306a36Sopenharmony_ci		case ISCSI_PARAM_IFACE_NAME:
42662306a36Sopenharmony_ci		case ISCSI_PARAM_CHAP_OUT_IDX:
42762306a36Sopenharmony_ci		case ISCSI_PARAM_CHAP_IN_IDX:
42862306a36Sopenharmony_ci		case ISCSI_PARAM_USERNAME:
42962306a36Sopenharmony_ci		case ISCSI_PARAM_PASSWORD:
43062306a36Sopenharmony_ci		case ISCSI_PARAM_USERNAME_IN:
43162306a36Sopenharmony_ci		case ISCSI_PARAM_PASSWORD_IN:
43262306a36Sopenharmony_ci		case ISCSI_PARAM_AUTO_SND_TGT_DISABLE:
43362306a36Sopenharmony_ci		case ISCSI_PARAM_DISCOVERY_SESS:
43462306a36Sopenharmony_ci		case ISCSI_PARAM_PORTAL_TYPE:
43562306a36Sopenharmony_ci		case ISCSI_PARAM_CHAP_AUTH_EN:
43662306a36Sopenharmony_ci		case ISCSI_PARAM_DISCOVERY_LOGOUT_EN:
43762306a36Sopenharmony_ci		case ISCSI_PARAM_BIDI_CHAP_EN:
43862306a36Sopenharmony_ci		case ISCSI_PARAM_DISCOVERY_AUTH_OPTIONAL:
43962306a36Sopenharmony_ci		case ISCSI_PARAM_DEF_TIME2WAIT:
44062306a36Sopenharmony_ci		case ISCSI_PARAM_DEF_TIME2RETAIN:
44162306a36Sopenharmony_ci		case ISCSI_PARAM_HDRDGST_EN:
44262306a36Sopenharmony_ci		case ISCSI_PARAM_DATADGST_EN:
44362306a36Sopenharmony_ci		case ISCSI_PARAM_INITIAL_R2T_EN:
44462306a36Sopenharmony_ci		case ISCSI_PARAM_IMM_DATA_EN:
44562306a36Sopenharmony_ci		case ISCSI_PARAM_PDU_INORDER_EN:
44662306a36Sopenharmony_ci		case ISCSI_PARAM_DATASEQ_INORDER_EN:
44762306a36Sopenharmony_ci		case ISCSI_PARAM_MAX_SEGMENT_SIZE:
44862306a36Sopenharmony_ci		case ISCSI_PARAM_TCP_TIMESTAMP_STAT:
44962306a36Sopenharmony_ci		case ISCSI_PARAM_TCP_WSF_DISABLE:
45062306a36Sopenharmony_ci		case ISCSI_PARAM_TCP_NAGLE_DISABLE:
45162306a36Sopenharmony_ci		case ISCSI_PARAM_TCP_TIMER_SCALE:
45262306a36Sopenharmony_ci		case ISCSI_PARAM_TCP_TIMESTAMP_EN:
45362306a36Sopenharmony_ci		case ISCSI_PARAM_TCP_XMIT_WSF:
45462306a36Sopenharmony_ci		case ISCSI_PARAM_TCP_RECV_WSF:
45562306a36Sopenharmony_ci		case ISCSI_PARAM_IP_FRAGMENT_DISABLE:
45662306a36Sopenharmony_ci		case ISCSI_PARAM_IPV4_TOS:
45762306a36Sopenharmony_ci		case ISCSI_PARAM_IPV6_TC:
45862306a36Sopenharmony_ci		case ISCSI_PARAM_IPV6_FLOW_LABEL:
45962306a36Sopenharmony_ci		case ISCSI_PARAM_IS_FW_ASSIGNED_IPV6:
46062306a36Sopenharmony_ci		case ISCSI_PARAM_KEEPALIVE_TMO:
46162306a36Sopenharmony_ci		case ISCSI_PARAM_LOCAL_PORT:
46262306a36Sopenharmony_ci		case ISCSI_PARAM_ISID:
46362306a36Sopenharmony_ci		case ISCSI_PARAM_TSID:
46462306a36Sopenharmony_ci		case ISCSI_PARAM_DEF_TASKMGMT_TMO:
46562306a36Sopenharmony_ci		case ISCSI_PARAM_ERL:
46662306a36Sopenharmony_ci		case ISCSI_PARAM_STATSN:
46762306a36Sopenharmony_ci		case ISCSI_PARAM_EXP_STATSN:
46862306a36Sopenharmony_ci		case ISCSI_PARAM_DISCOVERY_PARENT_IDX:
46962306a36Sopenharmony_ci		case ISCSI_PARAM_DISCOVERY_PARENT_TYPE:
47062306a36Sopenharmony_ci		case ISCSI_PARAM_LOCAL_IPADDR:
47162306a36Sopenharmony_ci			return S_IRUGO;
47262306a36Sopenharmony_ci		default:
47362306a36Sopenharmony_ci			return 0;
47462306a36Sopenharmony_ci		}
47562306a36Sopenharmony_ci	case ISCSI_NET_PARAM:
47662306a36Sopenharmony_ci		switch (param) {
47762306a36Sopenharmony_ci		case ISCSI_NET_PARAM_IPV4_ADDR:
47862306a36Sopenharmony_ci		case ISCSI_NET_PARAM_IPV4_SUBNET:
47962306a36Sopenharmony_ci		case ISCSI_NET_PARAM_IPV4_GW:
48062306a36Sopenharmony_ci		case ISCSI_NET_PARAM_IPV4_BOOTPROTO:
48162306a36Sopenharmony_ci		case ISCSI_NET_PARAM_IFACE_ENABLE:
48262306a36Sopenharmony_ci		case ISCSI_NET_PARAM_IPV6_LINKLOCAL:
48362306a36Sopenharmony_ci		case ISCSI_NET_PARAM_IPV6_ADDR:
48462306a36Sopenharmony_ci		case ISCSI_NET_PARAM_IPV6_ROUTER:
48562306a36Sopenharmony_ci		case ISCSI_NET_PARAM_IPV6_ADDR_AUTOCFG:
48662306a36Sopenharmony_ci		case ISCSI_NET_PARAM_IPV6_LINKLOCAL_AUTOCFG:
48762306a36Sopenharmony_ci		case ISCSI_NET_PARAM_VLAN_ID:
48862306a36Sopenharmony_ci		case ISCSI_NET_PARAM_VLAN_PRIORITY:
48962306a36Sopenharmony_ci		case ISCSI_NET_PARAM_VLAN_ENABLED:
49062306a36Sopenharmony_ci		case ISCSI_NET_PARAM_MTU:
49162306a36Sopenharmony_ci		case ISCSI_NET_PARAM_PORT:
49262306a36Sopenharmony_ci		case ISCSI_NET_PARAM_IPADDR_STATE:
49362306a36Sopenharmony_ci		case ISCSI_NET_PARAM_IPV6_LINKLOCAL_STATE:
49462306a36Sopenharmony_ci		case ISCSI_NET_PARAM_IPV6_ROUTER_STATE:
49562306a36Sopenharmony_ci		case ISCSI_NET_PARAM_DELAYED_ACK_EN:
49662306a36Sopenharmony_ci		case ISCSI_NET_PARAM_TCP_NAGLE_DISABLE:
49762306a36Sopenharmony_ci		case ISCSI_NET_PARAM_TCP_WSF_DISABLE:
49862306a36Sopenharmony_ci		case ISCSI_NET_PARAM_TCP_WSF:
49962306a36Sopenharmony_ci		case ISCSI_NET_PARAM_TCP_TIMER_SCALE:
50062306a36Sopenharmony_ci		case ISCSI_NET_PARAM_TCP_TIMESTAMP_EN:
50162306a36Sopenharmony_ci		case ISCSI_NET_PARAM_CACHE_ID:
50262306a36Sopenharmony_ci		case ISCSI_NET_PARAM_IPV4_DHCP_DNS_ADDR_EN:
50362306a36Sopenharmony_ci		case ISCSI_NET_PARAM_IPV4_DHCP_SLP_DA_EN:
50462306a36Sopenharmony_ci		case ISCSI_NET_PARAM_IPV4_TOS_EN:
50562306a36Sopenharmony_ci		case ISCSI_NET_PARAM_IPV4_TOS:
50662306a36Sopenharmony_ci		case ISCSI_NET_PARAM_IPV4_GRAT_ARP_EN:
50762306a36Sopenharmony_ci		case ISCSI_NET_PARAM_IPV4_DHCP_ALT_CLIENT_ID_EN:
50862306a36Sopenharmony_ci		case ISCSI_NET_PARAM_IPV4_DHCP_ALT_CLIENT_ID:
50962306a36Sopenharmony_ci		case ISCSI_NET_PARAM_IPV4_DHCP_REQ_VENDOR_ID_EN:
51062306a36Sopenharmony_ci		case ISCSI_NET_PARAM_IPV4_DHCP_USE_VENDOR_ID_EN:
51162306a36Sopenharmony_ci		case ISCSI_NET_PARAM_IPV4_DHCP_VENDOR_ID:
51262306a36Sopenharmony_ci		case ISCSI_NET_PARAM_IPV4_DHCP_LEARN_IQN_EN:
51362306a36Sopenharmony_ci		case ISCSI_NET_PARAM_IPV4_FRAGMENT_DISABLE:
51462306a36Sopenharmony_ci		case ISCSI_NET_PARAM_IPV4_IN_FORWARD_EN:
51562306a36Sopenharmony_ci		case ISCSI_NET_PARAM_REDIRECT_EN:
51662306a36Sopenharmony_ci		case ISCSI_NET_PARAM_IPV4_TTL:
51762306a36Sopenharmony_ci		case ISCSI_NET_PARAM_IPV6_GRAT_NEIGHBOR_ADV_EN:
51862306a36Sopenharmony_ci		case ISCSI_NET_PARAM_IPV6_MLD_EN:
51962306a36Sopenharmony_ci		case ISCSI_NET_PARAM_IPV6_FLOW_LABEL:
52062306a36Sopenharmony_ci		case ISCSI_NET_PARAM_IPV6_TRAFFIC_CLASS:
52162306a36Sopenharmony_ci		case ISCSI_NET_PARAM_IPV6_HOP_LIMIT:
52262306a36Sopenharmony_ci		case ISCSI_NET_PARAM_IPV6_ND_REACHABLE_TMO:
52362306a36Sopenharmony_ci		case ISCSI_NET_PARAM_IPV6_ND_REXMIT_TIME:
52462306a36Sopenharmony_ci		case ISCSI_NET_PARAM_IPV6_ND_STALE_TMO:
52562306a36Sopenharmony_ci		case ISCSI_NET_PARAM_IPV6_DUP_ADDR_DETECT_CNT:
52662306a36Sopenharmony_ci		case ISCSI_NET_PARAM_IPV6_RTR_ADV_LINK_MTU:
52762306a36Sopenharmony_ci			return S_IRUGO;
52862306a36Sopenharmony_ci		default:
52962306a36Sopenharmony_ci			return 0;
53062306a36Sopenharmony_ci		}
53162306a36Sopenharmony_ci	case ISCSI_IFACE_PARAM:
53262306a36Sopenharmony_ci		switch (param) {
53362306a36Sopenharmony_ci		case ISCSI_IFACE_PARAM_DEF_TASKMGMT_TMO:
53462306a36Sopenharmony_ci		case ISCSI_IFACE_PARAM_HDRDGST_EN:
53562306a36Sopenharmony_ci		case ISCSI_IFACE_PARAM_DATADGST_EN:
53662306a36Sopenharmony_ci		case ISCSI_IFACE_PARAM_IMM_DATA_EN:
53762306a36Sopenharmony_ci		case ISCSI_IFACE_PARAM_INITIAL_R2T_EN:
53862306a36Sopenharmony_ci		case ISCSI_IFACE_PARAM_DATASEQ_INORDER_EN:
53962306a36Sopenharmony_ci		case ISCSI_IFACE_PARAM_PDU_INORDER_EN:
54062306a36Sopenharmony_ci		case ISCSI_IFACE_PARAM_ERL:
54162306a36Sopenharmony_ci		case ISCSI_IFACE_PARAM_MAX_RECV_DLENGTH:
54262306a36Sopenharmony_ci		case ISCSI_IFACE_PARAM_FIRST_BURST:
54362306a36Sopenharmony_ci		case ISCSI_IFACE_PARAM_MAX_R2T:
54462306a36Sopenharmony_ci		case ISCSI_IFACE_PARAM_MAX_BURST:
54562306a36Sopenharmony_ci		case ISCSI_IFACE_PARAM_CHAP_AUTH_EN:
54662306a36Sopenharmony_ci		case ISCSI_IFACE_PARAM_BIDI_CHAP_EN:
54762306a36Sopenharmony_ci		case ISCSI_IFACE_PARAM_DISCOVERY_AUTH_OPTIONAL:
54862306a36Sopenharmony_ci		case ISCSI_IFACE_PARAM_DISCOVERY_LOGOUT_EN:
54962306a36Sopenharmony_ci		case ISCSI_IFACE_PARAM_STRICT_LOGIN_COMP_EN:
55062306a36Sopenharmony_ci		case ISCSI_IFACE_PARAM_INITIATOR_NAME:
55162306a36Sopenharmony_ci			return S_IRUGO;
55262306a36Sopenharmony_ci		default:
55362306a36Sopenharmony_ci			return 0;
55462306a36Sopenharmony_ci		}
55562306a36Sopenharmony_ci	case ISCSI_FLASHNODE_PARAM:
55662306a36Sopenharmony_ci		switch (param) {
55762306a36Sopenharmony_ci		case ISCSI_FLASHNODE_IS_FW_ASSIGNED_IPV6:
55862306a36Sopenharmony_ci		case ISCSI_FLASHNODE_PORTAL_TYPE:
55962306a36Sopenharmony_ci		case ISCSI_FLASHNODE_AUTO_SND_TGT_DISABLE:
56062306a36Sopenharmony_ci		case ISCSI_FLASHNODE_DISCOVERY_SESS:
56162306a36Sopenharmony_ci		case ISCSI_FLASHNODE_ENTRY_EN:
56262306a36Sopenharmony_ci		case ISCSI_FLASHNODE_HDR_DGST_EN:
56362306a36Sopenharmony_ci		case ISCSI_FLASHNODE_DATA_DGST_EN:
56462306a36Sopenharmony_ci		case ISCSI_FLASHNODE_IMM_DATA_EN:
56562306a36Sopenharmony_ci		case ISCSI_FLASHNODE_INITIAL_R2T_EN:
56662306a36Sopenharmony_ci		case ISCSI_FLASHNODE_DATASEQ_INORDER:
56762306a36Sopenharmony_ci		case ISCSI_FLASHNODE_PDU_INORDER:
56862306a36Sopenharmony_ci		case ISCSI_FLASHNODE_CHAP_AUTH_EN:
56962306a36Sopenharmony_ci		case ISCSI_FLASHNODE_SNACK_REQ_EN:
57062306a36Sopenharmony_ci		case ISCSI_FLASHNODE_DISCOVERY_LOGOUT_EN:
57162306a36Sopenharmony_ci		case ISCSI_FLASHNODE_BIDI_CHAP_EN:
57262306a36Sopenharmony_ci		case ISCSI_FLASHNODE_DISCOVERY_AUTH_OPTIONAL:
57362306a36Sopenharmony_ci		case ISCSI_FLASHNODE_ERL:
57462306a36Sopenharmony_ci		case ISCSI_FLASHNODE_TCP_TIMESTAMP_STAT:
57562306a36Sopenharmony_ci		case ISCSI_FLASHNODE_TCP_NAGLE_DISABLE:
57662306a36Sopenharmony_ci		case ISCSI_FLASHNODE_TCP_WSF_DISABLE:
57762306a36Sopenharmony_ci		case ISCSI_FLASHNODE_TCP_TIMER_SCALE:
57862306a36Sopenharmony_ci		case ISCSI_FLASHNODE_TCP_TIMESTAMP_EN:
57962306a36Sopenharmony_ci		case ISCSI_FLASHNODE_IP_FRAG_DISABLE:
58062306a36Sopenharmony_ci		case ISCSI_FLASHNODE_MAX_RECV_DLENGTH:
58162306a36Sopenharmony_ci		case ISCSI_FLASHNODE_MAX_XMIT_DLENGTH:
58262306a36Sopenharmony_ci		case ISCSI_FLASHNODE_FIRST_BURST:
58362306a36Sopenharmony_ci		case ISCSI_FLASHNODE_DEF_TIME2WAIT:
58462306a36Sopenharmony_ci		case ISCSI_FLASHNODE_DEF_TIME2RETAIN:
58562306a36Sopenharmony_ci		case ISCSI_FLASHNODE_MAX_R2T:
58662306a36Sopenharmony_ci		case ISCSI_FLASHNODE_KEEPALIVE_TMO:
58762306a36Sopenharmony_ci		case ISCSI_FLASHNODE_ISID:
58862306a36Sopenharmony_ci		case ISCSI_FLASHNODE_TSID:
58962306a36Sopenharmony_ci		case ISCSI_FLASHNODE_PORT:
59062306a36Sopenharmony_ci		case ISCSI_FLASHNODE_MAX_BURST:
59162306a36Sopenharmony_ci		case ISCSI_FLASHNODE_DEF_TASKMGMT_TMO:
59262306a36Sopenharmony_ci		case ISCSI_FLASHNODE_IPADDR:
59362306a36Sopenharmony_ci		case ISCSI_FLASHNODE_ALIAS:
59462306a36Sopenharmony_ci		case ISCSI_FLASHNODE_REDIRECT_IPADDR:
59562306a36Sopenharmony_ci		case ISCSI_FLASHNODE_MAX_SEGMENT_SIZE:
59662306a36Sopenharmony_ci		case ISCSI_FLASHNODE_LOCAL_PORT:
59762306a36Sopenharmony_ci		case ISCSI_FLASHNODE_IPV4_TOS:
59862306a36Sopenharmony_ci		case ISCSI_FLASHNODE_IPV6_TC:
59962306a36Sopenharmony_ci		case ISCSI_FLASHNODE_IPV6_FLOW_LABEL:
60062306a36Sopenharmony_ci		case ISCSI_FLASHNODE_NAME:
60162306a36Sopenharmony_ci		case ISCSI_FLASHNODE_TPGT:
60262306a36Sopenharmony_ci		case ISCSI_FLASHNODE_LINK_LOCAL_IPV6:
60362306a36Sopenharmony_ci		case ISCSI_FLASHNODE_DISCOVERY_PARENT_IDX:
60462306a36Sopenharmony_ci		case ISCSI_FLASHNODE_DISCOVERY_PARENT_TYPE:
60562306a36Sopenharmony_ci		case ISCSI_FLASHNODE_TCP_XMIT_WSF:
60662306a36Sopenharmony_ci		case ISCSI_FLASHNODE_TCP_RECV_WSF:
60762306a36Sopenharmony_ci		case ISCSI_FLASHNODE_CHAP_OUT_IDX:
60862306a36Sopenharmony_ci		case ISCSI_FLASHNODE_USERNAME:
60962306a36Sopenharmony_ci		case ISCSI_FLASHNODE_PASSWORD:
61062306a36Sopenharmony_ci		case ISCSI_FLASHNODE_STATSN:
61162306a36Sopenharmony_ci		case ISCSI_FLASHNODE_EXP_STATSN:
61262306a36Sopenharmony_ci		case ISCSI_FLASHNODE_IS_BOOT_TGT:
61362306a36Sopenharmony_ci			return S_IRUGO;
61462306a36Sopenharmony_ci		default:
61562306a36Sopenharmony_ci			return 0;
61662306a36Sopenharmony_ci		}
61762306a36Sopenharmony_ci	}
61862306a36Sopenharmony_ci
61962306a36Sopenharmony_ci	return 0;
62062306a36Sopenharmony_ci}
62162306a36Sopenharmony_ci
62262306a36Sopenharmony_ci/**
62362306a36Sopenharmony_ci * qla4xxx_create_chap_list - Create CHAP list from FLASH
62462306a36Sopenharmony_ci * @ha: pointer to adapter structure
62562306a36Sopenharmony_ci *
62662306a36Sopenharmony_ci * Read flash and make a list of CHAP entries, during login when a CHAP entry
62762306a36Sopenharmony_ci * is received, it will be checked in this list. If entry exist then the CHAP
62862306a36Sopenharmony_ci * entry index is set in the DDB. If CHAP entry does not exist in this list
62962306a36Sopenharmony_ci * then a new entry is added in FLASH in CHAP table and the index obtained is
63062306a36Sopenharmony_ci * used in the DDB.
63162306a36Sopenharmony_ci **/
63262306a36Sopenharmony_cistatic void qla4xxx_create_chap_list(struct scsi_qla_host *ha)
63362306a36Sopenharmony_ci{
63462306a36Sopenharmony_ci	int rval = 0;
63562306a36Sopenharmony_ci	uint8_t *chap_flash_data = NULL;
63662306a36Sopenharmony_ci	uint32_t offset;
63762306a36Sopenharmony_ci	dma_addr_t chap_dma;
63862306a36Sopenharmony_ci	uint32_t chap_size = 0;
63962306a36Sopenharmony_ci
64062306a36Sopenharmony_ci	if (is_qla40XX(ha))
64162306a36Sopenharmony_ci		chap_size = MAX_CHAP_ENTRIES_40XX *
64262306a36Sopenharmony_ci			    sizeof(struct ql4_chap_table);
64362306a36Sopenharmony_ci	else	/* Single region contains CHAP info for both
64462306a36Sopenharmony_ci		 * ports which is divided into half for each port.
64562306a36Sopenharmony_ci		 */
64662306a36Sopenharmony_ci		chap_size = ha->hw.flt_chap_size / 2;
64762306a36Sopenharmony_ci
64862306a36Sopenharmony_ci	chap_flash_data = dma_alloc_coherent(&ha->pdev->dev, chap_size,
64962306a36Sopenharmony_ci					     &chap_dma, GFP_KERNEL);
65062306a36Sopenharmony_ci	if (!chap_flash_data) {
65162306a36Sopenharmony_ci		ql4_printk(KERN_ERR, ha, "No memory for chap_flash_data\n");
65262306a36Sopenharmony_ci		return;
65362306a36Sopenharmony_ci	}
65462306a36Sopenharmony_ci
65562306a36Sopenharmony_ci	if (is_qla40XX(ha)) {
65662306a36Sopenharmony_ci		offset = FLASH_CHAP_OFFSET;
65762306a36Sopenharmony_ci	} else {
65862306a36Sopenharmony_ci		offset = FLASH_RAW_ACCESS_ADDR + (ha->hw.flt_region_chap << 2);
65962306a36Sopenharmony_ci		if (ha->port_num == 1)
66062306a36Sopenharmony_ci			offset += chap_size;
66162306a36Sopenharmony_ci	}
66262306a36Sopenharmony_ci
66362306a36Sopenharmony_ci	rval = qla4xxx_get_flash(ha, chap_dma, offset, chap_size);
66462306a36Sopenharmony_ci	if (rval != QLA_SUCCESS)
66562306a36Sopenharmony_ci		goto exit_chap_list;
66662306a36Sopenharmony_ci
66762306a36Sopenharmony_ci	if (ha->chap_list == NULL)
66862306a36Sopenharmony_ci		ha->chap_list = vmalloc(chap_size);
66962306a36Sopenharmony_ci	if (ha->chap_list == NULL) {
67062306a36Sopenharmony_ci		ql4_printk(KERN_ERR, ha, "No memory for ha->chap_list\n");
67162306a36Sopenharmony_ci		goto exit_chap_list;
67262306a36Sopenharmony_ci	}
67362306a36Sopenharmony_ci
67462306a36Sopenharmony_ci	memcpy(ha->chap_list, chap_flash_data, chap_size);
67562306a36Sopenharmony_ci
67662306a36Sopenharmony_ciexit_chap_list:
67762306a36Sopenharmony_ci	dma_free_coherent(&ha->pdev->dev, chap_size, chap_flash_data, chap_dma);
67862306a36Sopenharmony_ci}
67962306a36Sopenharmony_ci
68062306a36Sopenharmony_cistatic int qla4xxx_get_chap_by_index(struct scsi_qla_host *ha,
68162306a36Sopenharmony_ci				     int16_t chap_index,
68262306a36Sopenharmony_ci				     struct ql4_chap_table **chap_entry)
68362306a36Sopenharmony_ci{
68462306a36Sopenharmony_ci	int rval = QLA_ERROR;
68562306a36Sopenharmony_ci	int max_chap_entries;
68662306a36Sopenharmony_ci
68762306a36Sopenharmony_ci	if (!ha->chap_list) {
68862306a36Sopenharmony_ci		ql4_printk(KERN_ERR, ha, "CHAP table cache is empty!\n");
68962306a36Sopenharmony_ci		goto exit_get_chap;
69062306a36Sopenharmony_ci	}
69162306a36Sopenharmony_ci
69262306a36Sopenharmony_ci	if (is_qla80XX(ha))
69362306a36Sopenharmony_ci		max_chap_entries = (ha->hw.flt_chap_size / 2) /
69462306a36Sopenharmony_ci				   sizeof(struct ql4_chap_table);
69562306a36Sopenharmony_ci	else
69662306a36Sopenharmony_ci		max_chap_entries = MAX_CHAP_ENTRIES_40XX;
69762306a36Sopenharmony_ci
69862306a36Sopenharmony_ci	if (chap_index > max_chap_entries) {
69962306a36Sopenharmony_ci		ql4_printk(KERN_ERR, ha, "Invalid Chap index\n");
70062306a36Sopenharmony_ci		goto exit_get_chap;
70162306a36Sopenharmony_ci	}
70262306a36Sopenharmony_ci
70362306a36Sopenharmony_ci	*chap_entry = (struct ql4_chap_table *)ha->chap_list + chap_index;
70462306a36Sopenharmony_ci	if ((*chap_entry)->cookie !=
70562306a36Sopenharmony_ci	     cpu_to_le16(CHAP_VALID_COOKIE)) {
70662306a36Sopenharmony_ci		*chap_entry = NULL;
70762306a36Sopenharmony_ci	} else {
70862306a36Sopenharmony_ci		rval = QLA_SUCCESS;
70962306a36Sopenharmony_ci	}
71062306a36Sopenharmony_ci
71162306a36Sopenharmony_ciexit_get_chap:
71262306a36Sopenharmony_ci	return rval;
71362306a36Sopenharmony_ci}
71462306a36Sopenharmony_ci
71562306a36Sopenharmony_ci/**
71662306a36Sopenharmony_ci * qla4xxx_find_free_chap_index - Find the first free chap index
71762306a36Sopenharmony_ci * @ha: pointer to adapter structure
71862306a36Sopenharmony_ci * @chap_index: CHAP index to be returned
71962306a36Sopenharmony_ci *
72062306a36Sopenharmony_ci * Find the first free chap index available in the chap table
72162306a36Sopenharmony_ci *
72262306a36Sopenharmony_ci * Note: Caller should acquire the chap lock before getting here.
72362306a36Sopenharmony_ci **/
72462306a36Sopenharmony_cistatic int qla4xxx_find_free_chap_index(struct scsi_qla_host *ha,
72562306a36Sopenharmony_ci					uint16_t *chap_index)
72662306a36Sopenharmony_ci{
72762306a36Sopenharmony_ci	int i, rval;
72862306a36Sopenharmony_ci	int free_index = -1;
72962306a36Sopenharmony_ci	int max_chap_entries = 0;
73062306a36Sopenharmony_ci	struct ql4_chap_table *chap_table;
73162306a36Sopenharmony_ci
73262306a36Sopenharmony_ci	if (is_qla80XX(ha))
73362306a36Sopenharmony_ci		max_chap_entries = (ha->hw.flt_chap_size / 2) /
73462306a36Sopenharmony_ci						sizeof(struct ql4_chap_table);
73562306a36Sopenharmony_ci	else
73662306a36Sopenharmony_ci		max_chap_entries = MAX_CHAP_ENTRIES_40XX;
73762306a36Sopenharmony_ci
73862306a36Sopenharmony_ci	if (!ha->chap_list) {
73962306a36Sopenharmony_ci		ql4_printk(KERN_ERR, ha, "CHAP table cache is empty!\n");
74062306a36Sopenharmony_ci		rval = QLA_ERROR;
74162306a36Sopenharmony_ci		goto exit_find_chap;
74262306a36Sopenharmony_ci	}
74362306a36Sopenharmony_ci
74462306a36Sopenharmony_ci	for (i = 0; i < max_chap_entries; i++) {
74562306a36Sopenharmony_ci		chap_table = (struct ql4_chap_table *)ha->chap_list + i;
74662306a36Sopenharmony_ci
74762306a36Sopenharmony_ci		if ((chap_table->cookie !=
74862306a36Sopenharmony_ci		    cpu_to_le16(CHAP_VALID_COOKIE)) &&
74962306a36Sopenharmony_ci		   (i > MAX_RESRV_CHAP_IDX)) {
75062306a36Sopenharmony_ci				free_index = i;
75162306a36Sopenharmony_ci				break;
75262306a36Sopenharmony_ci		}
75362306a36Sopenharmony_ci	}
75462306a36Sopenharmony_ci
75562306a36Sopenharmony_ci	if (free_index != -1) {
75662306a36Sopenharmony_ci		*chap_index = free_index;
75762306a36Sopenharmony_ci		rval = QLA_SUCCESS;
75862306a36Sopenharmony_ci	} else {
75962306a36Sopenharmony_ci		rval = QLA_ERROR;
76062306a36Sopenharmony_ci	}
76162306a36Sopenharmony_ci
76262306a36Sopenharmony_ciexit_find_chap:
76362306a36Sopenharmony_ci	return rval;
76462306a36Sopenharmony_ci}
76562306a36Sopenharmony_ci
76662306a36Sopenharmony_cistatic int qla4xxx_get_chap_list(struct Scsi_Host *shost, uint16_t chap_tbl_idx,
76762306a36Sopenharmony_ci				  uint32_t *num_entries, char *buf)
76862306a36Sopenharmony_ci{
76962306a36Sopenharmony_ci	struct scsi_qla_host *ha = to_qla_host(shost);
77062306a36Sopenharmony_ci	struct ql4_chap_table *chap_table;
77162306a36Sopenharmony_ci	struct iscsi_chap_rec *chap_rec;
77262306a36Sopenharmony_ci	int max_chap_entries = 0;
77362306a36Sopenharmony_ci	int valid_chap_entries = 0;
77462306a36Sopenharmony_ci	int ret = 0, i;
77562306a36Sopenharmony_ci
77662306a36Sopenharmony_ci	if (is_qla80XX(ha))
77762306a36Sopenharmony_ci		max_chap_entries = (ha->hw.flt_chap_size / 2) /
77862306a36Sopenharmony_ci					sizeof(struct ql4_chap_table);
77962306a36Sopenharmony_ci	else
78062306a36Sopenharmony_ci		max_chap_entries = MAX_CHAP_ENTRIES_40XX;
78162306a36Sopenharmony_ci
78262306a36Sopenharmony_ci	ql4_printk(KERN_INFO, ha, "%s: num_entries = %d, CHAP idx = %d\n",
78362306a36Sopenharmony_ci			__func__, *num_entries, chap_tbl_idx);
78462306a36Sopenharmony_ci
78562306a36Sopenharmony_ci	if (!buf) {
78662306a36Sopenharmony_ci		ret = -ENOMEM;
78762306a36Sopenharmony_ci		goto exit_get_chap_list;
78862306a36Sopenharmony_ci	}
78962306a36Sopenharmony_ci
79062306a36Sopenharmony_ci	qla4xxx_create_chap_list(ha);
79162306a36Sopenharmony_ci
79262306a36Sopenharmony_ci	chap_rec = (struct iscsi_chap_rec *) buf;
79362306a36Sopenharmony_ci	mutex_lock(&ha->chap_sem);
79462306a36Sopenharmony_ci	for (i = chap_tbl_idx; i < max_chap_entries; i++) {
79562306a36Sopenharmony_ci		chap_table = (struct ql4_chap_table *)ha->chap_list + i;
79662306a36Sopenharmony_ci		if (chap_table->cookie !=
79762306a36Sopenharmony_ci		    cpu_to_le16(CHAP_VALID_COOKIE))
79862306a36Sopenharmony_ci			continue;
79962306a36Sopenharmony_ci
80062306a36Sopenharmony_ci		chap_rec->chap_tbl_idx = i;
80162306a36Sopenharmony_ci		strscpy(chap_rec->username, chap_table->name,
80262306a36Sopenharmony_ci			ISCSI_CHAP_AUTH_NAME_MAX_LEN);
80362306a36Sopenharmony_ci		strscpy(chap_rec->password, chap_table->secret,
80462306a36Sopenharmony_ci			QL4_CHAP_MAX_SECRET_LEN);
80562306a36Sopenharmony_ci		chap_rec->password_length = chap_table->secret_len;
80662306a36Sopenharmony_ci
80762306a36Sopenharmony_ci		if (chap_table->flags & BIT_7) /* local */
80862306a36Sopenharmony_ci			chap_rec->chap_type = CHAP_TYPE_OUT;
80962306a36Sopenharmony_ci
81062306a36Sopenharmony_ci		if (chap_table->flags & BIT_6) /* peer */
81162306a36Sopenharmony_ci			chap_rec->chap_type = CHAP_TYPE_IN;
81262306a36Sopenharmony_ci
81362306a36Sopenharmony_ci		chap_rec++;
81462306a36Sopenharmony_ci
81562306a36Sopenharmony_ci		valid_chap_entries++;
81662306a36Sopenharmony_ci		if (valid_chap_entries == *num_entries)
81762306a36Sopenharmony_ci			break;
81862306a36Sopenharmony_ci	}
81962306a36Sopenharmony_ci	mutex_unlock(&ha->chap_sem);
82062306a36Sopenharmony_ci
82162306a36Sopenharmony_ciexit_get_chap_list:
82262306a36Sopenharmony_ci	ql4_printk(KERN_INFO, ha, "%s: Valid CHAP Entries = %d\n",
82362306a36Sopenharmony_ci			__func__,  valid_chap_entries);
82462306a36Sopenharmony_ci	*num_entries = valid_chap_entries;
82562306a36Sopenharmony_ci	return ret;
82662306a36Sopenharmony_ci}
82762306a36Sopenharmony_ci
82862306a36Sopenharmony_cistatic int __qla4xxx_is_chap_active(struct device *dev, void *data)
82962306a36Sopenharmony_ci{
83062306a36Sopenharmony_ci	int ret = 0;
83162306a36Sopenharmony_ci	uint16_t *chap_tbl_idx = (uint16_t *) data;
83262306a36Sopenharmony_ci	struct iscsi_cls_session *cls_session;
83362306a36Sopenharmony_ci	struct iscsi_session *sess;
83462306a36Sopenharmony_ci	struct ddb_entry *ddb_entry;
83562306a36Sopenharmony_ci
83662306a36Sopenharmony_ci	if (!iscsi_is_session_dev(dev))
83762306a36Sopenharmony_ci		goto exit_is_chap_active;
83862306a36Sopenharmony_ci
83962306a36Sopenharmony_ci	cls_session = iscsi_dev_to_session(dev);
84062306a36Sopenharmony_ci	sess = cls_session->dd_data;
84162306a36Sopenharmony_ci	ddb_entry = sess->dd_data;
84262306a36Sopenharmony_ci
84362306a36Sopenharmony_ci	if (iscsi_is_session_online(cls_session))
84462306a36Sopenharmony_ci		goto exit_is_chap_active;
84562306a36Sopenharmony_ci
84662306a36Sopenharmony_ci	if (ddb_entry->chap_tbl_idx == *chap_tbl_idx)
84762306a36Sopenharmony_ci		ret = 1;
84862306a36Sopenharmony_ci
84962306a36Sopenharmony_ciexit_is_chap_active:
85062306a36Sopenharmony_ci	return ret;
85162306a36Sopenharmony_ci}
85262306a36Sopenharmony_ci
85362306a36Sopenharmony_cistatic int qla4xxx_is_chap_active(struct Scsi_Host *shost,
85462306a36Sopenharmony_ci				  uint16_t chap_tbl_idx)
85562306a36Sopenharmony_ci{
85662306a36Sopenharmony_ci	int ret = 0;
85762306a36Sopenharmony_ci
85862306a36Sopenharmony_ci	ret = device_for_each_child(&shost->shost_gendev, &chap_tbl_idx,
85962306a36Sopenharmony_ci				    __qla4xxx_is_chap_active);
86062306a36Sopenharmony_ci
86162306a36Sopenharmony_ci	return ret;
86262306a36Sopenharmony_ci}
86362306a36Sopenharmony_ci
86462306a36Sopenharmony_cistatic int qla4xxx_delete_chap(struct Scsi_Host *shost, uint16_t chap_tbl_idx)
86562306a36Sopenharmony_ci{
86662306a36Sopenharmony_ci	struct scsi_qla_host *ha = to_qla_host(shost);
86762306a36Sopenharmony_ci	struct ql4_chap_table *chap_table;
86862306a36Sopenharmony_ci	dma_addr_t chap_dma;
86962306a36Sopenharmony_ci	int max_chap_entries = 0;
87062306a36Sopenharmony_ci	uint32_t offset = 0;
87162306a36Sopenharmony_ci	uint32_t chap_size;
87262306a36Sopenharmony_ci	int ret = 0;
87362306a36Sopenharmony_ci
87462306a36Sopenharmony_ci	chap_table = dma_pool_zalloc(ha->chap_dma_pool, GFP_KERNEL, &chap_dma);
87562306a36Sopenharmony_ci	if (chap_table == NULL)
87662306a36Sopenharmony_ci		return -ENOMEM;
87762306a36Sopenharmony_ci
87862306a36Sopenharmony_ci	if (is_qla80XX(ha))
87962306a36Sopenharmony_ci		max_chap_entries = (ha->hw.flt_chap_size / 2) /
88062306a36Sopenharmony_ci				   sizeof(struct ql4_chap_table);
88162306a36Sopenharmony_ci	else
88262306a36Sopenharmony_ci		max_chap_entries = MAX_CHAP_ENTRIES_40XX;
88362306a36Sopenharmony_ci
88462306a36Sopenharmony_ci	if (chap_tbl_idx > max_chap_entries) {
88562306a36Sopenharmony_ci		ret = -EINVAL;
88662306a36Sopenharmony_ci		goto exit_delete_chap;
88762306a36Sopenharmony_ci	}
88862306a36Sopenharmony_ci
88962306a36Sopenharmony_ci	/* Check if chap index is in use.
89062306a36Sopenharmony_ci	 * If chap is in use don't delet chap entry */
89162306a36Sopenharmony_ci	ret = qla4xxx_is_chap_active(shost, chap_tbl_idx);
89262306a36Sopenharmony_ci	if (ret) {
89362306a36Sopenharmony_ci		ql4_printk(KERN_INFO, ha, "CHAP entry %d is in use, cannot "
89462306a36Sopenharmony_ci			   "delete from flash\n", chap_tbl_idx);
89562306a36Sopenharmony_ci		ret = -EBUSY;
89662306a36Sopenharmony_ci		goto exit_delete_chap;
89762306a36Sopenharmony_ci	}
89862306a36Sopenharmony_ci
89962306a36Sopenharmony_ci	chap_size = sizeof(struct ql4_chap_table);
90062306a36Sopenharmony_ci	if (is_qla40XX(ha))
90162306a36Sopenharmony_ci		offset = FLASH_CHAP_OFFSET | (chap_tbl_idx * chap_size);
90262306a36Sopenharmony_ci	else {
90362306a36Sopenharmony_ci		offset = FLASH_RAW_ACCESS_ADDR + (ha->hw.flt_region_chap << 2);
90462306a36Sopenharmony_ci		/* flt_chap_size is CHAP table size for both ports
90562306a36Sopenharmony_ci		 * so divide it by 2 to calculate the offset for second port
90662306a36Sopenharmony_ci		 */
90762306a36Sopenharmony_ci		if (ha->port_num == 1)
90862306a36Sopenharmony_ci			offset += (ha->hw.flt_chap_size / 2);
90962306a36Sopenharmony_ci		offset += (chap_tbl_idx * chap_size);
91062306a36Sopenharmony_ci	}
91162306a36Sopenharmony_ci
91262306a36Sopenharmony_ci	ret = qla4xxx_get_flash(ha, chap_dma, offset, chap_size);
91362306a36Sopenharmony_ci	if (ret != QLA_SUCCESS) {
91462306a36Sopenharmony_ci		ret = -EINVAL;
91562306a36Sopenharmony_ci		goto exit_delete_chap;
91662306a36Sopenharmony_ci	}
91762306a36Sopenharmony_ci
91862306a36Sopenharmony_ci	DEBUG2(ql4_printk(KERN_INFO, ha, "Chap Cookie: x%x\n",
91962306a36Sopenharmony_ci			  __le16_to_cpu(chap_table->cookie)));
92062306a36Sopenharmony_ci
92162306a36Sopenharmony_ci	if (__le16_to_cpu(chap_table->cookie) != CHAP_VALID_COOKIE) {
92262306a36Sopenharmony_ci		ql4_printk(KERN_ERR, ha, "No valid chap entry found\n");
92362306a36Sopenharmony_ci		goto exit_delete_chap;
92462306a36Sopenharmony_ci	}
92562306a36Sopenharmony_ci
92662306a36Sopenharmony_ci	chap_table->cookie = cpu_to_le16(0xFFFF);
92762306a36Sopenharmony_ci
92862306a36Sopenharmony_ci	offset = FLASH_CHAP_OFFSET |
92962306a36Sopenharmony_ci			(chap_tbl_idx * sizeof(struct ql4_chap_table));
93062306a36Sopenharmony_ci	ret = qla4xxx_set_flash(ha, chap_dma, offset, chap_size,
93162306a36Sopenharmony_ci				FLASH_OPT_RMW_COMMIT);
93262306a36Sopenharmony_ci	if (ret == QLA_SUCCESS && ha->chap_list) {
93362306a36Sopenharmony_ci		mutex_lock(&ha->chap_sem);
93462306a36Sopenharmony_ci		/* Update ha chap_list cache */
93562306a36Sopenharmony_ci		memcpy((struct ql4_chap_table *)ha->chap_list + chap_tbl_idx,
93662306a36Sopenharmony_ci			chap_table, sizeof(struct ql4_chap_table));
93762306a36Sopenharmony_ci		mutex_unlock(&ha->chap_sem);
93862306a36Sopenharmony_ci	}
93962306a36Sopenharmony_ci	if (ret != QLA_SUCCESS)
94062306a36Sopenharmony_ci		ret =  -EINVAL;
94162306a36Sopenharmony_ci
94262306a36Sopenharmony_ciexit_delete_chap:
94362306a36Sopenharmony_ci	dma_pool_free(ha->chap_dma_pool, chap_table, chap_dma);
94462306a36Sopenharmony_ci	return ret;
94562306a36Sopenharmony_ci}
94662306a36Sopenharmony_ci
94762306a36Sopenharmony_ci/**
94862306a36Sopenharmony_ci * qla4xxx_set_chap_entry - Make chap entry with given information
94962306a36Sopenharmony_ci * @shost: pointer to host
95062306a36Sopenharmony_ci * @data: chap info - credentials, index and type to make chap entry
95162306a36Sopenharmony_ci * @len: length of data
95262306a36Sopenharmony_ci *
95362306a36Sopenharmony_ci * Add or update chap entry with the given information
95462306a36Sopenharmony_ci **/
95562306a36Sopenharmony_cistatic int qla4xxx_set_chap_entry(struct Scsi_Host *shost, void *data, int len)
95662306a36Sopenharmony_ci{
95762306a36Sopenharmony_ci	struct scsi_qla_host *ha = to_qla_host(shost);
95862306a36Sopenharmony_ci	struct iscsi_chap_rec chap_rec;
95962306a36Sopenharmony_ci	struct ql4_chap_table *chap_entry = NULL;
96062306a36Sopenharmony_ci	struct iscsi_param_info *param_info;
96162306a36Sopenharmony_ci	struct nlattr *attr;
96262306a36Sopenharmony_ci	int max_chap_entries = 0;
96362306a36Sopenharmony_ci	int type;
96462306a36Sopenharmony_ci	int rem = len;
96562306a36Sopenharmony_ci	int rc = 0;
96662306a36Sopenharmony_ci	int size;
96762306a36Sopenharmony_ci
96862306a36Sopenharmony_ci	memset(&chap_rec, 0, sizeof(chap_rec));
96962306a36Sopenharmony_ci
97062306a36Sopenharmony_ci	nla_for_each_attr(attr, data, len, rem) {
97162306a36Sopenharmony_ci		if (nla_len(attr) < sizeof(*param_info)) {
97262306a36Sopenharmony_ci			rc = -EINVAL;
97362306a36Sopenharmony_ci			goto exit_set_chap;
97462306a36Sopenharmony_ci		}
97562306a36Sopenharmony_ci
97662306a36Sopenharmony_ci		param_info = nla_data(attr);
97762306a36Sopenharmony_ci
97862306a36Sopenharmony_ci		switch (param_info->param) {
97962306a36Sopenharmony_ci		case ISCSI_CHAP_PARAM_INDEX:
98062306a36Sopenharmony_ci			chap_rec.chap_tbl_idx = *(uint16_t *)param_info->value;
98162306a36Sopenharmony_ci			break;
98262306a36Sopenharmony_ci		case ISCSI_CHAP_PARAM_CHAP_TYPE:
98362306a36Sopenharmony_ci			chap_rec.chap_type = param_info->value[0];
98462306a36Sopenharmony_ci			break;
98562306a36Sopenharmony_ci		case ISCSI_CHAP_PARAM_USERNAME:
98662306a36Sopenharmony_ci			size = min_t(size_t, sizeof(chap_rec.username),
98762306a36Sopenharmony_ci				     param_info->len);
98862306a36Sopenharmony_ci			memcpy(chap_rec.username, param_info->value, size);
98962306a36Sopenharmony_ci			break;
99062306a36Sopenharmony_ci		case ISCSI_CHAP_PARAM_PASSWORD:
99162306a36Sopenharmony_ci			size = min_t(size_t, sizeof(chap_rec.password),
99262306a36Sopenharmony_ci				     param_info->len);
99362306a36Sopenharmony_ci			memcpy(chap_rec.password, param_info->value, size);
99462306a36Sopenharmony_ci			break;
99562306a36Sopenharmony_ci		case ISCSI_CHAP_PARAM_PASSWORD_LEN:
99662306a36Sopenharmony_ci			chap_rec.password_length = param_info->value[0];
99762306a36Sopenharmony_ci			break;
99862306a36Sopenharmony_ci		default:
99962306a36Sopenharmony_ci			ql4_printk(KERN_ERR, ha,
100062306a36Sopenharmony_ci				   "%s: No such sysfs attribute\n", __func__);
100162306a36Sopenharmony_ci			rc = -ENOSYS;
100262306a36Sopenharmony_ci			goto exit_set_chap;
100362306a36Sopenharmony_ci		}
100462306a36Sopenharmony_ci	}
100562306a36Sopenharmony_ci
100662306a36Sopenharmony_ci	if (chap_rec.chap_type == CHAP_TYPE_IN)
100762306a36Sopenharmony_ci		type = BIDI_CHAP;
100862306a36Sopenharmony_ci	else
100962306a36Sopenharmony_ci		type = LOCAL_CHAP;
101062306a36Sopenharmony_ci
101162306a36Sopenharmony_ci	if (is_qla80XX(ha))
101262306a36Sopenharmony_ci		max_chap_entries = (ha->hw.flt_chap_size / 2) /
101362306a36Sopenharmony_ci				   sizeof(struct ql4_chap_table);
101462306a36Sopenharmony_ci	else
101562306a36Sopenharmony_ci		max_chap_entries = MAX_CHAP_ENTRIES_40XX;
101662306a36Sopenharmony_ci
101762306a36Sopenharmony_ci	mutex_lock(&ha->chap_sem);
101862306a36Sopenharmony_ci	if (chap_rec.chap_tbl_idx < max_chap_entries) {
101962306a36Sopenharmony_ci		rc = qla4xxx_get_chap_by_index(ha, chap_rec.chap_tbl_idx,
102062306a36Sopenharmony_ci					       &chap_entry);
102162306a36Sopenharmony_ci		if (!rc) {
102262306a36Sopenharmony_ci			if (!(type == qla4xxx_get_chap_type(chap_entry))) {
102362306a36Sopenharmony_ci				ql4_printk(KERN_INFO, ha,
102462306a36Sopenharmony_ci					   "Type mismatch for CHAP entry %d\n",
102562306a36Sopenharmony_ci					   chap_rec.chap_tbl_idx);
102662306a36Sopenharmony_ci				rc = -EINVAL;
102762306a36Sopenharmony_ci				goto exit_unlock_chap;
102862306a36Sopenharmony_ci			}
102962306a36Sopenharmony_ci
103062306a36Sopenharmony_ci			/* If chap index is in use then don't modify it */
103162306a36Sopenharmony_ci			rc = qla4xxx_is_chap_active(shost,
103262306a36Sopenharmony_ci						    chap_rec.chap_tbl_idx);
103362306a36Sopenharmony_ci			if (rc) {
103462306a36Sopenharmony_ci				ql4_printk(KERN_INFO, ha,
103562306a36Sopenharmony_ci					   "CHAP entry %d is in use\n",
103662306a36Sopenharmony_ci					   chap_rec.chap_tbl_idx);
103762306a36Sopenharmony_ci				rc = -EBUSY;
103862306a36Sopenharmony_ci				goto exit_unlock_chap;
103962306a36Sopenharmony_ci			}
104062306a36Sopenharmony_ci		}
104162306a36Sopenharmony_ci	} else {
104262306a36Sopenharmony_ci		rc = qla4xxx_find_free_chap_index(ha, &chap_rec.chap_tbl_idx);
104362306a36Sopenharmony_ci		if (rc) {
104462306a36Sopenharmony_ci			ql4_printk(KERN_INFO, ha, "CHAP entry not available\n");
104562306a36Sopenharmony_ci			rc = -EBUSY;
104662306a36Sopenharmony_ci			goto exit_unlock_chap;
104762306a36Sopenharmony_ci		}
104862306a36Sopenharmony_ci	}
104962306a36Sopenharmony_ci
105062306a36Sopenharmony_ci	rc = qla4xxx_set_chap(ha, chap_rec.username, chap_rec.password,
105162306a36Sopenharmony_ci			      chap_rec.chap_tbl_idx, type);
105262306a36Sopenharmony_ci
105362306a36Sopenharmony_ciexit_unlock_chap:
105462306a36Sopenharmony_ci	mutex_unlock(&ha->chap_sem);
105562306a36Sopenharmony_ci
105662306a36Sopenharmony_ciexit_set_chap:
105762306a36Sopenharmony_ci	return rc;
105862306a36Sopenharmony_ci}
105962306a36Sopenharmony_ci
106062306a36Sopenharmony_ci
106162306a36Sopenharmony_cistatic int qla4xxx_get_host_stats(struct Scsi_Host *shost, char *buf, int len)
106262306a36Sopenharmony_ci{
106362306a36Sopenharmony_ci	struct scsi_qla_host *ha = to_qla_host(shost);
106462306a36Sopenharmony_ci	struct iscsi_offload_host_stats *host_stats = NULL;
106562306a36Sopenharmony_ci	int host_stats_size;
106662306a36Sopenharmony_ci	int ret = 0;
106762306a36Sopenharmony_ci	int ddb_idx = 0;
106862306a36Sopenharmony_ci	struct ql_iscsi_stats *ql_iscsi_stats = NULL;
106962306a36Sopenharmony_ci	int stats_size;
107062306a36Sopenharmony_ci	dma_addr_t iscsi_stats_dma;
107162306a36Sopenharmony_ci
107262306a36Sopenharmony_ci	DEBUG2(ql4_printk(KERN_INFO, ha, "Func: %s\n", __func__));
107362306a36Sopenharmony_ci
107462306a36Sopenharmony_ci	host_stats_size = sizeof(struct iscsi_offload_host_stats);
107562306a36Sopenharmony_ci
107662306a36Sopenharmony_ci	if (host_stats_size != len) {
107762306a36Sopenharmony_ci		ql4_printk(KERN_INFO, ha, "%s: host_stats size mismatch expected = %d, is = %d\n",
107862306a36Sopenharmony_ci			   __func__, len, host_stats_size);
107962306a36Sopenharmony_ci		ret = -EINVAL;
108062306a36Sopenharmony_ci		goto exit_host_stats;
108162306a36Sopenharmony_ci	}
108262306a36Sopenharmony_ci	host_stats = (struct iscsi_offload_host_stats *)buf;
108362306a36Sopenharmony_ci
108462306a36Sopenharmony_ci	if (!buf) {
108562306a36Sopenharmony_ci		ret = -ENOMEM;
108662306a36Sopenharmony_ci		goto exit_host_stats;
108762306a36Sopenharmony_ci	}
108862306a36Sopenharmony_ci
108962306a36Sopenharmony_ci	stats_size = PAGE_ALIGN(sizeof(struct ql_iscsi_stats));
109062306a36Sopenharmony_ci
109162306a36Sopenharmony_ci	ql_iscsi_stats = dma_alloc_coherent(&ha->pdev->dev, stats_size,
109262306a36Sopenharmony_ci					    &iscsi_stats_dma, GFP_KERNEL);
109362306a36Sopenharmony_ci	if (!ql_iscsi_stats) {
109462306a36Sopenharmony_ci		ql4_printk(KERN_ERR, ha,
109562306a36Sopenharmony_ci			   "Unable to allocate memory for iscsi stats\n");
109662306a36Sopenharmony_ci		ret = -ENOMEM;
109762306a36Sopenharmony_ci		goto exit_host_stats;
109862306a36Sopenharmony_ci	}
109962306a36Sopenharmony_ci
110062306a36Sopenharmony_ci	ret =  qla4xxx_get_mgmt_data(ha, ddb_idx, stats_size,
110162306a36Sopenharmony_ci				     iscsi_stats_dma);
110262306a36Sopenharmony_ci	if (ret != QLA_SUCCESS) {
110362306a36Sopenharmony_ci		ql4_printk(KERN_ERR, ha,
110462306a36Sopenharmony_ci			   "Unable to retrieve iscsi stats\n");
110562306a36Sopenharmony_ci		ret = -EIO;
110662306a36Sopenharmony_ci		goto exit_host_stats;
110762306a36Sopenharmony_ci	}
110862306a36Sopenharmony_ci	host_stats->mactx_frames = le64_to_cpu(ql_iscsi_stats->mac_tx_frames);
110962306a36Sopenharmony_ci	host_stats->mactx_bytes = le64_to_cpu(ql_iscsi_stats->mac_tx_bytes);
111062306a36Sopenharmony_ci	host_stats->mactx_multicast_frames =
111162306a36Sopenharmony_ci			le64_to_cpu(ql_iscsi_stats->mac_tx_multicast_frames);
111262306a36Sopenharmony_ci	host_stats->mactx_broadcast_frames =
111362306a36Sopenharmony_ci			le64_to_cpu(ql_iscsi_stats->mac_tx_broadcast_frames);
111462306a36Sopenharmony_ci	host_stats->mactx_pause_frames =
111562306a36Sopenharmony_ci			le64_to_cpu(ql_iscsi_stats->mac_tx_pause_frames);
111662306a36Sopenharmony_ci	host_stats->mactx_control_frames =
111762306a36Sopenharmony_ci			le64_to_cpu(ql_iscsi_stats->mac_tx_control_frames);
111862306a36Sopenharmony_ci	host_stats->mactx_deferral =
111962306a36Sopenharmony_ci			le64_to_cpu(ql_iscsi_stats->mac_tx_deferral);
112062306a36Sopenharmony_ci	host_stats->mactx_excess_deferral =
112162306a36Sopenharmony_ci			le64_to_cpu(ql_iscsi_stats->mac_tx_excess_deferral);
112262306a36Sopenharmony_ci	host_stats->mactx_late_collision =
112362306a36Sopenharmony_ci			le64_to_cpu(ql_iscsi_stats->mac_tx_late_collision);
112462306a36Sopenharmony_ci	host_stats->mactx_abort	= le64_to_cpu(ql_iscsi_stats->mac_tx_abort);
112562306a36Sopenharmony_ci	host_stats->mactx_single_collision =
112662306a36Sopenharmony_ci			le64_to_cpu(ql_iscsi_stats->mac_tx_single_collision);
112762306a36Sopenharmony_ci	host_stats->mactx_multiple_collision =
112862306a36Sopenharmony_ci			le64_to_cpu(ql_iscsi_stats->mac_tx_multiple_collision);
112962306a36Sopenharmony_ci	host_stats->mactx_collision =
113062306a36Sopenharmony_ci			le64_to_cpu(ql_iscsi_stats->mac_tx_collision);
113162306a36Sopenharmony_ci	host_stats->mactx_frames_dropped =
113262306a36Sopenharmony_ci			le64_to_cpu(ql_iscsi_stats->mac_tx_frames_dropped);
113362306a36Sopenharmony_ci	host_stats->mactx_jumbo_frames =
113462306a36Sopenharmony_ci			le64_to_cpu(ql_iscsi_stats->mac_tx_jumbo_frames);
113562306a36Sopenharmony_ci	host_stats->macrx_frames = le64_to_cpu(ql_iscsi_stats->mac_rx_frames);
113662306a36Sopenharmony_ci	host_stats->macrx_bytes = le64_to_cpu(ql_iscsi_stats->mac_rx_bytes);
113762306a36Sopenharmony_ci	host_stats->macrx_unknown_control_frames =
113862306a36Sopenharmony_ci		le64_to_cpu(ql_iscsi_stats->mac_rx_unknown_control_frames);
113962306a36Sopenharmony_ci	host_stats->macrx_pause_frames =
114062306a36Sopenharmony_ci			le64_to_cpu(ql_iscsi_stats->mac_rx_pause_frames);
114162306a36Sopenharmony_ci	host_stats->macrx_control_frames =
114262306a36Sopenharmony_ci			le64_to_cpu(ql_iscsi_stats->mac_rx_control_frames);
114362306a36Sopenharmony_ci	host_stats->macrx_dribble =
114462306a36Sopenharmony_ci			le64_to_cpu(ql_iscsi_stats->mac_rx_dribble);
114562306a36Sopenharmony_ci	host_stats->macrx_frame_length_error =
114662306a36Sopenharmony_ci			le64_to_cpu(ql_iscsi_stats->mac_rx_frame_length_error);
114762306a36Sopenharmony_ci	host_stats->macrx_jabber = le64_to_cpu(ql_iscsi_stats->mac_rx_jabber);
114862306a36Sopenharmony_ci	host_stats->macrx_carrier_sense_error =
114962306a36Sopenharmony_ci		le64_to_cpu(ql_iscsi_stats->mac_rx_carrier_sense_error);
115062306a36Sopenharmony_ci	host_stats->macrx_frame_discarded =
115162306a36Sopenharmony_ci			le64_to_cpu(ql_iscsi_stats->mac_rx_frame_discarded);
115262306a36Sopenharmony_ci	host_stats->macrx_frames_dropped =
115362306a36Sopenharmony_ci			le64_to_cpu(ql_iscsi_stats->mac_rx_frames_dropped);
115462306a36Sopenharmony_ci	host_stats->mac_crc_error = le64_to_cpu(ql_iscsi_stats->mac_crc_error);
115562306a36Sopenharmony_ci	host_stats->mac_encoding_error =
115662306a36Sopenharmony_ci			le64_to_cpu(ql_iscsi_stats->mac_encoding_error);
115762306a36Sopenharmony_ci	host_stats->macrx_length_error_large =
115862306a36Sopenharmony_ci			le64_to_cpu(ql_iscsi_stats->mac_rx_length_error_large);
115962306a36Sopenharmony_ci	host_stats->macrx_length_error_small =
116062306a36Sopenharmony_ci			le64_to_cpu(ql_iscsi_stats->mac_rx_length_error_small);
116162306a36Sopenharmony_ci	host_stats->macrx_multicast_frames =
116262306a36Sopenharmony_ci			le64_to_cpu(ql_iscsi_stats->mac_rx_multicast_frames);
116362306a36Sopenharmony_ci	host_stats->macrx_broadcast_frames =
116462306a36Sopenharmony_ci			le64_to_cpu(ql_iscsi_stats->mac_rx_broadcast_frames);
116562306a36Sopenharmony_ci	host_stats->iptx_packets = le64_to_cpu(ql_iscsi_stats->ip_tx_packets);
116662306a36Sopenharmony_ci	host_stats->iptx_bytes = le64_to_cpu(ql_iscsi_stats->ip_tx_bytes);
116762306a36Sopenharmony_ci	host_stats->iptx_fragments =
116862306a36Sopenharmony_ci			le64_to_cpu(ql_iscsi_stats->ip_tx_fragments);
116962306a36Sopenharmony_ci	host_stats->iprx_packets = le64_to_cpu(ql_iscsi_stats->ip_rx_packets);
117062306a36Sopenharmony_ci	host_stats->iprx_bytes = le64_to_cpu(ql_iscsi_stats->ip_rx_bytes);
117162306a36Sopenharmony_ci	host_stats->iprx_fragments =
117262306a36Sopenharmony_ci			le64_to_cpu(ql_iscsi_stats->ip_rx_fragments);
117362306a36Sopenharmony_ci	host_stats->ip_datagram_reassembly =
117462306a36Sopenharmony_ci			le64_to_cpu(ql_iscsi_stats->ip_datagram_reassembly);
117562306a36Sopenharmony_ci	host_stats->ip_invalid_address_error =
117662306a36Sopenharmony_ci			le64_to_cpu(ql_iscsi_stats->ip_invalid_address_error);
117762306a36Sopenharmony_ci	host_stats->ip_error_packets =
117862306a36Sopenharmony_ci			le64_to_cpu(ql_iscsi_stats->ip_error_packets);
117962306a36Sopenharmony_ci	host_stats->ip_fragrx_overlap =
118062306a36Sopenharmony_ci			le64_to_cpu(ql_iscsi_stats->ip_fragrx_overlap);
118162306a36Sopenharmony_ci	host_stats->ip_fragrx_outoforder =
118262306a36Sopenharmony_ci			le64_to_cpu(ql_iscsi_stats->ip_fragrx_outoforder);
118362306a36Sopenharmony_ci	host_stats->ip_datagram_reassembly_timeout =
118462306a36Sopenharmony_ci		le64_to_cpu(ql_iscsi_stats->ip_datagram_reassembly_timeout);
118562306a36Sopenharmony_ci	host_stats->ipv6tx_packets =
118662306a36Sopenharmony_ci			le64_to_cpu(ql_iscsi_stats->ipv6_tx_packets);
118762306a36Sopenharmony_ci	host_stats->ipv6tx_bytes = le64_to_cpu(ql_iscsi_stats->ipv6_tx_bytes);
118862306a36Sopenharmony_ci	host_stats->ipv6tx_fragments =
118962306a36Sopenharmony_ci			le64_to_cpu(ql_iscsi_stats->ipv6_tx_fragments);
119062306a36Sopenharmony_ci	host_stats->ipv6rx_packets =
119162306a36Sopenharmony_ci			le64_to_cpu(ql_iscsi_stats->ipv6_rx_packets);
119262306a36Sopenharmony_ci	host_stats->ipv6rx_bytes = le64_to_cpu(ql_iscsi_stats->ipv6_rx_bytes);
119362306a36Sopenharmony_ci	host_stats->ipv6rx_fragments =
119462306a36Sopenharmony_ci			le64_to_cpu(ql_iscsi_stats->ipv6_rx_fragments);
119562306a36Sopenharmony_ci	host_stats->ipv6_datagram_reassembly =
119662306a36Sopenharmony_ci			le64_to_cpu(ql_iscsi_stats->ipv6_datagram_reassembly);
119762306a36Sopenharmony_ci	host_stats->ipv6_invalid_address_error =
119862306a36Sopenharmony_ci		le64_to_cpu(ql_iscsi_stats->ipv6_invalid_address_error);
119962306a36Sopenharmony_ci	host_stats->ipv6_error_packets =
120062306a36Sopenharmony_ci			le64_to_cpu(ql_iscsi_stats->ipv6_error_packets);
120162306a36Sopenharmony_ci	host_stats->ipv6_fragrx_overlap =
120262306a36Sopenharmony_ci			le64_to_cpu(ql_iscsi_stats->ipv6_fragrx_overlap);
120362306a36Sopenharmony_ci	host_stats->ipv6_fragrx_outoforder =
120462306a36Sopenharmony_ci			le64_to_cpu(ql_iscsi_stats->ipv6_fragrx_outoforder);
120562306a36Sopenharmony_ci	host_stats->ipv6_datagram_reassembly_timeout =
120662306a36Sopenharmony_ci		le64_to_cpu(ql_iscsi_stats->ipv6_datagram_reassembly_timeout);
120762306a36Sopenharmony_ci	host_stats->tcptx_segments =
120862306a36Sopenharmony_ci			le64_to_cpu(ql_iscsi_stats->tcp_tx_segments);
120962306a36Sopenharmony_ci	host_stats->tcptx_bytes	= le64_to_cpu(ql_iscsi_stats->tcp_tx_bytes);
121062306a36Sopenharmony_ci	host_stats->tcprx_segments =
121162306a36Sopenharmony_ci			le64_to_cpu(ql_iscsi_stats->tcp_rx_segments);
121262306a36Sopenharmony_ci	host_stats->tcprx_byte = le64_to_cpu(ql_iscsi_stats->tcp_rx_byte);
121362306a36Sopenharmony_ci	host_stats->tcp_duplicate_ack_retx =
121462306a36Sopenharmony_ci			le64_to_cpu(ql_iscsi_stats->tcp_duplicate_ack_retx);
121562306a36Sopenharmony_ci	host_stats->tcp_retx_timer_expired =
121662306a36Sopenharmony_ci			le64_to_cpu(ql_iscsi_stats->tcp_retx_timer_expired);
121762306a36Sopenharmony_ci	host_stats->tcprx_duplicate_ack	=
121862306a36Sopenharmony_ci			le64_to_cpu(ql_iscsi_stats->tcp_rx_duplicate_ack);
121962306a36Sopenharmony_ci	host_stats->tcprx_pure_ackr =
122062306a36Sopenharmony_ci			le64_to_cpu(ql_iscsi_stats->tcp_rx_pure_ackr);
122162306a36Sopenharmony_ci	host_stats->tcptx_delayed_ack =
122262306a36Sopenharmony_ci			le64_to_cpu(ql_iscsi_stats->tcp_tx_delayed_ack);
122362306a36Sopenharmony_ci	host_stats->tcptx_pure_ack =
122462306a36Sopenharmony_ci			le64_to_cpu(ql_iscsi_stats->tcp_tx_pure_ack);
122562306a36Sopenharmony_ci	host_stats->tcprx_segment_error =
122662306a36Sopenharmony_ci			le64_to_cpu(ql_iscsi_stats->tcp_rx_segment_error);
122762306a36Sopenharmony_ci	host_stats->tcprx_segment_outoforder =
122862306a36Sopenharmony_ci			le64_to_cpu(ql_iscsi_stats->tcp_rx_segment_outoforder);
122962306a36Sopenharmony_ci	host_stats->tcprx_window_probe =
123062306a36Sopenharmony_ci			le64_to_cpu(ql_iscsi_stats->tcp_rx_window_probe);
123162306a36Sopenharmony_ci	host_stats->tcprx_window_update =
123262306a36Sopenharmony_ci			le64_to_cpu(ql_iscsi_stats->tcp_rx_window_update);
123362306a36Sopenharmony_ci	host_stats->tcptx_window_probe_persist =
123462306a36Sopenharmony_ci		le64_to_cpu(ql_iscsi_stats->tcp_tx_window_probe_persist);
123562306a36Sopenharmony_ci	host_stats->ecc_error_correction =
123662306a36Sopenharmony_ci			le64_to_cpu(ql_iscsi_stats->ecc_error_correction);
123762306a36Sopenharmony_ci	host_stats->iscsi_pdu_tx = le64_to_cpu(ql_iscsi_stats->iscsi_pdu_tx);
123862306a36Sopenharmony_ci	host_stats->iscsi_data_bytes_tx =
123962306a36Sopenharmony_ci			le64_to_cpu(ql_iscsi_stats->iscsi_data_bytes_tx);
124062306a36Sopenharmony_ci	host_stats->iscsi_pdu_rx = le64_to_cpu(ql_iscsi_stats->iscsi_pdu_rx);
124162306a36Sopenharmony_ci	host_stats->iscsi_data_bytes_rx	=
124262306a36Sopenharmony_ci			le64_to_cpu(ql_iscsi_stats->iscsi_data_bytes_rx);
124362306a36Sopenharmony_ci	host_stats->iscsi_io_completed =
124462306a36Sopenharmony_ci			le64_to_cpu(ql_iscsi_stats->iscsi_io_completed);
124562306a36Sopenharmony_ci	host_stats->iscsi_unexpected_io_rx =
124662306a36Sopenharmony_ci			le64_to_cpu(ql_iscsi_stats->iscsi_unexpected_io_rx);
124762306a36Sopenharmony_ci	host_stats->iscsi_format_error =
124862306a36Sopenharmony_ci			le64_to_cpu(ql_iscsi_stats->iscsi_format_error);
124962306a36Sopenharmony_ci	host_stats->iscsi_hdr_digest_error =
125062306a36Sopenharmony_ci			le64_to_cpu(ql_iscsi_stats->iscsi_hdr_digest_error);
125162306a36Sopenharmony_ci	host_stats->iscsi_data_digest_error =
125262306a36Sopenharmony_ci			le64_to_cpu(ql_iscsi_stats->iscsi_data_digest_error);
125362306a36Sopenharmony_ci	host_stats->iscsi_sequence_error =
125462306a36Sopenharmony_ci			le64_to_cpu(ql_iscsi_stats->iscsi_sequence_error);
125562306a36Sopenharmony_ciexit_host_stats:
125662306a36Sopenharmony_ci	if (ql_iscsi_stats)
125762306a36Sopenharmony_ci		dma_free_coherent(&ha->pdev->dev, stats_size,
125862306a36Sopenharmony_ci				  ql_iscsi_stats, iscsi_stats_dma);
125962306a36Sopenharmony_ci
126062306a36Sopenharmony_ci	ql4_printk(KERN_INFO, ha, "%s: Get host stats done\n",
126162306a36Sopenharmony_ci		   __func__);
126262306a36Sopenharmony_ci	return ret;
126362306a36Sopenharmony_ci}
126462306a36Sopenharmony_ci
126562306a36Sopenharmony_cistatic int qla4xxx_get_iface_param(struct iscsi_iface *iface,
126662306a36Sopenharmony_ci				   enum iscsi_param_type param_type,
126762306a36Sopenharmony_ci				   int param, char *buf)
126862306a36Sopenharmony_ci{
126962306a36Sopenharmony_ci	struct Scsi_Host *shost = iscsi_iface_to_shost(iface);
127062306a36Sopenharmony_ci	struct scsi_qla_host *ha = to_qla_host(shost);
127162306a36Sopenharmony_ci	int ival;
127262306a36Sopenharmony_ci	char *pval = NULL;
127362306a36Sopenharmony_ci	int len = -ENOSYS;
127462306a36Sopenharmony_ci
127562306a36Sopenharmony_ci	if (param_type == ISCSI_NET_PARAM) {
127662306a36Sopenharmony_ci		switch (param) {
127762306a36Sopenharmony_ci		case ISCSI_NET_PARAM_IPV4_ADDR:
127862306a36Sopenharmony_ci			len = sprintf(buf, "%pI4\n", &ha->ip_config.ip_address);
127962306a36Sopenharmony_ci			break;
128062306a36Sopenharmony_ci		case ISCSI_NET_PARAM_IPV4_SUBNET:
128162306a36Sopenharmony_ci			len = sprintf(buf, "%pI4\n",
128262306a36Sopenharmony_ci				      &ha->ip_config.subnet_mask);
128362306a36Sopenharmony_ci			break;
128462306a36Sopenharmony_ci		case ISCSI_NET_PARAM_IPV4_GW:
128562306a36Sopenharmony_ci			len = sprintf(buf, "%pI4\n", &ha->ip_config.gateway);
128662306a36Sopenharmony_ci			break;
128762306a36Sopenharmony_ci		case ISCSI_NET_PARAM_IFACE_ENABLE:
128862306a36Sopenharmony_ci			if (iface->iface_type == ISCSI_IFACE_TYPE_IPV4) {
128962306a36Sopenharmony_ci				OP_STATE(ha->ip_config.ipv4_options,
129062306a36Sopenharmony_ci					 IPOPT_IPV4_PROTOCOL_ENABLE, pval);
129162306a36Sopenharmony_ci			} else {
129262306a36Sopenharmony_ci				OP_STATE(ha->ip_config.ipv6_options,
129362306a36Sopenharmony_ci					 IPV6_OPT_IPV6_PROTOCOL_ENABLE, pval);
129462306a36Sopenharmony_ci			}
129562306a36Sopenharmony_ci
129662306a36Sopenharmony_ci			len = sprintf(buf, "%s\n", pval);
129762306a36Sopenharmony_ci			break;
129862306a36Sopenharmony_ci		case ISCSI_NET_PARAM_IPV4_BOOTPROTO:
129962306a36Sopenharmony_ci			len = sprintf(buf, "%s\n",
130062306a36Sopenharmony_ci				      (ha->ip_config.tcp_options &
130162306a36Sopenharmony_ci				       TCPOPT_DHCP_ENABLE) ?
130262306a36Sopenharmony_ci				      "dhcp" : "static");
130362306a36Sopenharmony_ci			break;
130462306a36Sopenharmony_ci		case ISCSI_NET_PARAM_IPV6_ADDR:
130562306a36Sopenharmony_ci			if (iface->iface_num == 0)
130662306a36Sopenharmony_ci				len = sprintf(buf, "%pI6\n",
130762306a36Sopenharmony_ci					      &ha->ip_config.ipv6_addr0);
130862306a36Sopenharmony_ci			if (iface->iface_num == 1)
130962306a36Sopenharmony_ci				len = sprintf(buf, "%pI6\n",
131062306a36Sopenharmony_ci					      &ha->ip_config.ipv6_addr1);
131162306a36Sopenharmony_ci			break;
131262306a36Sopenharmony_ci		case ISCSI_NET_PARAM_IPV6_LINKLOCAL:
131362306a36Sopenharmony_ci			len = sprintf(buf, "%pI6\n",
131462306a36Sopenharmony_ci				      &ha->ip_config.ipv6_link_local_addr);
131562306a36Sopenharmony_ci			break;
131662306a36Sopenharmony_ci		case ISCSI_NET_PARAM_IPV6_ROUTER:
131762306a36Sopenharmony_ci			len = sprintf(buf, "%pI6\n",
131862306a36Sopenharmony_ci				      &ha->ip_config.ipv6_default_router_addr);
131962306a36Sopenharmony_ci			break;
132062306a36Sopenharmony_ci		case ISCSI_NET_PARAM_IPV6_ADDR_AUTOCFG:
132162306a36Sopenharmony_ci			pval = (ha->ip_config.ipv6_addl_options &
132262306a36Sopenharmony_ci				IPV6_ADDOPT_NEIGHBOR_DISCOVERY_ADDR_ENABLE) ?
132362306a36Sopenharmony_ci				"nd" : "static";
132462306a36Sopenharmony_ci
132562306a36Sopenharmony_ci			len = sprintf(buf, "%s\n", pval);
132662306a36Sopenharmony_ci			break;
132762306a36Sopenharmony_ci		case ISCSI_NET_PARAM_IPV6_LINKLOCAL_AUTOCFG:
132862306a36Sopenharmony_ci			pval = (ha->ip_config.ipv6_addl_options &
132962306a36Sopenharmony_ci				IPV6_ADDOPT_AUTOCONFIG_LINK_LOCAL_ADDR) ?
133062306a36Sopenharmony_ci				"auto" : "static";
133162306a36Sopenharmony_ci
133262306a36Sopenharmony_ci			len = sprintf(buf, "%s\n", pval);
133362306a36Sopenharmony_ci			break;
133462306a36Sopenharmony_ci		case ISCSI_NET_PARAM_VLAN_ID:
133562306a36Sopenharmony_ci			if (iface->iface_type == ISCSI_IFACE_TYPE_IPV4)
133662306a36Sopenharmony_ci				ival = ha->ip_config.ipv4_vlan_tag &
133762306a36Sopenharmony_ci				       ISCSI_MAX_VLAN_ID;
133862306a36Sopenharmony_ci			else
133962306a36Sopenharmony_ci				ival = ha->ip_config.ipv6_vlan_tag &
134062306a36Sopenharmony_ci				       ISCSI_MAX_VLAN_ID;
134162306a36Sopenharmony_ci
134262306a36Sopenharmony_ci			len = sprintf(buf, "%d\n", ival);
134362306a36Sopenharmony_ci			break;
134462306a36Sopenharmony_ci		case ISCSI_NET_PARAM_VLAN_PRIORITY:
134562306a36Sopenharmony_ci			if (iface->iface_type == ISCSI_IFACE_TYPE_IPV4)
134662306a36Sopenharmony_ci				ival = (ha->ip_config.ipv4_vlan_tag >> 13) &
134762306a36Sopenharmony_ci				       ISCSI_MAX_VLAN_PRIORITY;
134862306a36Sopenharmony_ci			else
134962306a36Sopenharmony_ci				ival = (ha->ip_config.ipv6_vlan_tag >> 13) &
135062306a36Sopenharmony_ci				       ISCSI_MAX_VLAN_PRIORITY;
135162306a36Sopenharmony_ci
135262306a36Sopenharmony_ci			len = sprintf(buf, "%d\n", ival);
135362306a36Sopenharmony_ci			break;
135462306a36Sopenharmony_ci		case ISCSI_NET_PARAM_VLAN_ENABLED:
135562306a36Sopenharmony_ci			if (iface->iface_type == ISCSI_IFACE_TYPE_IPV4) {
135662306a36Sopenharmony_ci				OP_STATE(ha->ip_config.ipv4_options,
135762306a36Sopenharmony_ci					 IPOPT_VLAN_TAGGING_ENABLE, pval);
135862306a36Sopenharmony_ci			} else {
135962306a36Sopenharmony_ci				OP_STATE(ha->ip_config.ipv6_options,
136062306a36Sopenharmony_ci					 IPV6_OPT_VLAN_TAGGING_ENABLE, pval);
136162306a36Sopenharmony_ci			}
136262306a36Sopenharmony_ci			len = sprintf(buf, "%s\n", pval);
136362306a36Sopenharmony_ci			break;
136462306a36Sopenharmony_ci		case ISCSI_NET_PARAM_MTU:
136562306a36Sopenharmony_ci			len = sprintf(buf, "%d\n", ha->ip_config.eth_mtu_size);
136662306a36Sopenharmony_ci			break;
136762306a36Sopenharmony_ci		case ISCSI_NET_PARAM_PORT:
136862306a36Sopenharmony_ci			if (iface->iface_type == ISCSI_IFACE_TYPE_IPV4)
136962306a36Sopenharmony_ci				len = sprintf(buf, "%d\n",
137062306a36Sopenharmony_ci					      ha->ip_config.ipv4_port);
137162306a36Sopenharmony_ci			else
137262306a36Sopenharmony_ci				len = sprintf(buf, "%d\n",
137362306a36Sopenharmony_ci					      ha->ip_config.ipv6_port);
137462306a36Sopenharmony_ci			break;
137562306a36Sopenharmony_ci		case ISCSI_NET_PARAM_IPADDR_STATE:
137662306a36Sopenharmony_ci			if (iface->iface_type == ISCSI_IFACE_TYPE_IPV4) {
137762306a36Sopenharmony_ci				pval = iscsi_get_ipaddress_state_name(
137862306a36Sopenharmony_ci						ha->ip_config.ipv4_addr_state);
137962306a36Sopenharmony_ci			} else {
138062306a36Sopenharmony_ci				if (iface->iface_num == 0)
138162306a36Sopenharmony_ci					pval = iscsi_get_ipaddress_state_name(
138262306a36Sopenharmony_ci						ha->ip_config.ipv6_addr0_state);
138362306a36Sopenharmony_ci				else if (iface->iface_num == 1)
138462306a36Sopenharmony_ci					pval = iscsi_get_ipaddress_state_name(
138562306a36Sopenharmony_ci						ha->ip_config.ipv6_addr1_state);
138662306a36Sopenharmony_ci			}
138762306a36Sopenharmony_ci
138862306a36Sopenharmony_ci			len = sprintf(buf, "%s\n", pval);
138962306a36Sopenharmony_ci			break;
139062306a36Sopenharmony_ci		case ISCSI_NET_PARAM_IPV6_LINKLOCAL_STATE:
139162306a36Sopenharmony_ci			pval = iscsi_get_ipaddress_state_name(
139262306a36Sopenharmony_ci					ha->ip_config.ipv6_link_local_state);
139362306a36Sopenharmony_ci			len = sprintf(buf, "%s\n", pval);
139462306a36Sopenharmony_ci			break;
139562306a36Sopenharmony_ci		case ISCSI_NET_PARAM_IPV6_ROUTER_STATE:
139662306a36Sopenharmony_ci			pval = iscsi_get_router_state_name(
139762306a36Sopenharmony_ci				      ha->ip_config.ipv6_default_router_state);
139862306a36Sopenharmony_ci			len = sprintf(buf, "%s\n", pval);
139962306a36Sopenharmony_ci			break;
140062306a36Sopenharmony_ci		case ISCSI_NET_PARAM_DELAYED_ACK_EN:
140162306a36Sopenharmony_ci			if (iface->iface_type == ISCSI_IFACE_TYPE_IPV4) {
140262306a36Sopenharmony_ci				OP_STATE(~ha->ip_config.tcp_options,
140362306a36Sopenharmony_ci					 TCPOPT_DELAYED_ACK_DISABLE, pval);
140462306a36Sopenharmony_ci			} else {
140562306a36Sopenharmony_ci				OP_STATE(~ha->ip_config.ipv6_tcp_options,
140662306a36Sopenharmony_ci					 IPV6_TCPOPT_DELAYED_ACK_DISABLE, pval);
140762306a36Sopenharmony_ci			}
140862306a36Sopenharmony_ci			len = sprintf(buf, "%s\n", pval);
140962306a36Sopenharmony_ci			break;
141062306a36Sopenharmony_ci		case ISCSI_NET_PARAM_TCP_NAGLE_DISABLE:
141162306a36Sopenharmony_ci			if (iface->iface_type == ISCSI_IFACE_TYPE_IPV4) {
141262306a36Sopenharmony_ci				OP_STATE(~ha->ip_config.tcp_options,
141362306a36Sopenharmony_ci					 TCPOPT_NAGLE_ALGO_DISABLE, pval);
141462306a36Sopenharmony_ci			} else {
141562306a36Sopenharmony_ci				OP_STATE(~ha->ip_config.ipv6_tcp_options,
141662306a36Sopenharmony_ci					 IPV6_TCPOPT_NAGLE_ALGO_DISABLE, pval);
141762306a36Sopenharmony_ci			}
141862306a36Sopenharmony_ci			len = sprintf(buf, "%s\n", pval);
141962306a36Sopenharmony_ci			break;
142062306a36Sopenharmony_ci		case ISCSI_NET_PARAM_TCP_WSF_DISABLE:
142162306a36Sopenharmony_ci			if (iface->iface_type == ISCSI_IFACE_TYPE_IPV4) {
142262306a36Sopenharmony_ci				OP_STATE(~ha->ip_config.tcp_options,
142362306a36Sopenharmony_ci					 TCPOPT_WINDOW_SCALE_DISABLE, pval);
142462306a36Sopenharmony_ci			} else {
142562306a36Sopenharmony_ci				OP_STATE(~ha->ip_config.ipv6_tcp_options,
142662306a36Sopenharmony_ci					 IPV6_TCPOPT_WINDOW_SCALE_DISABLE,
142762306a36Sopenharmony_ci					 pval);
142862306a36Sopenharmony_ci			}
142962306a36Sopenharmony_ci			len = sprintf(buf, "%s\n", pval);
143062306a36Sopenharmony_ci			break;
143162306a36Sopenharmony_ci		case ISCSI_NET_PARAM_TCP_WSF:
143262306a36Sopenharmony_ci			if (iface->iface_type == ISCSI_IFACE_TYPE_IPV4)
143362306a36Sopenharmony_ci				len = sprintf(buf, "%d\n",
143462306a36Sopenharmony_ci					      ha->ip_config.tcp_wsf);
143562306a36Sopenharmony_ci			else
143662306a36Sopenharmony_ci				len = sprintf(buf, "%d\n",
143762306a36Sopenharmony_ci					      ha->ip_config.ipv6_tcp_wsf);
143862306a36Sopenharmony_ci			break;
143962306a36Sopenharmony_ci		case ISCSI_NET_PARAM_TCP_TIMER_SCALE:
144062306a36Sopenharmony_ci			if (iface->iface_type == ISCSI_IFACE_TYPE_IPV4)
144162306a36Sopenharmony_ci				ival = (ha->ip_config.tcp_options &
144262306a36Sopenharmony_ci					TCPOPT_TIMER_SCALE) >> 1;
144362306a36Sopenharmony_ci			else
144462306a36Sopenharmony_ci				ival = (ha->ip_config.ipv6_tcp_options &
144562306a36Sopenharmony_ci					IPV6_TCPOPT_TIMER_SCALE) >> 1;
144662306a36Sopenharmony_ci
144762306a36Sopenharmony_ci			len = sprintf(buf, "%d\n", ival);
144862306a36Sopenharmony_ci			break;
144962306a36Sopenharmony_ci		case ISCSI_NET_PARAM_TCP_TIMESTAMP_EN:
145062306a36Sopenharmony_ci			if (iface->iface_type == ISCSI_IFACE_TYPE_IPV4) {
145162306a36Sopenharmony_ci				OP_STATE(ha->ip_config.tcp_options,
145262306a36Sopenharmony_ci					 TCPOPT_TIMESTAMP_ENABLE, pval);
145362306a36Sopenharmony_ci			} else {
145462306a36Sopenharmony_ci				OP_STATE(ha->ip_config.ipv6_tcp_options,
145562306a36Sopenharmony_ci					 IPV6_TCPOPT_TIMESTAMP_EN, pval);
145662306a36Sopenharmony_ci			}
145762306a36Sopenharmony_ci			len = sprintf(buf, "%s\n", pval);
145862306a36Sopenharmony_ci			break;
145962306a36Sopenharmony_ci		case ISCSI_NET_PARAM_CACHE_ID:
146062306a36Sopenharmony_ci			if (iface->iface_type == ISCSI_IFACE_TYPE_IPV4)
146162306a36Sopenharmony_ci				len = sprintf(buf, "%d\n",
146262306a36Sopenharmony_ci					      ha->ip_config.ipv4_cache_id);
146362306a36Sopenharmony_ci			else
146462306a36Sopenharmony_ci				len = sprintf(buf, "%d\n",
146562306a36Sopenharmony_ci					      ha->ip_config.ipv6_cache_id);
146662306a36Sopenharmony_ci			break;
146762306a36Sopenharmony_ci		case ISCSI_NET_PARAM_IPV4_DHCP_DNS_ADDR_EN:
146862306a36Sopenharmony_ci			OP_STATE(ha->ip_config.tcp_options,
146962306a36Sopenharmony_ci				 TCPOPT_DNS_SERVER_IP_EN, pval);
147062306a36Sopenharmony_ci
147162306a36Sopenharmony_ci			len = sprintf(buf, "%s\n", pval);
147262306a36Sopenharmony_ci			break;
147362306a36Sopenharmony_ci		case ISCSI_NET_PARAM_IPV4_DHCP_SLP_DA_EN:
147462306a36Sopenharmony_ci			OP_STATE(ha->ip_config.tcp_options,
147562306a36Sopenharmony_ci				 TCPOPT_SLP_DA_INFO_EN, pval);
147662306a36Sopenharmony_ci
147762306a36Sopenharmony_ci			len = sprintf(buf, "%s\n", pval);
147862306a36Sopenharmony_ci			break;
147962306a36Sopenharmony_ci		case ISCSI_NET_PARAM_IPV4_TOS_EN:
148062306a36Sopenharmony_ci			OP_STATE(ha->ip_config.ipv4_options,
148162306a36Sopenharmony_ci				 IPOPT_IPV4_TOS_EN, pval);
148262306a36Sopenharmony_ci
148362306a36Sopenharmony_ci			len = sprintf(buf, "%s\n", pval);
148462306a36Sopenharmony_ci			break;
148562306a36Sopenharmony_ci		case ISCSI_NET_PARAM_IPV4_TOS:
148662306a36Sopenharmony_ci			len = sprintf(buf, "%d\n", ha->ip_config.ipv4_tos);
148762306a36Sopenharmony_ci			break;
148862306a36Sopenharmony_ci		case ISCSI_NET_PARAM_IPV4_GRAT_ARP_EN:
148962306a36Sopenharmony_ci			OP_STATE(ha->ip_config.ipv4_options,
149062306a36Sopenharmony_ci				 IPOPT_GRAT_ARP_EN, pval);
149162306a36Sopenharmony_ci
149262306a36Sopenharmony_ci			len = sprintf(buf, "%s\n", pval);
149362306a36Sopenharmony_ci			break;
149462306a36Sopenharmony_ci		case ISCSI_NET_PARAM_IPV4_DHCP_ALT_CLIENT_ID_EN:
149562306a36Sopenharmony_ci			OP_STATE(ha->ip_config.ipv4_options, IPOPT_ALT_CID_EN,
149662306a36Sopenharmony_ci				 pval);
149762306a36Sopenharmony_ci
149862306a36Sopenharmony_ci			len = sprintf(buf, "%s\n", pval);
149962306a36Sopenharmony_ci			break;
150062306a36Sopenharmony_ci		case ISCSI_NET_PARAM_IPV4_DHCP_ALT_CLIENT_ID:
150162306a36Sopenharmony_ci			pval = (ha->ip_config.ipv4_alt_cid_len) ?
150262306a36Sopenharmony_ci			       (char *)ha->ip_config.ipv4_alt_cid : "";
150362306a36Sopenharmony_ci
150462306a36Sopenharmony_ci			len = sprintf(buf, "%s\n", pval);
150562306a36Sopenharmony_ci			break;
150662306a36Sopenharmony_ci		case ISCSI_NET_PARAM_IPV4_DHCP_REQ_VENDOR_ID_EN:
150762306a36Sopenharmony_ci			OP_STATE(ha->ip_config.ipv4_options,
150862306a36Sopenharmony_ci				 IPOPT_REQ_VID_EN, pval);
150962306a36Sopenharmony_ci
151062306a36Sopenharmony_ci			len = sprintf(buf, "%s\n", pval);
151162306a36Sopenharmony_ci			break;
151262306a36Sopenharmony_ci		case ISCSI_NET_PARAM_IPV4_DHCP_USE_VENDOR_ID_EN:
151362306a36Sopenharmony_ci			OP_STATE(ha->ip_config.ipv4_options,
151462306a36Sopenharmony_ci				 IPOPT_USE_VID_EN, pval);
151562306a36Sopenharmony_ci
151662306a36Sopenharmony_ci			len = sprintf(buf, "%s\n", pval);
151762306a36Sopenharmony_ci			break;
151862306a36Sopenharmony_ci		case ISCSI_NET_PARAM_IPV4_DHCP_VENDOR_ID:
151962306a36Sopenharmony_ci			pval = (ha->ip_config.ipv4_vid_len) ?
152062306a36Sopenharmony_ci			       (char *)ha->ip_config.ipv4_vid : "";
152162306a36Sopenharmony_ci
152262306a36Sopenharmony_ci			len = sprintf(buf, "%s\n", pval);
152362306a36Sopenharmony_ci			break;
152462306a36Sopenharmony_ci		case ISCSI_NET_PARAM_IPV4_DHCP_LEARN_IQN_EN:
152562306a36Sopenharmony_ci			OP_STATE(ha->ip_config.ipv4_options,
152662306a36Sopenharmony_ci				 IPOPT_LEARN_IQN_EN, pval);
152762306a36Sopenharmony_ci
152862306a36Sopenharmony_ci			len = sprintf(buf, "%s\n", pval);
152962306a36Sopenharmony_ci			break;
153062306a36Sopenharmony_ci		case ISCSI_NET_PARAM_IPV4_FRAGMENT_DISABLE:
153162306a36Sopenharmony_ci			OP_STATE(~ha->ip_config.ipv4_options,
153262306a36Sopenharmony_ci				 IPOPT_FRAGMENTATION_DISABLE, pval);
153362306a36Sopenharmony_ci
153462306a36Sopenharmony_ci			len = sprintf(buf, "%s\n", pval);
153562306a36Sopenharmony_ci			break;
153662306a36Sopenharmony_ci		case ISCSI_NET_PARAM_IPV4_IN_FORWARD_EN:
153762306a36Sopenharmony_ci			OP_STATE(ha->ip_config.ipv4_options,
153862306a36Sopenharmony_ci				 IPOPT_IN_FORWARD_EN, pval);
153962306a36Sopenharmony_ci
154062306a36Sopenharmony_ci			len = sprintf(buf, "%s\n", pval);
154162306a36Sopenharmony_ci			break;
154262306a36Sopenharmony_ci		case ISCSI_NET_PARAM_REDIRECT_EN:
154362306a36Sopenharmony_ci			if (iface->iface_type == ISCSI_IFACE_TYPE_IPV4) {
154462306a36Sopenharmony_ci				OP_STATE(ha->ip_config.ipv4_options,
154562306a36Sopenharmony_ci					 IPOPT_ARP_REDIRECT_EN, pval);
154662306a36Sopenharmony_ci			} else {
154762306a36Sopenharmony_ci				OP_STATE(ha->ip_config.ipv6_options,
154862306a36Sopenharmony_ci					 IPV6_OPT_REDIRECT_EN, pval);
154962306a36Sopenharmony_ci			}
155062306a36Sopenharmony_ci			len = sprintf(buf, "%s\n", pval);
155162306a36Sopenharmony_ci			break;
155262306a36Sopenharmony_ci		case ISCSI_NET_PARAM_IPV4_TTL:
155362306a36Sopenharmony_ci			len = sprintf(buf, "%d\n", ha->ip_config.ipv4_ttl);
155462306a36Sopenharmony_ci			break;
155562306a36Sopenharmony_ci		case ISCSI_NET_PARAM_IPV6_GRAT_NEIGHBOR_ADV_EN:
155662306a36Sopenharmony_ci			OP_STATE(ha->ip_config.ipv6_options,
155762306a36Sopenharmony_ci				 IPV6_OPT_GRAT_NEIGHBOR_ADV_EN, pval);
155862306a36Sopenharmony_ci
155962306a36Sopenharmony_ci			len = sprintf(buf, "%s\n", pval);
156062306a36Sopenharmony_ci			break;
156162306a36Sopenharmony_ci		case ISCSI_NET_PARAM_IPV6_MLD_EN:
156262306a36Sopenharmony_ci			OP_STATE(ha->ip_config.ipv6_addl_options,
156362306a36Sopenharmony_ci				 IPV6_ADDOPT_MLD_EN, pval);
156462306a36Sopenharmony_ci
156562306a36Sopenharmony_ci			len = sprintf(buf, "%s\n", pval);
156662306a36Sopenharmony_ci			break;
156762306a36Sopenharmony_ci		case ISCSI_NET_PARAM_IPV6_FLOW_LABEL:
156862306a36Sopenharmony_ci			len = sprintf(buf, "%u\n", ha->ip_config.ipv6_flow_lbl);
156962306a36Sopenharmony_ci			break;
157062306a36Sopenharmony_ci		case ISCSI_NET_PARAM_IPV6_TRAFFIC_CLASS:
157162306a36Sopenharmony_ci			len = sprintf(buf, "%d\n",
157262306a36Sopenharmony_ci				      ha->ip_config.ipv6_traffic_class);
157362306a36Sopenharmony_ci			break;
157462306a36Sopenharmony_ci		case ISCSI_NET_PARAM_IPV6_HOP_LIMIT:
157562306a36Sopenharmony_ci			len = sprintf(buf, "%d\n",
157662306a36Sopenharmony_ci				      ha->ip_config.ipv6_hop_limit);
157762306a36Sopenharmony_ci			break;
157862306a36Sopenharmony_ci		case ISCSI_NET_PARAM_IPV6_ND_REACHABLE_TMO:
157962306a36Sopenharmony_ci			len = sprintf(buf, "%d\n",
158062306a36Sopenharmony_ci				      ha->ip_config.ipv6_nd_reach_time);
158162306a36Sopenharmony_ci			break;
158262306a36Sopenharmony_ci		case ISCSI_NET_PARAM_IPV6_ND_REXMIT_TIME:
158362306a36Sopenharmony_ci			len = sprintf(buf, "%d\n",
158462306a36Sopenharmony_ci				      ha->ip_config.ipv6_nd_rexmit_timer);
158562306a36Sopenharmony_ci			break;
158662306a36Sopenharmony_ci		case ISCSI_NET_PARAM_IPV6_ND_STALE_TMO:
158762306a36Sopenharmony_ci			len = sprintf(buf, "%d\n",
158862306a36Sopenharmony_ci				      ha->ip_config.ipv6_nd_stale_timeout);
158962306a36Sopenharmony_ci			break;
159062306a36Sopenharmony_ci		case ISCSI_NET_PARAM_IPV6_DUP_ADDR_DETECT_CNT:
159162306a36Sopenharmony_ci			len = sprintf(buf, "%d\n",
159262306a36Sopenharmony_ci				      ha->ip_config.ipv6_dup_addr_detect_count);
159362306a36Sopenharmony_ci			break;
159462306a36Sopenharmony_ci		case ISCSI_NET_PARAM_IPV6_RTR_ADV_LINK_MTU:
159562306a36Sopenharmony_ci			len = sprintf(buf, "%d\n",
159662306a36Sopenharmony_ci				      ha->ip_config.ipv6_gw_advrt_mtu);
159762306a36Sopenharmony_ci			break;
159862306a36Sopenharmony_ci		default:
159962306a36Sopenharmony_ci			len = -ENOSYS;
160062306a36Sopenharmony_ci		}
160162306a36Sopenharmony_ci	} else if (param_type == ISCSI_IFACE_PARAM) {
160262306a36Sopenharmony_ci		switch (param) {
160362306a36Sopenharmony_ci		case ISCSI_IFACE_PARAM_DEF_TASKMGMT_TMO:
160462306a36Sopenharmony_ci			len = sprintf(buf, "%d\n", ha->ip_config.def_timeout);
160562306a36Sopenharmony_ci			break;
160662306a36Sopenharmony_ci		case ISCSI_IFACE_PARAM_HDRDGST_EN:
160762306a36Sopenharmony_ci			OP_STATE(ha->ip_config.iscsi_options,
160862306a36Sopenharmony_ci				 ISCSIOPTS_HEADER_DIGEST_EN, pval);
160962306a36Sopenharmony_ci
161062306a36Sopenharmony_ci			len = sprintf(buf, "%s\n", pval);
161162306a36Sopenharmony_ci			break;
161262306a36Sopenharmony_ci		case ISCSI_IFACE_PARAM_DATADGST_EN:
161362306a36Sopenharmony_ci			OP_STATE(ha->ip_config.iscsi_options,
161462306a36Sopenharmony_ci				 ISCSIOPTS_DATA_DIGEST_EN, pval);
161562306a36Sopenharmony_ci
161662306a36Sopenharmony_ci			len = sprintf(buf, "%s\n", pval);
161762306a36Sopenharmony_ci			break;
161862306a36Sopenharmony_ci		case ISCSI_IFACE_PARAM_IMM_DATA_EN:
161962306a36Sopenharmony_ci			OP_STATE(ha->ip_config.iscsi_options,
162062306a36Sopenharmony_ci				 ISCSIOPTS_IMMEDIATE_DATA_EN, pval);
162162306a36Sopenharmony_ci
162262306a36Sopenharmony_ci			len = sprintf(buf, "%s\n", pval);
162362306a36Sopenharmony_ci			break;
162462306a36Sopenharmony_ci		case ISCSI_IFACE_PARAM_INITIAL_R2T_EN:
162562306a36Sopenharmony_ci			OP_STATE(ha->ip_config.iscsi_options,
162662306a36Sopenharmony_ci				 ISCSIOPTS_INITIAL_R2T_EN, pval);
162762306a36Sopenharmony_ci
162862306a36Sopenharmony_ci			len = sprintf(buf, "%s\n", pval);
162962306a36Sopenharmony_ci			break;
163062306a36Sopenharmony_ci		case ISCSI_IFACE_PARAM_DATASEQ_INORDER_EN:
163162306a36Sopenharmony_ci			OP_STATE(ha->ip_config.iscsi_options,
163262306a36Sopenharmony_ci				 ISCSIOPTS_DATA_SEQ_INORDER_EN, pval);
163362306a36Sopenharmony_ci
163462306a36Sopenharmony_ci			len = sprintf(buf, "%s\n", pval);
163562306a36Sopenharmony_ci			break;
163662306a36Sopenharmony_ci		case ISCSI_IFACE_PARAM_PDU_INORDER_EN:
163762306a36Sopenharmony_ci			OP_STATE(ha->ip_config.iscsi_options,
163862306a36Sopenharmony_ci				 ISCSIOPTS_DATA_PDU_INORDER_EN, pval);
163962306a36Sopenharmony_ci
164062306a36Sopenharmony_ci			len = sprintf(buf, "%s\n", pval);
164162306a36Sopenharmony_ci			break;
164262306a36Sopenharmony_ci		case ISCSI_IFACE_PARAM_ERL:
164362306a36Sopenharmony_ci			len = sprintf(buf, "%d\n",
164462306a36Sopenharmony_ci				      (ha->ip_config.iscsi_options &
164562306a36Sopenharmony_ci				       ISCSIOPTS_ERL));
164662306a36Sopenharmony_ci			break;
164762306a36Sopenharmony_ci		case ISCSI_IFACE_PARAM_MAX_RECV_DLENGTH:
164862306a36Sopenharmony_ci			len = sprintf(buf, "%u\n",
164962306a36Sopenharmony_ci				      ha->ip_config.iscsi_max_pdu_size *
165062306a36Sopenharmony_ci				      BYTE_UNITS);
165162306a36Sopenharmony_ci			break;
165262306a36Sopenharmony_ci		case ISCSI_IFACE_PARAM_FIRST_BURST:
165362306a36Sopenharmony_ci			len = sprintf(buf, "%u\n",
165462306a36Sopenharmony_ci				      ha->ip_config.iscsi_first_burst_len *
165562306a36Sopenharmony_ci				      BYTE_UNITS);
165662306a36Sopenharmony_ci			break;
165762306a36Sopenharmony_ci		case ISCSI_IFACE_PARAM_MAX_R2T:
165862306a36Sopenharmony_ci			len = sprintf(buf, "%d\n",
165962306a36Sopenharmony_ci				      ha->ip_config.iscsi_max_outstnd_r2t);
166062306a36Sopenharmony_ci			break;
166162306a36Sopenharmony_ci		case ISCSI_IFACE_PARAM_MAX_BURST:
166262306a36Sopenharmony_ci			len = sprintf(buf, "%u\n",
166362306a36Sopenharmony_ci				      ha->ip_config.iscsi_max_burst_len *
166462306a36Sopenharmony_ci				      BYTE_UNITS);
166562306a36Sopenharmony_ci			break;
166662306a36Sopenharmony_ci		case ISCSI_IFACE_PARAM_CHAP_AUTH_EN:
166762306a36Sopenharmony_ci			OP_STATE(ha->ip_config.iscsi_options,
166862306a36Sopenharmony_ci				 ISCSIOPTS_CHAP_AUTH_EN, pval);
166962306a36Sopenharmony_ci
167062306a36Sopenharmony_ci			len = sprintf(buf, "%s\n", pval);
167162306a36Sopenharmony_ci			break;
167262306a36Sopenharmony_ci		case ISCSI_IFACE_PARAM_BIDI_CHAP_EN:
167362306a36Sopenharmony_ci			OP_STATE(ha->ip_config.iscsi_options,
167462306a36Sopenharmony_ci				 ISCSIOPTS_BIDI_CHAP_EN, pval);
167562306a36Sopenharmony_ci
167662306a36Sopenharmony_ci			len = sprintf(buf, "%s\n", pval);
167762306a36Sopenharmony_ci			break;
167862306a36Sopenharmony_ci		case ISCSI_IFACE_PARAM_DISCOVERY_AUTH_OPTIONAL:
167962306a36Sopenharmony_ci			OP_STATE(ha->ip_config.iscsi_options,
168062306a36Sopenharmony_ci				 ISCSIOPTS_DISCOVERY_AUTH_EN, pval);
168162306a36Sopenharmony_ci
168262306a36Sopenharmony_ci			len = sprintf(buf, "%s\n", pval);
168362306a36Sopenharmony_ci			break;
168462306a36Sopenharmony_ci		case ISCSI_IFACE_PARAM_DISCOVERY_LOGOUT_EN:
168562306a36Sopenharmony_ci			OP_STATE(ha->ip_config.iscsi_options,
168662306a36Sopenharmony_ci				 ISCSIOPTS_DISCOVERY_LOGOUT_EN, pval);
168762306a36Sopenharmony_ci
168862306a36Sopenharmony_ci			len = sprintf(buf, "%s\n", pval);
168962306a36Sopenharmony_ci			break;
169062306a36Sopenharmony_ci		case ISCSI_IFACE_PARAM_STRICT_LOGIN_COMP_EN:
169162306a36Sopenharmony_ci			OP_STATE(ha->ip_config.iscsi_options,
169262306a36Sopenharmony_ci				 ISCSIOPTS_STRICT_LOGIN_COMP_EN, pval);
169362306a36Sopenharmony_ci
169462306a36Sopenharmony_ci			len = sprintf(buf, "%s\n", pval);
169562306a36Sopenharmony_ci			break;
169662306a36Sopenharmony_ci		case ISCSI_IFACE_PARAM_INITIATOR_NAME:
169762306a36Sopenharmony_ci			len = sprintf(buf, "%s\n", ha->ip_config.iscsi_name);
169862306a36Sopenharmony_ci			break;
169962306a36Sopenharmony_ci		default:
170062306a36Sopenharmony_ci			len = -ENOSYS;
170162306a36Sopenharmony_ci		}
170262306a36Sopenharmony_ci	}
170362306a36Sopenharmony_ci
170462306a36Sopenharmony_ci	return len;
170562306a36Sopenharmony_ci}
170662306a36Sopenharmony_ci
170762306a36Sopenharmony_cistatic struct iscsi_endpoint *
170862306a36Sopenharmony_ciqla4xxx_ep_connect(struct Scsi_Host *shost, struct sockaddr *dst_addr,
170962306a36Sopenharmony_ci		   int non_blocking)
171062306a36Sopenharmony_ci{
171162306a36Sopenharmony_ci	int ret;
171262306a36Sopenharmony_ci	struct iscsi_endpoint *ep;
171362306a36Sopenharmony_ci	struct qla_endpoint *qla_ep;
171462306a36Sopenharmony_ci	struct scsi_qla_host *ha;
171562306a36Sopenharmony_ci	struct sockaddr_in *addr;
171662306a36Sopenharmony_ci	struct sockaddr_in6 *addr6;
171762306a36Sopenharmony_ci
171862306a36Sopenharmony_ci	if (!shost) {
171962306a36Sopenharmony_ci		ret = -ENXIO;
172062306a36Sopenharmony_ci		pr_err("%s: shost is NULL\n", __func__);
172162306a36Sopenharmony_ci		return ERR_PTR(ret);
172262306a36Sopenharmony_ci	}
172362306a36Sopenharmony_ci
172462306a36Sopenharmony_ci	ha = iscsi_host_priv(shost);
172562306a36Sopenharmony_ci	ep = iscsi_create_endpoint(sizeof(struct qla_endpoint));
172662306a36Sopenharmony_ci	if (!ep) {
172762306a36Sopenharmony_ci		ret = -ENOMEM;
172862306a36Sopenharmony_ci		return ERR_PTR(ret);
172962306a36Sopenharmony_ci	}
173062306a36Sopenharmony_ci
173162306a36Sopenharmony_ci	qla_ep = ep->dd_data;
173262306a36Sopenharmony_ci	memset(qla_ep, 0, sizeof(struct qla_endpoint));
173362306a36Sopenharmony_ci	if (dst_addr->sa_family == AF_INET) {
173462306a36Sopenharmony_ci		memcpy(&qla_ep->dst_addr, dst_addr, sizeof(struct sockaddr_in));
173562306a36Sopenharmony_ci		addr = (struct sockaddr_in *)&qla_ep->dst_addr;
173662306a36Sopenharmony_ci		DEBUG2(ql4_printk(KERN_INFO, ha, "%s: %pI4\n", __func__,
173762306a36Sopenharmony_ci				  (char *)&addr->sin_addr));
173862306a36Sopenharmony_ci	} else if (dst_addr->sa_family == AF_INET6) {
173962306a36Sopenharmony_ci		memcpy(&qla_ep->dst_addr, dst_addr,
174062306a36Sopenharmony_ci		       sizeof(struct sockaddr_in6));
174162306a36Sopenharmony_ci		addr6 = (struct sockaddr_in6 *)&qla_ep->dst_addr;
174262306a36Sopenharmony_ci		DEBUG2(ql4_printk(KERN_INFO, ha, "%s: %pI6\n", __func__,
174362306a36Sopenharmony_ci				  (char *)&addr6->sin6_addr));
174462306a36Sopenharmony_ci	} else {
174562306a36Sopenharmony_ci		ql4_printk(KERN_WARNING, ha, "%s: Invalid endpoint\n",
174662306a36Sopenharmony_ci			   __func__);
174762306a36Sopenharmony_ci	}
174862306a36Sopenharmony_ci
174962306a36Sopenharmony_ci	qla_ep->host = shost;
175062306a36Sopenharmony_ci
175162306a36Sopenharmony_ci	return ep;
175262306a36Sopenharmony_ci}
175362306a36Sopenharmony_ci
175462306a36Sopenharmony_cistatic int qla4xxx_ep_poll(struct iscsi_endpoint *ep, int timeout_ms)
175562306a36Sopenharmony_ci{
175662306a36Sopenharmony_ci	struct qla_endpoint *qla_ep;
175762306a36Sopenharmony_ci	struct scsi_qla_host *ha;
175862306a36Sopenharmony_ci	int ret = 0;
175962306a36Sopenharmony_ci
176062306a36Sopenharmony_ci	qla_ep = ep->dd_data;
176162306a36Sopenharmony_ci	ha = to_qla_host(qla_ep->host);
176262306a36Sopenharmony_ci	DEBUG2(pr_info_ratelimited("%s: host: %ld\n", __func__, ha->host_no));
176362306a36Sopenharmony_ci
176462306a36Sopenharmony_ci	if (adapter_up(ha) && !test_bit(AF_BUILD_DDB_LIST, &ha->flags))
176562306a36Sopenharmony_ci		ret = 1;
176662306a36Sopenharmony_ci
176762306a36Sopenharmony_ci	return ret;
176862306a36Sopenharmony_ci}
176962306a36Sopenharmony_ci
177062306a36Sopenharmony_cistatic void qla4xxx_ep_disconnect(struct iscsi_endpoint *ep)
177162306a36Sopenharmony_ci{
177262306a36Sopenharmony_ci	struct qla_endpoint *qla_ep;
177362306a36Sopenharmony_ci	struct scsi_qla_host *ha;
177462306a36Sopenharmony_ci
177562306a36Sopenharmony_ci	qla_ep = ep->dd_data;
177662306a36Sopenharmony_ci	ha = to_qla_host(qla_ep->host);
177762306a36Sopenharmony_ci	DEBUG2(ql4_printk(KERN_INFO, ha, "%s: host: %ld\n", __func__,
177862306a36Sopenharmony_ci			  ha->host_no));
177962306a36Sopenharmony_ci	iscsi_destroy_endpoint(ep);
178062306a36Sopenharmony_ci}
178162306a36Sopenharmony_ci
178262306a36Sopenharmony_cistatic int qla4xxx_get_ep_param(struct iscsi_endpoint *ep,
178362306a36Sopenharmony_ci				enum iscsi_param param,
178462306a36Sopenharmony_ci				char *buf)
178562306a36Sopenharmony_ci{
178662306a36Sopenharmony_ci	struct qla_endpoint *qla_ep = ep->dd_data;
178762306a36Sopenharmony_ci	struct sockaddr *dst_addr;
178862306a36Sopenharmony_ci	struct scsi_qla_host *ha;
178962306a36Sopenharmony_ci
179062306a36Sopenharmony_ci	if (!qla_ep)
179162306a36Sopenharmony_ci		return -ENOTCONN;
179262306a36Sopenharmony_ci
179362306a36Sopenharmony_ci	ha = to_qla_host(qla_ep->host);
179462306a36Sopenharmony_ci	DEBUG2(ql4_printk(KERN_INFO, ha, "%s: host: %ld\n", __func__,
179562306a36Sopenharmony_ci			  ha->host_no));
179662306a36Sopenharmony_ci
179762306a36Sopenharmony_ci	switch (param) {
179862306a36Sopenharmony_ci	case ISCSI_PARAM_CONN_PORT:
179962306a36Sopenharmony_ci	case ISCSI_PARAM_CONN_ADDRESS:
180062306a36Sopenharmony_ci		dst_addr = (struct sockaddr *)&qla_ep->dst_addr;
180162306a36Sopenharmony_ci		if (!dst_addr)
180262306a36Sopenharmony_ci			return -ENOTCONN;
180362306a36Sopenharmony_ci
180462306a36Sopenharmony_ci		return iscsi_conn_get_addr_param((struct sockaddr_storage *)
180562306a36Sopenharmony_ci						 &qla_ep->dst_addr, param, buf);
180662306a36Sopenharmony_ci	default:
180762306a36Sopenharmony_ci		return -ENOSYS;
180862306a36Sopenharmony_ci	}
180962306a36Sopenharmony_ci}
181062306a36Sopenharmony_ci
181162306a36Sopenharmony_cistatic void qla4xxx_conn_get_stats(struct iscsi_cls_conn *cls_conn,
181262306a36Sopenharmony_ci				   struct iscsi_stats *stats)
181362306a36Sopenharmony_ci{
181462306a36Sopenharmony_ci	struct iscsi_session *sess;
181562306a36Sopenharmony_ci	struct iscsi_cls_session *cls_sess;
181662306a36Sopenharmony_ci	struct ddb_entry *ddb_entry;
181762306a36Sopenharmony_ci	struct scsi_qla_host *ha;
181862306a36Sopenharmony_ci	struct ql_iscsi_stats *ql_iscsi_stats;
181962306a36Sopenharmony_ci	int stats_size;
182062306a36Sopenharmony_ci	int ret;
182162306a36Sopenharmony_ci	dma_addr_t iscsi_stats_dma;
182262306a36Sopenharmony_ci
182362306a36Sopenharmony_ci	cls_sess = iscsi_conn_to_session(cls_conn);
182462306a36Sopenharmony_ci	sess = cls_sess->dd_data;
182562306a36Sopenharmony_ci	ddb_entry = sess->dd_data;
182662306a36Sopenharmony_ci	ha = ddb_entry->ha;
182762306a36Sopenharmony_ci
182862306a36Sopenharmony_ci	DEBUG2(ql4_printk(KERN_INFO, ha, "%s: host: %ld\n", __func__,
182962306a36Sopenharmony_ci			  ha->host_no));
183062306a36Sopenharmony_ci	stats_size = PAGE_ALIGN(sizeof(struct ql_iscsi_stats));
183162306a36Sopenharmony_ci	/* Allocate memory */
183262306a36Sopenharmony_ci	ql_iscsi_stats = dma_alloc_coherent(&ha->pdev->dev, stats_size,
183362306a36Sopenharmony_ci					    &iscsi_stats_dma, GFP_KERNEL);
183462306a36Sopenharmony_ci	if (!ql_iscsi_stats) {
183562306a36Sopenharmony_ci		ql4_printk(KERN_ERR, ha,
183662306a36Sopenharmony_ci			   "Unable to allocate memory for iscsi stats\n");
183762306a36Sopenharmony_ci		goto exit_get_stats;
183862306a36Sopenharmony_ci	}
183962306a36Sopenharmony_ci
184062306a36Sopenharmony_ci	ret =  qla4xxx_get_mgmt_data(ha, ddb_entry->fw_ddb_index, stats_size,
184162306a36Sopenharmony_ci				     iscsi_stats_dma);
184262306a36Sopenharmony_ci	if (ret != QLA_SUCCESS) {
184362306a36Sopenharmony_ci		ql4_printk(KERN_ERR, ha,
184462306a36Sopenharmony_ci			   "Unable to retrieve iscsi stats\n");
184562306a36Sopenharmony_ci		goto free_stats;
184662306a36Sopenharmony_ci	}
184762306a36Sopenharmony_ci
184862306a36Sopenharmony_ci	/* octets */
184962306a36Sopenharmony_ci	stats->txdata_octets = le64_to_cpu(ql_iscsi_stats->tx_data_octets);
185062306a36Sopenharmony_ci	stats->rxdata_octets = le64_to_cpu(ql_iscsi_stats->rx_data_octets);
185162306a36Sopenharmony_ci	/* xmit pdus */
185262306a36Sopenharmony_ci	stats->noptx_pdus = le32_to_cpu(ql_iscsi_stats->tx_nopout_pdus);
185362306a36Sopenharmony_ci	stats->scsicmd_pdus = le32_to_cpu(ql_iscsi_stats->tx_scsi_cmd_pdus);
185462306a36Sopenharmony_ci	stats->tmfcmd_pdus = le32_to_cpu(ql_iscsi_stats->tx_tmf_cmd_pdus);
185562306a36Sopenharmony_ci	stats->login_pdus = le32_to_cpu(ql_iscsi_stats->tx_login_cmd_pdus);
185662306a36Sopenharmony_ci	stats->text_pdus = le32_to_cpu(ql_iscsi_stats->tx_text_cmd_pdus);
185762306a36Sopenharmony_ci	stats->dataout_pdus = le32_to_cpu(ql_iscsi_stats->tx_scsi_write_pdus);
185862306a36Sopenharmony_ci	stats->logout_pdus = le32_to_cpu(ql_iscsi_stats->tx_logout_cmd_pdus);
185962306a36Sopenharmony_ci	stats->snack_pdus = le32_to_cpu(ql_iscsi_stats->tx_snack_req_pdus);
186062306a36Sopenharmony_ci	/* recv pdus */
186162306a36Sopenharmony_ci	stats->noprx_pdus = le32_to_cpu(ql_iscsi_stats->rx_nopin_pdus);
186262306a36Sopenharmony_ci	stats->scsirsp_pdus = le32_to_cpu(ql_iscsi_stats->rx_scsi_resp_pdus);
186362306a36Sopenharmony_ci	stats->tmfrsp_pdus = le32_to_cpu(ql_iscsi_stats->rx_tmf_resp_pdus);
186462306a36Sopenharmony_ci	stats->textrsp_pdus = le32_to_cpu(ql_iscsi_stats->rx_text_resp_pdus);
186562306a36Sopenharmony_ci	stats->datain_pdus = le32_to_cpu(ql_iscsi_stats->rx_scsi_read_pdus);
186662306a36Sopenharmony_ci	stats->logoutrsp_pdus =
186762306a36Sopenharmony_ci			le32_to_cpu(ql_iscsi_stats->rx_logout_resp_pdus);
186862306a36Sopenharmony_ci	stats->r2t_pdus = le32_to_cpu(ql_iscsi_stats->rx_r2t_pdus);
186962306a36Sopenharmony_ci	stats->async_pdus = le32_to_cpu(ql_iscsi_stats->rx_async_pdus);
187062306a36Sopenharmony_ci	stats->rjt_pdus = le32_to_cpu(ql_iscsi_stats->rx_reject_pdus);
187162306a36Sopenharmony_ci
187262306a36Sopenharmony_cifree_stats:
187362306a36Sopenharmony_ci	dma_free_coherent(&ha->pdev->dev, stats_size, ql_iscsi_stats,
187462306a36Sopenharmony_ci			  iscsi_stats_dma);
187562306a36Sopenharmony_ciexit_get_stats:
187662306a36Sopenharmony_ci	return;
187762306a36Sopenharmony_ci}
187862306a36Sopenharmony_ci
187962306a36Sopenharmony_cistatic enum scsi_timeout_action qla4xxx_eh_cmd_timed_out(struct scsi_cmnd *sc)
188062306a36Sopenharmony_ci{
188162306a36Sopenharmony_ci	struct iscsi_cls_session *session;
188262306a36Sopenharmony_ci	unsigned long flags;
188362306a36Sopenharmony_ci	enum scsi_timeout_action ret = SCSI_EH_NOT_HANDLED;
188462306a36Sopenharmony_ci
188562306a36Sopenharmony_ci	session = starget_to_session(scsi_target(sc->device));
188662306a36Sopenharmony_ci
188762306a36Sopenharmony_ci	spin_lock_irqsave(&session->lock, flags);
188862306a36Sopenharmony_ci	if (session->state == ISCSI_SESSION_FAILED)
188962306a36Sopenharmony_ci		ret = SCSI_EH_RESET_TIMER;
189062306a36Sopenharmony_ci	spin_unlock_irqrestore(&session->lock, flags);
189162306a36Sopenharmony_ci
189262306a36Sopenharmony_ci	return ret;
189362306a36Sopenharmony_ci}
189462306a36Sopenharmony_ci
189562306a36Sopenharmony_cistatic void qla4xxx_set_port_speed(struct Scsi_Host *shost)
189662306a36Sopenharmony_ci{
189762306a36Sopenharmony_ci	struct scsi_qla_host *ha = to_qla_host(shost);
189862306a36Sopenharmony_ci	struct iscsi_cls_host *ihost = shost->shost_data;
189962306a36Sopenharmony_ci	uint32_t speed = ISCSI_PORT_SPEED_UNKNOWN;
190062306a36Sopenharmony_ci
190162306a36Sopenharmony_ci	qla4xxx_get_firmware_state(ha);
190262306a36Sopenharmony_ci
190362306a36Sopenharmony_ci	switch (ha->addl_fw_state & 0x0F00) {
190462306a36Sopenharmony_ci	case FW_ADDSTATE_LINK_SPEED_10MBPS:
190562306a36Sopenharmony_ci		speed = ISCSI_PORT_SPEED_10MBPS;
190662306a36Sopenharmony_ci		break;
190762306a36Sopenharmony_ci	case FW_ADDSTATE_LINK_SPEED_100MBPS:
190862306a36Sopenharmony_ci		speed = ISCSI_PORT_SPEED_100MBPS;
190962306a36Sopenharmony_ci		break;
191062306a36Sopenharmony_ci	case FW_ADDSTATE_LINK_SPEED_1GBPS:
191162306a36Sopenharmony_ci		speed = ISCSI_PORT_SPEED_1GBPS;
191262306a36Sopenharmony_ci		break;
191362306a36Sopenharmony_ci	case FW_ADDSTATE_LINK_SPEED_10GBPS:
191462306a36Sopenharmony_ci		speed = ISCSI_PORT_SPEED_10GBPS;
191562306a36Sopenharmony_ci		break;
191662306a36Sopenharmony_ci	}
191762306a36Sopenharmony_ci	ihost->port_speed = speed;
191862306a36Sopenharmony_ci}
191962306a36Sopenharmony_ci
192062306a36Sopenharmony_cistatic void qla4xxx_set_port_state(struct Scsi_Host *shost)
192162306a36Sopenharmony_ci{
192262306a36Sopenharmony_ci	struct scsi_qla_host *ha = to_qla_host(shost);
192362306a36Sopenharmony_ci	struct iscsi_cls_host *ihost = shost->shost_data;
192462306a36Sopenharmony_ci	uint32_t state = ISCSI_PORT_STATE_DOWN;
192562306a36Sopenharmony_ci
192662306a36Sopenharmony_ci	if (test_bit(AF_LINK_UP, &ha->flags))
192762306a36Sopenharmony_ci		state = ISCSI_PORT_STATE_UP;
192862306a36Sopenharmony_ci
192962306a36Sopenharmony_ci	ihost->port_state = state;
193062306a36Sopenharmony_ci}
193162306a36Sopenharmony_ci
193262306a36Sopenharmony_cistatic int qla4xxx_host_get_param(struct Scsi_Host *shost,
193362306a36Sopenharmony_ci				  enum iscsi_host_param param, char *buf)
193462306a36Sopenharmony_ci{
193562306a36Sopenharmony_ci	struct scsi_qla_host *ha = to_qla_host(shost);
193662306a36Sopenharmony_ci	int len;
193762306a36Sopenharmony_ci
193862306a36Sopenharmony_ci	switch (param) {
193962306a36Sopenharmony_ci	case ISCSI_HOST_PARAM_HWADDRESS:
194062306a36Sopenharmony_ci		len = sysfs_format_mac(buf, ha->my_mac, MAC_ADDR_LEN);
194162306a36Sopenharmony_ci		break;
194262306a36Sopenharmony_ci	case ISCSI_HOST_PARAM_IPADDRESS:
194362306a36Sopenharmony_ci		len = sprintf(buf, "%pI4\n", &ha->ip_config.ip_address);
194462306a36Sopenharmony_ci		break;
194562306a36Sopenharmony_ci	case ISCSI_HOST_PARAM_INITIATOR_NAME:
194662306a36Sopenharmony_ci		len = sprintf(buf, "%s\n", ha->name_string);
194762306a36Sopenharmony_ci		break;
194862306a36Sopenharmony_ci	case ISCSI_HOST_PARAM_PORT_STATE:
194962306a36Sopenharmony_ci		qla4xxx_set_port_state(shost);
195062306a36Sopenharmony_ci		len = sprintf(buf, "%s\n", iscsi_get_port_state_name(shost));
195162306a36Sopenharmony_ci		break;
195262306a36Sopenharmony_ci	case ISCSI_HOST_PARAM_PORT_SPEED:
195362306a36Sopenharmony_ci		qla4xxx_set_port_speed(shost);
195462306a36Sopenharmony_ci		len = sprintf(buf, "%s\n", iscsi_get_port_speed_name(shost));
195562306a36Sopenharmony_ci		break;
195662306a36Sopenharmony_ci	default:
195762306a36Sopenharmony_ci		return -ENOSYS;
195862306a36Sopenharmony_ci	}
195962306a36Sopenharmony_ci
196062306a36Sopenharmony_ci	return len;
196162306a36Sopenharmony_ci}
196262306a36Sopenharmony_ci
196362306a36Sopenharmony_cistatic void qla4xxx_create_ipv4_iface(struct scsi_qla_host *ha)
196462306a36Sopenharmony_ci{
196562306a36Sopenharmony_ci	if (ha->iface_ipv4)
196662306a36Sopenharmony_ci		return;
196762306a36Sopenharmony_ci
196862306a36Sopenharmony_ci	/* IPv4 */
196962306a36Sopenharmony_ci	ha->iface_ipv4 = iscsi_create_iface(ha->host,
197062306a36Sopenharmony_ci					    &qla4xxx_iscsi_transport,
197162306a36Sopenharmony_ci					    ISCSI_IFACE_TYPE_IPV4, 0, 0);
197262306a36Sopenharmony_ci	if (!ha->iface_ipv4)
197362306a36Sopenharmony_ci		ql4_printk(KERN_ERR, ha, "Could not create IPv4 iSCSI "
197462306a36Sopenharmony_ci			   "iface0.\n");
197562306a36Sopenharmony_ci}
197662306a36Sopenharmony_ci
197762306a36Sopenharmony_cistatic void qla4xxx_create_ipv6_iface(struct scsi_qla_host *ha)
197862306a36Sopenharmony_ci{
197962306a36Sopenharmony_ci	if (!ha->iface_ipv6_0)
198062306a36Sopenharmony_ci		/* IPv6 iface-0 */
198162306a36Sopenharmony_ci		ha->iface_ipv6_0 = iscsi_create_iface(ha->host,
198262306a36Sopenharmony_ci						      &qla4xxx_iscsi_transport,
198362306a36Sopenharmony_ci						      ISCSI_IFACE_TYPE_IPV6, 0,
198462306a36Sopenharmony_ci						      0);
198562306a36Sopenharmony_ci	if (!ha->iface_ipv6_0)
198662306a36Sopenharmony_ci		ql4_printk(KERN_ERR, ha, "Could not create IPv6 iSCSI "
198762306a36Sopenharmony_ci			   "iface0.\n");
198862306a36Sopenharmony_ci
198962306a36Sopenharmony_ci	if (!ha->iface_ipv6_1)
199062306a36Sopenharmony_ci		/* IPv6 iface-1 */
199162306a36Sopenharmony_ci		ha->iface_ipv6_1 = iscsi_create_iface(ha->host,
199262306a36Sopenharmony_ci						      &qla4xxx_iscsi_transport,
199362306a36Sopenharmony_ci						      ISCSI_IFACE_TYPE_IPV6, 1,
199462306a36Sopenharmony_ci						      0);
199562306a36Sopenharmony_ci	if (!ha->iface_ipv6_1)
199662306a36Sopenharmony_ci		ql4_printk(KERN_ERR, ha, "Could not create IPv6 iSCSI "
199762306a36Sopenharmony_ci			   "iface1.\n");
199862306a36Sopenharmony_ci}
199962306a36Sopenharmony_ci
200062306a36Sopenharmony_cistatic void qla4xxx_create_ifaces(struct scsi_qla_host *ha)
200162306a36Sopenharmony_ci{
200262306a36Sopenharmony_ci	if (ha->ip_config.ipv4_options & IPOPT_IPV4_PROTOCOL_ENABLE)
200362306a36Sopenharmony_ci		qla4xxx_create_ipv4_iface(ha);
200462306a36Sopenharmony_ci
200562306a36Sopenharmony_ci	if (ha->ip_config.ipv6_options & IPV6_OPT_IPV6_PROTOCOL_ENABLE)
200662306a36Sopenharmony_ci		qla4xxx_create_ipv6_iface(ha);
200762306a36Sopenharmony_ci}
200862306a36Sopenharmony_ci
200962306a36Sopenharmony_cistatic void qla4xxx_destroy_ipv4_iface(struct scsi_qla_host *ha)
201062306a36Sopenharmony_ci{
201162306a36Sopenharmony_ci	if (ha->iface_ipv4) {
201262306a36Sopenharmony_ci		iscsi_destroy_iface(ha->iface_ipv4);
201362306a36Sopenharmony_ci		ha->iface_ipv4 = NULL;
201462306a36Sopenharmony_ci	}
201562306a36Sopenharmony_ci}
201662306a36Sopenharmony_ci
201762306a36Sopenharmony_cistatic void qla4xxx_destroy_ipv6_iface(struct scsi_qla_host *ha)
201862306a36Sopenharmony_ci{
201962306a36Sopenharmony_ci	if (ha->iface_ipv6_0) {
202062306a36Sopenharmony_ci		iscsi_destroy_iface(ha->iface_ipv6_0);
202162306a36Sopenharmony_ci		ha->iface_ipv6_0 = NULL;
202262306a36Sopenharmony_ci	}
202362306a36Sopenharmony_ci	if (ha->iface_ipv6_1) {
202462306a36Sopenharmony_ci		iscsi_destroy_iface(ha->iface_ipv6_1);
202562306a36Sopenharmony_ci		ha->iface_ipv6_1 = NULL;
202662306a36Sopenharmony_ci	}
202762306a36Sopenharmony_ci}
202862306a36Sopenharmony_ci
202962306a36Sopenharmony_cistatic void qla4xxx_destroy_ifaces(struct scsi_qla_host *ha)
203062306a36Sopenharmony_ci{
203162306a36Sopenharmony_ci	qla4xxx_destroy_ipv4_iface(ha);
203262306a36Sopenharmony_ci	qla4xxx_destroy_ipv6_iface(ha);
203362306a36Sopenharmony_ci}
203462306a36Sopenharmony_ci
203562306a36Sopenharmony_cistatic void qla4xxx_set_ipv6(struct scsi_qla_host *ha,
203662306a36Sopenharmony_ci			     struct iscsi_iface_param_info *iface_param,
203762306a36Sopenharmony_ci			     struct addr_ctrl_blk *init_fw_cb)
203862306a36Sopenharmony_ci{
203962306a36Sopenharmony_ci	/*
204062306a36Sopenharmony_ci	 * iface_num 0 is valid for IPv6 Addr, linklocal, router, autocfg.
204162306a36Sopenharmony_ci	 * iface_num 1 is valid only for IPv6 Addr.
204262306a36Sopenharmony_ci	 */
204362306a36Sopenharmony_ci	switch (iface_param->param) {
204462306a36Sopenharmony_ci	case ISCSI_NET_PARAM_IPV6_ADDR:
204562306a36Sopenharmony_ci		if (iface_param->iface_num & 0x1)
204662306a36Sopenharmony_ci			/* IPv6 Addr 1 */
204762306a36Sopenharmony_ci			memcpy(init_fw_cb->ipv6_addr1, iface_param->value,
204862306a36Sopenharmony_ci			       sizeof(init_fw_cb->ipv6_addr1));
204962306a36Sopenharmony_ci		else
205062306a36Sopenharmony_ci			/* IPv6 Addr 0 */
205162306a36Sopenharmony_ci			memcpy(init_fw_cb->ipv6_addr0, iface_param->value,
205262306a36Sopenharmony_ci			       sizeof(init_fw_cb->ipv6_addr0));
205362306a36Sopenharmony_ci		break;
205462306a36Sopenharmony_ci	case ISCSI_NET_PARAM_IPV6_LINKLOCAL:
205562306a36Sopenharmony_ci		if (iface_param->iface_num & 0x1)
205662306a36Sopenharmony_ci			break;
205762306a36Sopenharmony_ci		memcpy(init_fw_cb->ipv6_if_id, &iface_param->value[8],
205862306a36Sopenharmony_ci		       sizeof(init_fw_cb->ipv6_if_id));
205962306a36Sopenharmony_ci		break;
206062306a36Sopenharmony_ci	case ISCSI_NET_PARAM_IPV6_ROUTER:
206162306a36Sopenharmony_ci		if (iface_param->iface_num & 0x1)
206262306a36Sopenharmony_ci			break;
206362306a36Sopenharmony_ci		memcpy(init_fw_cb->ipv6_dflt_rtr_addr, iface_param->value,
206462306a36Sopenharmony_ci		       sizeof(init_fw_cb->ipv6_dflt_rtr_addr));
206562306a36Sopenharmony_ci		break;
206662306a36Sopenharmony_ci	case ISCSI_NET_PARAM_IPV6_ADDR_AUTOCFG:
206762306a36Sopenharmony_ci		/* Autocfg applies to even interface */
206862306a36Sopenharmony_ci		if (iface_param->iface_num & 0x1)
206962306a36Sopenharmony_ci			break;
207062306a36Sopenharmony_ci
207162306a36Sopenharmony_ci		if (iface_param->value[0] == ISCSI_IPV6_AUTOCFG_DISABLE)
207262306a36Sopenharmony_ci			init_fw_cb->ipv6_addtl_opts &=
207362306a36Sopenharmony_ci				cpu_to_le16(
207462306a36Sopenharmony_ci				  ~IPV6_ADDOPT_NEIGHBOR_DISCOVERY_ADDR_ENABLE);
207562306a36Sopenharmony_ci		else if (iface_param->value[0] == ISCSI_IPV6_AUTOCFG_ND_ENABLE)
207662306a36Sopenharmony_ci			init_fw_cb->ipv6_addtl_opts |=
207762306a36Sopenharmony_ci				cpu_to_le16(
207862306a36Sopenharmony_ci				  IPV6_ADDOPT_NEIGHBOR_DISCOVERY_ADDR_ENABLE);
207962306a36Sopenharmony_ci		else
208062306a36Sopenharmony_ci			ql4_printk(KERN_ERR, ha,
208162306a36Sopenharmony_ci				   "Invalid autocfg setting for IPv6 addr\n");
208262306a36Sopenharmony_ci		break;
208362306a36Sopenharmony_ci	case ISCSI_NET_PARAM_IPV6_LINKLOCAL_AUTOCFG:
208462306a36Sopenharmony_ci		/* Autocfg applies to even interface */
208562306a36Sopenharmony_ci		if (iface_param->iface_num & 0x1)
208662306a36Sopenharmony_ci			break;
208762306a36Sopenharmony_ci
208862306a36Sopenharmony_ci		if (iface_param->value[0] ==
208962306a36Sopenharmony_ci		    ISCSI_IPV6_LINKLOCAL_AUTOCFG_ENABLE)
209062306a36Sopenharmony_ci			init_fw_cb->ipv6_addtl_opts |= cpu_to_le16(
209162306a36Sopenharmony_ci					IPV6_ADDOPT_AUTOCONFIG_LINK_LOCAL_ADDR);
209262306a36Sopenharmony_ci		else if (iface_param->value[0] ==
209362306a36Sopenharmony_ci			 ISCSI_IPV6_LINKLOCAL_AUTOCFG_DISABLE)
209462306a36Sopenharmony_ci			init_fw_cb->ipv6_addtl_opts &= cpu_to_le16(
209562306a36Sopenharmony_ci				       ~IPV6_ADDOPT_AUTOCONFIG_LINK_LOCAL_ADDR);
209662306a36Sopenharmony_ci		else
209762306a36Sopenharmony_ci			ql4_printk(KERN_ERR, ha,
209862306a36Sopenharmony_ci				   "Invalid autocfg setting for IPv6 linklocal addr\n");
209962306a36Sopenharmony_ci		break;
210062306a36Sopenharmony_ci	case ISCSI_NET_PARAM_IPV6_ROUTER_AUTOCFG:
210162306a36Sopenharmony_ci		/* Autocfg applies to even interface */
210262306a36Sopenharmony_ci		if (iface_param->iface_num & 0x1)
210362306a36Sopenharmony_ci			break;
210462306a36Sopenharmony_ci
210562306a36Sopenharmony_ci		if (iface_param->value[0] == ISCSI_IPV6_ROUTER_AUTOCFG_ENABLE)
210662306a36Sopenharmony_ci			memset(init_fw_cb->ipv6_dflt_rtr_addr, 0,
210762306a36Sopenharmony_ci			       sizeof(init_fw_cb->ipv6_dflt_rtr_addr));
210862306a36Sopenharmony_ci		break;
210962306a36Sopenharmony_ci	case ISCSI_NET_PARAM_IFACE_ENABLE:
211062306a36Sopenharmony_ci		if (iface_param->value[0] == ISCSI_IFACE_ENABLE) {
211162306a36Sopenharmony_ci			init_fw_cb->ipv6_opts |=
211262306a36Sopenharmony_ci				cpu_to_le16(IPV6_OPT_IPV6_PROTOCOL_ENABLE);
211362306a36Sopenharmony_ci			qla4xxx_create_ipv6_iface(ha);
211462306a36Sopenharmony_ci		} else {
211562306a36Sopenharmony_ci			init_fw_cb->ipv6_opts &=
211662306a36Sopenharmony_ci				cpu_to_le16(~IPV6_OPT_IPV6_PROTOCOL_ENABLE &
211762306a36Sopenharmony_ci					    0xFFFF);
211862306a36Sopenharmony_ci			qla4xxx_destroy_ipv6_iface(ha);
211962306a36Sopenharmony_ci		}
212062306a36Sopenharmony_ci		break;
212162306a36Sopenharmony_ci	case ISCSI_NET_PARAM_VLAN_TAG:
212262306a36Sopenharmony_ci		if (iface_param->len != sizeof(init_fw_cb->ipv6_vlan_tag))
212362306a36Sopenharmony_ci			break;
212462306a36Sopenharmony_ci		init_fw_cb->ipv6_vlan_tag =
212562306a36Sopenharmony_ci				cpu_to_be16(*(uint16_t *)iface_param->value);
212662306a36Sopenharmony_ci		break;
212762306a36Sopenharmony_ci	case ISCSI_NET_PARAM_VLAN_ENABLED:
212862306a36Sopenharmony_ci		if (iface_param->value[0] == ISCSI_VLAN_ENABLE)
212962306a36Sopenharmony_ci			init_fw_cb->ipv6_opts |=
213062306a36Sopenharmony_ci				cpu_to_le16(IPV6_OPT_VLAN_TAGGING_ENABLE);
213162306a36Sopenharmony_ci		else
213262306a36Sopenharmony_ci			init_fw_cb->ipv6_opts &=
213362306a36Sopenharmony_ci				cpu_to_le16(~IPV6_OPT_VLAN_TAGGING_ENABLE);
213462306a36Sopenharmony_ci		break;
213562306a36Sopenharmony_ci	case ISCSI_NET_PARAM_MTU:
213662306a36Sopenharmony_ci		init_fw_cb->eth_mtu_size =
213762306a36Sopenharmony_ci				cpu_to_le16(*(uint16_t *)iface_param->value);
213862306a36Sopenharmony_ci		break;
213962306a36Sopenharmony_ci	case ISCSI_NET_PARAM_PORT:
214062306a36Sopenharmony_ci		/* Autocfg applies to even interface */
214162306a36Sopenharmony_ci		if (iface_param->iface_num & 0x1)
214262306a36Sopenharmony_ci			break;
214362306a36Sopenharmony_ci
214462306a36Sopenharmony_ci		init_fw_cb->ipv6_port =
214562306a36Sopenharmony_ci				cpu_to_le16(*(uint16_t *)iface_param->value);
214662306a36Sopenharmony_ci		break;
214762306a36Sopenharmony_ci	case ISCSI_NET_PARAM_DELAYED_ACK_EN:
214862306a36Sopenharmony_ci		if (iface_param->iface_num & 0x1)
214962306a36Sopenharmony_ci			break;
215062306a36Sopenharmony_ci		if (iface_param->value[0] == ISCSI_NET_PARAM_DISABLE)
215162306a36Sopenharmony_ci			init_fw_cb->ipv6_tcp_opts |=
215262306a36Sopenharmony_ci				cpu_to_le16(IPV6_TCPOPT_DELAYED_ACK_DISABLE);
215362306a36Sopenharmony_ci		else
215462306a36Sopenharmony_ci			init_fw_cb->ipv6_tcp_opts &=
215562306a36Sopenharmony_ci				cpu_to_le16(~IPV6_TCPOPT_DELAYED_ACK_DISABLE &
215662306a36Sopenharmony_ci					    0xFFFF);
215762306a36Sopenharmony_ci		break;
215862306a36Sopenharmony_ci	case ISCSI_NET_PARAM_TCP_NAGLE_DISABLE:
215962306a36Sopenharmony_ci		if (iface_param->iface_num & 0x1)
216062306a36Sopenharmony_ci			break;
216162306a36Sopenharmony_ci		if (iface_param->value[0] == ISCSI_NET_PARAM_DISABLE)
216262306a36Sopenharmony_ci			init_fw_cb->ipv6_tcp_opts |=
216362306a36Sopenharmony_ci				cpu_to_le16(IPV6_TCPOPT_NAGLE_ALGO_DISABLE);
216462306a36Sopenharmony_ci		else
216562306a36Sopenharmony_ci			init_fw_cb->ipv6_tcp_opts &=
216662306a36Sopenharmony_ci				cpu_to_le16(~IPV6_TCPOPT_NAGLE_ALGO_DISABLE);
216762306a36Sopenharmony_ci		break;
216862306a36Sopenharmony_ci	case ISCSI_NET_PARAM_TCP_WSF_DISABLE:
216962306a36Sopenharmony_ci		if (iface_param->iface_num & 0x1)
217062306a36Sopenharmony_ci			break;
217162306a36Sopenharmony_ci		if (iface_param->value[0] == ISCSI_NET_PARAM_DISABLE)
217262306a36Sopenharmony_ci			init_fw_cb->ipv6_tcp_opts |=
217362306a36Sopenharmony_ci				cpu_to_le16(IPV6_TCPOPT_WINDOW_SCALE_DISABLE);
217462306a36Sopenharmony_ci		else
217562306a36Sopenharmony_ci			init_fw_cb->ipv6_tcp_opts &=
217662306a36Sopenharmony_ci				cpu_to_le16(~IPV6_TCPOPT_WINDOW_SCALE_DISABLE);
217762306a36Sopenharmony_ci		break;
217862306a36Sopenharmony_ci	case ISCSI_NET_PARAM_TCP_WSF:
217962306a36Sopenharmony_ci		if (iface_param->iface_num & 0x1)
218062306a36Sopenharmony_ci			break;
218162306a36Sopenharmony_ci		init_fw_cb->ipv6_tcp_wsf = iface_param->value[0];
218262306a36Sopenharmony_ci		break;
218362306a36Sopenharmony_ci	case ISCSI_NET_PARAM_TCP_TIMER_SCALE:
218462306a36Sopenharmony_ci		if (iface_param->iface_num & 0x1)
218562306a36Sopenharmony_ci			break;
218662306a36Sopenharmony_ci		init_fw_cb->ipv6_tcp_opts &=
218762306a36Sopenharmony_ci					cpu_to_le16(~IPV6_TCPOPT_TIMER_SCALE);
218862306a36Sopenharmony_ci		init_fw_cb->ipv6_tcp_opts |=
218962306a36Sopenharmony_ci				cpu_to_le16((iface_param->value[0] << 1) &
219062306a36Sopenharmony_ci					    IPV6_TCPOPT_TIMER_SCALE);
219162306a36Sopenharmony_ci		break;
219262306a36Sopenharmony_ci	case ISCSI_NET_PARAM_TCP_TIMESTAMP_EN:
219362306a36Sopenharmony_ci		if (iface_param->iface_num & 0x1)
219462306a36Sopenharmony_ci			break;
219562306a36Sopenharmony_ci		if (iface_param->value[0] == ISCSI_NET_PARAM_ENABLE)
219662306a36Sopenharmony_ci			init_fw_cb->ipv6_tcp_opts |=
219762306a36Sopenharmony_ci				cpu_to_le16(IPV6_TCPOPT_TIMESTAMP_EN);
219862306a36Sopenharmony_ci		else
219962306a36Sopenharmony_ci			init_fw_cb->ipv6_tcp_opts &=
220062306a36Sopenharmony_ci				cpu_to_le16(~IPV6_TCPOPT_TIMESTAMP_EN);
220162306a36Sopenharmony_ci		break;
220262306a36Sopenharmony_ci	case ISCSI_NET_PARAM_IPV6_GRAT_NEIGHBOR_ADV_EN:
220362306a36Sopenharmony_ci		if (iface_param->iface_num & 0x1)
220462306a36Sopenharmony_ci			break;
220562306a36Sopenharmony_ci		if (iface_param->value[0] == ISCSI_NET_PARAM_ENABLE)
220662306a36Sopenharmony_ci			init_fw_cb->ipv6_opts |=
220762306a36Sopenharmony_ci				cpu_to_le16(IPV6_OPT_GRAT_NEIGHBOR_ADV_EN);
220862306a36Sopenharmony_ci		else
220962306a36Sopenharmony_ci			init_fw_cb->ipv6_opts &=
221062306a36Sopenharmony_ci				cpu_to_le16(~IPV6_OPT_GRAT_NEIGHBOR_ADV_EN);
221162306a36Sopenharmony_ci		break;
221262306a36Sopenharmony_ci	case ISCSI_NET_PARAM_REDIRECT_EN:
221362306a36Sopenharmony_ci		if (iface_param->iface_num & 0x1)
221462306a36Sopenharmony_ci			break;
221562306a36Sopenharmony_ci		if (iface_param->value[0] == ISCSI_NET_PARAM_ENABLE)
221662306a36Sopenharmony_ci			init_fw_cb->ipv6_opts |=
221762306a36Sopenharmony_ci				cpu_to_le16(IPV6_OPT_REDIRECT_EN);
221862306a36Sopenharmony_ci		else
221962306a36Sopenharmony_ci			init_fw_cb->ipv6_opts &=
222062306a36Sopenharmony_ci				cpu_to_le16(~IPV6_OPT_REDIRECT_EN);
222162306a36Sopenharmony_ci		break;
222262306a36Sopenharmony_ci	case ISCSI_NET_PARAM_IPV6_MLD_EN:
222362306a36Sopenharmony_ci		if (iface_param->iface_num & 0x1)
222462306a36Sopenharmony_ci			break;
222562306a36Sopenharmony_ci		if (iface_param->value[0] == ISCSI_NET_PARAM_ENABLE)
222662306a36Sopenharmony_ci			init_fw_cb->ipv6_addtl_opts |=
222762306a36Sopenharmony_ci				cpu_to_le16(IPV6_ADDOPT_MLD_EN);
222862306a36Sopenharmony_ci		else
222962306a36Sopenharmony_ci			init_fw_cb->ipv6_addtl_opts &=
223062306a36Sopenharmony_ci				cpu_to_le16(~IPV6_ADDOPT_MLD_EN);
223162306a36Sopenharmony_ci		break;
223262306a36Sopenharmony_ci	case ISCSI_NET_PARAM_IPV6_FLOW_LABEL:
223362306a36Sopenharmony_ci		if (iface_param->iface_num & 0x1)
223462306a36Sopenharmony_ci			break;
223562306a36Sopenharmony_ci		init_fw_cb->ipv6_flow_lbl =
223662306a36Sopenharmony_ci				cpu_to_le16(*(uint16_t *)iface_param->value);
223762306a36Sopenharmony_ci		break;
223862306a36Sopenharmony_ci	case ISCSI_NET_PARAM_IPV6_TRAFFIC_CLASS:
223962306a36Sopenharmony_ci		if (iface_param->iface_num & 0x1)
224062306a36Sopenharmony_ci			break;
224162306a36Sopenharmony_ci		init_fw_cb->ipv6_traffic_class = iface_param->value[0];
224262306a36Sopenharmony_ci		break;
224362306a36Sopenharmony_ci	case ISCSI_NET_PARAM_IPV6_HOP_LIMIT:
224462306a36Sopenharmony_ci		if (iface_param->iface_num & 0x1)
224562306a36Sopenharmony_ci			break;
224662306a36Sopenharmony_ci		init_fw_cb->ipv6_hop_limit = iface_param->value[0];
224762306a36Sopenharmony_ci		break;
224862306a36Sopenharmony_ci	case ISCSI_NET_PARAM_IPV6_ND_REACHABLE_TMO:
224962306a36Sopenharmony_ci		if (iface_param->iface_num & 0x1)
225062306a36Sopenharmony_ci			break;
225162306a36Sopenharmony_ci		init_fw_cb->ipv6_nd_reach_time =
225262306a36Sopenharmony_ci				cpu_to_le32(*(uint32_t *)iface_param->value);
225362306a36Sopenharmony_ci		break;
225462306a36Sopenharmony_ci	case ISCSI_NET_PARAM_IPV6_ND_REXMIT_TIME:
225562306a36Sopenharmony_ci		if (iface_param->iface_num & 0x1)
225662306a36Sopenharmony_ci			break;
225762306a36Sopenharmony_ci		init_fw_cb->ipv6_nd_rexmit_timer =
225862306a36Sopenharmony_ci				cpu_to_le32(*(uint32_t *)iface_param->value);
225962306a36Sopenharmony_ci		break;
226062306a36Sopenharmony_ci	case ISCSI_NET_PARAM_IPV6_ND_STALE_TMO:
226162306a36Sopenharmony_ci		if (iface_param->iface_num & 0x1)
226262306a36Sopenharmony_ci			break;
226362306a36Sopenharmony_ci		init_fw_cb->ipv6_nd_stale_timeout =
226462306a36Sopenharmony_ci				cpu_to_le32(*(uint32_t *)iface_param->value);
226562306a36Sopenharmony_ci		break;
226662306a36Sopenharmony_ci	case ISCSI_NET_PARAM_IPV6_DUP_ADDR_DETECT_CNT:
226762306a36Sopenharmony_ci		if (iface_param->iface_num & 0x1)
226862306a36Sopenharmony_ci			break;
226962306a36Sopenharmony_ci		init_fw_cb->ipv6_dup_addr_detect_count = iface_param->value[0];
227062306a36Sopenharmony_ci		break;
227162306a36Sopenharmony_ci	case ISCSI_NET_PARAM_IPV6_RTR_ADV_LINK_MTU:
227262306a36Sopenharmony_ci		if (iface_param->iface_num & 0x1)
227362306a36Sopenharmony_ci			break;
227462306a36Sopenharmony_ci		init_fw_cb->ipv6_gw_advrt_mtu =
227562306a36Sopenharmony_ci				cpu_to_le32(*(uint32_t *)iface_param->value);
227662306a36Sopenharmony_ci		break;
227762306a36Sopenharmony_ci	default:
227862306a36Sopenharmony_ci		ql4_printk(KERN_ERR, ha, "Unknown IPv6 param = %d\n",
227962306a36Sopenharmony_ci			   iface_param->param);
228062306a36Sopenharmony_ci		break;
228162306a36Sopenharmony_ci	}
228262306a36Sopenharmony_ci}
228362306a36Sopenharmony_ci
228462306a36Sopenharmony_cistatic void qla4xxx_set_ipv4(struct scsi_qla_host *ha,
228562306a36Sopenharmony_ci			     struct iscsi_iface_param_info *iface_param,
228662306a36Sopenharmony_ci			     struct addr_ctrl_blk *init_fw_cb)
228762306a36Sopenharmony_ci{
228862306a36Sopenharmony_ci	switch (iface_param->param) {
228962306a36Sopenharmony_ci	case ISCSI_NET_PARAM_IPV4_ADDR:
229062306a36Sopenharmony_ci		memcpy(init_fw_cb->ipv4_addr, iface_param->value,
229162306a36Sopenharmony_ci		       sizeof(init_fw_cb->ipv4_addr));
229262306a36Sopenharmony_ci		break;
229362306a36Sopenharmony_ci	case ISCSI_NET_PARAM_IPV4_SUBNET:
229462306a36Sopenharmony_ci		memcpy(init_fw_cb->ipv4_subnet,	iface_param->value,
229562306a36Sopenharmony_ci		       sizeof(init_fw_cb->ipv4_subnet));
229662306a36Sopenharmony_ci		break;
229762306a36Sopenharmony_ci	case ISCSI_NET_PARAM_IPV4_GW:
229862306a36Sopenharmony_ci		memcpy(init_fw_cb->ipv4_gw_addr, iface_param->value,
229962306a36Sopenharmony_ci		       sizeof(init_fw_cb->ipv4_gw_addr));
230062306a36Sopenharmony_ci		break;
230162306a36Sopenharmony_ci	case ISCSI_NET_PARAM_IPV4_BOOTPROTO:
230262306a36Sopenharmony_ci		if (iface_param->value[0] == ISCSI_BOOTPROTO_DHCP)
230362306a36Sopenharmony_ci			init_fw_cb->ipv4_tcp_opts |=
230462306a36Sopenharmony_ci					cpu_to_le16(TCPOPT_DHCP_ENABLE);
230562306a36Sopenharmony_ci		else if (iface_param->value[0] == ISCSI_BOOTPROTO_STATIC)
230662306a36Sopenharmony_ci			init_fw_cb->ipv4_tcp_opts &=
230762306a36Sopenharmony_ci					cpu_to_le16(~TCPOPT_DHCP_ENABLE);
230862306a36Sopenharmony_ci		else
230962306a36Sopenharmony_ci			ql4_printk(KERN_ERR, ha, "Invalid IPv4 bootproto\n");
231062306a36Sopenharmony_ci		break;
231162306a36Sopenharmony_ci	case ISCSI_NET_PARAM_IFACE_ENABLE:
231262306a36Sopenharmony_ci		if (iface_param->value[0] == ISCSI_IFACE_ENABLE) {
231362306a36Sopenharmony_ci			init_fw_cb->ipv4_ip_opts |=
231462306a36Sopenharmony_ci				cpu_to_le16(IPOPT_IPV4_PROTOCOL_ENABLE);
231562306a36Sopenharmony_ci			qla4xxx_create_ipv4_iface(ha);
231662306a36Sopenharmony_ci		} else {
231762306a36Sopenharmony_ci			init_fw_cb->ipv4_ip_opts &=
231862306a36Sopenharmony_ci				cpu_to_le16(~IPOPT_IPV4_PROTOCOL_ENABLE &
231962306a36Sopenharmony_ci					    0xFFFF);
232062306a36Sopenharmony_ci			qla4xxx_destroy_ipv4_iface(ha);
232162306a36Sopenharmony_ci		}
232262306a36Sopenharmony_ci		break;
232362306a36Sopenharmony_ci	case ISCSI_NET_PARAM_VLAN_TAG:
232462306a36Sopenharmony_ci		if (iface_param->len != sizeof(init_fw_cb->ipv4_vlan_tag))
232562306a36Sopenharmony_ci			break;
232662306a36Sopenharmony_ci		init_fw_cb->ipv4_vlan_tag =
232762306a36Sopenharmony_ci				cpu_to_be16(*(uint16_t *)iface_param->value);
232862306a36Sopenharmony_ci		break;
232962306a36Sopenharmony_ci	case ISCSI_NET_PARAM_VLAN_ENABLED:
233062306a36Sopenharmony_ci		if (iface_param->value[0] == ISCSI_VLAN_ENABLE)
233162306a36Sopenharmony_ci			init_fw_cb->ipv4_ip_opts |=
233262306a36Sopenharmony_ci					cpu_to_le16(IPOPT_VLAN_TAGGING_ENABLE);
233362306a36Sopenharmony_ci		else
233462306a36Sopenharmony_ci			init_fw_cb->ipv4_ip_opts &=
233562306a36Sopenharmony_ci					cpu_to_le16(~IPOPT_VLAN_TAGGING_ENABLE);
233662306a36Sopenharmony_ci		break;
233762306a36Sopenharmony_ci	case ISCSI_NET_PARAM_MTU:
233862306a36Sopenharmony_ci		init_fw_cb->eth_mtu_size =
233962306a36Sopenharmony_ci				cpu_to_le16(*(uint16_t *)iface_param->value);
234062306a36Sopenharmony_ci		break;
234162306a36Sopenharmony_ci	case ISCSI_NET_PARAM_PORT:
234262306a36Sopenharmony_ci		init_fw_cb->ipv4_port =
234362306a36Sopenharmony_ci				cpu_to_le16(*(uint16_t *)iface_param->value);
234462306a36Sopenharmony_ci		break;
234562306a36Sopenharmony_ci	case ISCSI_NET_PARAM_DELAYED_ACK_EN:
234662306a36Sopenharmony_ci		if (iface_param->iface_num & 0x1)
234762306a36Sopenharmony_ci			break;
234862306a36Sopenharmony_ci		if (iface_param->value[0] == ISCSI_NET_PARAM_DISABLE)
234962306a36Sopenharmony_ci			init_fw_cb->ipv4_tcp_opts |=
235062306a36Sopenharmony_ci				cpu_to_le16(TCPOPT_DELAYED_ACK_DISABLE);
235162306a36Sopenharmony_ci		else
235262306a36Sopenharmony_ci			init_fw_cb->ipv4_tcp_opts &=
235362306a36Sopenharmony_ci				cpu_to_le16(~TCPOPT_DELAYED_ACK_DISABLE &
235462306a36Sopenharmony_ci					    0xFFFF);
235562306a36Sopenharmony_ci		break;
235662306a36Sopenharmony_ci	case ISCSI_NET_PARAM_TCP_NAGLE_DISABLE:
235762306a36Sopenharmony_ci		if (iface_param->iface_num & 0x1)
235862306a36Sopenharmony_ci			break;
235962306a36Sopenharmony_ci		if (iface_param->value[0] == ISCSI_NET_PARAM_DISABLE)
236062306a36Sopenharmony_ci			init_fw_cb->ipv4_tcp_opts |=
236162306a36Sopenharmony_ci				cpu_to_le16(TCPOPT_NAGLE_ALGO_DISABLE);
236262306a36Sopenharmony_ci		else
236362306a36Sopenharmony_ci			init_fw_cb->ipv4_tcp_opts &=
236462306a36Sopenharmony_ci				cpu_to_le16(~TCPOPT_NAGLE_ALGO_DISABLE);
236562306a36Sopenharmony_ci		break;
236662306a36Sopenharmony_ci	case ISCSI_NET_PARAM_TCP_WSF_DISABLE:
236762306a36Sopenharmony_ci		if (iface_param->iface_num & 0x1)
236862306a36Sopenharmony_ci			break;
236962306a36Sopenharmony_ci		if (iface_param->value[0] == ISCSI_NET_PARAM_DISABLE)
237062306a36Sopenharmony_ci			init_fw_cb->ipv4_tcp_opts |=
237162306a36Sopenharmony_ci				cpu_to_le16(TCPOPT_WINDOW_SCALE_DISABLE);
237262306a36Sopenharmony_ci		else
237362306a36Sopenharmony_ci			init_fw_cb->ipv4_tcp_opts &=
237462306a36Sopenharmony_ci				cpu_to_le16(~TCPOPT_WINDOW_SCALE_DISABLE);
237562306a36Sopenharmony_ci		break;
237662306a36Sopenharmony_ci	case ISCSI_NET_PARAM_TCP_WSF:
237762306a36Sopenharmony_ci		if (iface_param->iface_num & 0x1)
237862306a36Sopenharmony_ci			break;
237962306a36Sopenharmony_ci		init_fw_cb->ipv4_tcp_wsf = iface_param->value[0];
238062306a36Sopenharmony_ci		break;
238162306a36Sopenharmony_ci	case ISCSI_NET_PARAM_TCP_TIMER_SCALE:
238262306a36Sopenharmony_ci		if (iface_param->iface_num & 0x1)
238362306a36Sopenharmony_ci			break;
238462306a36Sopenharmony_ci		init_fw_cb->ipv4_tcp_opts &= cpu_to_le16(~TCPOPT_TIMER_SCALE);
238562306a36Sopenharmony_ci		init_fw_cb->ipv4_tcp_opts |=
238662306a36Sopenharmony_ci				cpu_to_le16((iface_param->value[0] << 1) &
238762306a36Sopenharmony_ci					    TCPOPT_TIMER_SCALE);
238862306a36Sopenharmony_ci		break;
238962306a36Sopenharmony_ci	case ISCSI_NET_PARAM_TCP_TIMESTAMP_EN:
239062306a36Sopenharmony_ci		if (iface_param->iface_num & 0x1)
239162306a36Sopenharmony_ci			break;
239262306a36Sopenharmony_ci		if (iface_param->value[0] == ISCSI_NET_PARAM_ENABLE)
239362306a36Sopenharmony_ci			init_fw_cb->ipv4_tcp_opts |=
239462306a36Sopenharmony_ci				cpu_to_le16(TCPOPT_TIMESTAMP_ENABLE);
239562306a36Sopenharmony_ci		else
239662306a36Sopenharmony_ci			init_fw_cb->ipv4_tcp_opts &=
239762306a36Sopenharmony_ci				cpu_to_le16(~TCPOPT_TIMESTAMP_ENABLE);
239862306a36Sopenharmony_ci		break;
239962306a36Sopenharmony_ci	case ISCSI_NET_PARAM_IPV4_DHCP_DNS_ADDR_EN:
240062306a36Sopenharmony_ci		if (iface_param->iface_num & 0x1)
240162306a36Sopenharmony_ci			break;
240262306a36Sopenharmony_ci		if (iface_param->value[0] == ISCSI_NET_PARAM_ENABLE)
240362306a36Sopenharmony_ci			init_fw_cb->ipv4_tcp_opts |=
240462306a36Sopenharmony_ci				cpu_to_le16(TCPOPT_DNS_SERVER_IP_EN);
240562306a36Sopenharmony_ci		else
240662306a36Sopenharmony_ci			init_fw_cb->ipv4_tcp_opts &=
240762306a36Sopenharmony_ci				cpu_to_le16(~TCPOPT_DNS_SERVER_IP_EN);
240862306a36Sopenharmony_ci		break;
240962306a36Sopenharmony_ci	case ISCSI_NET_PARAM_IPV4_DHCP_SLP_DA_EN:
241062306a36Sopenharmony_ci		if (iface_param->iface_num & 0x1)
241162306a36Sopenharmony_ci			break;
241262306a36Sopenharmony_ci		if (iface_param->value[0] == ISCSI_NET_PARAM_ENABLE)
241362306a36Sopenharmony_ci			init_fw_cb->ipv4_tcp_opts |=
241462306a36Sopenharmony_ci				cpu_to_le16(TCPOPT_SLP_DA_INFO_EN);
241562306a36Sopenharmony_ci		else
241662306a36Sopenharmony_ci			init_fw_cb->ipv4_tcp_opts &=
241762306a36Sopenharmony_ci				cpu_to_le16(~TCPOPT_SLP_DA_INFO_EN);
241862306a36Sopenharmony_ci		break;
241962306a36Sopenharmony_ci	case ISCSI_NET_PARAM_IPV4_TOS_EN:
242062306a36Sopenharmony_ci		if (iface_param->iface_num & 0x1)
242162306a36Sopenharmony_ci			break;
242262306a36Sopenharmony_ci		if (iface_param->value[0] == ISCSI_NET_PARAM_ENABLE)
242362306a36Sopenharmony_ci			init_fw_cb->ipv4_ip_opts |=
242462306a36Sopenharmony_ci				cpu_to_le16(IPOPT_IPV4_TOS_EN);
242562306a36Sopenharmony_ci		else
242662306a36Sopenharmony_ci			init_fw_cb->ipv4_ip_opts &=
242762306a36Sopenharmony_ci				cpu_to_le16(~IPOPT_IPV4_TOS_EN);
242862306a36Sopenharmony_ci		break;
242962306a36Sopenharmony_ci	case ISCSI_NET_PARAM_IPV4_TOS:
243062306a36Sopenharmony_ci		if (iface_param->iface_num & 0x1)
243162306a36Sopenharmony_ci			break;
243262306a36Sopenharmony_ci		init_fw_cb->ipv4_tos = iface_param->value[0];
243362306a36Sopenharmony_ci		break;
243462306a36Sopenharmony_ci	case ISCSI_NET_PARAM_IPV4_GRAT_ARP_EN:
243562306a36Sopenharmony_ci		if (iface_param->iface_num & 0x1)
243662306a36Sopenharmony_ci			break;
243762306a36Sopenharmony_ci		if (iface_param->value[0] == ISCSI_NET_PARAM_ENABLE)
243862306a36Sopenharmony_ci			init_fw_cb->ipv4_ip_opts |=
243962306a36Sopenharmony_ci					cpu_to_le16(IPOPT_GRAT_ARP_EN);
244062306a36Sopenharmony_ci		else
244162306a36Sopenharmony_ci			init_fw_cb->ipv4_ip_opts &=
244262306a36Sopenharmony_ci					cpu_to_le16(~IPOPT_GRAT_ARP_EN);
244362306a36Sopenharmony_ci		break;
244462306a36Sopenharmony_ci	case ISCSI_NET_PARAM_IPV4_DHCP_ALT_CLIENT_ID_EN:
244562306a36Sopenharmony_ci		if (iface_param->iface_num & 0x1)
244662306a36Sopenharmony_ci			break;
244762306a36Sopenharmony_ci		if (iface_param->value[0] == ISCSI_NET_PARAM_ENABLE)
244862306a36Sopenharmony_ci			init_fw_cb->ipv4_ip_opts |=
244962306a36Sopenharmony_ci				cpu_to_le16(IPOPT_ALT_CID_EN);
245062306a36Sopenharmony_ci		else
245162306a36Sopenharmony_ci			init_fw_cb->ipv4_ip_opts &=
245262306a36Sopenharmony_ci				cpu_to_le16(~IPOPT_ALT_CID_EN);
245362306a36Sopenharmony_ci		break;
245462306a36Sopenharmony_ci	case ISCSI_NET_PARAM_IPV4_DHCP_ALT_CLIENT_ID:
245562306a36Sopenharmony_ci		if (iface_param->iface_num & 0x1)
245662306a36Sopenharmony_ci			break;
245762306a36Sopenharmony_ci		memcpy(init_fw_cb->ipv4_dhcp_alt_cid, iface_param->value,
245862306a36Sopenharmony_ci		       (sizeof(init_fw_cb->ipv4_dhcp_alt_cid) - 1));
245962306a36Sopenharmony_ci		init_fw_cb->ipv4_dhcp_alt_cid_len =
246062306a36Sopenharmony_ci					strlen(init_fw_cb->ipv4_dhcp_alt_cid);
246162306a36Sopenharmony_ci		break;
246262306a36Sopenharmony_ci	case ISCSI_NET_PARAM_IPV4_DHCP_REQ_VENDOR_ID_EN:
246362306a36Sopenharmony_ci		if (iface_param->iface_num & 0x1)
246462306a36Sopenharmony_ci			break;
246562306a36Sopenharmony_ci		if (iface_param->value[0] == ISCSI_NET_PARAM_ENABLE)
246662306a36Sopenharmony_ci			init_fw_cb->ipv4_ip_opts |=
246762306a36Sopenharmony_ci					cpu_to_le16(IPOPT_REQ_VID_EN);
246862306a36Sopenharmony_ci		else
246962306a36Sopenharmony_ci			init_fw_cb->ipv4_ip_opts &=
247062306a36Sopenharmony_ci					cpu_to_le16(~IPOPT_REQ_VID_EN);
247162306a36Sopenharmony_ci		break;
247262306a36Sopenharmony_ci	case ISCSI_NET_PARAM_IPV4_DHCP_USE_VENDOR_ID_EN:
247362306a36Sopenharmony_ci		if (iface_param->iface_num & 0x1)
247462306a36Sopenharmony_ci			break;
247562306a36Sopenharmony_ci		if (iface_param->value[0] == ISCSI_NET_PARAM_ENABLE)
247662306a36Sopenharmony_ci			init_fw_cb->ipv4_ip_opts |=
247762306a36Sopenharmony_ci					cpu_to_le16(IPOPT_USE_VID_EN);
247862306a36Sopenharmony_ci		else
247962306a36Sopenharmony_ci			init_fw_cb->ipv4_ip_opts &=
248062306a36Sopenharmony_ci					cpu_to_le16(~IPOPT_USE_VID_EN);
248162306a36Sopenharmony_ci		break;
248262306a36Sopenharmony_ci	case ISCSI_NET_PARAM_IPV4_DHCP_VENDOR_ID:
248362306a36Sopenharmony_ci		if (iface_param->iface_num & 0x1)
248462306a36Sopenharmony_ci			break;
248562306a36Sopenharmony_ci		memcpy(init_fw_cb->ipv4_dhcp_vid, iface_param->value,
248662306a36Sopenharmony_ci		       (sizeof(init_fw_cb->ipv4_dhcp_vid) - 1));
248762306a36Sopenharmony_ci		init_fw_cb->ipv4_dhcp_vid_len =
248862306a36Sopenharmony_ci					strlen(init_fw_cb->ipv4_dhcp_vid);
248962306a36Sopenharmony_ci		break;
249062306a36Sopenharmony_ci	case ISCSI_NET_PARAM_IPV4_DHCP_LEARN_IQN_EN:
249162306a36Sopenharmony_ci		if (iface_param->iface_num & 0x1)
249262306a36Sopenharmony_ci			break;
249362306a36Sopenharmony_ci		if (iface_param->value[0] == ISCSI_NET_PARAM_ENABLE)
249462306a36Sopenharmony_ci			init_fw_cb->ipv4_ip_opts |=
249562306a36Sopenharmony_ci					cpu_to_le16(IPOPT_LEARN_IQN_EN);
249662306a36Sopenharmony_ci		else
249762306a36Sopenharmony_ci			init_fw_cb->ipv4_ip_opts &=
249862306a36Sopenharmony_ci					cpu_to_le16(~IPOPT_LEARN_IQN_EN);
249962306a36Sopenharmony_ci		break;
250062306a36Sopenharmony_ci	case ISCSI_NET_PARAM_IPV4_FRAGMENT_DISABLE:
250162306a36Sopenharmony_ci		if (iface_param->iface_num & 0x1)
250262306a36Sopenharmony_ci			break;
250362306a36Sopenharmony_ci		if (iface_param->value[0] == ISCSI_NET_PARAM_DISABLE)
250462306a36Sopenharmony_ci			init_fw_cb->ipv4_ip_opts |=
250562306a36Sopenharmony_ci				cpu_to_le16(IPOPT_FRAGMENTATION_DISABLE);
250662306a36Sopenharmony_ci		else
250762306a36Sopenharmony_ci			init_fw_cb->ipv4_ip_opts &=
250862306a36Sopenharmony_ci				cpu_to_le16(~IPOPT_FRAGMENTATION_DISABLE);
250962306a36Sopenharmony_ci		break;
251062306a36Sopenharmony_ci	case ISCSI_NET_PARAM_IPV4_IN_FORWARD_EN:
251162306a36Sopenharmony_ci		if (iface_param->iface_num & 0x1)
251262306a36Sopenharmony_ci			break;
251362306a36Sopenharmony_ci		if (iface_param->value[0] == ISCSI_NET_PARAM_ENABLE)
251462306a36Sopenharmony_ci			init_fw_cb->ipv4_ip_opts |=
251562306a36Sopenharmony_ci				cpu_to_le16(IPOPT_IN_FORWARD_EN);
251662306a36Sopenharmony_ci		else
251762306a36Sopenharmony_ci			init_fw_cb->ipv4_ip_opts &=
251862306a36Sopenharmony_ci				cpu_to_le16(~IPOPT_IN_FORWARD_EN);
251962306a36Sopenharmony_ci		break;
252062306a36Sopenharmony_ci	case ISCSI_NET_PARAM_REDIRECT_EN:
252162306a36Sopenharmony_ci		if (iface_param->iface_num & 0x1)
252262306a36Sopenharmony_ci			break;
252362306a36Sopenharmony_ci		if (iface_param->value[0] == ISCSI_NET_PARAM_ENABLE)
252462306a36Sopenharmony_ci			init_fw_cb->ipv4_ip_opts |=
252562306a36Sopenharmony_ci				cpu_to_le16(IPOPT_ARP_REDIRECT_EN);
252662306a36Sopenharmony_ci		else
252762306a36Sopenharmony_ci			init_fw_cb->ipv4_ip_opts &=
252862306a36Sopenharmony_ci				cpu_to_le16(~IPOPT_ARP_REDIRECT_EN);
252962306a36Sopenharmony_ci		break;
253062306a36Sopenharmony_ci	case ISCSI_NET_PARAM_IPV4_TTL:
253162306a36Sopenharmony_ci		if (iface_param->iface_num & 0x1)
253262306a36Sopenharmony_ci			break;
253362306a36Sopenharmony_ci		init_fw_cb->ipv4_ttl = iface_param->value[0];
253462306a36Sopenharmony_ci		break;
253562306a36Sopenharmony_ci	default:
253662306a36Sopenharmony_ci		ql4_printk(KERN_ERR, ha, "Unknown IPv4 param = %d\n",
253762306a36Sopenharmony_ci			   iface_param->param);
253862306a36Sopenharmony_ci		break;
253962306a36Sopenharmony_ci	}
254062306a36Sopenharmony_ci}
254162306a36Sopenharmony_ci
254262306a36Sopenharmony_cistatic void qla4xxx_set_iscsi_param(struct scsi_qla_host *ha,
254362306a36Sopenharmony_ci				    struct iscsi_iface_param_info *iface_param,
254462306a36Sopenharmony_ci				    struct addr_ctrl_blk *init_fw_cb)
254562306a36Sopenharmony_ci{
254662306a36Sopenharmony_ci	switch (iface_param->param) {
254762306a36Sopenharmony_ci	case ISCSI_IFACE_PARAM_DEF_TASKMGMT_TMO:
254862306a36Sopenharmony_ci		if (iface_param->iface_num & 0x1)
254962306a36Sopenharmony_ci			break;
255062306a36Sopenharmony_ci		init_fw_cb->def_timeout =
255162306a36Sopenharmony_ci				cpu_to_le16(*(uint16_t *)iface_param->value);
255262306a36Sopenharmony_ci		break;
255362306a36Sopenharmony_ci	case ISCSI_IFACE_PARAM_HDRDGST_EN:
255462306a36Sopenharmony_ci		if (iface_param->iface_num & 0x1)
255562306a36Sopenharmony_ci			break;
255662306a36Sopenharmony_ci		if (iface_param->value[0] == ISCSI_NET_PARAM_ENABLE)
255762306a36Sopenharmony_ci			init_fw_cb->iscsi_opts |=
255862306a36Sopenharmony_ci				cpu_to_le16(ISCSIOPTS_HEADER_DIGEST_EN);
255962306a36Sopenharmony_ci		else
256062306a36Sopenharmony_ci			init_fw_cb->iscsi_opts &=
256162306a36Sopenharmony_ci				cpu_to_le16(~ISCSIOPTS_HEADER_DIGEST_EN);
256262306a36Sopenharmony_ci		break;
256362306a36Sopenharmony_ci	case ISCSI_IFACE_PARAM_DATADGST_EN:
256462306a36Sopenharmony_ci		if (iface_param->iface_num & 0x1)
256562306a36Sopenharmony_ci			break;
256662306a36Sopenharmony_ci		if (iface_param->value[0] == ISCSI_NET_PARAM_ENABLE)
256762306a36Sopenharmony_ci			init_fw_cb->iscsi_opts |=
256862306a36Sopenharmony_ci				cpu_to_le16(ISCSIOPTS_DATA_DIGEST_EN);
256962306a36Sopenharmony_ci		else
257062306a36Sopenharmony_ci			init_fw_cb->iscsi_opts &=
257162306a36Sopenharmony_ci				cpu_to_le16(~ISCSIOPTS_DATA_DIGEST_EN);
257262306a36Sopenharmony_ci		break;
257362306a36Sopenharmony_ci	case ISCSI_IFACE_PARAM_IMM_DATA_EN:
257462306a36Sopenharmony_ci		if (iface_param->iface_num & 0x1)
257562306a36Sopenharmony_ci			break;
257662306a36Sopenharmony_ci		if (iface_param->value[0] == ISCSI_NET_PARAM_ENABLE)
257762306a36Sopenharmony_ci			init_fw_cb->iscsi_opts |=
257862306a36Sopenharmony_ci				cpu_to_le16(ISCSIOPTS_IMMEDIATE_DATA_EN);
257962306a36Sopenharmony_ci		else
258062306a36Sopenharmony_ci			init_fw_cb->iscsi_opts &=
258162306a36Sopenharmony_ci				cpu_to_le16(~ISCSIOPTS_IMMEDIATE_DATA_EN);
258262306a36Sopenharmony_ci		break;
258362306a36Sopenharmony_ci	case ISCSI_IFACE_PARAM_INITIAL_R2T_EN:
258462306a36Sopenharmony_ci		if (iface_param->iface_num & 0x1)
258562306a36Sopenharmony_ci			break;
258662306a36Sopenharmony_ci		if (iface_param->value[0] == ISCSI_NET_PARAM_ENABLE)
258762306a36Sopenharmony_ci			init_fw_cb->iscsi_opts |=
258862306a36Sopenharmony_ci				cpu_to_le16(ISCSIOPTS_INITIAL_R2T_EN);
258962306a36Sopenharmony_ci		else
259062306a36Sopenharmony_ci			init_fw_cb->iscsi_opts &=
259162306a36Sopenharmony_ci				cpu_to_le16(~ISCSIOPTS_INITIAL_R2T_EN);
259262306a36Sopenharmony_ci		break;
259362306a36Sopenharmony_ci	case ISCSI_IFACE_PARAM_DATASEQ_INORDER_EN:
259462306a36Sopenharmony_ci		if (iface_param->iface_num & 0x1)
259562306a36Sopenharmony_ci			break;
259662306a36Sopenharmony_ci		if (iface_param->value[0] == ISCSI_NET_PARAM_ENABLE)
259762306a36Sopenharmony_ci			init_fw_cb->iscsi_opts |=
259862306a36Sopenharmony_ci				cpu_to_le16(ISCSIOPTS_DATA_SEQ_INORDER_EN);
259962306a36Sopenharmony_ci		else
260062306a36Sopenharmony_ci			init_fw_cb->iscsi_opts &=
260162306a36Sopenharmony_ci				cpu_to_le16(~ISCSIOPTS_DATA_SEQ_INORDER_EN);
260262306a36Sopenharmony_ci		break;
260362306a36Sopenharmony_ci	case ISCSI_IFACE_PARAM_PDU_INORDER_EN:
260462306a36Sopenharmony_ci		if (iface_param->iface_num & 0x1)
260562306a36Sopenharmony_ci			break;
260662306a36Sopenharmony_ci		if (iface_param->value[0] == ISCSI_NET_PARAM_ENABLE)
260762306a36Sopenharmony_ci			init_fw_cb->iscsi_opts |=
260862306a36Sopenharmony_ci				cpu_to_le16(ISCSIOPTS_DATA_PDU_INORDER_EN);
260962306a36Sopenharmony_ci		else
261062306a36Sopenharmony_ci			init_fw_cb->iscsi_opts &=
261162306a36Sopenharmony_ci				cpu_to_le16(~ISCSIOPTS_DATA_PDU_INORDER_EN);
261262306a36Sopenharmony_ci		break;
261362306a36Sopenharmony_ci	case ISCSI_IFACE_PARAM_ERL:
261462306a36Sopenharmony_ci		if (iface_param->iface_num & 0x1)
261562306a36Sopenharmony_ci			break;
261662306a36Sopenharmony_ci		init_fw_cb->iscsi_opts &= cpu_to_le16(~ISCSIOPTS_ERL);
261762306a36Sopenharmony_ci		init_fw_cb->iscsi_opts |= cpu_to_le16(iface_param->value[0] &
261862306a36Sopenharmony_ci						      ISCSIOPTS_ERL);
261962306a36Sopenharmony_ci		break;
262062306a36Sopenharmony_ci	case ISCSI_IFACE_PARAM_MAX_RECV_DLENGTH:
262162306a36Sopenharmony_ci		if (iface_param->iface_num & 0x1)
262262306a36Sopenharmony_ci			break;
262362306a36Sopenharmony_ci		init_fw_cb->iscsi_max_pdu_size =
262462306a36Sopenharmony_ci				cpu_to_le32(*(uint32_t *)iface_param->value) /
262562306a36Sopenharmony_ci				BYTE_UNITS;
262662306a36Sopenharmony_ci		break;
262762306a36Sopenharmony_ci	case ISCSI_IFACE_PARAM_FIRST_BURST:
262862306a36Sopenharmony_ci		if (iface_param->iface_num & 0x1)
262962306a36Sopenharmony_ci			break;
263062306a36Sopenharmony_ci		init_fw_cb->iscsi_fburst_len =
263162306a36Sopenharmony_ci				cpu_to_le32(*(uint32_t *)iface_param->value) /
263262306a36Sopenharmony_ci				BYTE_UNITS;
263362306a36Sopenharmony_ci		break;
263462306a36Sopenharmony_ci	case ISCSI_IFACE_PARAM_MAX_R2T:
263562306a36Sopenharmony_ci		if (iface_param->iface_num & 0x1)
263662306a36Sopenharmony_ci			break;
263762306a36Sopenharmony_ci		init_fw_cb->iscsi_max_outstnd_r2t =
263862306a36Sopenharmony_ci				cpu_to_le16(*(uint16_t *)iface_param->value);
263962306a36Sopenharmony_ci		break;
264062306a36Sopenharmony_ci	case ISCSI_IFACE_PARAM_MAX_BURST:
264162306a36Sopenharmony_ci		if (iface_param->iface_num & 0x1)
264262306a36Sopenharmony_ci			break;
264362306a36Sopenharmony_ci		init_fw_cb->iscsi_max_burst_len =
264462306a36Sopenharmony_ci				cpu_to_le32(*(uint32_t *)iface_param->value) /
264562306a36Sopenharmony_ci				BYTE_UNITS;
264662306a36Sopenharmony_ci		break;
264762306a36Sopenharmony_ci	case ISCSI_IFACE_PARAM_CHAP_AUTH_EN:
264862306a36Sopenharmony_ci		if (iface_param->iface_num & 0x1)
264962306a36Sopenharmony_ci			break;
265062306a36Sopenharmony_ci		if (iface_param->value[0] == ISCSI_NET_PARAM_ENABLE)
265162306a36Sopenharmony_ci			init_fw_cb->iscsi_opts |=
265262306a36Sopenharmony_ci				cpu_to_le16(ISCSIOPTS_CHAP_AUTH_EN);
265362306a36Sopenharmony_ci		else
265462306a36Sopenharmony_ci			init_fw_cb->iscsi_opts &=
265562306a36Sopenharmony_ci				cpu_to_le16(~ISCSIOPTS_CHAP_AUTH_EN);
265662306a36Sopenharmony_ci		break;
265762306a36Sopenharmony_ci	case ISCSI_IFACE_PARAM_BIDI_CHAP_EN:
265862306a36Sopenharmony_ci		if (iface_param->iface_num & 0x1)
265962306a36Sopenharmony_ci			break;
266062306a36Sopenharmony_ci		if (iface_param->value[0] == ISCSI_NET_PARAM_ENABLE)
266162306a36Sopenharmony_ci			init_fw_cb->iscsi_opts |=
266262306a36Sopenharmony_ci				cpu_to_le16(ISCSIOPTS_BIDI_CHAP_EN);
266362306a36Sopenharmony_ci		else
266462306a36Sopenharmony_ci			init_fw_cb->iscsi_opts &=
266562306a36Sopenharmony_ci				cpu_to_le16(~ISCSIOPTS_BIDI_CHAP_EN);
266662306a36Sopenharmony_ci		break;
266762306a36Sopenharmony_ci	case ISCSI_IFACE_PARAM_DISCOVERY_AUTH_OPTIONAL:
266862306a36Sopenharmony_ci		if (iface_param->iface_num & 0x1)
266962306a36Sopenharmony_ci			break;
267062306a36Sopenharmony_ci		if (iface_param->value[0] == ISCSI_NET_PARAM_ENABLE)
267162306a36Sopenharmony_ci			init_fw_cb->iscsi_opts |=
267262306a36Sopenharmony_ci				cpu_to_le16(ISCSIOPTS_DISCOVERY_AUTH_EN);
267362306a36Sopenharmony_ci		else
267462306a36Sopenharmony_ci			init_fw_cb->iscsi_opts &=
267562306a36Sopenharmony_ci				cpu_to_le16(~ISCSIOPTS_DISCOVERY_AUTH_EN);
267662306a36Sopenharmony_ci		break;
267762306a36Sopenharmony_ci	case ISCSI_IFACE_PARAM_DISCOVERY_LOGOUT_EN:
267862306a36Sopenharmony_ci		if (iface_param->iface_num & 0x1)
267962306a36Sopenharmony_ci			break;
268062306a36Sopenharmony_ci		if (iface_param->value[0] == ISCSI_NET_PARAM_ENABLE)
268162306a36Sopenharmony_ci			init_fw_cb->iscsi_opts |=
268262306a36Sopenharmony_ci				cpu_to_le16(ISCSIOPTS_DISCOVERY_LOGOUT_EN);
268362306a36Sopenharmony_ci		else
268462306a36Sopenharmony_ci			init_fw_cb->iscsi_opts &=
268562306a36Sopenharmony_ci				cpu_to_le16(~ISCSIOPTS_DISCOVERY_LOGOUT_EN);
268662306a36Sopenharmony_ci		break;
268762306a36Sopenharmony_ci	case ISCSI_IFACE_PARAM_STRICT_LOGIN_COMP_EN:
268862306a36Sopenharmony_ci		if (iface_param->iface_num & 0x1)
268962306a36Sopenharmony_ci			break;
269062306a36Sopenharmony_ci		if (iface_param->value[0] == ISCSI_NET_PARAM_ENABLE)
269162306a36Sopenharmony_ci			init_fw_cb->iscsi_opts |=
269262306a36Sopenharmony_ci				cpu_to_le16(ISCSIOPTS_STRICT_LOGIN_COMP_EN);
269362306a36Sopenharmony_ci		else
269462306a36Sopenharmony_ci			init_fw_cb->iscsi_opts &=
269562306a36Sopenharmony_ci				cpu_to_le16(~ISCSIOPTS_STRICT_LOGIN_COMP_EN);
269662306a36Sopenharmony_ci		break;
269762306a36Sopenharmony_ci	default:
269862306a36Sopenharmony_ci		ql4_printk(KERN_ERR, ha, "Unknown iscsi param = %d\n",
269962306a36Sopenharmony_ci			   iface_param->param);
270062306a36Sopenharmony_ci		break;
270162306a36Sopenharmony_ci	}
270262306a36Sopenharmony_ci}
270362306a36Sopenharmony_ci
270462306a36Sopenharmony_cistatic void
270562306a36Sopenharmony_ciqla4xxx_initcb_to_acb(struct addr_ctrl_blk *init_fw_cb)
270662306a36Sopenharmony_ci{
270762306a36Sopenharmony_ci	struct addr_ctrl_blk_def *acb;
270862306a36Sopenharmony_ci	acb = (struct addr_ctrl_blk_def *)init_fw_cb;
270962306a36Sopenharmony_ci	memset(acb->reserved1, 0, sizeof(acb->reserved1));
271062306a36Sopenharmony_ci	memset(acb->reserved2, 0, sizeof(acb->reserved2));
271162306a36Sopenharmony_ci	memset(acb->reserved3, 0, sizeof(acb->reserved3));
271262306a36Sopenharmony_ci	memset(acb->reserved4, 0, sizeof(acb->reserved4));
271362306a36Sopenharmony_ci	memset(acb->reserved5, 0, sizeof(acb->reserved5));
271462306a36Sopenharmony_ci	memset(acb->reserved6, 0, sizeof(acb->reserved6));
271562306a36Sopenharmony_ci	memset(acb->reserved7, 0, sizeof(acb->reserved7));
271662306a36Sopenharmony_ci	memset(acb->reserved8, 0, sizeof(acb->reserved8));
271762306a36Sopenharmony_ci	memset(acb->reserved9, 0, sizeof(acb->reserved9));
271862306a36Sopenharmony_ci	memset(acb->reserved10, 0, sizeof(acb->reserved10));
271962306a36Sopenharmony_ci	memset(acb->reserved11, 0, sizeof(acb->reserved11));
272062306a36Sopenharmony_ci	memset(acb->reserved12, 0, sizeof(acb->reserved12));
272162306a36Sopenharmony_ci	memset(acb->reserved13, 0, sizeof(acb->reserved13));
272262306a36Sopenharmony_ci	memset(acb->reserved14, 0, sizeof(acb->reserved14));
272362306a36Sopenharmony_ci	memset(acb->reserved15, 0, sizeof(acb->reserved15));
272462306a36Sopenharmony_ci}
272562306a36Sopenharmony_ci
272662306a36Sopenharmony_cistatic int
272762306a36Sopenharmony_ciqla4xxx_iface_set_param(struct Scsi_Host *shost, void *data, uint32_t len)
272862306a36Sopenharmony_ci{
272962306a36Sopenharmony_ci	struct scsi_qla_host *ha = to_qla_host(shost);
273062306a36Sopenharmony_ci	int rval = 0;
273162306a36Sopenharmony_ci	struct iscsi_iface_param_info *iface_param = NULL;
273262306a36Sopenharmony_ci	struct addr_ctrl_blk *init_fw_cb = NULL;
273362306a36Sopenharmony_ci	dma_addr_t init_fw_cb_dma;
273462306a36Sopenharmony_ci	uint32_t mbox_cmd[MBOX_REG_COUNT];
273562306a36Sopenharmony_ci	uint32_t mbox_sts[MBOX_REG_COUNT];
273662306a36Sopenharmony_ci	uint32_t rem = len;
273762306a36Sopenharmony_ci	struct nlattr *attr;
273862306a36Sopenharmony_ci
273962306a36Sopenharmony_ci	init_fw_cb = dma_alloc_coherent(&ha->pdev->dev,
274062306a36Sopenharmony_ci					sizeof(struct addr_ctrl_blk),
274162306a36Sopenharmony_ci					&init_fw_cb_dma, GFP_KERNEL);
274262306a36Sopenharmony_ci	if (!init_fw_cb) {
274362306a36Sopenharmony_ci		ql4_printk(KERN_ERR, ha, "%s: Unable to alloc init_cb\n",
274462306a36Sopenharmony_ci			   __func__);
274562306a36Sopenharmony_ci		return -ENOMEM;
274662306a36Sopenharmony_ci	}
274762306a36Sopenharmony_ci
274862306a36Sopenharmony_ci	memset(&mbox_cmd, 0, sizeof(mbox_cmd));
274962306a36Sopenharmony_ci	memset(&mbox_sts, 0, sizeof(mbox_sts));
275062306a36Sopenharmony_ci
275162306a36Sopenharmony_ci	if (qla4xxx_get_ifcb(ha, &mbox_cmd[0], &mbox_sts[0], init_fw_cb_dma)) {
275262306a36Sopenharmony_ci		ql4_printk(KERN_ERR, ha, "%s: get ifcb failed\n", __func__);
275362306a36Sopenharmony_ci		rval = -EIO;
275462306a36Sopenharmony_ci		goto exit_init_fw_cb;
275562306a36Sopenharmony_ci	}
275662306a36Sopenharmony_ci
275762306a36Sopenharmony_ci	nla_for_each_attr(attr, data, len, rem) {
275862306a36Sopenharmony_ci		if (nla_len(attr) < sizeof(*iface_param)) {
275962306a36Sopenharmony_ci			rval = -EINVAL;
276062306a36Sopenharmony_ci			goto exit_init_fw_cb;
276162306a36Sopenharmony_ci		}
276262306a36Sopenharmony_ci
276362306a36Sopenharmony_ci		iface_param = nla_data(attr);
276462306a36Sopenharmony_ci
276562306a36Sopenharmony_ci		if (iface_param->param_type == ISCSI_NET_PARAM) {
276662306a36Sopenharmony_ci			switch (iface_param->iface_type) {
276762306a36Sopenharmony_ci			case ISCSI_IFACE_TYPE_IPV4:
276862306a36Sopenharmony_ci				switch (iface_param->iface_num) {
276962306a36Sopenharmony_ci				case 0:
277062306a36Sopenharmony_ci					qla4xxx_set_ipv4(ha, iface_param,
277162306a36Sopenharmony_ci							 init_fw_cb);
277262306a36Sopenharmony_ci					break;
277362306a36Sopenharmony_ci				default:
277462306a36Sopenharmony_ci				/* Cannot have more than one IPv4 interface */
277562306a36Sopenharmony_ci					ql4_printk(KERN_ERR, ha,
277662306a36Sopenharmony_ci						   "Invalid IPv4 iface number = %d\n",
277762306a36Sopenharmony_ci						   iface_param->iface_num);
277862306a36Sopenharmony_ci					break;
277962306a36Sopenharmony_ci				}
278062306a36Sopenharmony_ci				break;
278162306a36Sopenharmony_ci			case ISCSI_IFACE_TYPE_IPV6:
278262306a36Sopenharmony_ci				switch (iface_param->iface_num) {
278362306a36Sopenharmony_ci				case 0:
278462306a36Sopenharmony_ci				case 1:
278562306a36Sopenharmony_ci					qla4xxx_set_ipv6(ha, iface_param,
278662306a36Sopenharmony_ci							 init_fw_cb);
278762306a36Sopenharmony_ci					break;
278862306a36Sopenharmony_ci				default:
278962306a36Sopenharmony_ci				/* Cannot have more than two IPv6 interface */
279062306a36Sopenharmony_ci					ql4_printk(KERN_ERR, ha,
279162306a36Sopenharmony_ci						   "Invalid IPv6 iface number = %d\n",
279262306a36Sopenharmony_ci						   iface_param->iface_num);
279362306a36Sopenharmony_ci					break;
279462306a36Sopenharmony_ci				}
279562306a36Sopenharmony_ci				break;
279662306a36Sopenharmony_ci			default:
279762306a36Sopenharmony_ci				ql4_printk(KERN_ERR, ha,
279862306a36Sopenharmony_ci					   "Invalid iface type\n");
279962306a36Sopenharmony_ci				break;
280062306a36Sopenharmony_ci			}
280162306a36Sopenharmony_ci		} else if (iface_param->param_type == ISCSI_IFACE_PARAM) {
280262306a36Sopenharmony_ci				qla4xxx_set_iscsi_param(ha, iface_param,
280362306a36Sopenharmony_ci							init_fw_cb);
280462306a36Sopenharmony_ci		} else {
280562306a36Sopenharmony_ci			continue;
280662306a36Sopenharmony_ci		}
280762306a36Sopenharmony_ci	}
280862306a36Sopenharmony_ci
280962306a36Sopenharmony_ci	init_fw_cb->cookie = cpu_to_le32(0x11BEAD5A);
281062306a36Sopenharmony_ci
281162306a36Sopenharmony_ci	rval = qla4xxx_set_flash(ha, init_fw_cb_dma, FLASH_SEGMENT_IFCB,
281262306a36Sopenharmony_ci				 sizeof(struct addr_ctrl_blk),
281362306a36Sopenharmony_ci				 FLASH_OPT_RMW_COMMIT);
281462306a36Sopenharmony_ci	if (rval != QLA_SUCCESS) {
281562306a36Sopenharmony_ci		ql4_printk(KERN_ERR, ha, "%s: set flash mbx failed\n",
281662306a36Sopenharmony_ci			   __func__);
281762306a36Sopenharmony_ci		rval = -EIO;
281862306a36Sopenharmony_ci		goto exit_init_fw_cb;
281962306a36Sopenharmony_ci	}
282062306a36Sopenharmony_ci
282162306a36Sopenharmony_ci	rval = qla4xxx_disable_acb(ha);
282262306a36Sopenharmony_ci	if (rval != QLA_SUCCESS) {
282362306a36Sopenharmony_ci		ql4_printk(KERN_ERR, ha, "%s: disable acb mbx failed\n",
282462306a36Sopenharmony_ci			   __func__);
282562306a36Sopenharmony_ci		rval = -EIO;
282662306a36Sopenharmony_ci		goto exit_init_fw_cb;
282762306a36Sopenharmony_ci	}
282862306a36Sopenharmony_ci
282962306a36Sopenharmony_ci	wait_for_completion_timeout(&ha->disable_acb_comp,
283062306a36Sopenharmony_ci				    DISABLE_ACB_TOV * HZ);
283162306a36Sopenharmony_ci
283262306a36Sopenharmony_ci	qla4xxx_initcb_to_acb(init_fw_cb);
283362306a36Sopenharmony_ci
283462306a36Sopenharmony_ci	rval = qla4xxx_set_acb(ha, &mbox_cmd[0], &mbox_sts[0], init_fw_cb_dma);
283562306a36Sopenharmony_ci	if (rval != QLA_SUCCESS) {
283662306a36Sopenharmony_ci		ql4_printk(KERN_ERR, ha, "%s: set acb mbx failed\n",
283762306a36Sopenharmony_ci			   __func__);
283862306a36Sopenharmony_ci		rval = -EIO;
283962306a36Sopenharmony_ci		goto exit_init_fw_cb;
284062306a36Sopenharmony_ci	}
284162306a36Sopenharmony_ci
284262306a36Sopenharmony_ci	memset(init_fw_cb, 0, sizeof(struct addr_ctrl_blk));
284362306a36Sopenharmony_ci	qla4xxx_update_local_ifcb(ha, &mbox_cmd[0], &mbox_sts[0], init_fw_cb,
284462306a36Sopenharmony_ci				  init_fw_cb_dma);
284562306a36Sopenharmony_ci
284662306a36Sopenharmony_ciexit_init_fw_cb:
284762306a36Sopenharmony_ci	dma_free_coherent(&ha->pdev->dev, sizeof(struct addr_ctrl_blk),
284862306a36Sopenharmony_ci			  init_fw_cb, init_fw_cb_dma);
284962306a36Sopenharmony_ci
285062306a36Sopenharmony_ci	return rval;
285162306a36Sopenharmony_ci}
285262306a36Sopenharmony_ci
285362306a36Sopenharmony_cistatic int qla4xxx_session_get_param(struct iscsi_cls_session *cls_sess,
285462306a36Sopenharmony_ci				     enum iscsi_param param, char *buf)
285562306a36Sopenharmony_ci{
285662306a36Sopenharmony_ci	struct iscsi_session *sess = cls_sess->dd_data;
285762306a36Sopenharmony_ci	struct ddb_entry *ddb_entry = sess->dd_data;
285862306a36Sopenharmony_ci	struct scsi_qla_host *ha = ddb_entry->ha;
285962306a36Sopenharmony_ci	struct iscsi_cls_conn *cls_conn = ddb_entry->conn;
286062306a36Sopenharmony_ci	struct ql4_chap_table chap_tbl;
286162306a36Sopenharmony_ci	int rval, len;
286262306a36Sopenharmony_ci	uint16_t idx;
286362306a36Sopenharmony_ci
286462306a36Sopenharmony_ci	memset(&chap_tbl, 0, sizeof(chap_tbl));
286562306a36Sopenharmony_ci	switch (param) {
286662306a36Sopenharmony_ci	case ISCSI_PARAM_CHAP_IN_IDX:
286762306a36Sopenharmony_ci		rval = qla4xxx_get_chap_index(ha, sess->username_in,
286862306a36Sopenharmony_ci					      sess->password_in, BIDI_CHAP,
286962306a36Sopenharmony_ci					      &idx);
287062306a36Sopenharmony_ci		if (rval)
287162306a36Sopenharmony_ci			len = sprintf(buf, "\n");
287262306a36Sopenharmony_ci		else
287362306a36Sopenharmony_ci			len = sprintf(buf, "%hu\n", idx);
287462306a36Sopenharmony_ci		break;
287562306a36Sopenharmony_ci	case ISCSI_PARAM_CHAP_OUT_IDX:
287662306a36Sopenharmony_ci		if (ddb_entry->ddb_type == FLASH_DDB) {
287762306a36Sopenharmony_ci			if (ddb_entry->chap_tbl_idx != INVALID_ENTRY) {
287862306a36Sopenharmony_ci				idx = ddb_entry->chap_tbl_idx;
287962306a36Sopenharmony_ci				rval = QLA_SUCCESS;
288062306a36Sopenharmony_ci			} else {
288162306a36Sopenharmony_ci				rval = QLA_ERROR;
288262306a36Sopenharmony_ci			}
288362306a36Sopenharmony_ci		} else {
288462306a36Sopenharmony_ci			rval = qla4xxx_get_chap_index(ha, sess->username,
288562306a36Sopenharmony_ci						      sess->password,
288662306a36Sopenharmony_ci						      LOCAL_CHAP, &idx);
288762306a36Sopenharmony_ci		}
288862306a36Sopenharmony_ci		if (rval)
288962306a36Sopenharmony_ci			len = sprintf(buf, "\n");
289062306a36Sopenharmony_ci		else
289162306a36Sopenharmony_ci			len = sprintf(buf, "%hu\n", idx);
289262306a36Sopenharmony_ci		break;
289362306a36Sopenharmony_ci	case ISCSI_PARAM_USERNAME:
289462306a36Sopenharmony_ci	case ISCSI_PARAM_PASSWORD:
289562306a36Sopenharmony_ci		/* First, populate session username and password for FLASH DDB,
289662306a36Sopenharmony_ci		 * if not already done. This happens when session login fails
289762306a36Sopenharmony_ci		 * for a FLASH DDB.
289862306a36Sopenharmony_ci		 */
289962306a36Sopenharmony_ci		if (ddb_entry->ddb_type == FLASH_DDB &&
290062306a36Sopenharmony_ci		    ddb_entry->chap_tbl_idx != INVALID_ENTRY &&
290162306a36Sopenharmony_ci		    !sess->username && !sess->password) {
290262306a36Sopenharmony_ci			idx = ddb_entry->chap_tbl_idx;
290362306a36Sopenharmony_ci			rval = qla4xxx_get_uni_chap_at_index(ha, chap_tbl.name,
290462306a36Sopenharmony_ci							    chap_tbl.secret,
290562306a36Sopenharmony_ci							    idx);
290662306a36Sopenharmony_ci			if (!rval) {
290762306a36Sopenharmony_ci				iscsi_set_param(cls_conn, ISCSI_PARAM_USERNAME,
290862306a36Sopenharmony_ci						(char *)chap_tbl.name,
290962306a36Sopenharmony_ci						strlen((char *)chap_tbl.name));
291062306a36Sopenharmony_ci				iscsi_set_param(cls_conn, ISCSI_PARAM_PASSWORD,
291162306a36Sopenharmony_ci						(char *)chap_tbl.secret,
291262306a36Sopenharmony_ci						chap_tbl.secret_len);
291362306a36Sopenharmony_ci			}
291462306a36Sopenharmony_ci		}
291562306a36Sopenharmony_ci		fallthrough;
291662306a36Sopenharmony_ci	default:
291762306a36Sopenharmony_ci		return iscsi_session_get_param(cls_sess, param, buf);
291862306a36Sopenharmony_ci	}
291962306a36Sopenharmony_ci
292062306a36Sopenharmony_ci	return len;
292162306a36Sopenharmony_ci}
292262306a36Sopenharmony_ci
292362306a36Sopenharmony_cistatic int qla4xxx_conn_get_param(struct iscsi_cls_conn *cls_conn,
292462306a36Sopenharmony_ci				  enum iscsi_param param, char *buf)
292562306a36Sopenharmony_ci{
292662306a36Sopenharmony_ci	struct iscsi_conn *conn;
292762306a36Sopenharmony_ci	struct qla_conn *qla_conn;
292862306a36Sopenharmony_ci	struct sockaddr *dst_addr;
292962306a36Sopenharmony_ci
293062306a36Sopenharmony_ci	conn = cls_conn->dd_data;
293162306a36Sopenharmony_ci	qla_conn = conn->dd_data;
293262306a36Sopenharmony_ci	dst_addr = (struct sockaddr *)&qla_conn->qla_ep->dst_addr;
293362306a36Sopenharmony_ci
293462306a36Sopenharmony_ci	switch (param) {
293562306a36Sopenharmony_ci	case ISCSI_PARAM_CONN_PORT:
293662306a36Sopenharmony_ci	case ISCSI_PARAM_CONN_ADDRESS:
293762306a36Sopenharmony_ci		return iscsi_conn_get_addr_param((struct sockaddr_storage *)
293862306a36Sopenharmony_ci						 dst_addr, param, buf);
293962306a36Sopenharmony_ci	default:
294062306a36Sopenharmony_ci		return iscsi_conn_get_param(cls_conn, param, buf);
294162306a36Sopenharmony_ci	}
294262306a36Sopenharmony_ci}
294362306a36Sopenharmony_ci
294462306a36Sopenharmony_ciint qla4xxx_get_ddb_index(struct scsi_qla_host *ha, uint16_t *ddb_index)
294562306a36Sopenharmony_ci{
294662306a36Sopenharmony_ci	uint32_t mbx_sts = 0;
294762306a36Sopenharmony_ci	uint16_t tmp_ddb_index;
294862306a36Sopenharmony_ci	int ret;
294962306a36Sopenharmony_ci
295062306a36Sopenharmony_ciget_ddb_index:
295162306a36Sopenharmony_ci	tmp_ddb_index = find_first_zero_bit(ha->ddb_idx_map, MAX_DDB_ENTRIES);
295262306a36Sopenharmony_ci
295362306a36Sopenharmony_ci	if (tmp_ddb_index >= MAX_DDB_ENTRIES) {
295462306a36Sopenharmony_ci		DEBUG2(ql4_printk(KERN_INFO, ha,
295562306a36Sopenharmony_ci				  "Free DDB index not available\n"));
295662306a36Sopenharmony_ci		ret = QLA_ERROR;
295762306a36Sopenharmony_ci		goto exit_get_ddb_index;
295862306a36Sopenharmony_ci	}
295962306a36Sopenharmony_ci
296062306a36Sopenharmony_ci	if (test_and_set_bit(tmp_ddb_index, ha->ddb_idx_map))
296162306a36Sopenharmony_ci		goto get_ddb_index;
296262306a36Sopenharmony_ci
296362306a36Sopenharmony_ci	DEBUG2(ql4_printk(KERN_INFO, ha,
296462306a36Sopenharmony_ci			  "Found a free DDB index at %d\n", tmp_ddb_index));
296562306a36Sopenharmony_ci	ret = qla4xxx_req_ddb_entry(ha, tmp_ddb_index, &mbx_sts);
296662306a36Sopenharmony_ci	if (ret == QLA_ERROR) {
296762306a36Sopenharmony_ci		if (mbx_sts == MBOX_STS_COMMAND_ERROR) {
296862306a36Sopenharmony_ci			ql4_printk(KERN_INFO, ha,
296962306a36Sopenharmony_ci				   "DDB index = %d not available trying next\n",
297062306a36Sopenharmony_ci				   tmp_ddb_index);
297162306a36Sopenharmony_ci			goto get_ddb_index;
297262306a36Sopenharmony_ci		}
297362306a36Sopenharmony_ci		DEBUG2(ql4_printk(KERN_INFO, ha,
297462306a36Sopenharmony_ci				  "Free FW DDB not available\n"));
297562306a36Sopenharmony_ci	}
297662306a36Sopenharmony_ci
297762306a36Sopenharmony_ci	*ddb_index = tmp_ddb_index;
297862306a36Sopenharmony_ci
297962306a36Sopenharmony_ciexit_get_ddb_index:
298062306a36Sopenharmony_ci	return ret;
298162306a36Sopenharmony_ci}
298262306a36Sopenharmony_ci
298362306a36Sopenharmony_cistatic int qla4xxx_match_ipaddress(struct scsi_qla_host *ha,
298462306a36Sopenharmony_ci				   struct ddb_entry *ddb_entry,
298562306a36Sopenharmony_ci				   char *existing_ipaddr,
298662306a36Sopenharmony_ci				   char *user_ipaddr)
298762306a36Sopenharmony_ci{
298862306a36Sopenharmony_ci	uint8_t dst_ipaddr[IPv6_ADDR_LEN];
298962306a36Sopenharmony_ci	char formatted_ipaddr[DDB_IPADDR_LEN];
299062306a36Sopenharmony_ci	int status = QLA_SUCCESS, ret = 0;
299162306a36Sopenharmony_ci
299262306a36Sopenharmony_ci	if (ddb_entry->fw_ddb_entry.options & DDB_OPT_IPV6_DEVICE) {
299362306a36Sopenharmony_ci		ret = in6_pton(user_ipaddr, strlen(user_ipaddr), dst_ipaddr,
299462306a36Sopenharmony_ci			       '\0', NULL);
299562306a36Sopenharmony_ci		if (ret == 0) {
299662306a36Sopenharmony_ci			status = QLA_ERROR;
299762306a36Sopenharmony_ci			goto out_match;
299862306a36Sopenharmony_ci		}
299962306a36Sopenharmony_ci		ret = sprintf(formatted_ipaddr, "%pI6", dst_ipaddr);
300062306a36Sopenharmony_ci	} else {
300162306a36Sopenharmony_ci		ret = in4_pton(user_ipaddr, strlen(user_ipaddr), dst_ipaddr,
300262306a36Sopenharmony_ci			       '\0', NULL);
300362306a36Sopenharmony_ci		if (ret == 0) {
300462306a36Sopenharmony_ci			status = QLA_ERROR;
300562306a36Sopenharmony_ci			goto out_match;
300662306a36Sopenharmony_ci		}
300762306a36Sopenharmony_ci		ret = sprintf(formatted_ipaddr, "%pI4", dst_ipaddr);
300862306a36Sopenharmony_ci	}
300962306a36Sopenharmony_ci
301062306a36Sopenharmony_ci	if (strcmp(existing_ipaddr, formatted_ipaddr))
301162306a36Sopenharmony_ci		status = QLA_ERROR;
301262306a36Sopenharmony_ci
301362306a36Sopenharmony_ciout_match:
301462306a36Sopenharmony_ci	return status;
301562306a36Sopenharmony_ci}
301662306a36Sopenharmony_ci
301762306a36Sopenharmony_cistatic int qla4xxx_match_fwdb_session(struct scsi_qla_host *ha,
301862306a36Sopenharmony_ci				      struct iscsi_cls_conn *cls_conn)
301962306a36Sopenharmony_ci{
302062306a36Sopenharmony_ci	int idx = 0, max_ddbs, rval;
302162306a36Sopenharmony_ci	struct iscsi_cls_session *cls_sess = iscsi_conn_to_session(cls_conn);
302262306a36Sopenharmony_ci	struct iscsi_session *sess, *existing_sess;
302362306a36Sopenharmony_ci	struct iscsi_conn *conn, *existing_conn;
302462306a36Sopenharmony_ci	struct ddb_entry *ddb_entry;
302562306a36Sopenharmony_ci
302662306a36Sopenharmony_ci	sess = cls_sess->dd_data;
302762306a36Sopenharmony_ci	conn = cls_conn->dd_data;
302862306a36Sopenharmony_ci
302962306a36Sopenharmony_ci	if (sess->targetname == NULL ||
303062306a36Sopenharmony_ci	    conn->persistent_address == NULL ||
303162306a36Sopenharmony_ci	    conn->persistent_port == 0)
303262306a36Sopenharmony_ci		return QLA_ERROR;
303362306a36Sopenharmony_ci
303462306a36Sopenharmony_ci	max_ddbs =  is_qla40XX(ha) ? MAX_DEV_DB_ENTRIES_40XX :
303562306a36Sopenharmony_ci				     MAX_DEV_DB_ENTRIES;
303662306a36Sopenharmony_ci
303762306a36Sopenharmony_ci	for (idx = 0; idx < max_ddbs; idx++) {
303862306a36Sopenharmony_ci		ddb_entry = qla4xxx_lookup_ddb_by_fw_index(ha, idx);
303962306a36Sopenharmony_ci		if (ddb_entry == NULL)
304062306a36Sopenharmony_ci			continue;
304162306a36Sopenharmony_ci
304262306a36Sopenharmony_ci		if (ddb_entry->ddb_type != FLASH_DDB)
304362306a36Sopenharmony_ci			continue;
304462306a36Sopenharmony_ci
304562306a36Sopenharmony_ci		existing_sess = ddb_entry->sess->dd_data;
304662306a36Sopenharmony_ci		existing_conn = ddb_entry->conn->dd_data;
304762306a36Sopenharmony_ci
304862306a36Sopenharmony_ci		if (existing_sess->targetname == NULL ||
304962306a36Sopenharmony_ci		    existing_conn->persistent_address == NULL ||
305062306a36Sopenharmony_ci		    existing_conn->persistent_port == 0)
305162306a36Sopenharmony_ci			continue;
305262306a36Sopenharmony_ci
305362306a36Sopenharmony_ci		DEBUG2(ql4_printk(KERN_INFO, ha,
305462306a36Sopenharmony_ci				  "IQN = %s User IQN = %s\n",
305562306a36Sopenharmony_ci				  existing_sess->targetname,
305662306a36Sopenharmony_ci				  sess->targetname));
305762306a36Sopenharmony_ci
305862306a36Sopenharmony_ci		DEBUG2(ql4_printk(KERN_INFO, ha,
305962306a36Sopenharmony_ci				  "IP = %s User IP = %s\n",
306062306a36Sopenharmony_ci				  existing_conn->persistent_address,
306162306a36Sopenharmony_ci				  conn->persistent_address));
306262306a36Sopenharmony_ci
306362306a36Sopenharmony_ci		DEBUG2(ql4_printk(KERN_INFO, ha,
306462306a36Sopenharmony_ci				  "Port = %d User Port = %d\n",
306562306a36Sopenharmony_ci				  existing_conn->persistent_port,
306662306a36Sopenharmony_ci				  conn->persistent_port));
306762306a36Sopenharmony_ci
306862306a36Sopenharmony_ci		if (strcmp(existing_sess->targetname, sess->targetname))
306962306a36Sopenharmony_ci			continue;
307062306a36Sopenharmony_ci		rval = qla4xxx_match_ipaddress(ha, ddb_entry,
307162306a36Sopenharmony_ci					existing_conn->persistent_address,
307262306a36Sopenharmony_ci					conn->persistent_address);
307362306a36Sopenharmony_ci		if (rval == QLA_ERROR)
307462306a36Sopenharmony_ci			continue;
307562306a36Sopenharmony_ci		if (existing_conn->persistent_port != conn->persistent_port)
307662306a36Sopenharmony_ci			continue;
307762306a36Sopenharmony_ci		break;
307862306a36Sopenharmony_ci	}
307962306a36Sopenharmony_ci
308062306a36Sopenharmony_ci	if (idx == max_ddbs)
308162306a36Sopenharmony_ci		return QLA_ERROR;
308262306a36Sopenharmony_ci
308362306a36Sopenharmony_ci	DEBUG2(ql4_printk(KERN_INFO, ha,
308462306a36Sopenharmony_ci			  "Match found in fwdb sessions\n"));
308562306a36Sopenharmony_ci	return QLA_SUCCESS;
308662306a36Sopenharmony_ci}
308762306a36Sopenharmony_ci
308862306a36Sopenharmony_cistatic struct iscsi_cls_session *
308962306a36Sopenharmony_ciqla4xxx_session_create(struct iscsi_endpoint *ep,
309062306a36Sopenharmony_ci			uint16_t cmds_max, uint16_t qdepth,
309162306a36Sopenharmony_ci			uint32_t initial_cmdsn)
309262306a36Sopenharmony_ci{
309362306a36Sopenharmony_ci	struct iscsi_cls_session *cls_sess;
309462306a36Sopenharmony_ci	struct scsi_qla_host *ha;
309562306a36Sopenharmony_ci	struct qla_endpoint *qla_ep;
309662306a36Sopenharmony_ci	struct ddb_entry *ddb_entry;
309762306a36Sopenharmony_ci	uint16_t ddb_index;
309862306a36Sopenharmony_ci	struct iscsi_session *sess;
309962306a36Sopenharmony_ci	int ret;
310062306a36Sopenharmony_ci
310162306a36Sopenharmony_ci	if (!ep) {
310262306a36Sopenharmony_ci		printk(KERN_ERR "qla4xxx: missing ep.\n");
310362306a36Sopenharmony_ci		return NULL;
310462306a36Sopenharmony_ci	}
310562306a36Sopenharmony_ci
310662306a36Sopenharmony_ci	qla_ep = ep->dd_data;
310762306a36Sopenharmony_ci	ha = to_qla_host(qla_ep->host);
310862306a36Sopenharmony_ci	DEBUG2(ql4_printk(KERN_INFO, ha, "%s: host: %ld\n", __func__,
310962306a36Sopenharmony_ci			  ha->host_no));
311062306a36Sopenharmony_ci
311162306a36Sopenharmony_ci	ret = qla4xxx_get_ddb_index(ha, &ddb_index);
311262306a36Sopenharmony_ci	if (ret == QLA_ERROR)
311362306a36Sopenharmony_ci		return NULL;
311462306a36Sopenharmony_ci
311562306a36Sopenharmony_ci	cls_sess = iscsi_session_setup(&qla4xxx_iscsi_transport, qla_ep->host,
311662306a36Sopenharmony_ci				       cmds_max, sizeof(struct ddb_entry),
311762306a36Sopenharmony_ci				       sizeof(struct ql4_task_data),
311862306a36Sopenharmony_ci				       initial_cmdsn, ddb_index);
311962306a36Sopenharmony_ci	if (!cls_sess)
312062306a36Sopenharmony_ci		return NULL;
312162306a36Sopenharmony_ci
312262306a36Sopenharmony_ci	sess = cls_sess->dd_data;
312362306a36Sopenharmony_ci	ddb_entry = sess->dd_data;
312462306a36Sopenharmony_ci	ddb_entry->fw_ddb_index = ddb_index;
312562306a36Sopenharmony_ci	ddb_entry->fw_ddb_device_state = DDB_DS_NO_CONNECTION_ACTIVE;
312662306a36Sopenharmony_ci	ddb_entry->ha = ha;
312762306a36Sopenharmony_ci	ddb_entry->sess = cls_sess;
312862306a36Sopenharmony_ci	ddb_entry->unblock_sess = qla4xxx_unblock_ddb;
312962306a36Sopenharmony_ci	ddb_entry->ddb_change = qla4xxx_ddb_change;
313062306a36Sopenharmony_ci	clear_bit(DDB_CONN_CLOSE_FAILURE, &ddb_entry->flags);
313162306a36Sopenharmony_ci	cls_sess->recovery_tmo = ql4xsess_recovery_tmo;
313262306a36Sopenharmony_ci	ha->fw_ddb_index_map[ddb_entry->fw_ddb_index] = ddb_entry;
313362306a36Sopenharmony_ci	ha->tot_ddbs++;
313462306a36Sopenharmony_ci
313562306a36Sopenharmony_ci	return cls_sess;
313662306a36Sopenharmony_ci}
313762306a36Sopenharmony_ci
313862306a36Sopenharmony_cistatic void qla4xxx_session_destroy(struct iscsi_cls_session *cls_sess)
313962306a36Sopenharmony_ci{
314062306a36Sopenharmony_ci	struct iscsi_session *sess;
314162306a36Sopenharmony_ci	struct ddb_entry *ddb_entry;
314262306a36Sopenharmony_ci	struct scsi_qla_host *ha;
314362306a36Sopenharmony_ci	unsigned long flags, wtime;
314462306a36Sopenharmony_ci	struct dev_db_entry *fw_ddb_entry = NULL;
314562306a36Sopenharmony_ci	dma_addr_t fw_ddb_entry_dma;
314662306a36Sopenharmony_ci	uint32_t ddb_state;
314762306a36Sopenharmony_ci	int ret;
314862306a36Sopenharmony_ci
314962306a36Sopenharmony_ci	sess = cls_sess->dd_data;
315062306a36Sopenharmony_ci	ddb_entry = sess->dd_data;
315162306a36Sopenharmony_ci	ha = ddb_entry->ha;
315262306a36Sopenharmony_ci	DEBUG2(ql4_printk(KERN_INFO, ha, "%s: host: %ld\n", __func__,
315362306a36Sopenharmony_ci			  ha->host_no));
315462306a36Sopenharmony_ci
315562306a36Sopenharmony_ci	fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
315662306a36Sopenharmony_ci					  &fw_ddb_entry_dma, GFP_KERNEL);
315762306a36Sopenharmony_ci	if (!fw_ddb_entry) {
315862306a36Sopenharmony_ci		ql4_printk(KERN_ERR, ha,
315962306a36Sopenharmony_ci			   "%s: Unable to allocate dma buffer\n", __func__);
316062306a36Sopenharmony_ci		goto destroy_session;
316162306a36Sopenharmony_ci	}
316262306a36Sopenharmony_ci
316362306a36Sopenharmony_ci	wtime = jiffies + (HZ * LOGOUT_TOV);
316462306a36Sopenharmony_ci	do {
316562306a36Sopenharmony_ci		ret = qla4xxx_get_fwddb_entry(ha, ddb_entry->fw_ddb_index,
316662306a36Sopenharmony_ci					      fw_ddb_entry, fw_ddb_entry_dma,
316762306a36Sopenharmony_ci					      NULL, NULL, &ddb_state, NULL,
316862306a36Sopenharmony_ci					      NULL, NULL);
316962306a36Sopenharmony_ci		if (ret == QLA_ERROR)
317062306a36Sopenharmony_ci			goto destroy_session;
317162306a36Sopenharmony_ci
317262306a36Sopenharmony_ci		if ((ddb_state == DDB_DS_NO_CONNECTION_ACTIVE) ||
317362306a36Sopenharmony_ci		    (ddb_state == DDB_DS_SESSION_FAILED))
317462306a36Sopenharmony_ci			goto destroy_session;
317562306a36Sopenharmony_ci
317662306a36Sopenharmony_ci		schedule_timeout_uninterruptible(HZ);
317762306a36Sopenharmony_ci	} while ((time_after(wtime, jiffies)));
317862306a36Sopenharmony_ci
317962306a36Sopenharmony_cidestroy_session:
318062306a36Sopenharmony_ci	qla4xxx_clear_ddb_entry(ha, ddb_entry->fw_ddb_index);
318162306a36Sopenharmony_ci	if (test_and_clear_bit(DDB_CONN_CLOSE_FAILURE, &ddb_entry->flags))
318262306a36Sopenharmony_ci		clear_bit(ddb_entry->fw_ddb_index, ha->ddb_idx_map);
318362306a36Sopenharmony_ci	spin_lock_irqsave(&ha->hardware_lock, flags);
318462306a36Sopenharmony_ci	qla4xxx_free_ddb(ha, ddb_entry);
318562306a36Sopenharmony_ci	spin_unlock_irqrestore(&ha->hardware_lock, flags);
318662306a36Sopenharmony_ci
318762306a36Sopenharmony_ci	iscsi_session_teardown(cls_sess);
318862306a36Sopenharmony_ci
318962306a36Sopenharmony_ci	if (fw_ddb_entry)
319062306a36Sopenharmony_ci		dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
319162306a36Sopenharmony_ci				  fw_ddb_entry, fw_ddb_entry_dma);
319262306a36Sopenharmony_ci}
319362306a36Sopenharmony_ci
319462306a36Sopenharmony_cistatic struct iscsi_cls_conn *
319562306a36Sopenharmony_ciqla4xxx_conn_create(struct iscsi_cls_session *cls_sess, uint32_t conn_idx)
319662306a36Sopenharmony_ci{
319762306a36Sopenharmony_ci	struct iscsi_cls_conn *cls_conn;
319862306a36Sopenharmony_ci	struct iscsi_session *sess;
319962306a36Sopenharmony_ci	struct ddb_entry *ddb_entry;
320062306a36Sopenharmony_ci	struct scsi_qla_host *ha;
320162306a36Sopenharmony_ci
320262306a36Sopenharmony_ci	cls_conn = iscsi_conn_setup(cls_sess, sizeof(struct qla_conn),
320362306a36Sopenharmony_ci				    conn_idx);
320462306a36Sopenharmony_ci	if (!cls_conn) {
320562306a36Sopenharmony_ci		pr_info("%s: Can not create connection for conn_idx = %u\n",
320662306a36Sopenharmony_ci			__func__, conn_idx);
320762306a36Sopenharmony_ci		return NULL;
320862306a36Sopenharmony_ci	}
320962306a36Sopenharmony_ci
321062306a36Sopenharmony_ci	sess = cls_sess->dd_data;
321162306a36Sopenharmony_ci	ddb_entry = sess->dd_data;
321262306a36Sopenharmony_ci	ddb_entry->conn = cls_conn;
321362306a36Sopenharmony_ci
321462306a36Sopenharmony_ci	ha = ddb_entry->ha;
321562306a36Sopenharmony_ci	DEBUG2(ql4_printk(KERN_INFO, ha, "%s: conn_idx = %u\n", __func__,
321662306a36Sopenharmony_ci			  conn_idx));
321762306a36Sopenharmony_ci	return cls_conn;
321862306a36Sopenharmony_ci}
321962306a36Sopenharmony_ci
322062306a36Sopenharmony_cistatic int qla4xxx_conn_bind(struct iscsi_cls_session *cls_session,
322162306a36Sopenharmony_ci			     struct iscsi_cls_conn *cls_conn,
322262306a36Sopenharmony_ci			     uint64_t transport_fd, int is_leading)
322362306a36Sopenharmony_ci{
322462306a36Sopenharmony_ci	struct iscsi_conn *conn;
322562306a36Sopenharmony_ci	struct qla_conn *qla_conn;
322662306a36Sopenharmony_ci	struct iscsi_endpoint *ep;
322762306a36Sopenharmony_ci	struct ddb_entry *ddb_entry;
322862306a36Sopenharmony_ci	struct scsi_qla_host *ha;
322962306a36Sopenharmony_ci	struct iscsi_session *sess;
323062306a36Sopenharmony_ci
323162306a36Sopenharmony_ci	sess = cls_session->dd_data;
323262306a36Sopenharmony_ci	ddb_entry = sess->dd_data;
323362306a36Sopenharmony_ci	ha = ddb_entry->ha;
323462306a36Sopenharmony_ci
323562306a36Sopenharmony_ci	DEBUG2(ql4_printk(KERN_INFO, ha, "%s: sid = %d, cid = %d\n", __func__,
323662306a36Sopenharmony_ci			  cls_session->sid, cls_conn->cid));
323762306a36Sopenharmony_ci
323862306a36Sopenharmony_ci	if (iscsi_conn_bind(cls_session, cls_conn, is_leading))
323962306a36Sopenharmony_ci		return -EINVAL;
324062306a36Sopenharmony_ci	ep = iscsi_lookup_endpoint(transport_fd);
324162306a36Sopenharmony_ci	if (!ep)
324262306a36Sopenharmony_ci		return -EINVAL;
324362306a36Sopenharmony_ci	conn = cls_conn->dd_data;
324462306a36Sopenharmony_ci	qla_conn = conn->dd_data;
324562306a36Sopenharmony_ci	qla_conn->qla_ep = ep->dd_data;
324662306a36Sopenharmony_ci	iscsi_put_endpoint(ep);
324762306a36Sopenharmony_ci	return 0;
324862306a36Sopenharmony_ci}
324962306a36Sopenharmony_ci
325062306a36Sopenharmony_cistatic int qla4xxx_conn_start(struct iscsi_cls_conn *cls_conn)
325162306a36Sopenharmony_ci{
325262306a36Sopenharmony_ci	struct iscsi_cls_session *cls_sess = iscsi_conn_to_session(cls_conn);
325362306a36Sopenharmony_ci	struct iscsi_session *sess;
325462306a36Sopenharmony_ci	struct ddb_entry *ddb_entry;
325562306a36Sopenharmony_ci	struct scsi_qla_host *ha;
325662306a36Sopenharmony_ci	struct dev_db_entry *fw_ddb_entry = NULL;
325762306a36Sopenharmony_ci	dma_addr_t fw_ddb_entry_dma;
325862306a36Sopenharmony_ci	uint32_t mbx_sts = 0;
325962306a36Sopenharmony_ci	int ret = 0;
326062306a36Sopenharmony_ci	int status = QLA_SUCCESS;
326162306a36Sopenharmony_ci
326262306a36Sopenharmony_ci	sess = cls_sess->dd_data;
326362306a36Sopenharmony_ci	ddb_entry = sess->dd_data;
326462306a36Sopenharmony_ci	ha = ddb_entry->ha;
326562306a36Sopenharmony_ci	DEBUG2(ql4_printk(KERN_INFO, ha, "%s: sid = %d, cid = %d\n", __func__,
326662306a36Sopenharmony_ci			  cls_sess->sid, cls_conn->cid));
326762306a36Sopenharmony_ci
326862306a36Sopenharmony_ci	/* Check if we have  matching FW DDB, if yes then do not
326962306a36Sopenharmony_ci	 * login to this target. This could cause target to logout previous
327062306a36Sopenharmony_ci	 * connection
327162306a36Sopenharmony_ci	 */
327262306a36Sopenharmony_ci	ret = qla4xxx_match_fwdb_session(ha, cls_conn);
327362306a36Sopenharmony_ci	if (ret == QLA_SUCCESS) {
327462306a36Sopenharmony_ci		ql4_printk(KERN_INFO, ha,
327562306a36Sopenharmony_ci			   "Session already exist in FW.\n");
327662306a36Sopenharmony_ci		ret = -EEXIST;
327762306a36Sopenharmony_ci		goto exit_conn_start;
327862306a36Sopenharmony_ci	}
327962306a36Sopenharmony_ci
328062306a36Sopenharmony_ci	fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
328162306a36Sopenharmony_ci					  &fw_ddb_entry_dma, GFP_KERNEL);
328262306a36Sopenharmony_ci	if (!fw_ddb_entry) {
328362306a36Sopenharmony_ci		ql4_printk(KERN_ERR, ha,
328462306a36Sopenharmony_ci			   "%s: Unable to allocate dma buffer\n", __func__);
328562306a36Sopenharmony_ci		ret = -ENOMEM;
328662306a36Sopenharmony_ci		goto exit_conn_start;
328762306a36Sopenharmony_ci	}
328862306a36Sopenharmony_ci
328962306a36Sopenharmony_ci	ret = qla4xxx_set_param_ddbentry(ha, ddb_entry, cls_conn, &mbx_sts);
329062306a36Sopenharmony_ci	if (ret) {
329162306a36Sopenharmony_ci		/* If iscsid is stopped and started then no need to do
329262306a36Sopenharmony_ci		* set param again since ddb state will be already
329362306a36Sopenharmony_ci		* active and FW does not allow set ddb to an
329462306a36Sopenharmony_ci		* active session.
329562306a36Sopenharmony_ci		*/
329662306a36Sopenharmony_ci		if (mbx_sts)
329762306a36Sopenharmony_ci			if (ddb_entry->fw_ddb_device_state ==
329862306a36Sopenharmony_ci						DDB_DS_SESSION_ACTIVE) {
329962306a36Sopenharmony_ci				ddb_entry->unblock_sess(ddb_entry->sess);
330062306a36Sopenharmony_ci				goto exit_set_param;
330162306a36Sopenharmony_ci			}
330262306a36Sopenharmony_ci
330362306a36Sopenharmony_ci		ql4_printk(KERN_ERR, ha, "%s: Failed set param for index[%d]\n",
330462306a36Sopenharmony_ci			   __func__, ddb_entry->fw_ddb_index);
330562306a36Sopenharmony_ci		goto exit_conn_start;
330662306a36Sopenharmony_ci	}
330762306a36Sopenharmony_ci
330862306a36Sopenharmony_ci	status = qla4xxx_conn_open(ha, ddb_entry->fw_ddb_index);
330962306a36Sopenharmony_ci	if (status == QLA_ERROR) {
331062306a36Sopenharmony_ci		ql4_printk(KERN_ERR, ha, "%s: Login failed: %s\n", __func__,
331162306a36Sopenharmony_ci			   sess->targetname);
331262306a36Sopenharmony_ci		ret = -EINVAL;
331362306a36Sopenharmony_ci		goto exit_conn_start;
331462306a36Sopenharmony_ci	}
331562306a36Sopenharmony_ci
331662306a36Sopenharmony_ci	if (ddb_entry->fw_ddb_device_state == DDB_DS_NO_CONNECTION_ACTIVE)
331762306a36Sopenharmony_ci		ddb_entry->fw_ddb_device_state = DDB_DS_LOGIN_IN_PROCESS;
331862306a36Sopenharmony_ci
331962306a36Sopenharmony_ci	DEBUG2(printk(KERN_INFO "%s: DDB state [%d]\n", __func__,
332062306a36Sopenharmony_ci		      ddb_entry->fw_ddb_device_state));
332162306a36Sopenharmony_ci
332262306a36Sopenharmony_ciexit_set_param:
332362306a36Sopenharmony_ci	ret = 0;
332462306a36Sopenharmony_ci
332562306a36Sopenharmony_ciexit_conn_start:
332662306a36Sopenharmony_ci	if (fw_ddb_entry)
332762306a36Sopenharmony_ci		dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
332862306a36Sopenharmony_ci				  fw_ddb_entry, fw_ddb_entry_dma);
332962306a36Sopenharmony_ci	return ret;
333062306a36Sopenharmony_ci}
333162306a36Sopenharmony_ci
333262306a36Sopenharmony_cistatic void qla4xxx_conn_destroy(struct iscsi_cls_conn *cls_conn)
333362306a36Sopenharmony_ci{
333462306a36Sopenharmony_ci	struct iscsi_cls_session *cls_sess = iscsi_conn_to_session(cls_conn);
333562306a36Sopenharmony_ci	struct iscsi_session *sess;
333662306a36Sopenharmony_ci	struct scsi_qla_host *ha;
333762306a36Sopenharmony_ci	struct ddb_entry *ddb_entry;
333862306a36Sopenharmony_ci	int options;
333962306a36Sopenharmony_ci
334062306a36Sopenharmony_ci	sess = cls_sess->dd_data;
334162306a36Sopenharmony_ci	ddb_entry = sess->dd_data;
334262306a36Sopenharmony_ci	ha = ddb_entry->ha;
334362306a36Sopenharmony_ci	DEBUG2(ql4_printk(KERN_INFO, ha, "%s: cid = %d\n", __func__,
334462306a36Sopenharmony_ci			  cls_conn->cid));
334562306a36Sopenharmony_ci
334662306a36Sopenharmony_ci	options = LOGOUT_OPTION_CLOSE_SESSION;
334762306a36Sopenharmony_ci	if (qla4xxx_session_logout_ddb(ha, ddb_entry, options) == QLA_ERROR)
334862306a36Sopenharmony_ci		ql4_printk(KERN_ERR, ha, "%s: Logout failed\n", __func__);
334962306a36Sopenharmony_ci}
335062306a36Sopenharmony_ci
335162306a36Sopenharmony_cistatic void qla4xxx_task_work(struct work_struct *wdata)
335262306a36Sopenharmony_ci{
335362306a36Sopenharmony_ci	struct ql4_task_data *task_data;
335462306a36Sopenharmony_ci	struct scsi_qla_host *ha;
335562306a36Sopenharmony_ci	struct passthru_status *sts;
335662306a36Sopenharmony_ci	struct iscsi_task *task;
335762306a36Sopenharmony_ci	struct iscsi_hdr *hdr;
335862306a36Sopenharmony_ci	uint8_t *data;
335962306a36Sopenharmony_ci	uint32_t data_len;
336062306a36Sopenharmony_ci	struct iscsi_conn *conn;
336162306a36Sopenharmony_ci	int hdr_len;
336262306a36Sopenharmony_ci	itt_t itt;
336362306a36Sopenharmony_ci
336462306a36Sopenharmony_ci	task_data = container_of(wdata, struct ql4_task_data, task_work);
336562306a36Sopenharmony_ci	ha = task_data->ha;
336662306a36Sopenharmony_ci	task = task_data->task;
336762306a36Sopenharmony_ci	sts = &task_data->sts;
336862306a36Sopenharmony_ci	hdr_len = sizeof(struct iscsi_hdr);
336962306a36Sopenharmony_ci
337062306a36Sopenharmony_ci	DEBUG3(printk(KERN_INFO "Status returned\n"));
337162306a36Sopenharmony_ci	DEBUG3(qla4xxx_dump_buffer(sts, 64));
337262306a36Sopenharmony_ci	DEBUG3(printk(KERN_INFO "Response buffer"));
337362306a36Sopenharmony_ci	DEBUG3(qla4xxx_dump_buffer(task_data->resp_buffer, 64));
337462306a36Sopenharmony_ci
337562306a36Sopenharmony_ci	conn = task->conn;
337662306a36Sopenharmony_ci
337762306a36Sopenharmony_ci	switch (sts->completionStatus) {
337862306a36Sopenharmony_ci	case PASSTHRU_STATUS_COMPLETE:
337962306a36Sopenharmony_ci		hdr = (struct iscsi_hdr *)task_data->resp_buffer;
338062306a36Sopenharmony_ci		/* Assign back the itt in hdr, until we use the PREASSIGN_TAG */
338162306a36Sopenharmony_ci		itt = sts->handle;
338262306a36Sopenharmony_ci		hdr->itt = itt;
338362306a36Sopenharmony_ci		data = task_data->resp_buffer + hdr_len;
338462306a36Sopenharmony_ci		data_len = task_data->resp_len - hdr_len;
338562306a36Sopenharmony_ci		iscsi_complete_pdu(conn, hdr, data, data_len);
338662306a36Sopenharmony_ci		break;
338762306a36Sopenharmony_ci	default:
338862306a36Sopenharmony_ci		ql4_printk(KERN_ERR, ha, "Passthru failed status = 0x%x\n",
338962306a36Sopenharmony_ci			   sts->completionStatus);
339062306a36Sopenharmony_ci		break;
339162306a36Sopenharmony_ci	}
339262306a36Sopenharmony_ci	return;
339362306a36Sopenharmony_ci}
339462306a36Sopenharmony_ci
339562306a36Sopenharmony_cistatic int qla4xxx_alloc_pdu(struct iscsi_task *task, uint8_t opcode)
339662306a36Sopenharmony_ci{
339762306a36Sopenharmony_ci	struct ql4_task_data *task_data;
339862306a36Sopenharmony_ci	struct iscsi_session *sess;
339962306a36Sopenharmony_ci	struct ddb_entry *ddb_entry;
340062306a36Sopenharmony_ci	struct scsi_qla_host *ha;
340162306a36Sopenharmony_ci	int hdr_len;
340262306a36Sopenharmony_ci
340362306a36Sopenharmony_ci	sess = task->conn->session;
340462306a36Sopenharmony_ci	ddb_entry = sess->dd_data;
340562306a36Sopenharmony_ci	ha = ddb_entry->ha;
340662306a36Sopenharmony_ci	task_data = task->dd_data;
340762306a36Sopenharmony_ci	memset(task_data, 0, sizeof(struct ql4_task_data));
340862306a36Sopenharmony_ci
340962306a36Sopenharmony_ci	if (task->sc) {
341062306a36Sopenharmony_ci		ql4_printk(KERN_INFO, ha,
341162306a36Sopenharmony_ci			   "%s: SCSI Commands not implemented\n", __func__);
341262306a36Sopenharmony_ci		return -EINVAL;
341362306a36Sopenharmony_ci	}
341462306a36Sopenharmony_ci
341562306a36Sopenharmony_ci	hdr_len = sizeof(struct iscsi_hdr);
341662306a36Sopenharmony_ci	task_data->ha = ha;
341762306a36Sopenharmony_ci	task_data->task = task;
341862306a36Sopenharmony_ci
341962306a36Sopenharmony_ci	if (task->data_count) {
342062306a36Sopenharmony_ci		task_data->data_dma = dma_map_single(&ha->pdev->dev, task->data,
342162306a36Sopenharmony_ci						     task->data_count,
342262306a36Sopenharmony_ci						     DMA_TO_DEVICE);
342362306a36Sopenharmony_ci	}
342462306a36Sopenharmony_ci
342562306a36Sopenharmony_ci	DEBUG2(ql4_printk(KERN_INFO, ha, "%s: MaxRecvLen %u, iscsi hrd %d\n",
342662306a36Sopenharmony_ci		      __func__, task->conn->max_recv_dlength, hdr_len));
342762306a36Sopenharmony_ci
342862306a36Sopenharmony_ci	task_data->resp_len = task->conn->max_recv_dlength + hdr_len;
342962306a36Sopenharmony_ci	task_data->resp_buffer = dma_alloc_coherent(&ha->pdev->dev,
343062306a36Sopenharmony_ci						    task_data->resp_len,
343162306a36Sopenharmony_ci						    &task_data->resp_dma,
343262306a36Sopenharmony_ci						    GFP_ATOMIC);
343362306a36Sopenharmony_ci	if (!task_data->resp_buffer)
343462306a36Sopenharmony_ci		goto exit_alloc_pdu;
343562306a36Sopenharmony_ci
343662306a36Sopenharmony_ci	task_data->req_len = task->data_count + hdr_len;
343762306a36Sopenharmony_ci	task_data->req_buffer = dma_alloc_coherent(&ha->pdev->dev,
343862306a36Sopenharmony_ci						   task_data->req_len,
343962306a36Sopenharmony_ci						   &task_data->req_dma,
344062306a36Sopenharmony_ci						   GFP_ATOMIC);
344162306a36Sopenharmony_ci	if (!task_data->req_buffer)
344262306a36Sopenharmony_ci		goto exit_alloc_pdu;
344362306a36Sopenharmony_ci
344462306a36Sopenharmony_ci	task->hdr = task_data->req_buffer;
344562306a36Sopenharmony_ci
344662306a36Sopenharmony_ci	INIT_WORK(&task_data->task_work, qla4xxx_task_work);
344762306a36Sopenharmony_ci
344862306a36Sopenharmony_ci	return 0;
344962306a36Sopenharmony_ci
345062306a36Sopenharmony_ciexit_alloc_pdu:
345162306a36Sopenharmony_ci	if (task_data->resp_buffer)
345262306a36Sopenharmony_ci		dma_free_coherent(&ha->pdev->dev, task_data->resp_len,
345362306a36Sopenharmony_ci				  task_data->resp_buffer, task_data->resp_dma);
345462306a36Sopenharmony_ci
345562306a36Sopenharmony_ci	if (task_data->req_buffer)
345662306a36Sopenharmony_ci		dma_free_coherent(&ha->pdev->dev, task_data->req_len,
345762306a36Sopenharmony_ci				  task_data->req_buffer, task_data->req_dma);
345862306a36Sopenharmony_ci	return -ENOMEM;
345962306a36Sopenharmony_ci}
346062306a36Sopenharmony_ci
346162306a36Sopenharmony_cistatic void qla4xxx_task_cleanup(struct iscsi_task *task)
346262306a36Sopenharmony_ci{
346362306a36Sopenharmony_ci	struct ql4_task_data *task_data;
346462306a36Sopenharmony_ci	struct iscsi_session *sess;
346562306a36Sopenharmony_ci	struct ddb_entry *ddb_entry;
346662306a36Sopenharmony_ci	struct scsi_qla_host *ha;
346762306a36Sopenharmony_ci	int hdr_len;
346862306a36Sopenharmony_ci
346962306a36Sopenharmony_ci	hdr_len = sizeof(struct iscsi_hdr);
347062306a36Sopenharmony_ci	sess = task->conn->session;
347162306a36Sopenharmony_ci	ddb_entry = sess->dd_data;
347262306a36Sopenharmony_ci	ha = ddb_entry->ha;
347362306a36Sopenharmony_ci	task_data = task->dd_data;
347462306a36Sopenharmony_ci
347562306a36Sopenharmony_ci	if (task->data_count) {
347662306a36Sopenharmony_ci		dma_unmap_single(&ha->pdev->dev, task_data->data_dma,
347762306a36Sopenharmony_ci				 task->data_count, DMA_TO_DEVICE);
347862306a36Sopenharmony_ci	}
347962306a36Sopenharmony_ci
348062306a36Sopenharmony_ci	DEBUG2(ql4_printk(KERN_INFO, ha, "%s: MaxRecvLen %u, iscsi hrd %d\n",
348162306a36Sopenharmony_ci		      __func__, task->conn->max_recv_dlength, hdr_len));
348262306a36Sopenharmony_ci
348362306a36Sopenharmony_ci	dma_free_coherent(&ha->pdev->dev, task_data->resp_len,
348462306a36Sopenharmony_ci			  task_data->resp_buffer, task_data->resp_dma);
348562306a36Sopenharmony_ci	dma_free_coherent(&ha->pdev->dev, task_data->req_len,
348662306a36Sopenharmony_ci			  task_data->req_buffer, task_data->req_dma);
348762306a36Sopenharmony_ci	return;
348862306a36Sopenharmony_ci}
348962306a36Sopenharmony_ci
349062306a36Sopenharmony_cistatic int qla4xxx_task_xmit(struct iscsi_task *task)
349162306a36Sopenharmony_ci{
349262306a36Sopenharmony_ci	struct scsi_cmnd *sc = task->sc;
349362306a36Sopenharmony_ci	struct iscsi_session *sess = task->conn->session;
349462306a36Sopenharmony_ci	struct ddb_entry *ddb_entry = sess->dd_data;
349562306a36Sopenharmony_ci	struct scsi_qla_host *ha = ddb_entry->ha;
349662306a36Sopenharmony_ci
349762306a36Sopenharmony_ci	if (!sc)
349862306a36Sopenharmony_ci		return qla4xxx_send_passthru0(task);
349962306a36Sopenharmony_ci
350062306a36Sopenharmony_ci	ql4_printk(KERN_INFO, ha, "%s: scsi cmd xmit not implemented\n",
350162306a36Sopenharmony_ci		   __func__);
350262306a36Sopenharmony_ci	return -ENOSYS;
350362306a36Sopenharmony_ci}
350462306a36Sopenharmony_ci
350562306a36Sopenharmony_cistatic int qla4xxx_copy_from_fwddb_param(struct iscsi_bus_flash_session *sess,
350662306a36Sopenharmony_ci					 struct iscsi_bus_flash_conn *conn,
350762306a36Sopenharmony_ci					 struct dev_db_entry *fw_ddb_entry)
350862306a36Sopenharmony_ci{
350962306a36Sopenharmony_ci	unsigned long options = 0;
351062306a36Sopenharmony_ci	int rc = 0;
351162306a36Sopenharmony_ci
351262306a36Sopenharmony_ci	options = le16_to_cpu(fw_ddb_entry->options);
351362306a36Sopenharmony_ci	conn->is_fw_assigned_ipv6 = test_bit(OPT_IS_FW_ASSIGNED_IPV6, &options);
351462306a36Sopenharmony_ci	if (test_bit(OPT_IPV6_DEVICE, &options)) {
351562306a36Sopenharmony_ci		rc = iscsi_switch_str_param(&sess->portal_type,
351662306a36Sopenharmony_ci					    PORTAL_TYPE_IPV6);
351762306a36Sopenharmony_ci		if (rc)
351862306a36Sopenharmony_ci			goto exit_copy;
351962306a36Sopenharmony_ci	} else {
352062306a36Sopenharmony_ci		rc = iscsi_switch_str_param(&sess->portal_type,
352162306a36Sopenharmony_ci					    PORTAL_TYPE_IPV4);
352262306a36Sopenharmony_ci		if (rc)
352362306a36Sopenharmony_ci			goto exit_copy;
352462306a36Sopenharmony_ci	}
352562306a36Sopenharmony_ci
352662306a36Sopenharmony_ci	sess->auto_snd_tgt_disable = test_bit(OPT_AUTO_SENDTGTS_DISABLE,
352762306a36Sopenharmony_ci					      &options);
352862306a36Sopenharmony_ci	sess->discovery_sess = test_bit(OPT_DISC_SESSION, &options);
352962306a36Sopenharmony_ci	sess->entry_state = test_bit(OPT_ENTRY_STATE, &options);
353062306a36Sopenharmony_ci
353162306a36Sopenharmony_ci	options = le16_to_cpu(fw_ddb_entry->iscsi_options);
353262306a36Sopenharmony_ci	conn->hdrdgst_en = test_bit(ISCSIOPT_HEADER_DIGEST_EN, &options);
353362306a36Sopenharmony_ci	conn->datadgst_en = test_bit(ISCSIOPT_DATA_DIGEST_EN, &options);
353462306a36Sopenharmony_ci	sess->imm_data_en = test_bit(ISCSIOPT_IMMEDIATE_DATA_EN, &options);
353562306a36Sopenharmony_ci	sess->initial_r2t_en = test_bit(ISCSIOPT_INITIAL_R2T_EN, &options);
353662306a36Sopenharmony_ci	sess->dataseq_inorder_en = test_bit(ISCSIOPT_DATA_SEQ_IN_ORDER,
353762306a36Sopenharmony_ci					    &options);
353862306a36Sopenharmony_ci	sess->pdu_inorder_en = test_bit(ISCSIOPT_DATA_PDU_IN_ORDER, &options);
353962306a36Sopenharmony_ci	sess->chap_auth_en = test_bit(ISCSIOPT_CHAP_AUTH_EN, &options);
354062306a36Sopenharmony_ci	conn->snack_req_en = test_bit(ISCSIOPT_SNACK_REQ_EN, &options);
354162306a36Sopenharmony_ci	sess->discovery_logout_en = test_bit(ISCSIOPT_DISCOVERY_LOGOUT_EN,
354262306a36Sopenharmony_ci					     &options);
354362306a36Sopenharmony_ci	sess->bidi_chap_en = test_bit(ISCSIOPT_BIDI_CHAP_EN, &options);
354462306a36Sopenharmony_ci	sess->discovery_auth_optional =
354562306a36Sopenharmony_ci			test_bit(ISCSIOPT_DISCOVERY_AUTH_OPTIONAL, &options);
354662306a36Sopenharmony_ci	if (test_bit(ISCSIOPT_ERL1, &options))
354762306a36Sopenharmony_ci		sess->erl |= BIT_1;
354862306a36Sopenharmony_ci	if (test_bit(ISCSIOPT_ERL0, &options))
354962306a36Sopenharmony_ci		sess->erl |= BIT_0;
355062306a36Sopenharmony_ci
355162306a36Sopenharmony_ci	options = le16_to_cpu(fw_ddb_entry->tcp_options);
355262306a36Sopenharmony_ci	conn->tcp_timestamp_stat = test_bit(TCPOPT_TIMESTAMP_STAT, &options);
355362306a36Sopenharmony_ci	conn->tcp_nagle_disable = test_bit(TCPOPT_NAGLE_DISABLE, &options);
355462306a36Sopenharmony_ci	conn->tcp_wsf_disable = test_bit(TCPOPT_WSF_DISABLE, &options);
355562306a36Sopenharmony_ci	if (test_bit(TCPOPT_TIMER_SCALE3, &options))
355662306a36Sopenharmony_ci		conn->tcp_timer_scale |= BIT_3;
355762306a36Sopenharmony_ci	if (test_bit(TCPOPT_TIMER_SCALE2, &options))
355862306a36Sopenharmony_ci		conn->tcp_timer_scale |= BIT_2;
355962306a36Sopenharmony_ci	if (test_bit(TCPOPT_TIMER_SCALE1, &options))
356062306a36Sopenharmony_ci		conn->tcp_timer_scale |= BIT_1;
356162306a36Sopenharmony_ci
356262306a36Sopenharmony_ci	conn->tcp_timer_scale >>= 1;
356362306a36Sopenharmony_ci	conn->tcp_timestamp_en = test_bit(TCPOPT_TIMESTAMP_EN, &options);
356462306a36Sopenharmony_ci
356562306a36Sopenharmony_ci	options = le16_to_cpu(fw_ddb_entry->ip_options);
356662306a36Sopenharmony_ci	conn->fragment_disable = test_bit(IPOPT_FRAGMENT_DISABLE, &options);
356762306a36Sopenharmony_ci
356862306a36Sopenharmony_ci	conn->max_recv_dlength = BYTE_UNITS *
356962306a36Sopenharmony_ci			  le16_to_cpu(fw_ddb_entry->iscsi_max_rcv_data_seg_len);
357062306a36Sopenharmony_ci	conn->max_xmit_dlength = BYTE_UNITS *
357162306a36Sopenharmony_ci			  le16_to_cpu(fw_ddb_entry->iscsi_max_snd_data_seg_len);
357262306a36Sopenharmony_ci	sess->first_burst = BYTE_UNITS *
357362306a36Sopenharmony_ci			       le16_to_cpu(fw_ddb_entry->iscsi_first_burst_len);
357462306a36Sopenharmony_ci	sess->max_burst = BYTE_UNITS *
357562306a36Sopenharmony_ci				 le16_to_cpu(fw_ddb_entry->iscsi_max_burst_len);
357662306a36Sopenharmony_ci	sess->max_r2t = le16_to_cpu(fw_ddb_entry->iscsi_max_outsnd_r2t);
357762306a36Sopenharmony_ci	sess->time2wait = le16_to_cpu(fw_ddb_entry->iscsi_def_time2wait);
357862306a36Sopenharmony_ci	sess->time2retain = le16_to_cpu(fw_ddb_entry->iscsi_def_time2retain);
357962306a36Sopenharmony_ci	sess->tpgt = le32_to_cpu(fw_ddb_entry->tgt_portal_grp);
358062306a36Sopenharmony_ci	conn->max_segment_size = le16_to_cpu(fw_ddb_entry->mss);
358162306a36Sopenharmony_ci	conn->tcp_xmit_wsf = fw_ddb_entry->tcp_xmt_wsf;
358262306a36Sopenharmony_ci	conn->tcp_recv_wsf = fw_ddb_entry->tcp_rcv_wsf;
358362306a36Sopenharmony_ci	conn->ipv6_flow_label = le16_to_cpu(fw_ddb_entry->ipv6_flow_lbl);
358462306a36Sopenharmony_ci	conn->keepalive_timeout = le16_to_cpu(fw_ddb_entry->ka_timeout);
358562306a36Sopenharmony_ci	conn->local_port = le16_to_cpu(fw_ddb_entry->lcl_port);
358662306a36Sopenharmony_ci	conn->statsn = le32_to_cpu(fw_ddb_entry->stat_sn);
358762306a36Sopenharmony_ci	conn->exp_statsn = le32_to_cpu(fw_ddb_entry->exp_stat_sn);
358862306a36Sopenharmony_ci	sess->discovery_parent_idx = le16_to_cpu(fw_ddb_entry->ddb_link);
358962306a36Sopenharmony_ci	sess->discovery_parent_type = le16_to_cpu(fw_ddb_entry->ddb_link);
359062306a36Sopenharmony_ci	sess->chap_out_idx = le16_to_cpu(fw_ddb_entry->chap_tbl_idx);
359162306a36Sopenharmony_ci	sess->tsid = le16_to_cpu(fw_ddb_entry->tsid);
359262306a36Sopenharmony_ci
359362306a36Sopenharmony_ci	sess->default_taskmgmt_timeout =
359462306a36Sopenharmony_ci				le16_to_cpu(fw_ddb_entry->def_timeout);
359562306a36Sopenharmony_ci	conn->port = le16_to_cpu(fw_ddb_entry->port);
359662306a36Sopenharmony_ci
359762306a36Sopenharmony_ci	options = le16_to_cpu(fw_ddb_entry->options);
359862306a36Sopenharmony_ci	conn->ipaddress = kzalloc(IPv6_ADDR_LEN, GFP_KERNEL);
359962306a36Sopenharmony_ci	if (!conn->ipaddress) {
360062306a36Sopenharmony_ci		rc = -ENOMEM;
360162306a36Sopenharmony_ci		goto exit_copy;
360262306a36Sopenharmony_ci	}
360362306a36Sopenharmony_ci
360462306a36Sopenharmony_ci	conn->redirect_ipaddr = kzalloc(IPv6_ADDR_LEN, GFP_KERNEL);
360562306a36Sopenharmony_ci	if (!conn->redirect_ipaddr) {
360662306a36Sopenharmony_ci		rc = -ENOMEM;
360762306a36Sopenharmony_ci		goto exit_copy;
360862306a36Sopenharmony_ci	}
360962306a36Sopenharmony_ci
361062306a36Sopenharmony_ci	memcpy(conn->ipaddress, fw_ddb_entry->ip_addr, IPv6_ADDR_LEN);
361162306a36Sopenharmony_ci	memcpy(conn->redirect_ipaddr, fw_ddb_entry->tgt_addr, IPv6_ADDR_LEN);
361262306a36Sopenharmony_ci
361362306a36Sopenharmony_ci	if (test_bit(OPT_IPV6_DEVICE, &options)) {
361462306a36Sopenharmony_ci		conn->ipv6_traffic_class = fw_ddb_entry->ipv4_tos;
361562306a36Sopenharmony_ci
361662306a36Sopenharmony_ci		conn->link_local_ipv6_addr = kmemdup(
361762306a36Sopenharmony_ci					fw_ddb_entry->link_local_ipv6_addr,
361862306a36Sopenharmony_ci					IPv6_ADDR_LEN, GFP_KERNEL);
361962306a36Sopenharmony_ci		if (!conn->link_local_ipv6_addr) {
362062306a36Sopenharmony_ci			rc = -ENOMEM;
362162306a36Sopenharmony_ci			goto exit_copy;
362262306a36Sopenharmony_ci		}
362362306a36Sopenharmony_ci	} else {
362462306a36Sopenharmony_ci		conn->ipv4_tos = fw_ddb_entry->ipv4_tos;
362562306a36Sopenharmony_ci	}
362662306a36Sopenharmony_ci
362762306a36Sopenharmony_ci	if (fw_ddb_entry->iscsi_name[0]) {
362862306a36Sopenharmony_ci		rc = iscsi_switch_str_param(&sess->targetname,
362962306a36Sopenharmony_ci					    (char *)fw_ddb_entry->iscsi_name);
363062306a36Sopenharmony_ci		if (rc)
363162306a36Sopenharmony_ci			goto exit_copy;
363262306a36Sopenharmony_ci	}
363362306a36Sopenharmony_ci
363462306a36Sopenharmony_ci	if (fw_ddb_entry->iscsi_alias[0]) {
363562306a36Sopenharmony_ci		rc = iscsi_switch_str_param(&sess->targetalias,
363662306a36Sopenharmony_ci					    (char *)fw_ddb_entry->iscsi_alias);
363762306a36Sopenharmony_ci		if (rc)
363862306a36Sopenharmony_ci			goto exit_copy;
363962306a36Sopenharmony_ci	}
364062306a36Sopenharmony_ci
364162306a36Sopenharmony_ci	COPY_ISID(sess->isid, fw_ddb_entry->isid);
364262306a36Sopenharmony_ci
364362306a36Sopenharmony_ciexit_copy:
364462306a36Sopenharmony_ci	return rc;
364562306a36Sopenharmony_ci}
364662306a36Sopenharmony_ci
364762306a36Sopenharmony_cistatic int qla4xxx_copy_to_fwddb_param(struct iscsi_bus_flash_session *sess,
364862306a36Sopenharmony_ci				       struct iscsi_bus_flash_conn *conn,
364962306a36Sopenharmony_ci				       struct dev_db_entry *fw_ddb_entry)
365062306a36Sopenharmony_ci{
365162306a36Sopenharmony_ci	uint16_t options;
365262306a36Sopenharmony_ci
365362306a36Sopenharmony_ci	options = le16_to_cpu(fw_ddb_entry->options);
365462306a36Sopenharmony_ci	SET_BITVAL(conn->is_fw_assigned_ipv6,  options, BIT_11);
365562306a36Sopenharmony_ci	if (!strncmp(sess->portal_type, PORTAL_TYPE_IPV6, 4))
365662306a36Sopenharmony_ci		options |= BIT_8;
365762306a36Sopenharmony_ci	else
365862306a36Sopenharmony_ci		options &= ~BIT_8;
365962306a36Sopenharmony_ci
366062306a36Sopenharmony_ci	SET_BITVAL(sess->auto_snd_tgt_disable, options, BIT_6);
366162306a36Sopenharmony_ci	SET_BITVAL(sess->discovery_sess, options, BIT_4);
366262306a36Sopenharmony_ci	SET_BITVAL(sess->entry_state, options, BIT_3);
366362306a36Sopenharmony_ci	fw_ddb_entry->options = cpu_to_le16(options);
366462306a36Sopenharmony_ci
366562306a36Sopenharmony_ci	options = le16_to_cpu(fw_ddb_entry->iscsi_options);
366662306a36Sopenharmony_ci	SET_BITVAL(conn->hdrdgst_en, options, BIT_13);
366762306a36Sopenharmony_ci	SET_BITVAL(conn->datadgst_en, options, BIT_12);
366862306a36Sopenharmony_ci	SET_BITVAL(sess->imm_data_en, options, BIT_11);
366962306a36Sopenharmony_ci	SET_BITVAL(sess->initial_r2t_en, options, BIT_10);
367062306a36Sopenharmony_ci	SET_BITVAL(sess->dataseq_inorder_en, options, BIT_9);
367162306a36Sopenharmony_ci	SET_BITVAL(sess->pdu_inorder_en, options, BIT_8);
367262306a36Sopenharmony_ci	SET_BITVAL(sess->chap_auth_en, options, BIT_7);
367362306a36Sopenharmony_ci	SET_BITVAL(conn->snack_req_en, options, BIT_6);
367462306a36Sopenharmony_ci	SET_BITVAL(sess->discovery_logout_en, options, BIT_5);
367562306a36Sopenharmony_ci	SET_BITVAL(sess->bidi_chap_en, options, BIT_4);
367662306a36Sopenharmony_ci	SET_BITVAL(sess->discovery_auth_optional, options, BIT_3);
367762306a36Sopenharmony_ci	SET_BITVAL(sess->erl & BIT_1, options, BIT_1);
367862306a36Sopenharmony_ci	SET_BITVAL(sess->erl & BIT_0, options, BIT_0);
367962306a36Sopenharmony_ci	fw_ddb_entry->iscsi_options = cpu_to_le16(options);
368062306a36Sopenharmony_ci
368162306a36Sopenharmony_ci	options = le16_to_cpu(fw_ddb_entry->tcp_options);
368262306a36Sopenharmony_ci	SET_BITVAL(conn->tcp_timestamp_stat, options, BIT_6);
368362306a36Sopenharmony_ci	SET_BITVAL(conn->tcp_nagle_disable, options, BIT_5);
368462306a36Sopenharmony_ci	SET_BITVAL(conn->tcp_wsf_disable, options, BIT_4);
368562306a36Sopenharmony_ci	SET_BITVAL(conn->tcp_timer_scale & BIT_2, options, BIT_3);
368662306a36Sopenharmony_ci	SET_BITVAL(conn->tcp_timer_scale & BIT_1, options, BIT_2);
368762306a36Sopenharmony_ci	SET_BITVAL(conn->tcp_timer_scale & BIT_0, options, BIT_1);
368862306a36Sopenharmony_ci	SET_BITVAL(conn->tcp_timestamp_en, options, BIT_0);
368962306a36Sopenharmony_ci	fw_ddb_entry->tcp_options = cpu_to_le16(options);
369062306a36Sopenharmony_ci
369162306a36Sopenharmony_ci	options = le16_to_cpu(fw_ddb_entry->ip_options);
369262306a36Sopenharmony_ci	SET_BITVAL(conn->fragment_disable, options, BIT_4);
369362306a36Sopenharmony_ci	fw_ddb_entry->ip_options = cpu_to_le16(options);
369462306a36Sopenharmony_ci
369562306a36Sopenharmony_ci	fw_ddb_entry->iscsi_max_outsnd_r2t = cpu_to_le16(sess->max_r2t);
369662306a36Sopenharmony_ci	fw_ddb_entry->iscsi_max_rcv_data_seg_len =
369762306a36Sopenharmony_ci			       cpu_to_le16(conn->max_recv_dlength / BYTE_UNITS);
369862306a36Sopenharmony_ci	fw_ddb_entry->iscsi_max_snd_data_seg_len =
369962306a36Sopenharmony_ci			       cpu_to_le16(conn->max_xmit_dlength / BYTE_UNITS);
370062306a36Sopenharmony_ci	fw_ddb_entry->iscsi_first_burst_len =
370162306a36Sopenharmony_ci				cpu_to_le16(sess->first_burst / BYTE_UNITS);
370262306a36Sopenharmony_ci	fw_ddb_entry->iscsi_max_burst_len = cpu_to_le16(sess->max_burst /
370362306a36Sopenharmony_ci					    BYTE_UNITS);
370462306a36Sopenharmony_ci	fw_ddb_entry->iscsi_def_time2wait = cpu_to_le16(sess->time2wait);
370562306a36Sopenharmony_ci	fw_ddb_entry->iscsi_def_time2retain = cpu_to_le16(sess->time2retain);
370662306a36Sopenharmony_ci	fw_ddb_entry->tgt_portal_grp = cpu_to_le16(sess->tpgt);
370762306a36Sopenharmony_ci	fw_ddb_entry->mss = cpu_to_le16(conn->max_segment_size);
370862306a36Sopenharmony_ci	fw_ddb_entry->tcp_xmt_wsf = (uint8_t) cpu_to_le32(conn->tcp_xmit_wsf);
370962306a36Sopenharmony_ci	fw_ddb_entry->tcp_rcv_wsf = (uint8_t) cpu_to_le32(conn->tcp_recv_wsf);
371062306a36Sopenharmony_ci	fw_ddb_entry->ipv6_flow_lbl = cpu_to_le16(conn->ipv6_flow_label);
371162306a36Sopenharmony_ci	fw_ddb_entry->ka_timeout = cpu_to_le16(conn->keepalive_timeout);
371262306a36Sopenharmony_ci	fw_ddb_entry->lcl_port = cpu_to_le16(conn->local_port);
371362306a36Sopenharmony_ci	fw_ddb_entry->stat_sn = cpu_to_le32(conn->statsn);
371462306a36Sopenharmony_ci	fw_ddb_entry->exp_stat_sn = cpu_to_le32(conn->exp_statsn);
371562306a36Sopenharmony_ci	fw_ddb_entry->ddb_link = cpu_to_le16(sess->discovery_parent_idx);
371662306a36Sopenharmony_ci	fw_ddb_entry->chap_tbl_idx = cpu_to_le16(sess->chap_out_idx);
371762306a36Sopenharmony_ci	fw_ddb_entry->tsid = cpu_to_le16(sess->tsid);
371862306a36Sopenharmony_ci	fw_ddb_entry->port = cpu_to_le16(conn->port);
371962306a36Sopenharmony_ci	fw_ddb_entry->def_timeout =
372062306a36Sopenharmony_ci				cpu_to_le16(sess->default_taskmgmt_timeout);
372162306a36Sopenharmony_ci
372262306a36Sopenharmony_ci	if (!strncmp(sess->portal_type, PORTAL_TYPE_IPV6, 4))
372362306a36Sopenharmony_ci		fw_ddb_entry->ipv4_tos = conn->ipv6_traffic_class;
372462306a36Sopenharmony_ci	else
372562306a36Sopenharmony_ci		fw_ddb_entry->ipv4_tos = conn->ipv4_tos;
372662306a36Sopenharmony_ci
372762306a36Sopenharmony_ci	if (conn->ipaddress)
372862306a36Sopenharmony_ci		memcpy(fw_ddb_entry->ip_addr, conn->ipaddress,
372962306a36Sopenharmony_ci		       sizeof(fw_ddb_entry->ip_addr));
373062306a36Sopenharmony_ci
373162306a36Sopenharmony_ci	if (conn->redirect_ipaddr)
373262306a36Sopenharmony_ci		memcpy(fw_ddb_entry->tgt_addr, conn->redirect_ipaddr,
373362306a36Sopenharmony_ci		       sizeof(fw_ddb_entry->tgt_addr));
373462306a36Sopenharmony_ci
373562306a36Sopenharmony_ci	if (conn->link_local_ipv6_addr)
373662306a36Sopenharmony_ci		memcpy(fw_ddb_entry->link_local_ipv6_addr,
373762306a36Sopenharmony_ci		       conn->link_local_ipv6_addr,
373862306a36Sopenharmony_ci		       sizeof(fw_ddb_entry->link_local_ipv6_addr));
373962306a36Sopenharmony_ci
374062306a36Sopenharmony_ci	if (sess->targetname)
374162306a36Sopenharmony_ci		memcpy(fw_ddb_entry->iscsi_name, sess->targetname,
374262306a36Sopenharmony_ci		       sizeof(fw_ddb_entry->iscsi_name));
374362306a36Sopenharmony_ci
374462306a36Sopenharmony_ci	if (sess->targetalias)
374562306a36Sopenharmony_ci		memcpy(fw_ddb_entry->iscsi_alias, sess->targetalias,
374662306a36Sopenharmony_ci		       sizeof(fw_ddb_entry->iscsi_alias));
374762306a36Sopenharmony_ci
374862306a36Sopenharmony_ci	COPY_ISID(fw_ddb_entry->isid, sess->isid);
374962306a36Sopenharmony_ci
375062306a36Sopenharmony_ci	return 0;
375162306a36Sopenharmony_ci}
375262306a36Sopenharmony_ci
375362306a36Sopenharmony_cistatic void qla4xxx_copy_to_sess_conn_params(struct iscsi_conn *conn,
375462306a36Sopenharmony_ci					     struct iscsi_session *sess,
375562306a36Sopenharmony_ci					     struct dev_db_entry *fw_ddb_entry)
375662306a36Sopenharmony_ci{
375762306a36Sopenharmony_ci	unsigned long options = 0;
375862306a36Sopenharmony_ci	uint16_t ddb_link;
375962306a36Sopenharmony_ci	uint16_t disc_parent;
376062306a36Sopenharmony_ci	char ip_addr[DDB_IPADDR_LEN];
376162306a36Sopenharmony_ci
376262306a36Sopenharmony_ci	options = le16_to_cpu(fw_ddb_entry->options);
376362306a36Sopenharmony_ci	conn->is_fw_assigned_ipv6 = test_bit(OPT_IS_FW_ASSIGNED_IPV6, &options);
376462306a36Sopenharmony_ci	sess->auto_snd_tgt_disable = test_bit(OPT_AUTO_SENDTGTS_DISABLE,
376562306a36Sopenharmony_ci					      &options);
376662306a36Sopenharmony_ci	sess->discovery_sess = test_bit(OPT_DISC_SESSION, &options);
376762306a36Sopenharmony_ci
376862306a36Sopenharmony_ci	options = le16_to_cpu(fw_ddb_entry->iscsi_options);
376962306a36Sopenharmony_ci	conn->hdrdgst_en = test_bit(ISCSIOPT_HEADER_DIGEST_EN, &options);
377062306a36Sopenharmony_ci	conn->datadgst_en = test_bit(ISCSIOPT_DATA_DIGEST_EN, &options);
377162306a36Sopenharmony_ci	sess->imm_data_en = test_bit(ISCSIOPT_IMMEDIATE_DATA_EN, &options);
377262306a36Sopenharmony_ci	sess->initial_r2t_en = test_bit(ISCSIOPT_INITIAL_R2T_EN, &options);
377362306a36Sopenharmony_ci	sess->dataseq_inorder_en = test_bit(ISCSIOPT_DATA_SEQ_IN_ORDER,
377462306a36Sopenharmony_ci					    &options);
377562306a36Sopenharmony_ci	sess->pdu_inorder_en = test_bit(ISCSIOPT_DATA_PDU_IN_ORDER, &options);
377662306a36Sopenharmony_ci	sess->chap_auth_en = test_bit(ISCSIOPT_CHAP_AUTH_EN, &options);
377762306a36Sopenharmony_ci	sess->discovery_logout_en = test_bit(ISCSIOPT_DISCOVERY_LOGOUT_EN,
377862306a36Sopenharmony_ci					     &options);
377962306a36Sopenharmony_ci	sess->bidi_chap_en = test_bit(ISCSIOPT_BIDI_CHAP_EN, &options);
378062306a36Sopenharmony_ci	sess->discovery_auth_optional =
378162306a36Sopenharmony_ci			test_bit(ISCSIOPT_DISCOVERY_AUTH_OPTIONAL, &options);
378262306a36Sopenharmony_ci	if (test_bit(ISCSIOPT_ERL1, &options))
378362306a36Sopenharmony_ci		sess->erl |= BIT_1;
378462306a36Sopenharmony_ci	if (test_bit(ISCSIOPT_ERL0, &options))
378562306a36Sopenharmony_ci		sess->erl |= BIT_0;
378662306a36Sopenharmony_ci
378762306a36Sopenharmony_ci	options = le16_to_cpu(fw_ddb_entry->tcp_options);
378862306a36Sopenharmony_ci	conn->tcp_timestamp_stat = test_bit(TCPOPT_TIMESTAMP_STAT, &options);
378962306a36Sopenharmony_ci	conn->tcp_nagle_disable = test_bit(TCPOPT_NAGLE_DISABLE, &options);
379062306a36Sopenharmony_ci	conn->tcp_wsf_disable = test_bit(TCPOPT_WSF_DISABLE, &options);
379162306a36Sopenharmony_ci	if (test_bit(TCPOPT_TIMER_SCALE3, &options))
379262306a36Sopenharmony_ci		conn->tcp_timer_scale |= BIT_3;
379362306a36Sopenharmony_ci	if (test_bit(TCPOPT_TIMER_SCALE2, &options))
379462306a36Sopenharmony_ci		conn->tcp_timer_scale |= BIT_2;
379562306a36Sopenharmony_ci	if (test_bit(TCPOPT_TIMER_SCALE1, &options))
379662306a36Sopenharmony_ci		conn->tcp_timer_scale |= BIT_1;
379762306a36Sopenharmony_ci
379862306a36Sopenharmony_ci	conn->tcp_timer_scale >>= 1;
379962306a36Sopenharmony_ci	conn->tcp_timestamp_en = test_bit(TCPOPT_TIMESTAMP_EN, &options);
380062306a36Sopenharmony_ci
380162306a36Sopenharmony_ci	options = le16_to_cpu(fw_ddb_entry->ip_options);
380262306a36Sopenharmony_ci	conn->fragment_disable = test_bit(IPOPT_FRAGMENT_DISABLE, &options);
380362306a36Sopenharmony_ci
380462306a36Sopenharmony_ci	conn->max_recv_dlength = BYTE_UNITS *
380562306a36Sopenharmony_ci			  le16_to_cpu(fw_ddb_entry->iscsi_max_rcv_data_seg_len);
380662306a36Sopenharmony_ci	conn->max_xmit_dlength = BYTE_UNITS *
380762306a36Sopenharmony_ci			  le16_to_cpu(fw_ddb_entry->iscsi_max_snd_data_seg_len);
380862306a36Sopenharmony_ci	sess->max_r2t = le16_to_cpu(fw_ddb_entry->iscsi_max_outsnd_r2t);
380962306a36Sopenharmony_ci	sess->first_burst = BYTE_UNITS *
381062306a36Sopenharmony_ci			       le16_to_cpu(fw_ddb_entry->iscsi_first_burst_len);
381162306a36Sopenharmony_ci	sess->max_burst = BYTE_UNITS *
381262306a36Sopenharmony_ci				 le16_to_cpu(fw_ddb_entry->iscsi_max_burst_len);
381362306a36Sopenharmony_ci	sess->time2wait = le16_to_cpu(fw_ddb_entry->iscsi_def_time2wait);
381462306a36Sopenharmony_ci	sess->time2retain = le16_to_cpu(fw_ddb_entry->iscsi_def_time2retain);
381562306a36Sopenharmony_ci	sess->tpgt = le32_to_cpu(fw_ddb_entry->tgt_portal_grp);
381662306a36Sopenharmony_ci	conn->max_segment_size = le16_to_cpu(fw_ddb_entry->mss);
381762306a36Sopenharmony_ci	conn->tcp_xmit_wsf = fw_ddb_entry->tcp_xmt_wsf;
381862306a36Sopenharmony_ci	conn->tcp_recv_wsf = fw_ddb_entry->tcp_rcv_wsf;
381962306a36Sopenharmony_ci	conn->ipv4_tos = fw_ddb_entry->ipv4_tos;
382062306a36Sopenharmony_ci	conn->keepalive_tmo = le16_to_cpu(fw_ddb_entry->ka_timeout);
382162306a36Sopenharmony_ci	conn->local_port = le16_to_cpu(fw_ddb_entry->lcl_port);
382262306a36Sopenharmony_ci	conn->statsn = le32_to_cpu(fw_ddb_entry->stat_sn);
382362306a36Sopenharmony_ci	conn->exp_statsn = le32_to_cpu(fw_ddb_entry->exp_stat_sn);
382462306a36Sopenharmony_ci	sess->tsid = le16_to_cpu(fw_ddb_entry->tsid);
382562306a36Sopenharmony_ci	COPY_ISID(sess->isid, fw_ddb_entry->isid);
382662306a36Sopenharmony_ci
382762306a36Sopenharmony_ci	ddb_link = le16_to_cpu(fw_ddb_entry->ddb_link);
382862306a36Sopenharmony_ci	if (ddb_link == DDB_ISNS)
382962306a36Sopenharmony_ci		disc_parent = ISCSI_DISC_PARENT_ISNS;
383062306a36Sopenharmony_ci	else if (ddb_link == DDB_NO_LINK)
383162306a36Sopenharmony_ci		disc_parent = ISCSI_DISC_PARENT_UNKNOWN;
383262306a36Sopenharmony_ci	else if (ddb_link < MAX_DDB_ENTRIES)
383362306a36Sopenharmony_ci		disc_parent = ISCSI_DISC_PARENT_SENDTGT;
383462306a36Sopenharmony_ci	else
383562306a36Sopenharmony_ci		disc_parent = ISCSI_DISC_PARENT_UNKNOWN;
383662306a36Sopenharmony_ci
383762306a36Sopenharmony_ci	iscsi_set_param(conn->cls_conn, ISCSI_PARAM_DISCOVERY_PARENT_TYPE,
383862306a36Sopenharmony_ci			iscsi_get_discovery_parent_name(disc_parent), 0);
383962306a36Sopenharmony_ci
384062306a36Sopenharmony_ci	iscsi_set_param(conn->cls_conn, ISCSI_PARAM_TARGET_ALIAS,
384162306a36Sopenharmony_ci			(char *)fw_ddb_entry->iscsi_alias, 0);
384262306a36Sopenharmony_ci
384362306a36Sopenharmony_ci	options = le16_to_cpu(fw_ddb_entry->options);
384462306a36Sopenharmony_ci	if (options & DDB_OPT_IPV6_DEVICE) {
384562306a36Sopenharmony_ci		memset(ip_addr, 0, sizeof(ip_addr));
384662306a36Sopenharmony_ci		sprintf(ip_addr, "%pI6", fw_ddb_entry->link_local_ipv6_addr);
384762306a36Sopenharmony_ci		iscsi_set_param(conn->cls_conn, ISCSI_PARAM_LOCAL_IPADDR,
384862306a36Sopenharmony_ci				(char *)ip_addr, 0);
384962306a36Sopenharmony_ci	}
385062306a36Sopenharmony_ci}
385162306a36Sopenharmony_ci
385262306a36Sopenharmony_cistatic void qla4xxx_copy_fwddb_param(struct scsi_qla_host *ha,
385362306a36Sopenharmony_ci				     struct dev_db_entry *fw_ddb_entry,
385462306a36Sopenharmony_ci				     struct iscsi_cls_session *cls_sess,
385562306a36Sopenharmony_ci				     struct iscsi_cls_conn *cls_conn)
385662306a36Sopenharmony_ci{
385762306a36Sopenharmony_ci	int buflen = 0;
385862306a36Sopenharmony_ci	struct iscsi_session *sess;
385962306a36Sopenharmony_ci	struct ddb_entry *ddb_entry;
386062306a36Sopenharmony_ci	struct ql4_chap_table chap_tbl;
386162306a36Sopenharmony_ci	struct iscsi_conn *conn;
386262306a36Sopenharmony_ci	char ip_addr[DDB_IPADDR_LEN];
386362306a36Sopenharmony_ci	uint16_t options = 0;
386462306a36Sopenharmony_ci
386562306a36Sopenharmony_ci	sess = cls_sess->dd_data;
386662306a36Sopenharmony_ci	ddb_entry = sess->dd_data;
386762306a36Sopenharmony_ci	conn = cls_conn->dd_data;
386862306a36Sopenharmony_ci	memset(&chap_tbl, 0, sizeof(chap_tbl));
386962306a36Sopenharmony_ci
387062306a36Sopenharmony_ci	ddb_entry->chap_tbl_idx = le16_to_cpu(fw_ddb_entry->chap_tbl_idx);
387162306a36Sopenharmony_ci
387262306a36Sopenharmony_ci	qla4xxx_copy_to_sess_conn_params(conn, sess, fw_ddb_entry);
387362306a36Sopenharmony_ci
387462306a36Sopenharmony_ci	sess->def_taskmgmt_tmo = le16_to_cpu(fw_ddb_entry->def_timeout);
387562306a36Sopenharmony_ci	conn->persistent_port = le16_to_cpu(fw_ddb_entry->port);
387662306a36Sopenharmony_ci
387762306a36Sopenharmony_ci	memset(ip_addr, 0, sizeof(ip_addr));
387862306a36Sopenharmony_ci	options = le16_to_cpu(fw_ddb_entry->options);
387962306a36Sopenharmony_ci	if (options & DDB_OPT_IPV6_DEVICE) {
388062306a36Sopenharmony_ci		iscsi_set_param(cls_conn, ISCSI_PARAM_PORTAL_TYPE, "ipv6", 4);
388162306a36Sopenharmony_ci
388262306a36Sopenharmony_ci		memset(ip_addr, 0, sizeof(ip_addr));
388362306a36Sopenharmony_ci		sprintf(ip_addr, "%pI6", fw_ddb_entry->ip_addr);
388462306a36Sopenharmony_ci	} else {
388562306a36Sopenharmony_ci		iscsi_set_param(cls_conn, ISCSI_PARAM_PORTAL_TYPE, "ipv4", 4);
388662306a36Sopenharmony_ci		sprintf(ip_addr, "%pI4", fw_ddb_entry->ip_addr);
388762306a36Sopenharmony_ci	}
388862306a36Sopenharmony_ci
388962306a36Sopenharmony_ci	iscsi_set_param(cls_conn, ISCSI_PARAM_PERSISTENT_ADDRESS,
389062306a36Sopenharmony_ci			(char *)ip_addr, buflen);
389162306a36Sopenharmony_ci	iscsi_set_param(cls_conn, ISCSI_PARAM_TARGET_NAME,
389262306a36Sopenharmony_ci			(char *)fw_ddb_entry->iscsi_name, buflen);
389362306a36Sopenharmony_ci	iscsi_set_param(cls_conn, ISCSI_PARAM_INITIATOR_NAME,
389462306a36Sopenharmony_ci			(char *)ha->name_string, buflen);
389562306a36Sopenharmony_ci
389662306a36Sopenharmony_ci	if (ddb_entry->chap_tbl_idx != INVALID_ENTRY) {
389762306a36Sopenharmony_ci		if (!qla4xxx_get_uni_chap_at_index(ha, chap_tbl.name,
389862306a36Sopenharmony_ci						   chap_tbl.secret,
389962306a36Sopenharmony_ci						   ddb_entry->chap_tbl_idx)) {
390062306a36Sopenharmony_ci			iscsi_set_param(cls_conn, ISCSI_PARAM_USERNAME,
390162306a36Sopenharmony_ci					(char *)chap_tbl.name,
390262306a36Sopenharmony_ci					strlen((char *)chap_tbl.name));
390362306a36Sopenharmony_ci			iscsi_set_param(cls_conn, ISCSI_PARAM_PASSWORD,
390462306a36Sopenharmony_ci					(char *)chap_tbl.secret,
390562306a36Sopenharmony_ci					chap_tbl.secret_len);
390662306a36Sopenharmony_ci		}
390762306a36Sopenharmony_ci	}
390862306a36Sopenharmony_ci}
390962306a36Sopenharmony_ci
391062306a36Sopenharmony_civoid qla4xxx_update_session_conn_fwddb_param(struct scsi_qla_host *ha,
391162306a36Sopenharmony_ci					     struct ddb_entry *ddb_entry)
391262306a36Sopenharmony_ci{
391362306a36Sopenharmony_ci	struct iscsi_cls_session *cls_sess;
391462306a36Sopenharmony_ci	struct iscsi_cls_conn *cls_conn;
391562306a36Sopenharmony_ci	uint32_t ddb_state;
391662306a36Sopenharmony_ci	dma_addr_t fw_ddb_entry_dma;
391762306a36Sopenharmony_ci	struct dev_db_entry *fw_ddb_entry;
391862306a36Sopenharmony_ci
391962306a36Sopenharmony_ci	fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
392062306a36Sopenharmony_ci					  &fw_ddb_entry_dma, GFP_KERNEL);
392162306a36Sopenharmony_ci	if (!fw_ddb_entry) {
392262306a36Sopenharmony_ci		ql4_printk(KERN_ERR, ha,
392362306a36Sopenharmony_ci			   "%s: Unable to allocate dma buffer\n", __func__);
392462306a36Sopenharmony_ci		goto exit_session_conn_fwddb_param;
392562306a36Sopenharmony_ci	}
392662306a36Sopenharmony_ci
392762306a36Sopenharmony_ci	if (qla4xxx_get_fwddb_entry(ha, ddb_entry->fw_ddb_index, fw_ddb_entry,
392862306a36Sopenharmony_ci				    fw_ddb_entry_dma, NULL, NULL, &ddb_state,
392962306a36Sopenharmony_ci				    NULL, NULL, NULL) == QLA_ERROR) {
393062306a36Sopenharmony_ci		DEBUG2(ql4_printk(KERN_ERR, ha, "scsi%ld: %s: failed "
393162306a36Sopenharmony_ci				  "get_ddb_entry for fw_ddb_index %d\n",
393262306a36Sopenharmony_ci				  ha->host_no, __func__,
393362306a36Sopenharmony_ci				  ddb_entry->fw_ddb_index));
393462306a36Sopenharmony_ci		goto exit_session_conn_fwddb_param;
393562306a36Sopenharmony_ci	}
393662306a36Sopenharmony_ci
393762306a36Sopenharmony_ci	cls_sess = ddb_entry->sess;
393862306a36Sopenharmony_ci
393962306a36Sopenharmony_ci	cls_conn = ddb_entry->conn;
394062306a36Sopenharmony_ci
394162306a36Sopenharmony_ci	/* Update params */
394262306a36Sopenharmony_ci	qla4xxx_copy_fwddb_param(ha, fw_ddb_entry, cls_sess, cls_conn);
394362306a36Sopenharmony_ci
394462306a36Sopenharmony_ciexit_session_conn_fwddb_param:
394562306a36Sopenharmony_ci	if (fw_ddb_entry)
394662306a36Sopenharmony_ci		dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
394762306a36Sopenharmony_ci				  fw_ddb_entry, fw_ddb_entry_dma);
394862306a36Sopenharmony_ci}
394962306a36Sopenharmony_ci
395062306a36Sopenharmony_civoid qla4xxx_update_session_conn_param(struct scsi_qla_host *ha,
395162306a36Sopenharmony_ci				       struct ddb_entry *ddb_entry)
395262306a36Sopenharmony_ci{
395362306a36Sopenharmony_ci	struct iscsi_cls_session *cls_sess;
395462306a36Sopenharmony_ci	struct iscsi_cls_conn *cls_conn;
395562306a36Sopenharmony_ci	struct iscsi_session *sess;
395662306a36Sopenharmony_ci	struct iscsi_conn *conn;
395762306a36Sopenharmony_ci	uint32_t ddb_state;
395862306a36Sopenharmony_ci	dma_addr_t fw_ddb_entry_dma;
395962306a36Sopenharmony_ci	struct dev_db_entry *fw_ddb_entry;
396062306a36Sopenharmony_ci
396162306a36Sopenharmony_ci	fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
396262306a36Sopenharmony_ci					  &fw_ddb_entry_dma, GFP_KERNEL);
396362306a36Sopenharmony_ci	if (!fw_ddb_entry) {
396462306a36Sopenharmony_ci		ql4_printk(KERN_ERR, ha,
396562306a36Sopenharmony_ci			   "%s: Unable to allocate dma buffer\n", __func__);
396662306a36Sopenharmony_ci		goto exit_session_conn_param;
396762306a36Sopenharmony_ci	}
396862306a36Sopenharmony_ci
396962306a36Sopenharmony_ci	if (qla4xxx_get_fwddb_entry(ha, ddb_entry->fw_ddb_index, fw_ddb_entry,
397062306a36Sopenharmony_ci				    fw_ddb_entry_dma, NULL, NULL, &ddb_state,
397162306a36Sopenharmony_ci				    NULL, NULL, NULL) == QLA_ERROR) {
397262306a36Sopenharmony_ci		DEBUG2(ql4_printk(KERN_ERR, ha, "scsi%ld: %s: failed "
397362306a36Sopenharmony_ci				  "get_ddb_entry for fw_ddb_index %d\n",
397462306a36Sopenharmony_ci				  ha->host_no, __func__,
397562306a36Sopenharmony_ci				  ddb_entry->fw_ddb_index));
397662306a36Sopenharmony_ci		goto exit_session_conn_param;
397762306a36Sopenharmony_ci	}
397862306a36Sopenharmony_ci
397962306a36Sopenharmony_ci	cls_sess = ddb_entry->sess;
398062306a36Sopenharmony_ci	sess = cls_sess->dd_data;
398162306a36Sopenharmony_ci
398262306a36Sopenharmony_ci	cls_conn = ddb_entry->conn;
398362306a36Sopenharmony_ci	conn = cls_conn->dd_data;
398462306a36Sopenharmony_ci
398562306a36Sopenharmony_ci	/* Update timers after login */
398662306a36Sopenharmony_ci	ddb_entry->default_relogin_timeout =
398762306a36Sopenharmony_ci		(le16_to_cpu(fw_ddb_entry->def_timeout) > LOGIN_TOV) &&
398862306a36Sopenharmony_ci		 (le16_to_cpu(fw_ddb_entry->def_timeout) < LOGIN_TOV * 10) ?
398962306a36Sopenharmony_ci		 le16_to_cpu(fw_ddb_entry->def_timeout) : LOGIN_TOV;
399062306a36Sopenharmony_ci	ddb_entry->default_time2wait =
399162306a36Sopenharmony_ci				le16_to_cpu(fw_ddb_entry->iscsi_def_time2wait);
399262306a36Sopenharmony_ci
399362306a36Sopenharmony_ci	/* Update params */
399462306a36Sopenharmony_ci	ddb_entry->chap_tbl_idx = le16_to_cpu(fw_ddb_entry->chap_tbl_idx);
399562306a36Sopenharmony_ci	qla4xxx_copy_to_sess_conn_params(conn, sess, fw_ddb_entry);
399662306a36Sopenharmony_ci
399762306a36Sopenharmony_ci	memcpy(sess->initiatorname, ha->name_string,
399862306a36Sopenharmony_ci	       min(sizeof(ha->name_string), sizeof(sess->initiatorname)));
399962306a36Sopenharmony_ci
400062306a36Sopenharmony_ciexit_session_conn_param:
400162306a36Sopenharmony_ci	if (fw_ddb_entry)
400262306a36Sopenharmony_ci		dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
400362306a36Sopenharmony_ci				  fw_ddb_entry, fw_ddb_entry_dma);
400462306a36Sopenharmony_ci}
400562306a36Sopenharmony_ci
400662306a36Sopenharmony_ci/*
400762306a36Sopenharmony_ci * Timer routines
400862306a36Sopenharmony_ci */
400962306a36Sopenharmony_cistatic void qla4xxx_timer(struct timer_list *t);
401062306a36Sopenharmony_ci
401162306a36Sopenharmony_cistatic void qla4xxx_start_timer(struct scsi_qla_host *ha,
401262306a36Sopenharmony_ci				unsigned long interval)
401362306a36Sopenharmony_ci{
401462306a36Sopenharmony_ci	DEBUG(printk("scsi: %s: Starting timer thread for adapter %d\n",
401562306a36Sopenharmony_ci		     __func__, ha->host->host_no));
401662306a36Sopenharmony_ci	timer_setup(&ha->timer, qla4xxx_timer, 0);
401762306a36Sopenharmony_ci	ha->timer.expires = jiffies + interval * HZ;
401862306a36Sopenharmony_ci	add_timer(&ha->timer);
401962306a36Sopenharmony_ci	ha->timer_active = 1;
402062306a36Sopenharmony_ci}
402162306a36Sopenharmony_ci
402262306a36Sopenharmony_cistatic void qla4xxx_stop_timer(struct scsi_qla_host *ha)
402362306a36Sopenharmony_ci{
402462306a36Sopenharmony_ci	del_timer_sync(&ha->timer);
402562306a36Sopenharmony_ci	ha->timer_active = 0;
402662306a36Sopenharmony_ci}
402762306a36Sopenharmony_ci
402862306a36Sopenharmony_ci/***
402962306a36Sopenharmony_ci * qla4xxx_mark_device_missing - blocks the session
403062306a36Sopenharmony_ci * @cls_session: Pointer to the session to be blocked
403162306a36Sopenharmony_ci * @ddb_entry: Pointer to device database entry
403262306a36Sopenharmony_ci *
403362306a36Sopenharmony_ci * This routine marks a device missing and close connection.
403462306a36Sopenharmony_ci **/
403562306a36Sopenharmony_civoid qla4xxx_mark_device_missing(struct iscsi_cls_session *cls_session)
403662306a36Sopenharmony_ci{
403762306a36Sopenharmony_ci	iscsi_block_session(cls_session);
403862306a36Sopenharmony_ci}
403962306a36Sopenharmony_ci
404062306a36Sopenharmony_ci/**
404162306a36Sopenharmony_ci * qla4xxx_mark_all_devices_missing - mark all devices as missing.
404262306a36Sopenharmony_ci * @ha: Pointer to host adapter structure.
404362306a36Sopenharmony_ci *
404462306a36Sopenharmony_ci * This routine marks a device missing and resets the relogin retry count.
404562306a36Sopenharmony_ci **/
404662306a36Sopenharmony_civoid qla4xxx_mark_all_devices_missing(struct scsi_qla_host *ha)
404762306a36Sopenharmony_ci{
404862306a36Sopenharmony_ci	iscsi_host_for_each_session(ha->host, qla4xxx_mark_device_missing);
404962306a36Sopenharmony_ci}
405062306a36Sopenharmony_ci
405162306a36Sopenharmony_cistatic struct srb* qla4xxx_get_new_srb(struct scsi_qla_host *ha,
405262306a36Sopenharmony_ci				       struct ddb_entry *ddb_entry,
405362306a36Sopenharmony_ci				       struct scsi_cmnd *cmd)
405462306a36Sopenharmony_ci{
405562306a36Sopenharmony_ci	struct srb *srb;
405662306a36Sopenharmony_ci
405762306a36Sopenharmony_ci	srb = mempool_alloc(ha->srb_mempool, GFP_ATOMIC);
405862306a36Sopenharmony_ci	if (!srb)
405962306a36Sopenharmony_ci		return srb;
406062306a36Sopenharmony_ci
406162306a36Sopenharmony_ci	kref_init(&srb->srb_ref);
406262306a36Sopenharmony_ci	srb->ha = ha;
406362306a36Sopenharmony_ci	srb->ddb = ddb_entry;
406462306a36Sopenharmony_ci	srb->cmd = cmd;
406562306a36Sopenharmony_ci	srb->flags = 0;
406662306a36Sopenharmony_ci	qla4xxx_cmd_priv(cmd)->srb = srb;
406762306a36Sopenharmony_ci
406862306a36Sopenharmony_ci	return srb;
406962306a36Sopenharmony_ci}
407062306a36Sopenharmony_ci
407162306a36Sopenharmony_cistatic void qla4xxx_srb_free_dma(struct scsi_qla_host *ha, struct srb *srb)
407262306a36Sopenharmony_ci{
407362306a36Sopenharmony_ci	struct scsi_cmnd *cmd = srb->cmd;
407462306a36Sopenharmony_ci
407562306a36Sopenharmony_ci	if (srb->flags & SRB_DMA_VALID) {
407662306a36Sopenharmony_ci		scsi_dma_unmap(cmd);
407762306a36Sopenharmony_ci		srb->flags &= ~SRB_DMA_VALID;
407862306a36Sopenharmony_ci	}
407962306a36Sopenharmony_ci	qla4xxx_cmd_priv(cmd)->srb = NULL;
408062306a36Sopenharmony_ci}
408162306a36Sopenharmony_ci
408262306a36Sopenharmony_civoid qla4xxx_srb_compl(struct kref *ref)
408362306a36Sopenharmony_ci{
408462306a36Sopenharmony_ci	struct srb *srb = container_of(ref, struct srb, srb_ref);
408562306a36Sopenharmony_ci	struct scsi_cmnd *cmd = srb->cmd;
408662306a36Sopenharmony_ci	struct scsi_qla_host *ha = srb->ha;
408762306a36Sopenharmony_ci
408862306a36Sopenharmony_ci	qla4xxx_srb_free_dma(ha, srb);
408962306a36Sopenharmony_ci
409062306a36Sopenharmony_ci	mempool_free(srb, ha->srb_mempool);
409162306a36Sopenharmony_ci
409262306a36Sopenharmony_ci	scsi_done(cmd);
409362306a36Sopenharmony_ci}
409462306a36Sopenharmony_ci
409562306a36Sopenharmony_ci/**
409662306a36Sopenharmony_ci * qla4xxx_queuecommand - scsi layer issues scsi command to driver.
409762306a36Sopenharmony_ci * @host: scsi host
409862306a36Sopenharmony_ci * @cmd: Pointer to Linux's SCSI command structure
409962306a36Sopenharmony_ci *
410062306a36Sopenharmony_ci * Remarks:
410162306a36Sopenharmony_ci * This routine is invoked by Linux to send a SCSI command to the driver.
410262306a36Sopenharmony_ci * The mid-level driver tries to ensure that queuecommand never gets
410362306a36Sopenharmony_ci * invoked concurrently with itself or the interrupt handler (although
410462306a36Sopenharmony_ci * the interrupt handler may call this routine as part of request-
410562306a36Sopenharmony_ci * completion handling).   Unfortunely, it sometimes calls the scheduler
410662306a36Sopenharmony_ci * in interrupt context which is a big NO! NO!.
410762306a36Sopenharmony_ci **/
410862306a36Sopenharmony_cistatic int qla4xxx_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd)
410962306a36Sopenharmony_ci{
411062306a36Sopenharmony_ci	struct scsi_qla_host *ha = to_qla_host(host);
411162306a36Sopenharmony_ci	struct ddb_entry *ddb_entry = cmd->device->hostdata;
411262306a36Sopenharmony_ci	struct iscsi_cls_session *sess = ddb_entry->sess;
411362306a36Sopenharmony_ci	struct srb *srb;
411462306a36Sopenharmony_ci	int rval;
411562306a36Sopenharmony_ci
411662306a36Sopenharmony_ci	if (test_bit(AF_EEH_BUSY, &ha->flags)) {
411762306a36Sopenharmony_ci		if (test_bit(AF_PCI_CHANNEL_IO_PERM_FAILURE, &ha->flags))
411862306a36Sopenharmony_ci			cmd->result = DID_NO_CONNECT << 16;
411962306a36Sopenharmony_ci		else
412062306a36Sopenharmony_ci			cmd->result = DID_REQUEUE << 16;
412162306a36Sopenharmony_ci		goto qc_fail_command;
412262306a36Sopenharmony_ci	}
412362306a36Sopenharmony_ci
412462306a36Sopenharmony_ci	if (!sess) {
412562306a36Sopenharmony_ci		cmd->result = DID_IMM_RETRY << 16;
412662306a36Sopenharmony_ci		goto qc_fail_command;
412762306a36Sopenharmony_ci	}
412862306a36Sopenharmony_ci
412962306a36Sopenharmony_ci	rval = iscsi_session_chkready(sess);
413062306a36Sopenharmony_ci	if (rval) {
413162306a36Sopenharmony_ci		cmd->result = rval;
413262306a36Sopenharmony_ci		goto qc_fail_command;
413362306a36Sopenharmony_ci	}
413462306a36Sopenharmony_ci
413562306a36Sopenharmony_ci	if (test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags) ||
413662306a36Sopenharmony_ci	    test_bit(DPC_RESET_ACTIVE, &ha->dpc_flags) ||
413762306a36Sopenharmony_ci	    test_bit(DPC_RESET_HA, &ha->dpc_flags) ||
413862306a36Sopenharmony_ci	    test_bit(DPC_HA_UNRECOVERABLE, &ha->dpc_flags) ||
413962306a36Sopenharmony_ci	    test_bit(DPC_HA_NEED_QUIESCENT, &ha->dpc_flags) ||
414062306a36Sopenharmony_ci	    !test_bit(AF_ONLINE, &ha->flags) ||
414162306a36Sopenharmony_ci	    !test_bit(AF_LINK_UP, &ha->flags) ||
414262306a36Sopenharmony_ci	    test_bit(AF_LOOPBACK, &ha->flags) ||
414362306a36Sopenharmony_ci	    test_bit(DPC_POST_IDC_ACK, &ha->dpc_flags) ||
414462306a36Sopenharmony_ci	    test_bit(DPC_RESTORE_ACB, &ha->dpc_flags) ||
414562306a36Sopenharmony_ci	    test_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags))
414662306a36Sopenharmony_ci		goto qc_host_busy;
414762306a36Sopenharmony_ci
414862306a36Sopenharmony_ci	srb = qla4xxx_get_new_srb(ha, ddb_entry, cmd);
414962306a36Sopenharmony_ci	if (!srb)
415062306a36Sopenharmony_ci		goto qc_host_busy;
415162306a36Sopenharmony_ci
415262306a36Sopenharmony_ci	rval = qla4xxx_send_command_to_isp(ha, srb);
415362306a36Sopenharmony_ci	if (rval != QLA_SUCCESS)
415462306a36Sopenharmony_ci		goto qc_host_busy_free_sp;
415562306a36Sopenharmony_ci
415662306a36Sopenharmony_ci	return 0;
415762306a36Sopenharmony_ci
415862306a36Sopenharmony_ciqc_host_busy_free_sp:
415962306a36Sopenharmony_ci	qla4xxx_srb_free_dma(ha, srb);
416062306a36Sopenharmony_ci	mempool_free(srb, ha->srb_mempool);
416162306a36Sopenharmony_ci
416262306a36Sopenharmony_ciqc_host_busy:
416362306a36Sopenharmony_ci	return SCSI_MLQUEUE_HOST_BUSY;
416462306a36Sopenharmony_ci
416562306a36Sopenharmony_ciqc_fail_command:
416662306a36Sopenharmony_ci	scsi_done(cmd);
416762306a36Sopenharmony_ci
416862306a36Sopenharmony_ci	return 0;
416962306a36Sopenharmony_ci}
417062306a36Sopenharmony_ci
417162306a36Sopenharmony_ci/**
417262306a36Sopenharmony_ci * qla4xxx_mem_free - frees memory allocated to adapter
417362306a36Sopenharmony_ci * @ha: Pointer to host adapter structure.
417462306a36Sopenharmony_ci *
417562306a36Sopenharmony_ci * Frees memory previously allocated by qla4xxx_mem_alloc
417662306a36Sopenharmony_ci **/
417762306a36Sopenharmony_cistatic void qla4xxx_mem_free(struct scsi_qla_host *ha)
417862306a36Sopenharmony_ci{
417962306a36Sopenharmony_ci	if (ha->queues)
418062306a36Sopenharmony_ci		dma_free_coherent(&ha->pdev->dev, ha->queues_len, ha->queues,
418162306a36Sopenharmony_ci				  ha->queues_dma);
418262306a36Sopenharmony_ci
418362306a36Sopenharmony_ci	vfree(ha->fw_dump);
418462306a36Sopenharmony_ci
418562306a36Sopenharmony_ci	ha->queues_len = 0;
418662306a36Sopenharmony_ci	ha->queues = NULL;
418762306a36Sopenharmony_ci	ha->queues_dma = 0;
418862306a36Sopenharmony_ci	ha->request_ring = NULL;
418962306a36Sopenharmony_ci	ha->request_dma = 0;
419062306a36Sopenharmony_ci	ha->response_ring = NULL;
419162306a36Sopenharmony_ci	ha->response_dma = 0;
419262306a36Sopenharmony_ci	ha->shadow_regs = NULL;
419362306a36Sopenharmony_ci	ha->shadow_regs_dma = 0;
419462306a36Sopenharmony_ci	ha->fw_dump = NULL;
419562306a36Sopenharmony_ci	ha->fw_dump_size = 0;
419662306a36Sopenharmony_ci
419762306a36Sopenharmony_ci	/* Free srb pool. */
419862306a36Sopenharmony_ci	mempool_destroy(ha->srb_mempool);
419962306a36Sopenharmony_ci	ha->srb_mempool = NULL;
420062306a36Sopenharmony_ci
420162306a36Sopenharmony_ci	dma_pool_destroy(ha->chap_dma_pool);
420262306a36Sopenharmony_ci
420362306a36Sopenharmony_ci	vfree(ha->chap_list);
420462306a36Sopenharmony_ci	ha->chap_list = NULL;
420562306a36Sopenharmony_ci
420662306a36Sopenharmony_ci	dma_pool_destroy(ha->fw_ddb_dma_pool);
420762306a36Sopenharmony_ci
420862306a36Sopenharmony_ci	/* release io space registers  */
420962306a36Sopenharmony_ci	if (is_qla8022(ha)) {
421062306a36Sopenharmony_ci		if (ha->nx_pcibase)
421162306a36Sopenharmony_ci			iounmap(
421262306a36Sopenharmony_ci			    (struct device_reg_82xx __iomem *)ha->nx_pcibase);
421362306a36Sopenharmony_ci	} else if (is_qla8032(ha) || is_qla8042(ha)) {
421462306a36Sopenharmony_ci		if (ha->nx_pcibase)
421562306a36Sopenharmony_ci			iounmap(
421662306a36Sopenharmony_ci			    (struct device_reg_83xx __iomem *)ha->nx_pcibase);
421762306a36Sopenharmony_ci	} else if (ha->reg) {
421862306a36Sopenharmony_ci		iounmap(ha->reg);
421962306a36Sopenharmony_ci	}
422062306a36Sopenharmony_ci
422162306a36Sopenharmony_ci	vfree(ha->reset_tmplt.buff);
422262306a36Sopenharmony_ci
422362306a36Sopenharmony_ci	pci_release_regions(ha->pdev);
422462306a36Sopenharmony_ci}
422562306a36Sopenharmony_ci
422662306a36Sopenharmony_ci/**
422762306a36Sopenharmony_ci * qla4xxx_mem_alloc - allocates memory for use by adapter.
422862306a36Sopenharmony_ci * @ha: Pointer to host adapter structure
422962306a36Sopenharmony_ci *
423062306a36Sopenharmony_ci * Allocates DMA memory for request and response queues. Also allocates memory
423162306a36Sopenharmony_ci * for srbs.
423262306a36Sopenharmony_ci **/
423362306a36Sopenharmony_cistatic int qla4xxx_mem_alloc(struct scsi_qla_host *ha)
423462306a36Sopenharmony_ci{
423562306a36Sopenharmony_ci	unsigned long align;
423662306a36Sopenharmony_ci
423762306a36Sopenharmony_ci	/* Allocate contiguous block of DMA memory for queues. */
423862306a36Sopenharmony_ci	ha->queues_len = ((REQUEST_QUEUE_DEPTH * QUEUE_SIZE) +
423962306a36Sopenharmony_ci			  (RESPONSE_QUEUE_DEPTH * QUEUE_SIZE) +
424062306a36Sopenharmony_ci			  sizeof(struct shadow_regs) +
424162306a36Sopenharmony_ci			  MEM_ALIGN_VALUE +
424262306a36Sopenharmony_ci			  (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1);
424362306a36Sopenharmony_ci	ha->queues = dma_alloc_coherent(&ha->pdev->dev, ha->queues_len,
424462306a36Sopenharmony_ci					&ha->queues_dma, GFP_KERNEL);
424562306a36Sopenharmony_ci	if (ha->queues == NULL) {
424662306a36Sopenharmony_ci		ql4_printk(KERN_WARNING, ha,
424762306a36Sopenharmony_ci		    "Memory Allocation failed - queues.\n");
424862306a36Sopenharmony_ci
424962306a36Sopenharmony_ci		goto mem_alloc_error_exit;
425062306a36Sopenharmony_ci	}
425162306a36Sopenharmony_ci
425262306a36Sopenharmony_ci	/*
425362306a36Sopenharmony_ci	 * As per RISC alignment requirements -- the bus-address must be a
425462306a36Sopenharmony_ci	 * multiple of the request-ring size (in bytes).
425562306a36Sopenharmony_ci	 */
425662306a36Sopenharmony_ci	align = 0;
425762306a36Sopenharmony_ci	if ((unsigned long)ha->queues_dma & (MEM_ALIGN_VALUE - 1))
425862306a36Sopenharmony_ci		align = MEM_ALIGN_VALUE - ((unsigned long)ha->queues_dma &
425962306a36Sopenharmony_ci					   (MEM_ALIGN_VALUE - 1));
426062306a36Sopenharmony_ci
426162306a36Sopenharmony_ci	/* Update request and response queue pointers. */
426262306a36Sopenharmony_ci	ha->request_dma = ha->queues_dma + align;
426362306a36Sopenharmony_ci	ha->request_ring = (struct queue_entry *) (ha->queues + align);
426462306a36Sopenharmony_ci	ha->response_dma = ha->queues_dma + align +
426562306a36Sopenharmony_ci		(REQUEST_QUEUE_DEPTH * QUEUE_SIZE);
426662306a36Sopenharmony_ci	ha->response_ring = (struct queue_entry *) (ha->queues + align +
426762306a36Sopenharmony_ci						    (REQUEST_QUEUE_DEPTH *
426862306a36Sopenharmony_ci						     QUEUE_SIZE));
426962306a36Sopenharmony_ci	ha->shadow_regs_dma = ha->queues_dma + align +
427062306a36Sopenharmony_ci		(REQUEST_QUEUE_DEPTH * QUEUE_SIZE) +
427162306a36Sopenharmony_ci		(RESPONSE_QUEUE_DEPTH * QUEUE_SIZE);
427262306a36Sopenharmony_ci	ha->shadow_regs = (struct shadow_regs *) (ha->queues + align +
427362306a36Sopenharmony_ci						  (REQUEST_QUEUE_DEPTH *
427462306a36Sopenharmony_ci						   QUEUE_SIZE) +
427562306a36Sopenharmony_ci						  (RESPONSE_QUEUE_DEPTH *
427662306a36Sopenharmony_ci						   QUEUE_SIZE));
427762306a36Sopenharmony_ci
427862306a36Sopenharmony_ci	/* Allocate memory for srb pool. */
427962306a36Sopenharmony_ci	ha->srb_mempool = mempool_create(SRB_MIN_REQ, mempool_alloc_slab,
428062306a36Sopenharmony_ci					 mempool_free_slab, srb_cachep);
428162306a36Sopenharmony_ci	if (ha->srb_mempool == NULL) {
428262306a36Sopenharmony_ci		ql4_printk(KERN_WARNING, ha,
428362306a36Sopenharmony_ci		    "Memory Allocation failed - SRB Pool.\n");
428462306a36Sopenharmony_ci
428562306a36Sopenharmony_ci		goto mem_alloc_error_exit;
428662306a36Sopenharmony_ci	}
428762306a36Sopenharmony_ci
428862306a36Sopenharmony_ci	ha->chap_dma_pool = dma_pool_create("ql4_chap", &ha->pdev->dev,
428962306a36Sopenharmony_ci					    CHAP_DMA_BLOCK_SIZE, 8, 0);
429062306a36Sopenharmony_ci
429162306a36Sopenharmony_ci	if (ha->chap_dma_pool == NULL) {
429262306a36Sopenharmony_ci		ql4_printk(KERN_WARNING, ha,
429362306a36Sopenharmony_ci		    "%s: chap_dma_pool allocation failed..\n", __func__);
429462306a36Sopenharmony_ci		goto mem_alloc_error_exit;
429562306a36Sopenharmony_ci	}
429662306a36Sopenharmony_ci
429762306a36Sopenharmony_ci	ha->fw_ddb_dma_pool = dma_pool_create("ql4_fw_ddb", &ha->pdev->dev,
429862306a36Sopenharmony_ci					      DDB_DMA_BLOCK_SIZE, 8, 0);
429962306a36Sopenharmony_ci
430062306a36Sopenharmony_ci	if (ha->fw_ddb_dma_pool == NULL) {
430162306a36Sopenharmony_ci		ql4_printk(KERN_WARNING, ha,
430262306a36Sopenharmony_ci			   "%s: fw_ddb_dma_pool allocation failed..\n",
430362306a36Sopenharmony_ci			   __func__);
430462306a36Sopenharmony_ci		goto mem_alloc_error_exit;
430562306a36Sopenharmony_ci	}
430662306a36Sopenharmony_ci
430762306a36Sopenharmony_ci	return QLA_SUCCESS;
430862306a36Sopenharmony_ci
430962306a36Sopenharmony_cimem_alloc_error_exit:
431062306a36Sopenharmony_ci	return QLA_ERROR;
431162306a36Sopenharmony_ci}
431262306a36Sopenharmony_ci
431362306a36Sopenharmony_ci/**
431462306a36Sopenharmony_ci * qla4_8xxx_check_temp - Check the ISP82XX temperature.
431562306a36Sopenharmony_ci * @ha: adapter block pointer.
431662306a36Sopenharmony_ci *
431762306a36Sopenharmony_ci * Note: The caller should not hold the idc lock.
431862306a36Sopenharmony_ci **/
431962306a36Sopenharmony_cistatic int qla4_8xxx_check_temp(struct scsi_qla_host *ha)
432062306a36Sopenharmony_ci{
432162306a36Sopenharmony_ci	uint32_t temp, temp_state, temp_val;
432262306a36Sopenharmony_ci	int status = QLA_SUCCESS;
432362306a36Sopenharmony_ci
432462306a36Sopenharmony_ci	temp = qla4_8xxx_rd_direct(ha, QLA8XXX_CRB_TEMP_STATE);
432562306a36Sopenharmony_ci
432662306a36Sopenharmony_ci	temp_state = qla82xx_get_temp_state(temp);
432762306a36Sopenharmony_ci	temp_val = qla82xx_get_temp_val(temp);
432862306a36Sopenharmony_ci
432962306a36Sopenharmony_ci	if (temp_state == QLA82XX_TEMP_PANIC) {
433062306a36Sopenharmony_ci		ql4_printk(KERN_WARNING, ha, "Device temperature %d degrees C"
433162306a36Sopenharmony_ci			   " exceeds maximum allowed. Hardware has been shut"
433262306a36Sopenharmony_ci			   " down.\n", temp_val);
433362306a36Sopenharmony_ci		status = QLA_ERROR;
433462306a36Sopenharmony_ci	} else if (temp_state == QLA82XX_TEMP_WARN) {
433562306a36Sopenharmony_ci		if (ha->temperature == QLA82XX_TEMP_NORMAL)
433662306a36Sopenharmony_ci			ql4_printk(KERN_WARNING, ha, "Device temperature %d"
433762306a36Sopenharmony_ci				   " degrees C exceeds operating range."
433862306a36Sopenharmony_ci				   " Immediate action needed.\n", temp_val);
433962306a36Sopenharmony_ci	} else {
434062306a36Sopenharmony_ci		if (ha->temperature == QLA82XX_TEMP_WARN)
434162306a36Sopenharmony_ci			ql4_printk(KERN_INFO, ha, "Device temperature is"
434262306a36Sopenharmony_ci				   " now %d degrees C in normal range.\n",
434362306a36Sopenharmony_ci				   temp_val);
434462306a36Sopenharmony_ci	}
434562306a36Sopenharmony_ci	ha->temperature = temp_state;
434662306a36Sopenharmony_ci	return status;
434762306a36Sopenharmony_ci}
434862306a36Sopenharmony_ci
434962306a36Sopenharmony_ci/**
435062306a36Sopenharmony_ci * qla4_8xxx_check_fw_alive  - Check firmware health
435162306a36Sopenharmony_ci * @ha: Pointer to host adapter structure.
435262306a36Sopenharmony_ci *
435362306a36Sopenharmony_ci * Context: Interrupt
435462306a36Sopenharmony_ci **/
435562306a36Sopenharmony_cistatic int qla4_8xxx_check_fw_alive(struct scsi_qla_host *ha)
435662306a36Sopenharmony_ci{
435762306a36Sopenharmony_ci	uint32_t fw_heartbeat_counter;
435862306a36Sopenharmony_ci	int status = QLA_SUCCESS;
435962306a36Sopenharmony_ci
436062306a36Sopenharmony_ci	fw_heartbeat_counter = qla4_8xxx_rd_direct(ha,
436162306a36Sopenharmony_ci						   QLA8XXX_PEG_ALIVE_COUNTER);
436262306a36Sopenharmony_ci	/* If PEG_ALIVE_COUNTER is 0xffffffff, AER/EEH is in progress, ignore */
436362306a36Sopenharmony_ci	if (fw_heartbeat_counter == 0xffffffff) {
436462306a36Sopenharmony_ci		DEBUG2(printk(KERN_WARNING "scsi%ld: %s: Device in frozen "
436562306a36Sopenharmony_ci		    "state, QLA82XX_PEG_ALIVE_COUNTER is 0xffffffff\n",
436662306a36Sopenharmony_ci		    ha->host_no, __func__));
436762306a36Sopenharmony_ci		return status;
436862306a36Sopenharmony_ci	}
436962306a36Sopenharmony_ci
437062306a36Sopenharmony_ci	if (ha->fw_heartbeat_counter == fw_heartbeat_counter) {
437162306a36Sopenharmony_ci		ha->seconds_since_last_heartbeat++;
437262306a36Sopenharmony_ci		/* FW not alive after 2 seconds */
437362306a36Sopenharmony_ci		if (ha->seconds_since_last_heartbeat == 2) {
437462306a36Sopenharmony_ci			ha->seconds_since_last_heartbeat = 0;
437562306a36Sopenharmony_ci			qla4_8xxx_dump_peg_reg(ha);
437662306a36Sopenharmony_ci			status = QLA_ERROR;
437762306a36Sopenharmony_ci		}
437862306a36Sopenharmony_ci	} else
437962306a36Sopenharmony_ci		ha->seconds_since_last_heartbeat = 0;
438062306a36Sopenharmony_ci
438162306a36Sopenharmony_ci	ha->fw_heartbeat_counter = fw_heartbeat_counter;
438262306a36Sopenharmony_ci	return status;
438362306a36Sopenharmony_ci}
438462306a36Sopenharmony_ci
438562306a36Sopenharmony_cistatic void qla4_8xxx_process_fw_error(struct scsi_qla_host *ha)
438662306a36Sopenharmony_ci{
438762306a36Sopenharmony_ci	uint32_t halt_status;
438862306a36Sopenharmony_ci	int halt_status_unrecoverable = 0;
438962306a36Sopenharmony_ci
439062306a36Sopenharmony_ci	halt_status = qla4_8xxx_rd_direct(ha, QLA8XXX_PEG_HALT_STATUS1);
439162306a36Sopenharmony_ci
439262306a36Sopenharmony_ci	if (is_qla8022(ha)) {
439362306a36Sopenharmony_ci		ql4_printk(KERN_INFO, ha, "%s: disabling pause transmit on port 0 & 1.\n",
439462306a36Sopenharmony_ci			   __func__);
439562306a36Sopenharmony_ci		qla4_82xx_wr_32(ha, QLA82XX_CRB_NIU + 0x98,
439662306a36Sopenharmony_ci				CRB_NIU_XG_PAUSE_CTL_P0 |
439762306a36Sopenharmony_ci				CRB_NIU_XG_PAUSE_CTL_P1);
439862306a36Sopenharmony_ci
439962306a36Sopenharmony_ci		if (QLA82XX_FWERROR_CODE(halt_status) == 0x67)
440062306a36Sopenharmony_ci			ql4_printk(KERN_ERR, ha, "%s: Firmware aborted with error code 0x00006700. Device is being reset\n",
440162306a36Sopenharmony_ci				   __func__);
440262306a36Sopenharmony_ci		if (halt_status & HALT_STATUS_UNRECOVERABLE)
440362306a36Sopenharmony_ci			halt_status_unrecoverable = 1;
440462306a36Sopenharmony_ci	} else if (is_qla8032(ha) || is_qla8042(ha)) {
440562306a36Sopenharmony_ci		if (halt_status & QLA83XX_HALT_STATUS_FW_RESET)
440662306a36Sopenharmony_ci			ql4_printk(KERN_ERR, ha, "%s: Firmware error detected device is being reset\n",
440762306a36Sopenharmony_ci				   __func__);
440862306a36Sopenharmony_ci		else if (halt_status & QLA83XX_HALT_STATUS_UNRECOVERABLE)
440962306a36Sopenharmony_ci			halt_status_unrecoverable = 1;
441062306a36Sopenharmony_ci	}
441162306a36Sopenharmony_ci
441262306a36Sopenharmony_ci	/*
441362306a36Sopenharmony_ci	 * Since we cannot change dev_state in interrupt context,
441462306a36Sopenharmony_ci	 * set appropriate DPC flag then wakeup DPC
441562306a36Sopenharmony_ci	 */
441662306a36Sopenharmony_ci	if (halt_status_unrecoverable) {
441762306a36Sopenharmony_ci		set_bit(DPC_HA_UNRECOVERABLE, &ha->dpc_flags);
441862306a36Sopenharmony_ci	} else {
441962306a36Sopenharmony_ci		ql4_printk(KERN_INFO, ha, "%s: detect abort needed!\n",
442062306a36Sopenharmony_ci			   __func__);
442162306a36Sopenharmony_ci		set_bit(DPC_RESET_HA, &ha->dpc_flags);
442262306a36Sopenharmony_ci	}
442362306a36Sopenharmony_ci	qla4xxx_mailbox_premature_completion(ha);
442462306a36Sopenharmony_ci	qla4xxx_wake_dpc(ha);
442562306a36Sopenharmony_ci}
442662306a36Sopenharmony_ci
442762306a36Sopenharmony_ci/**
442862306a36Sopenharmony_ci * qla4_8xxx_watchdog - Poll dev state
442962306a36Sopenharmony_ci * @ha: Pointer to host adapter structure.
443062306a36Sopenharmony_ci *
443162306a36Sopenharmony_ci * Context: Interrupt
443262306a36Sopenharmony_ci **/
443362306a36Sopenharmony_civoid qla4_8xxx_watchdog(struct scsi_qla_host *ha)
443462306a36Sopenharmony_ci{
443562306a36Sopenharmony_ci	uint32_t dev_state;
443662306a36Sopenharmony_ci	uint32_t idc_ctrl;
443762306a36Sopenharmony_ci
443862306a36Sopenharmony_ci	if (is_qla8032(ha) &&
443962306a36Sopenharmony_ci	    (qla4_83xx_is_detached(ha) == QLA_SUCCESS))
444062306a36Sopenharmony_ci		WARN_ONCE(1, "%s: iSCSI function %d marked invisible\n",
444162306a36Sopenharmony_ci			  __func__, ha->func_num);
444262306a36Sopenharmony_ci
444362306a36Sopenharmony_ci	/* don't poll if reset is going on */
444462306a36Sopenharmony_ci	if (!(test_bit(DPC_RESET_ACTIVE, &ha->dpc_flags) ||
444562306a36Sopenharmony_ci	    test_bit(DPC_RESET_HA, &ha->dpc_flags) ||
444662306a36Sopenharmony_ci	    test_bit(DPC_RETRY_RESET_HA, &ha->dpc_flags))) {
444762306a36Sopenharmony_ci		dev_state = qla4_8xxx_rd_direct(ha, QLA8XXX_CRB_DEV_STATE);
444862306a36Sopenharmony_ci
444962306a36Sopenharmony_ci		if (qla4_8xxx_check_temp(ha)) {
445062306a36Sopenharmony_ci			if (is_qla8022(ha)) {
445162306a36Sopenharmony_ci				ql4_printk(KERN_INFO, ha, "disabling pause transmit on port 0 & 1.\n");
445262306a36Sopenharmony_ci				qla4_82xx_wr_32(ha, QLA82XX_CRB_NIU + 0x98,
445362306a36Sopenharmony_ci						CRB_NIU_XG_PAUSE_CTL_P0 |
445462306a36Sopenharmony_ci						CRB_NIU_XG_PAUSE_CTL_P1);
445562306a36Sopenharmony_ci			}
445662306a36Sopenharmony_ci			set_bit(DPC_HA_UNRECOVERABLE, &ha->dpc_flags);
445762306a36Sopenharmony_ci			qla4xxx_wake_dpc(ha);
445862306a36Sopenharmony_ci		} else if (dev_state == QLA8XXX_DEV_NEED_RESET &&
445962306a36Sopenharmony_ci			   !test_bit(DPC_RESET_HA, &ha->dpc_flags)) {
446062306a36Sopenharmony_ci
446162306a36Sopenharmony_ci			ql4_printk(KERN_INFO, ha, "%s: HW State: NEED RESET!\n",
446262306a36Sopenharmony_ci				   __func__);
446362306a36Sopenharmony_ci
446462306a36Sopenharmony_ci			if (is_qla8032(ha) || is_qla8042(ha)) {
446562306a36Sopenharmony_ci				idc_ctrl = qla4_83xx_rd_reg(ha,
446662306a36Sopenharmony_ci							QLA83XX_IDC_DRV_CTRL);
446762306a36Sopenharmony_ci				if (!(idc_ctrl & GRACEFUL_RESET_BIT1)) {
446862306a36Sopenharmony_ci					ql4_printk(KERN_INFO, ha, "%s: Graceful reset bit is not set\n",
446962306a36Sopenharmony_ci						   __func__);
447062306a36Sopenharmony_ci					qla4xxx_mailbox_premature_completion(
447162306a36Sopenharmony_ci									    ha);
447262306a36Sopenharmony_ci				}
447362306a36Sopenharmony_ci			}
447462306a36Sopenharmony_ci
447562306a36Sopenharmony_ci			if ((is_qla8032(ha) || is_qla8042(ha)) ||
447662306a36Sopenharmony_ci			    (is_qla8022(ha) && !ql4xdontresethba)) {
447762306a36Sopenharmony_ci				set_bit(DPC_RESET_HA, &ha->dpc_flags);
447862306a36Sopenharmony_ci				qla4xxx_wake_dpc(ha);
447962306a36Sopenharmony_ci			}
448062306a36Sopenharmony_ci		} else if (dev_state == QLA8XXX_DEV_NEED_QUIESCENT &&
448162306a36Sopenharmony_ci		    !test_bit(DPC_HA_NEED_QUIESCENT, &ha->dpc_flags)) {
448262306a36Sopenharmony_ci			ql4_printk(KERN_INFO, ha, "%s: HW State: NEED QUIES!\n",
448362306a36Sopenharmony_ci			    __func__);
448462306a36Sopenharmony_ci			set_bit(DPC_HA_NEED_QUIESCENT, &ha->dpc_flags);
448562306a36Sopenharmony_ci			qla4xxx_wake_dpc(ha);
448662306a36Sopenharmony_ci		} else  {
448762306a36Sopenharmony_ci			/* Check firmware health */
448862306a36Sopenharmony_ci			if (qla4_8xxx_check_fw_alive(ha))
448962306a36Sopenharmony_ci				qla4_8xxx_process_fw_error(ha);
449062306a36Sopenharmony_ci		}
449162306a36Sopenharmony_ci	}
449262306a36Sopenharmony_ci}
449362306a36Sopenharmony_ci
449462306a36Sopenharmony_cistatic void qla4xxx_check_relogin_flash_ddb(struct iscsi_cls_session *cls_sess)
449562306a36Sopenharmony_ci{
449662306a36Sopenharmony_ci	struct iscsi_session *sess;
449762306a36Sopenharmony_ci	struct ddb_entry *ddb_entry;
449862306a36Sopenharmony_ci	struct scsi_qla_host *ha;
449962306a36Sopenharmony_ci
450062306a36Sopenharmony_ci	sess = cls_sess->dd_data;
450162306a36Sopenharmony_ci	ddb_entry = sess->dd_data;
450262306a36Sopenharmony_ci	ha = ddb_entry->ha;
450362306a36Sopenharmony_ci
450462306a36Sopenharmony_ci	if (!(ddb_entry->ddb_type == FLASH_DDB))
450562306a36Sopenharmony_ci		return;
450662306a36Sopenharmony_ci
450762306a36Sopenharmony_ci	if (adapter_up(ha) && !test_bit(DF_RELOGIN, &ddb_entry->flags) &&
450862306a36Sopenharmony_ci	    !iscsi_is_session_online(cls_sess)) {
450962306a36Sopenharmony_ci		if (atomic_read(&ddb_entry->retry_relogin_timer) !=
451062306a36Sopenharmony_ci		    INVALID_ENTRY) {
451162306a36Sopenharmony_ci			if (atomic_read(&ddb_entry->retry_relogin_timer) ==
451262306a36Sopenharmony_ci					0) {
451362306a36Sopenharmony_ci				atomic_set(&ddb_entry->retry_relogin_timer,
451462306a36Sopenharmony_ci					   INVALID_ENTRY);
451562306a36Sopenharmony_ci				set_bit(DPC_RELOGIN_DEVICE, &ha->dpc_flags);
451662306a36Sopenharmony_ci				set_bit(DF_RELOGIN, &ddb_entry->flags);
451762306a36Sopenharmony_ci				DEBUG2(ql4_printk(KERN_INFO, ha,
451862306a36Sopenharmony_ci				       "%s: index [%d] login device\n",
451962306a36Sopenharmony_ci					__func__, ddb_entry->fw_ddb_index));
452062306a36Sopenharmony_ci			} else
452162306a36Sopenharmony_ci				atomic_dec(&ddb_entry->retry_relogin_timer);
452262306a36Sopenharmony_ci		}
452362306a36Sopenharmony_ci	}
452462306a36Sopenharmony_ci
452562306a36Sopenharmony_ci	/* Wait for relogin to timeout */
452662306a36Sopenharmony_ci	if (atomic_read(&ddb_entry->relogin_timer) &&
452762306a36Sopenharmony_ci	    (atomic_dec_and_test(&ddb_entry->relogin_timer) != 0)) {
452862306a36Sopenharmony_ci		/*
452962306a36Sopenharmony_ci		 * If the relogin times out and the device is
453062306a36Sopenharmony_ci		 * still NOT ONLINE then try and relogin again.
453162306a36Sopenharmony_ci		 */
453262306a36Sopenharmony_ci		if (!iscsi_is_session_online(cls_sess)) {
453362306a36Sopenharmony_ci			/* Reset retry relogin timer */
453462306a36Sopenharmony_ci			atomic_inc(&ddb_entry->relogin_retry_count);
453562306a36Sopenharmony_ci			DEBUG2(ql4_printk(KERN_INFO, ha,
453662306a36Sopenharmony_ci				"%s: index[%d] relogin timed out-retrying"
453762306a36Sopenharmony_ci				" relogin (%d), retry (%d)\n", __func__,
453862306a36Sopenharmony_ci				ddb_entry->fw_ddb_index,
453962306a36Sopenharmony_ci				atomic_read(&ddb_entry->relogin_retry_count),
454062306a36Sopenharmony_ci				ddb_entry->default_time2wait + 4));
454162306a36Sopenharmony_ci			set_bit(DPC_RELOGIN_DEVICE, &ha->dpc_flags);
454262306a36Sopenharmony_ci			atomic_set(&ddb_entry->retry_relogin_timer,
454362306a36Sopenharmony_ci				   ddb_entry->default_time2wait + 4);
454462306a36Sopenharmony_ci		}
454562306a36Sopenharmony_ci	}
454662306a36Sopenharmony_ci}
454762306a36Sopenharmony_ci
454862306a36Sopenharmony_ci/**
454962306a36Sopenharmony_ci * qla4xxx_timer - checks every second for work to do.
455062306a36Sopenharmony_ci * @t: Context to obtain pointer to host adapter structure.
455162306a36Sopenharmony_ci **/
455262306a36Sopenharmony_cistatic void qla4xxx_timer(struct timer_list *t)
455362306a36Sopenharmony_ci{
455462306a36Sopenharmony_ci	struct scsi_qla_host *ha = from_timer(ha, t, timer);
455562306a36Sopenharmony_ci	int start_dpc = 0;
455662306a36Sopenharmony_ci	uint16_t w;
455762306a36Sopenharmony_ci
455862306a36Sopenharmony_ci	iscsi_host_for_each_session(ha->host, qla4xxx_check_relogin_flash_ddb);
455962306a36Sopenharmony_ci
456062306a36Sopenharmony_ci	/* If we are in the middle of AER/EEH processing
456162306a36Sopenharmony_ci	 * skip any processing and reschedule the timer
456262306a36Sopenharmony_ci	 */
456362306a36Sopenharmony_ci	if (test_bit(AF_EEH_BUSY, &ha->flags)) {
456462306a36Sopenharmony_ci		mod_timer(&ha->timer, jiffies + HZ);
456562306a36Sopenharmony_ci		return;
456662306a36Sopenharmony_ci	}
456762306a36Sopenharmony_ci
456862306a36Sopenharmony_ci	/* Hardware read to trigger an EEH error during mailbox waits. */
456962306a36Sopenharmony_ci	if (!pci_channel_offline(ha->pdev))
457062306a36Sopenharmony_ci		pci_read_config_word(ha->pdev, PCI_VENDOR_ID, &w);
457162306a36Sopenharmony_ci
457262306a36Sopenharmony_ci	if (is_qla80XX(ha))
457362306a36Sopenharmony_ci		qla4_8xxx_watchdog(ha);
457462306a36Sopenharmony_ci
457562306a36Sopenharmony_ci	if (is_qla40XX(ha)) {
457662306a36Sopenharmony_ci		/* Check for heartbeat interval. */
457762306a36Sopenharmony_ci		if (ha->firmware_options & FWOPT_HEARTBEAT_ENABLE &&
457862306a36Sopenharmony_ci		    ha->heartbeat_interval != 0) {
457962306a36Sopenharmony_ci			ha->seconds_since_last_heartbeat++;
458062306a36Sopenharmony_ci			if (ha->seconds_since_last_heartbeat >
458162306a36Sopenharmony_ci			    ha->heartbeat_interval + 2)
458262306a36Sopenharmony_ci				set_bit(DPC_RESET_HA, &ha->dpc_flags);
458362306a36Sopenharmony_ci		}
458462306a36Sopenharmony_ci	}
458562306a36Sopenharmony_ci
458662306a36Sopenharmony_ci	/* Process any deferred work. */
458762306a36Sopenharmony_ci	if (!list_empty(&ha->work_list))
458862306a36Sopenharmony_ci		start_dpc++;
458962306a36Sopenharmony_ci
459062306a36Sopenharmony_ci	/* Wakeup the dpc routine for this adapter, if needed. */
459162306a36Sopenharmony_ci	if (start_dpc ||
459262306a36Sopenharmony_ci	     test_bit(DPC_RESET_HA, &ha->dpc_flags) ||
459362306a36Sopenharmony_ci	     test_bit(DPC_RETRY_RESET_HA, &ha->dpc_flags) ||
459462306a36Sopenharmony_ci	     test_bit(DPC_RELOGIN_DEVICE, &ha->dpc_flags) ||
459562306a36Sopenharmony_ci	     test_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags) ||
459662306a36Sopenharmony_ci	     test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags) ||
459762306a36Sopenharmony_ci	     test_bit(DPC_GET_DHCP_IP_ADDR, &ha->dpc_flags) ||
459862306a36Sopenharmony_ci	     test_bit(DPC_LINK_CHANGED, &ha->dpc_flags) ||
459962306a36Sopenharmony_ci	     test_bit(DPC_HA_UNRECOVERABLE, &ha->dpc_flags) ||
460062306a36Sopenharmony_ci	     test_bit(DPC_HA_NEED_QUIESCENT, &ha->dpc_flags) ||
460162306a36Sopenharmony_ci	     test_bit(DPC_SYSFS_DDB_EXPORT, &ha->dpc_flags) ||
460262306a36Sopenharmony_ci	     test_bit(DPC_AEN, &ha->dpc_flags)) {
460362306a36Sopenharmony_ci		DEBUG2(printk("scsi%ld: %s: scheduling dpc routine"
460462306a36Sopenharmony_ci			      " - dpc flags = 0x%lx\n",
460562306a36Sopenharmony_ci			      ha->host_no, __func__, ha->dpc_flags));
460662306a36Sopenharmony_ci		qla4xxx_wake_dpc(ha);
460762306a36Sopenharmony_ci	}
460862306a36Sopenharmony_ci
460962306a36Sopenharmony_ci	/* Reschedule timer thread to call us back in one second */
461062306a36Sopenharmony_ci	mod_timer(&ha->timer, jiffies + HZ);
461162306a36Sopenharmony_ci
461262306a36Sopenharmony_ci	DEBUG2(ha->seconds_since_last_intr++);
461362306a36Sopenharmony_ci}
461462306a36Sopenharmony_ci
461562306a36Sopenharmony_ci/**
461662306a36Sopenharmony_ci * qla4xxx_cmd_wait - waits for all outstanding commands to complete
461762306a36Sopenharmony_ci * @ha: Pointer to host adapter structure.
461862306a36Sopenharmony_ci *
461962306a36Sopenharmony_ci * This routine stalls the driver until all outstanding commands are returned.
462062306a36Sopenharmony_ci * Caller must release the Hardware Lock prior to calling this routine.
462162306a36Sopenharmony_ci **/
462262306a36Sopenharmony_cistatic int qla4xxx_cmd_wait(struct scsi_qla_host *ha)
462362306a36Sopenharmony_ci{
462462306a36Sopenharmony_ci	uint32_t index = 0;
462562306a36Sopenharmony_ci	unsigned long flags;
462662306a36Sopenharmony_ci	struct scsi_cmnd *cmd;
462762306a36Sopenharmony_ci	unsigned long wtime;
462862306a36Sopenharmony_ci	uint32_t wtmo;
462962306a36Sopenharmony_ci
463062306a36Sopenharmony_ci	if (is_qla40XX(ha))
463162306a36Sopenharmony_ci		wtmo = WAIT_CMD_TOV;
463262306a36Sopenharmony_ci	else
463362306a36Sopenharmony_ci		wtmo = ha->nx_reset_timeout / 2;
463462306a36Sopenharmony_ci
463562306a36Sopenharmony_ci	wtime = jiffies + (wtmo * HZ);
463662306a36Sopenharmony_ci
463762306a36Sopenharmony_ci	DEBUG2(ql4_printk(KERN_INFO, ha,
463862306a36Sopenharmony_ci			  "Wait up to %u seconds for cmds to complete\n",
463962306a36Sopenharmony_ci			  wtmo));
464062306a36Sopenharmony_ci
464162306a36Sopenharmony_ci	while (!time_after_eq(jiffies, wtime)) {
464262306a36Sopenharmony_ci		spin_lock_irqsave(&ha->hardware_lock, flags);
464362306a36Sopenharmony_ci		/* Find a command that hasn't completed. */
464462306a36Sopenharmony_ci		for (index = 0; index < ha->host->can_queue; index++) {
464562306a36Sopenharmony_ci			cmd = scsi_host_find_tag(ha->host, index);
464662306a36Sopenharmony_ci			/*
464762306a36Sopenharmony_ci			 * We cannot just check if the index is valid,
464862306a36Sopenharmony_ci			 * becase if we are run from the scsi eh, then
464962306a36Sopenharmony_ci			 * the scsi/block layer is going to prevent
465062306a36Sopenharmony_ci			 * the tag from being released.
465162306a36Sopenharmony_ci			 */
465262306a36Sopenharmony_ci			if (cmd != NULL && qla4xxx_cmd_priv(cmd)->srb)
465362306a36Sopenharmony_ci				break;
465462306a36Sopenharmony_ci		}
465562306a36Sopenharmony_ci		spin_unlock_irqrestore(&ha->hardware_lock, flags);
465662306a36Sopenharmony_ci
465762306a36Sopenharmony_ci		/* If No Commands are pending, wait is complete */
465862306a36Sopenharmony_ci		if (index == ha->host->can_queue)
465962306a36Sopenharmony_ci			return QLA_SUCCESS;
466062306a36Sopenharmony_ci
466162306a36Sopenharmony_ci		msleep(1000);
466262306a36Sopenharmony_ci	}
466362306a36Sopenharmony_ci	/* If we timed out on waiting for commands to come back
466462306a36Sopenharmony_ci	 * return ERROR. */
466562306a36Sopenharmony_ci	return QLA_ERROR;
466662306a36Sopenharmony_ci}
466762306a36Sopenharmony_ci
466862306a36Sopenharmony_ciint qla4xxx_hw_reset(struct scsi_qla_host *ha)
466962306a36Sopenharmony_ci{
467062306a36Sopenharmony_ci	uint32_t ctrl_status;
467162306a36Sopenharmony_ci	unsigned long flags = 0;
467262306a36Sopenharmony_ci
467362306a36Sopenharmony_ci	DEBUG2(printk(KERN_ERR "scsi%ld: %s\n", ha->host_no, __func__));
467462306a36Sopenharmony_ci
467562306a36Sopenharmony_ci	if (ql4xxx_lock_drvr_wait(ha) != QLA_SUCCESS)
467662306a36Sopenharmony_ci		return QLA_ERROR;
467762306a36Sopenharmony_ci
467862306a36Sopenharmony_ci	spin_lock_irqsave(&ha->hardware_lock, flags);
467962306a36Sopenharmony_ci
468062306a36Sopenharmony_ci	/*
468162306a36Sopenharmony_ci	 * If the SCSI Reset Interrupt bit is set, clear it.
468262306a36Sopenharmony_ci	 * Otherwise, the Soft Reset won't work.
468362306a36Sopenharmony_ci	 */
468462306a36Sopenharmony_ci	ctrl_status = readw(&ha->reg->ctrl_status);
468562306a36Sopenharmony_ci	if ((ctrl_status & CSR_SCSI_RESET_INTR) != 0)
468662306a36Sopenharmony_ci		writel(set_rmask(CSR_SCSI_RESET_INTR), &ha->reg->ctrl_status);
468762306a36Sopenharmony_ci
468862306a36Sopenharmony_ci	/* Issue Soft Reset */
468962306a36Sopenharmony_ci	writel(set_rmask(CSR_SOFT_RESET), &ha->reg->ctrl_status);
469062306a36Sopenharmony_ci	readl(&ha->reg->ctrl_status);
469162306a36Sopenharmony_ci
469262306a36Sopenharmony_ci	spin_unlock_irqrestore(&ha->hardware_lock, flags);
469362306a36Sopenharmony_ci	return QLA_SUCCESS;
469462306a36Sopenharmony_ci}
469562306a36Sopenharmony_ci
469662306a36Sopenharmony_ci/**
469762306a36Sopenharmony_ci * qla4xxx_soft_reset - performs soft reset.
469862306a36Sopenharmony_ci * @ha: Pointer to host adapter structure.
469962306a36Sopenharmony_ci **/
470062306a36Sopenharmony_ciint qla4xxx_soft_reset(struct scsi_qla_host *ha)
470162306a36Sopenharmony_ci{
470262306a36Sopenharmony_ci	uint32_t max_wait_time;
470362306a36Sopenharmony_ci	unsigned long flags = 0;
470462306a36Sopenharmony_ci	int status;
470562306a36Sopenharmony_ci	uint32_t ctrl_status;
470662306a36Sopenharmony_ci
470762306a36Sopenharmony_ci	status = qla4xxx_hw_reset(ha);
470862306a36Sopenharmony_ci	if (status != QLA_SUCCESS)
470962306a36Sopenharmony_ci		return status;
471062306a36Sopenharmony_ci
471162306a36Sopenharmony_ci	status = QLA_ERROR;
471262306a36Sopenharmony_ci	/* Wait until the Network Reset Intr bit is cleared */
471362306a36Sopenharmony_ci	max_wait_time = RESET_INTR_TOV;
471462306a36Sopenharmony_ci	do {
471562306a36Sopenharmony_ci		spin_lock_irqsave(&ha->hardware_lock, flags);
471662306a36Sopenharmony_ci		ctrl_status = readw(&ha->reg->ctrl_status);
471762306a36Sopenharmony_ci		spin_unlock_irqrestore(&ha->hardware_lock, flags);
471862306a36Sopenharmony_ci
471962306a36Sopenharmony_ci		if ((ctrl_status & CSR_NET_RESET_INTR) == 0)
472062306a36Sopenharmony_ci			break;
472162306a36Sopenharmony_ci
472262306a36Sopenharmony_ci		msleep(1000);
472362306a36Sopenharmony_ci	} while ((--max_wait_time));
472462306a36Sopenharmony_ci
472562306a36Sopenharmony_ci	if ((ctrl_status & CSR_NET_RESET_INTR) != 0) {
472662306a36Sopenharmony_ci		DEBUG2(printk(KERN_WARNING
472762306a36Sopenharmony_ci			      "scsi%ld: Network Reset Intr not cleared by "
472862306a36Sopenharmony_ci			      "Network function, clearing it now!\n",
472962306a36Sopenharmony_ci			      ha->host_no));
473062306a36Sopenharmony_ci		spin_lock_irqsave(&ha->hardware_lock, flags);
473162306a36Sopenharmony_ci		writel(set_rmask(CSR_NET_RESET_INTR), &ha->reg->ctrl_status);
473262306a36Sopenharmony_ci		readl(&ha->reg->ctrl_status);
473362306a36Sopenharmony_ci		spin_unlock_irqrestore(&ha->hardware_lock, flags);
473462306a36Sopenharmony_ci	}
473562306a36Sopenharmony_ci
473662306a36Sopenharmony_ci	/* Wait until the firmware tells us the Soft Reset is done */
473762306a36Sopenharmony_ci	max_wait_time = SOFT_RESET_TOV;
473862306a36Sopenharmony_ci	do {
473962306a36Sopenharmony_ci		spin_lock_irqsave(&ha->hardware_lock, flags);
474062306a36Sopenharmony_ci		ctrl_status = readw(&ha->reg->ctrl_status);
474162306a36Sopenharmony_ci		spin_unlock_irqrestore(&ha->hardware_lock, flags);
474262306a36Sopenharmony_ci
474362306a36Sopenharmony_ci		if ((ctrl_status & CSR_SOFT_RESET) == 0) {
474462306a36Sopenharmony_ci			status = QLA_SUCCESS;
474562306a36Sopenharmony_ci			break;
474662306a36Sopenharmony_ci		}
474762306a36Sopenharmony_ci
474862306a36Sopenharmony_ci		msleep(1000);
474962306a36Sopenharmony_ci	} while ((--max_wait_time));
475062306a36Sopenharmony_ci
475162306a36Sopenharmony_ci	/*
475262306a36Sopenharmony_ci	 * Also, make sure that the SCSI Reset Interrupt bit has been cleared
475362306a36Sopenharmony_ci	 * after the soft reset has taken place.
475462306a36Sopenharmony_ci	 */
475562306a36Sopenharmony_ci	spin_lock_irqsave(&ha->hardware_lock, flags);
475662306a36Sopenharmony_ci	ctrl_status = readw(&ha->reg->ctrl_status);
475762306a36Sopenharmony_ci	if ((ctrl_status & CSR_SCSI_RESET_INTR) != 0) {
475862306a36Sopenharmony_ci		writel(set_rmask(CSR_SCSI_RESET_INTR), &ha->reg->ctrl_status);
475962306a36Sopenharmony_ci		readl(&ha->reg->ctrl_status);
476062306a36Sopenharmony_ci	}
476162306a36Sopenharmony_ci	spin_unlock_irqrestore(&ha->hardware_lock, flags);
476262306a36Sopenharmony_ci
476362306a36Sopenharmony_ci	/* If soft reset fails then most probably the bios on other
476462306a36Sopenharmony_ci	 * function is also enabled.
476562306a36Sopenharmony_ci	 * Since the initialization is sequential the other fn
476662306a36Sopenharmony_ci	 * wont be able to acknowledge the soft reset.
476762306a36Sopenharmony_ci	 * Issue a force soft reset to workaround this scenario.
476862306a36Sopenharmony_ci	 */
476962306a36Sopenharmony_ci	if (max_wait_time == 0) {
477062306a36Sopenharmony_ci		/* Issue Force Soft Reset */
477162306a36Sopenharmony_ci		spin_lock_irqsave(&ha->hardware_lock, flags);
477262306a36Sopenharmony_ci		writel(set_rmask(CSR_FORCE_SOFT_RESET), &ha->reg->ctrl_status);
477362306a36Sopenharmony_ci		readl(&ha->reg->ctrl_status);
477462306a36Sopenharmony_ci		spin_unlock_irqrestore(&ha->hardware_lock, flags);
477562306a36Sopenharmony_ci		/* Wait until the firmware tells us the Soft Reset is done */
477662306a36Sopenharmony_ci		max_wait_time = SOFT_RESET_TOV;
477762306a36Sopenharmony_ci		do {
477862306a36Sopenharmony_ci			spin_lock_irqsave(&ha->hardware_lock, flags);
477962306a36Sopenharmony_ci			ctrl_status = readw(&ha->reg->ctrl_status);
478062306a36Sopenharmony_ci			spin_unlock_irqrestore(&ha->hardware_lock, flags);
478162306a36Sopenharmony_ci
478262306a36Sopenharmony_ci			if ((ctrl_status & CSR_FORCE_SOFT_RESET) == 0) {
478362306a36Sopenharmony_ci				status = QLA_SUCCESS;
478462306a36Sopenharmony_ci				break;
478562306a36Sopenharmony_ci			}
478662306a36Sopenharmony_ci
478762306a36Sopenharmony_ci			msleep(1000);
478862306a36Sopenharmony_ci		} while ((--max_wait_time));
478962306a36Sopenharmony_ci	}
479062306a36Sopenharmony_ci
479162306a36Sopenharmony_ci	return status;
479262306a36Sopenharmony_ci}
479362306a36Sopenharmony_ci
479462306a36Sopenharmony_ci/**
479562306a36Sopenharmony_ci * qla4xxx_abort_active_cmds - returns all outstanding i/o requests to O.S.
479662306a36Sopenharmony_ci * @ha: Pointer to host adapter structure.
479762306a36Sopenharmony_ci * @res: returned scsi status
479862306a36Sopenharmony_ci *
479962306a36Sopenharmony_ci * This routine is called just prior to a HARD RESET to return all
480062306a36Sopenharmony_ci * outstanding commands back to the Operating System.
480162306a36Sopenharmony_ci * Caller should make sure that the following locks are released
480262306a36Sopenharmony_ci * before this calling routine: Hardware lock, and io_request_lock.
480362306a36Sopenharmony_ci **/
480462306a36Sopenharmony_cistatic void qla4xxx_abort_active_cmds(struct scsi_qla_host *ha, int res)
480562306a36Sopenharmony_ci{
480662306a36Sopenharmony_ci	struct srb *srb;
480762306a36Sopenharmony_ci	int i;
480862306a36Sopenharmony_ci	unsigned long flags;
480962306a36Sopenharmony_ci
481062306a36Sopenharmony_ci	spin_lock_irqsave(&ha->hardware_lock, flags);
481162306a36Sopenharmony_ci	for (i = 0; i < ha->host->can_queue; i++) {
481262306a36Sopenharmony_ci		srb = qla4xxx_del_from_active_array(ha, i);
481362306a36Sopenharmony_ci		if (srb != NULL) {
481462306a36Sopenharmony_ci			srb->cmd->result = res;
481562306a36Sopenharmony_ci			kref_put(&srb->srb_ref, qla4xxx_srb_compl);
481662306a36Sopenharmony_ci		}
481762306a36Sopenharmony_ci	}
481862306a36Sopenharmony_ci	spin_unlock_irqrestore(&ha->hardware_lock, flags);
481962306a36Sopenharmony_ci}
482062306a36Sopenharmony_ci
482162306a36Sopenharmony_civoid qla4xxx_dead_adapter_cleanup(struct scsi_qla_host *ha)
482262306a36Sopenharmony_ci{
482362306a36Sopenharmony_ci	clear_bit(AF_ONLINE, &ha->flags);
482462306a36Sopenharmony_ci
482562306a36Sopenharmony_ci	/* Disable the board */
482662306a36Sopenharmony_ci	ql4_printk(KERN_INFO, ha, "Disabling the board\n");
482762306a36Sopenharmony_ci
482862306a36Sopenharmony_ci	qla4xxx_abort_active_cmds(ha, DID_NO_CONNECT << 16);
482962306a36Sopenharmony_ci	qla4xxx_mark_all_devices_missing(ha);
483062306a36Sopenharmony_ci	clear_bit(AF_INIT_DONE, &ha->flags);
483162306a36Sopenharmony_ci}
483262306a36Sopenharmony_ci
483362306a36Sopenharmony_cistatic void qla4xxx_fail_session(struct iscsi_cls_session *cls_session)
483462306a36Sopenharmony_ci{
483562306a36Sopenharmony_ci	struct iscsi_session *sess;
483662306a36Sopenharmony_ci	struct ddb_entry *ddb_entry;
483762306a36Sopenharmony_ci
483862306a36Sopenharmony_ci	sess = cls_session->dd_data;
483962306a36Sopenharmony_ci	ddb_entry = sess->dd_data;
484062306a36Sopenharmony_ci	ddb_entry->fw_ddb_device_state = DDB_DS_SESSION_FAILED;
484162306a36Sopenharmony_ci
484262306a36Sopenharmony_ci	if (ddb_entry->ddb_type == FLASH_DDB)
484362306a36Sopenharmony_ci		iscsi_block_session(ddb_entry->sess);
484462306a36Sopenharmony_ci	else
484562306a36Sopenharmony_ci		iscsi_session_failure(cls_session->dd_data,
484662306a36Sopenharmony_ci				      ISCSI_ERR_CONN_FAILED);
484762306a36Sopenharmony_ci}
484862306a36Sopenharmony_ci
484962306a36Sopenharmony_ci/**
485062306a36Sopenharmony_ci * qla4xxx_recover_adapter - recovers adapter after a fatal error
485162306a36Sopenharmony_ci * @ha: Pointer to host adapter structure.
485262306a36Sopenharmony_ci **/
485362306a36Sopenharmony_cistatic int qla4xxx_recover_adapter(struct scsi_qla_host *ha)
485462306a36Sopenharmony_ci{
485562306a36Sopenharmony_ci	int status = QLA_ERROR;
485662306a36Sopenharmony_ci	uint8_t reset_chip = 0;
485762306a36Sopenharmony_ci	uint32_t dev_state;
485862306a36Sopenharmony_ci	unsigned long wait;
485962306a36Sopenharmony_ci
486062306a36Sopenharmony_ci	/* Stall incoming I/O until we are done */
486162306a36Sopenharmony_ci	scsi_block_requests(ha->host);
486262306a36Sopenharmony_ci	clear_bit(AF_ONLINE, &ha->flags);
486362306a36Sopenharmony_ci	clear_bit(AF_LINK_UP, &ha->flags);
486462306a36Sopenharmony_ci
486562306a36Sopenharmony_ci	DEBUG2(ql4_printk(KERN_INFO, ha, "%s: adapter OFFLINE\n", __func__));
486662306a36Sopenharmony_ci
486762306a36Sopenharmony_ci	set_bit(DPC_RESET_ACTIVE, &ha->dpc_flags);
486862306a36Sopenharmony_ci
486962306a36Sopenharmony_ci	if ((is_qla8032(ha) || is_qla8042(ha)) &&
487062306a36Sopenharmony_ci	    !test_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags)) {
487162306a36Sopenharmony_ci		ql4_printk(KERN_INFO, ha, "%s: disabling pause transmit on port 0 & 1.\n",
487262306a36Sopenharmony_ci			   __func__);
487362306a36Sopenharmony_ci		/* disable pause frame for ISP83xx */
487462306a36Sopenharmony_ci		qla4_83xx_disable_pause(ha);
487562306a36Sopenharmony_ci	}
487662306a36Sopenharmony_ci
487762306a36Sopenharmony_ci	iscsi_host_for_each_session(ha->host, qla4xxx_fail_session);
487862306a36Sopenharmony_ci
487962306a36Sopenharmony_ci	if (test_bit(DPC_RESET_HA, &ha->dpc_flags))
488062306a36Sopenharmony_ci		reset_chip = 1;
488162306a36Sopenharmony_ci
488262306a36Sopenharmony_ci	/* For the DPC_RESET_HA_INTR case (ISP-4xxx specific)
488362306a36Sopenharmony_ci	 * do not reset adapter, jump to initialize_adapter */
488462306a36Sopenharmony_ci	if (test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags)) {
488562306a36Sopenharmony_ci		status = QLA_SUCCESS;
488662306a36Sopenharmony_ci		goto recover_ha_init_adapter;
488762306a36Sopenharmony_ci	}
488862306a36Sopenharmony_ci
488962306a36Sopenharmony_ci	/* For the ISP-8xxx adapter, issue a stop_firmware if invoked
489062306a36Sopenharmony_ci	 * from eh_host_reset or ioctl module */
489162306a36Sopenharmony_ci	if (is_qla80XX(ha) && !reset_chip &&
489262306a36Sopenharmony_ci	    test_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags)) {
489362306a36Sopenharmony_ci
489462306a36Sopenharmony_ci		DEBUG2(ql4_printk(KERN_INFO, ha,
489562306a36Sopenharmony_ci		    "scsi%ld: %s - Performing stop_firmware...\n",
489662306a36Sopenharmony_ci		    ha->host_no, __func__));
489762306a36Sopenharmony_ci		status = ha->isp_ops->reset_firmware(ha);
489862306a36Sopenharmony_ci		if (status == QLA_SUCCESS) {
489962306a36Sopenharmony_ci			ha->isp_ops->disable_intrs(ha);
490062306a36Sopenharmony_ci			qla4xxx_process_aen(ha, FLUSH_DDB_CHANGED_AENS);
490162306a36Sopenharmony_ci			qla4xxx_abort_active_cmds(ha, DID_RESET << 16);
490262306a36Sopenharmony_ci		} else {
490362306a36Sopenharmony_ci			/* If the stop_firmware fails then
490462306a36Sopenharmony_ci			 * reset the entire chip */
490562306a36Sopenharmony_ci			reset_chip = 1;
490662306a36Sopenharmony_ci			clear_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags);
490762306a36Sopenharmony_ci			set_bit(DPC_RESET_HA, &ha->dpc_flags);
490862306a36Sopenharmony_ci		}
490962306a36Sopenharmony_ci	}
491062306a36Sopenharmony_ci
491162306a36Sopenharmony_ci	/* Issue full chip reset if recovering from a catastrophic error,
491262306a36Sopenharmony_ci	 * or if stop_firmware fails for ISP-8xxx.
491362306a36Sopenharmony_ci	 * This is the default case for ISP-4xxx */
491462306a36Sopenharmony_ci	if (is_qla40XX(ha) || reset_chip) {
491562306a36Sopenharmony_ci		if (is_qla40XX(ha))
491662306a36Sopenharmony_ci			goto chip_reset;
491762306a36Sopenharmony_ci
491862306a36Sopenharmony_ci		/* Check if 8XXX firmware is alive or not
491962306a36Sopenharmony_ci		 * We may have arrived here from NEED_RESET
492062306a36Sopenharmony_ci		 * detection only */
492162306a36Sopenharmony_ci		if (test_bit(AF_FW_RECOVERY, &ha->flags))
492262306a36Sopenharmony_ci			goto chip_reset;
492362306a36Sopenharmony_ci
492462306a36Sopenharmony_ci		wait = jiffies + (FW_ALIVE_WAIT_TOV * HZ);
492562306a36Sopenharmony_ci		while (time_before(jiffies, wait)) {
492662306a36Sopenharmony_ci			if (qla4_8xxx_check_fw_alive(ha)) {
492762306a36Sopenharmony_ci				qla4xxx_mailbox_premature_completion(ha);
492862306a36Sopenharmony_ci				break;
492962306a36Sopenharmony_ci			}
493062306a36Sopenharmony_ci
493162306a36Sopenharmony_ci			set_current_state(TASK_UNINTERRUPTIBLE);
493262306a36Sopenharmony_ci			schedule_timeout(HZ);
493362306a36Sopenharmony_ci		}
493462306a36Sopenharmony_cichip_reset:
493562306a36Sopenharmony_ci		if (!test_bit(AF_FW_RECOVERY, &ha->flags))
493662306a36Sopenharmony_ci			qla4xxx_cmd_wait(ha);
493762306a36Sopenharmony_ci
493862306a36Sopenharmony_ci		qla4xxx_process_aen(ha, FLUSH_DDB_CHANGED_AENS);
493962306a36Sopenharmony_ci		DEBUG2(ql4_printk(KERN_INFO, ha,
494062306a36Sopenharmony_ci		    "scsi%ld: %s - Performing chip reset..\n",
494162306a36Sopenharmony_ci		    ha->host_no, __func__));
494262306a36Sopenharmony_ci		status = ha->isp_ops->reset_chip(ha);
494362306a36Sopenharmony_ci		qla4xxx_abort_active_cmds(ha, DID_RESET << 16);
494462306a36Sopenharmony_ci	}
494562306a36Sopenharmony_ci
494662306a36Sopenharmony_ci	/* Flush any pending ddb changed AENs */
494762306a36Sopenharmony_ci	qla4xxx_process_aen(ha, FLUSH_DDB_CHANGED_AENS);
494862306a36Sopenharmony_ci
494962306a36Sopenharmony_cirecover_ha_init_adapter:
495062306a36Sopenharmony_ci	/* Upon successful firmware/chip reset, re-initialize the adapter */
495162306a36Sopenharmony_ci	if (status == QLA_SUCCESS) {
495262306a36Sopenharmony_ci		/* For ISP-4xxx, force function 1 to always initialize
495362306a36Sopenharmony_ci		 * before function 3 to prevent both funcions from
495462306a36Sopenharmony_ci		 * stepping on top of the other */
495562306a36Sopenharmony_ci		if (is_qla40XX(ha) && (ha->mac_index == 3))
495662306a36Sopenharmony_ci			ssleep(6);
495762306a36Sopenharmony_ci
495862306a36Sopenharmony_ci		/* NOTE: AF_ONLINE flag set upon successful completion of
495962306a36Sopenharmony_ci		 * qla4xxx_initialize_adapter */
496062306a36Sopenharmony_ci		status = qla4xxx_initialize_adapter(ha, RESET_ADAPTER);
496162306a36Sopenharmony_ci		if (is_qla80XX(ha) && (status == QLA_ERROR)) {
496262306a36Sopenharmony_ci			status = qla4_8xxx_check_init_adapter_retry(ha);
496362306a36Sopenharmony_ci			if (status == QLA_ERROR) {
496462306a36Sopenharmony_ci				ql4_printk(KERN_INFO, ha, "scsi%ld: %s: Don't retry recover adapter\n",
496562306a36Sopenharmony_ci					   ha->host_no, __func__);
496662306a36Sopenharmony_ci				qla4xxx_dead_adapter_cleanup(ha);
496762306a36Sopenharmony_ci				clear_bit(DPC_RETRY_RESET_HA, &ha->dpc_flags);
496862306a36Sopenharmony_ci				clear_bit(DPC_RESET_HA, &ha->dpc_flags);
496962306a36Sopenharmony_ci				clear_bit(DPC_RESET_HA_FW_CONTEXT,
497062306a36Sopenharmony_ci					  &ha->dpc_flags);
497162306a36Sopenharmony_ci				goto exit_recover;
497262306a36Sopenharmony_ci			}
497362306a36Sopenharmony_ci		}
497462306a36Sopenharmony_ci	}
497562306a36Sopenharmony_ci
497662306a36Sopenharmony_ci	/* Retry failed adapter initialization, if necessary
497762306a36Sopenharmony_ci	 * Do not retry initialize_adapter for RESET_HA_INTR (ISP-4xxx specific)
497862306a36Sopenharmony_ci	 * case to prevent ping-pong resets between functions */
497962306a36Sopenharmony_ci	if (!test_bit(AF_ONLINE, &ha->flags) &&
498062306a36Sopenharmony_ci	    !test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags)) {
498162306a36Sopenharmony_ci		/* Adapter initialization failed, see if we can retry
498262306a36Sopenharmony_ci		 * resetting the ha.
498362306a36Sopenharmony_ci		 * Since we don't want to block the DPC for too long
498462306a36Sopenharmony_ci		 * with multiple resets in the same thread,
498562306a36Sopenharmony_ci		 * utilize DPC to retry */
498662306a36Sopenharmony_ci		if (is_qla80XX(ha)) {
498762306a36Sopenharmony_ci			ha->isp_ops->idc_lock(ha);
498862306a36Sopenharmony_ci			dev_state = qla4_8xxx_rd_direct(ha,
498962306a36Sopenharmony_ci							QLA8XXX_CRB_DEV_STATE);
499062306a36Sopenharmony_ci			ha->isp_ops->idc_unlock(ha);
499162306a36Sopenharmony_ci			if (dev_state == QLA8XXX_DEV_FAILED) {
499262306a36Sopenharmony_ci				ql4_printk(KERN_INFO, ha, "%s: don't retry "
499362306a36Sopenharmony_ci					   "recover adapter. H/W is in Failed "
499462306a36Sopenharmony_ci					   "state\n", __func__);
499562306a36Sopenharmony_ci				qla4xxx_dead_adapter_cleanup(ha);
499662306a36Sopenharmony_ci				clear_bit(DPC_RETRY_RESET_HA, &ha->dpc_flags);
499762306a36Sopenharmony_ci				clear_bit(DPC_RESET_HA, &ha->dpc_flags);
499862306a36Sopenharmony_ci				clear_bit(DPC_RESET_HA_FW_CONTEXT,
499962306a36Sopenharmony_ci						&ha->dpc_flags);
500062306a36Sopenharmony_ci				status = QLA_ERROR;
500162306a36Sopenharmony_ci
500262306a36Sopenharmony_ci				goto exit_recover;
500362306a36Sopenharmony_ci			}
500462306a36Sopenharmony_ci		}
500562306a36Sopenharmony_ci
500662306a36Sopenharmony_ci		if (!test_bit(DPC_RETRY_RESET_HA, &ha->dpc_flags)) {
500762306a36Sopenharmony_ci			ha->retry_reset_ha_cnt = MAX_RESET_HA_RETRIES;
500862306a36Sopenharmony_ci			DEBUG2(printk("scsi%ld: recover adapter - retrying "
500962306a36Sopenharmony_ci				      "(%d) more times\n", ha->host_no,
501062306a36Sopenharmony_ci				      ha->retry_reset_ha_cnt));
501162306a36Sopenharmony_ci			set_bit(DPC_RETRY_RESET_HA, &ha->dpc_flags);
501262306a36Sopenharmony_ci			status = QLA_ERROR;
501362306a36Sopenharmony_ci		} else {
501462306a36Sopenharmony_ci			if (ha->retry_reset_ha_cnt > 0) {
501562306a36Sopenharmony_ci				/* Schedule another Reset HA--DPC will retry */
501662306a36Sopenharmony_ci				ha->retry_reset_ha_cnt--;
501762306a36Sopenharmony_ci				DEBUG2(printk("scsi%ld: recover adapter - "
501862306a36Sopenharmony_ci					      "retry remaining %d\n",
501962306a36Sopenharmony_ci					      ha->host_no,
502062306a36Sopenharmony_ci					      ha->retry_reset_ha_cnt));
502162306a36Sopenharmony_ci				status = QLA_ERROR;
502262306a36Sopenharmony_ci			}
502362306a36Sopenharmony_ci
502462306a36Sopenharmony_ci			if (ha->retry_reset_ha_cnt == 0) {
502562306a36Sopenharmony_ci				/* Recover adapter retries have been exhausted.
502662306a36Sopenharmony_ci				 * Adapter DEAD */
502762306a36Sopenharmony_ci				DEBUG2(printk("scsi%ld: recover adapter "
502862306a36Sopenharmony_ci					      "failed - board disabled\n",
502962306a36Sopenharmony_ci					      ha->host_no));
503062306a36Sopenharmony_ci				qla4xxx_dead_adapter_cleanup(ha);
503162306a36Sopenharmony_ci				clear_bit(DPC_RETRY_RESET_HA, &ha->dpc_flags);
503262306a36Sopenharmony_ci				clear_bit(DPC_RESET_HA, &ha->dpc_flags);
503362306a36Sopenharmony_ci				clear_bit(DPC_RESET_HA_FW_CONTEXT,
503462306a36Sopenharmony_ci					  &ha->dpc_flags);
503562306a36Sopenharmony_ci				status = QLA_ERROR;
503662306a36Sopenharmony_ci			}
503762306a36Sopenharmony_ci		}
503862306a36Sopenharmony_ci	} else {
503962306a36Sopenharmony_ci		clear_bit(DPC_RESET_HA, &ha->dpc_flags);
504062306a36Sopenharmony_ci		clear_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags);
504162306a36Sopenharmony_ci		clear_bit(DPC_RETRY_RESET_HA, &ha->dpc_flags);
504262306a36Sopenharmony_ci	}
504362306a36Sopenharmony_ci
504462306a36Sopenharmony_ciexit_recover:
504562306a36Sopenharmony_ci	ha->adapter_error_count++;
504662306a36Sopenharmony_ci
504762306a36Sopenharmony_ci	if (test_bit(AF_ONLINE, &ha->flags))
504862306a36Sopenharmony_ci		ha->isp_ops->enable_intrs(ha);
504962306a36Sopenharmony_ci
505062306a36Sopenharmony_ci	scsi_unblock_requests(ha->host);
505162306a36Sopenharmony_ci
505262306a36Sopenharmony_ci	clear_bit(DPC_RESET_ACTIVE, &ha->dpc_flags);
505362306a36Sopenharmony_ci	DEBUG2(printk("scsi%ld: recover adapter: %s\n", ha->host_no,
505462306a36Sopenharmony_ci	    status == QLA_ERROR ? "FAILED" : "SUCCEEDED"));
505562306a36Sopenharmony_ci
505662306a36Sopenharmony_ci	return status;
505762306a36Sopenharmony_ci}
505862306a36Sopenharmony_ci
505962306a36Sopenharmony_cistatic void qla4xxx_relogin_devices(struct iscsi_cls_session *cls_session)
506062306a36Sopenharmony_ci{
506162306a36Sopenharmony_ci	struct iscsi_session *sess;
506262306a36Sopenharmony_ci	struct ddb_entry *ddb_entry;
506362306a36Sopenharmony_ci	struct scsi_qla_host *ha;
506462306a36Sopenharmony_ci
506562306a36Sopenharmony_ci	sess = cls_session->dd_data;
506662306a36Sopenharmony_ci	ddb_entry = sess->dd_data;
506762306a36Sopenharmony_ci	ha = ddb_entry->ha;
506862306a36Sopenharmony_ci	if (!iscsi_is_session_online(cls_session)) {
506962306a36Sopenharmony_ci		if (ddb_entry->fw_ddb_device_state == DDB_DS_SESSION_ACTIVE) {
507062306a36Sopenharmony_ci			ql4_printk(KERN_INFO, ha, "scsi%ld: %s: ddb[%d]"
507162306a36Sopenharmony_ci				   " unblock session\n", ha->host_no, __func__,
507262306a36Sopenharmony_ci				   ddb_entry->fw_ddb_index);
507362306a36Sopenharmony_ci			iscsi_unblock_session(ddb_entry->sess);
507462306a36Sopenharmony_ci		} else {
507562306a36Sopenharmony_ci			/* Trigger relogin */
507662306a36Sopenharmony_ci			if (ddb_entry->ddb_type == FLASH_DDB) {
507762306a36Sopenharmony_ci				if (!(test_bit(DF_RELOGIN, &ddb_entry->flags) ||
507862306a36Sopenharmony_ci				      test_bit(DF_DISABLE_RELOGIN,
507962306a36Sopenharmony_ci					       &ddb_entry->flags)))
508062306a36Sopenharmony_ci					qla4xxx_arm_relogin_timer(ddb_entry);
508162306a36Sopenharmony_ci			} else
508262306a36Sopenharmony_ci				iscsi_session_failure(cls_session->dd_data,
508362306a36Sopenharmony_ci						      ISCSI_ERR_CONN_FAILED);
508462306a36Sopenharmony_ci		}
508562306a36Sopenharmony_ci	}
508662306a36Sopenharmony_ci}
508762306a36Sopenharmony_ci
508862306a36Sopenharmony_ciint qla4xxx_unblock_flash_ddb(struct iscsi_cls_session *cls_session)
508962306a36Sopenharmony_ci{
509062306a36Sopenharmony_ci	struct iscsi_session *sess;
509162306a36Sopenharmony_ci	struct ddb_entry *ddb_entry;
509262306a36Sopenharmony_ci	struct scsi_qla_host *ha;
509362306a36Sopenharmony_ci
509462306a36Sopenharmony_ci	sess = cls_session->dd_data;
509562306a36Sopenharmony_ci	ddb_entry = sess->dd_data;
509662306a36Sopenharmony_ci	ha = ddb_entry->ha;
509762306a36Sopenharmony_ci	ql4_printk(KERN_INFO, ha, "scsi%ld: %s: ddb[%d]"
509862306a36Sopenharmony_ci		   " unblock session\n", ha->host_no, __func__,
509962306a36Sopenharmony_ci		   ddb_entry->fw_ddb_index);
510062306a36Sopenharmony_ci
510162306a36Sopenharmony_ci	iscsi_unblock_session(ddb_entry->sess);
510262306a36Sopenharmony_ci
510362306a36Sopenharmony_ci	/* Start scan target */
510462306a36Sopenharmony_ci	if (test_bit(AF_ONLINE, &ha->flags)) {
510562306a36Sopenharmony_ci		ql4_printk(KERN_INFO, ha, "scsi%ld: %s: ddb[%d]"
510662306a36Sopenharmony_ci			   " start scan\n", ha->host_no, __func__,
510762306a36Sopenharmony_ci			   ddb_entry->fw_ddb_index);
510862306a36Sopenharmony_ci		queue_work(ddb_entry->sess->workq, &ddb_entry->sess->scan_work);
510962306a36Sopenharmony_ci	}
511062306a36Sopenharmony_ci	return QLA_SUCCESS;
511162306a36Sopenharmony_ci}
511262306a36Sopenharmony_ci
511362306a36Sopenharmony_ciint qla4xxx_unblock_ddb(struct iscsi_cls_session *cls_session)
511462306a36Sopenharmony_ci{
511562306a36Sopenharmony_ci	struct iscsi_session *sess;
511662306a36Sopenharmony_ci	struct ddb_entry *ddb_entry;
511762306a36Sopenharmony_ci	struct scsi_qla_host *ha;
511862306a36Sopenharmony_ci	int status = QLA_SUCCESS;
511962306a36Sopenharmony_ci
512062306a36Sopenharmony_ci	sess = cls_session->dd_data;
512162306a36Sopenharmony_ci	ddb_entry = sess->dd_data;
512262306a36Sopenharmony_ci	ha = ddb_entry->ha;
512362306a36Sopenharmony_ci	ql4_printk(KERN_INFO, ha, "scsi%ld: %s: ddb[%d]"
512462306a36Sopenharmony_ci		   " unblock user space session\n", ha->host_no, __func__,
512562306a36Sopenharmony_ci		   ddb_entry->fw_ddb_index);
512662306a36Sopenharmony_ci
512762306a36Sopenharmony_ci	if (!iscsi_is_session_online(cls_session)) {
512862306a36Sopenharmony_ci		iscsi_conn_start(ddb_entry->conn);
512962306a36Sopenharmony_ci		iscsi_conn_login_event(ddb_entry->conn,
513062306a36Sopenharmony_ci				       ISCSI_CONN_STATE_LOGGED_IN);
513162306a36Sopenharmony_ci	} else {
513262306a36Sopenharmony_ci		ql4_printk(KERN_INFO, ha,
513362306a36Sopenharmony_ci			   "scsi%ld: %s: ddb[%d] session [%d] already logged in\n",
513462306a36Sopenharmony_ci			   ha->host_no, __func__, ddb_entry->fw_ddb_index,
513562306a36Sopenharmony_ci			   cls_session->sid);
513662306a36Sopenharmony_ci		status = QLA_ERROR;
513762306a36Sopenharmony_ci	}
513862306a36Sopenharmony_ci
513962306a36Sopenharmony_ci	return status;
514062306a36Sopenharmony_ci}
514162306a36Sopenharmony_ci
514262306a36Sopenharmony_cistatic void qla4xxx_relogin_all_devices(struct scsi_qla_host *ha)
514362306a36Sopenharmony_ci{
514462306a36Sopenharmony_ci	iscsi_host_for_each_session(ha->host, qla4xxx_relogin_devices);
514562306a36Sopenharmony_ci}
514662306a36Sopenharmony_ci
514762306a36Sopenharmony_cistatic void qla4xxx_relogin_flash_ddb(struct iscsi_cls_session *cls_sess)
514862306a36Sopenharmony_ci{
514962306a36Sopenharmony_ci	uint16_t relogin_timer;
515062306a36Sopenharmony_ci	struct iscsi_session *sess;
515162306a36Sopenharmony_ci	struct ddb_entry *ddb_entry;
515262306a36Sopenharmony_ci	struct scsi_qla_host *ha;
515362306a36Sopenharmony_ci
515462306a36Sopenharmony_ci	sess = cls_sess->dd_data;
515562306a36Sopenharmony_ci	ddb_entry = sess->dd_data;
515662306a36Sopenharmony_ci	ha = ddb_entry->ha;
515762306a36Sopenharmony_ci
515862306a36Sopenharmony_ci	relogin_timer = max(ddb_entry->default_relogin_timeout,
515962306a36Sopenharmony_ci			    (uint16_t)RELOGIN_TOV);
516062306a36Sopenharmony_ci	atomic_set(&ddb_entry->relogin_timer, relogin_timer);
516162306a36Sopenharmony_ci
516262306a36Sopenharmony_ci	DEBUG2(ql4_printk(KERN_INFO, ha,
516362306a36Sopenharmony_ci			  "scsi%ld: Relogin index [%d]. TOV=%d\n", ha->host_no,
516462306a36Sopenharmony_ci			  ddb_entry->fw_ddb_index, relogin_timer));
516562306a36Sopenharmony_ci
516662306a36Sopenharmony_ci	qla4xxx_login_flash_ddb(cls_sess);
516762306a36Sopenharmony_ci}
516862306a36Sopenharmony_ci
516962306a36Sopenharmony_cistatic void qla4xxx_dpc_relogin(struct iscsi_cls_session *cls_sess)
517062306a36Sopenharmony_ci{
517162306a36Sopenharmony_ci	struct iscsi_session *sess;
517262306a36Sopenharmony_ci	struct ddb_entry *ddb_entry;
517362306a36Sopenharmony_ci	struct scsi_qla_host *ha;
517462306a36Sopenharmony_ci
517562306a36Sopenharmony_ci	sess = cls_sess->dd_data;
517662306a36Sopenharmony_ci	ddb_entry = sess->dd_data;
517762306a36Sopenharmony_ci	ha = ddb_entry->ha;
517862306a36Sopenharmony_ci
517962306a36Sopenharmony_ci	if (!(ddb_entry->ddb_type == FLASH_DDB))
518062306a36Sopenharmony_ci		return;
518162306a36Sopenharmony_ci
518262306a36Sopenharmony_ci	if (test_bit(DF_DISABLE_RELOGIN, &ddb_entry->flags))
518362306a36Sopenharmony_ci		return;
518462306a36Sopenharmony_ci
518562306a36Sopenharmony_ci	if (test_and_clear_bit(DF_RELOGIN, &ddb_entry->flags) &&
518662306a36Sopenharmony_ci	    !iscsi_is_session_online(cls_sess)) {
518762306a36Sopenharmony_ci		DEBUG2(ql4_printk(KERN_INFO, ha,
518862306a36Sopenharmony_ci				  "relogin issued\n"));
518962306a36Sopenharmony_ci		qla4xxx_relogin_flash_ddb(cls_sess);
519062306a36Sopenharmony_ci	}
519162306a36Sopenharmony_ci}
519262306a36Sopenharmony_ci
519362306a36Sopenharmony_civoid qla4xxx_wake_dpc(struct scsi_qla_host *ha)
519462306a36Sopenharmony_ci{
519562306a36Sopenharmony_ci	if (ha->dpc_thread)
519662306a36Sopenharmony_ci		queue_work(ha->dpc_thread, &ha->dpc_work);
519762306a36Sopenharmony_ci}
519862306a36Sopenharmony_ci
519962306a36Sopenharmony_cistatic struct qla4_work_evt *
520062306a36Sopenharmony_ciqla4xxx_alloc_work(struct scsi_qla_host *ha, uint32_t data_size,
520162306a36Sopenharmony_ci		   enum qla4_work_type type)
520262306a36Sopenharmony_ci{
520362306a36Sopenharmony_ci	struct qla4_work_evt *e;
520462306a36Sopenharmony_ci	uint32_t size = sizeof(struct qla4_work_evt) + data_size;
520562306a36Sopenharmony_ci
520662306a36Sopenharmony_ci	e = kzalloc(size, GFP_ATOMIC);
520762306a36Sopenharmony_ci	if (!e)
520862306a36Sopenharmony_ci		return NULL;
520962306a36Sopenharmony_ci
521062306a36Sopenharmony_ci	INIT_LIST_HEAD(&e->list);
521162306a36Sopenharmony_ci	e->type = type;
521262306a36Sopenharmony_ci	return e;
521362306a36Sopenharmony_ci}
521462306a36Sopenharmony_ci
521562306a36Sopenharmony_cistatic void qla4xxx_post_work(struct scsi_qla_host *ha,
521662306a36Sopenharmony_ci			     struct qla4_work_evt *e)
521762306a36Sopenharmony_ci{
521862306a36Sopenharmony_ci	unsigned long flags;
521962306a36Sopenharmony_ci
522062306a36Sopenharmony_ci	spin_lock_irqsave(&ha->work_lock, flags);
522162306a36Sopenharmony_ci	list_add_tail(&e->list, &ha->work_list);
522262306a36Sopenharmony_ci	spin_unlock_irqrestore(&ha->work_lock, flags);
522362306a36Sopenharmony_ci	qla4xxx_wake_dpc(ha);
522462306a36Sopenharmony_ci}
522562306a36Sopenharmony_ci
522662306a36Sopenharmony_ciint qla4xxx_post_aen_work(struct scsi_qla_host *ha,
522762306a36Sopenharmony_ci			  enum iscsi_host_event_code aen_code,
522862306a36Sopenharmony_ci			  uint32_t data_size, uint8_t *data)
522962306a36Sopenharmony_ci{
523062306a36Sopenharmony_ci	struct qla4_work_evt *e;
523162306a36Sopenharmony_ci
523262306a36Sopenharmony_ci	e = qla4xxx_alloc_work(ha, data_size, QLA4_EVENT_AEN);
523362306a36Sopenharmony_ci	if (!e)
523462306a36Sopenharmony_ci		return QLA_ERROR;
523562306a36Sopenharmony_ci
523662306a36Sopenharmony_ci	e->u.aen.code = aen_code;
523762306a36Sopenharmony_ci	e->u.aen.data_size = data_size;
523862306a36Sopenharmony_ci	memcpy(e->u.aen.data, data, data_size);
523962306a36Sopenharmony_ci
524062306a36Sopenharmony_ci	qla4xxx_post_work(ha, e);
524162306a36Sopenharmony_ci
524262306a36Sopenharmony_ci	return QLA_SUCCESS;
524362306a36Sopenharmony_ci}
524462306a36Sopenharmony_ci
524562306a36Sopenharmony_ciint qla4xxx_post_ping_evt_work(struct scsi_qla_host *ha,
524662306a36Sopenharmony_ci			       uint32_t status, uint32_t pid,
524762306a36Sopenharmony_ci			       uint32_t data_size, uint8_t *data)
524862306a36Sopenharmony_ci{
524962306a36Sopenharmony_ci	struct qla4_work_evt *e;
525062306a36Sopenharmony_ci
525162306a36Sopenharmony_ci	e = qla4xxx_alloc_work(ha, data_size, QLA4_EVENT_PING_STATUS);
525262306a36Sopenharmony_ci	if (!e)
525362306a36Sopenharmony_ci		return QLA_ERROR;
525462306a36Sopenharmony_ci
525562306a36Sopenharmony_ci	e->u.ping.status = status;
525662306a36Sopenharmony_ci	e->u.ping.pid = pid;
525762306a36Sopenharmony_ci	e->u.ping.data_size = data_size;
525862306a36Sopenharmony_ci	memcpy(e->u.ping.data, data, data_size);
525962306a36Sopenharmony_ci
526062306a36Sopenharmony_ci	qla4xxx_post_work(ha, e);
526162306a36Sopenharmony_ci
526262306a36Sopenharmony_ci	return QLA_SUCCESS;
526362306a36Sopenharmony_ci}
526462306a36Sopenharmony_ci
526562306a36Sopenharmony_cistatic void qla4xxx_do_work(struct scsi_qla_host *ha)
526662306a36Sopenharmony_ci{
526762306a36Sopenharmony_ci	struct qla4_work_evt *e, *tmp;
526862306a36Sopenharmony_ci	unsigned long flags;
526962306a36Sopenharmony_ci	LIST_HEAD(work);
527062306a36Sopenharmony_ci
527162306a36Sopenharmony_ci	spin_lock_irqsave(&ha->work_lock, flags);
527262306a36Sopenharmony_ci	list_splice_init(&ha->work_list, &work);
527362306a36Sopenharmony_ci	spin_unlock_irqrestore(&ha->work_lock, flags);
527462306a36Sopenharmony_ci
527562306a36Sopenharmony_ci	list_for_each_entry_safe(e, tmp, &work, list) {
527662306a36Sopenharmony_ci		list_del_init(&e->list);
527762306a36Sopenharmony_ci
527862306a36Sopenharmony_ci		switch (e->type) {
527962306a36Sopenharmony_ci		case QLA4_EVENT_AEN:
528062306a36Sopenharmony_ci			iscsi_post_host_event(ha->host_no,
528162306a36Sopenharmony_ci					      &qla4xxx_iscsi_transport,
528262306a36Sopenharmony_ci					      e->u.aen.code,
528362306a36Sopenharmony_ci					      e->u.aen.data_size,
528462306a36Sopenharmony_ci					      e->u.aen.data);
528562306a36Sopenharmony_ci			break;
528662306a36Sopenharmony_ci		case QLA4_EVENT_PING_STATUS:
528762306a36Sopenharmony_ci			iscsi_ping_comp_event(ha->host_no,
528862306a36Sopenharmony_ci					      &qla4xxx_iscsi_transport,
528962306a36Sopenharmony_ci					      e->u.ping.status,
529062306a36Sopenharmony_ci					      e->u.ping.pid,
529162306a36Sopenharmony_ci					      e->u.ping.data_size,
529262306a36Sopenharmony_ci					      e->u.ping.data);
529362306a36Sopenharmony_ci			break;
529462306a36Sopenharmony_ci		default:
529562306a36Sopenharmony_ci			ql4_printk(KERN_WARNING, ha, "event type: 0x%x not "
529662306a36Sopenharmony_ci				   "supported", e->type);
529762306a36Sopenharmony_ci		}
529862306a36Sopenharmony_ci		kfree(e);
529962306a36Sopenharmony_ci	}
530062306a36Sopenharmony_ci}
530162306a36Sopenharmony_ci
530262306a36Sopenharmony_ci/**
530362306a36Sopenharmony_ci * qla4xxx_do_dpc - dpc routine
530462306a36Sopenharmony_ci * @work: Context to obtain pointer to host adapter structure.
530562306a36Sopenharmony_ci *
530662306a36Sopenharmony_ci * This routine is a task that is schedule by the interrupt handler
530762306a36Sopenharmony_ci * to perform the background processing for interrupts.  We put it
530862306a36Sopenharmony_ci * on a task queue that is consumed whenever the scheduler runs; that's
530962306a36Sopenharmony_ci * so you can do anything (i.e. put the process to sleep etc).  In fact,
531062306a36Sopenharmony_ci * the mid-level tries to sleep when it reaches the driver threshold
531162306a36Sopenharmony_ci * "host->can_queue". This can cause a panic if we were in our interrupt code.
531262306a36Sopenharmony_ci **/
531362306a36Sopenharmony_cistatic void qla4xxx_do_dpc(struct work_struct *work)
531462306a36Sopenharmony_ci{
531562306a36Sopenharmony_ci	struct scsi_qla_host *ha =
531662306a36Sopenharmony_ci		container_of(work, struct scsi_qla_host, dpc_work);
531762306a36Sopenharmony_ci	int status = QLA_ERROR;
531862306a36Sopenharmony_ci
531962306a36Sopenharmony_ci	DEBUG2(ql4_printk(KERN_INFO, ha,
532062306a36Sopenharmony_ci			  "scsi%ld: %s: DPC handler waking up. flags = 0x%08lx, dpc_flags = 0x%08lx\n",
532162306a36Sopenharmony_ci			  ha->host_no, __func__, ha->flags, ha->dpc_flags));
532262306a36Sopenharmony_ci
532362306a36Sopenharmony_ci	/* Initialization not yet finished. Don't do anything yet. */
532462306a36Sopenharmony_ci	if (!test_bit(AF_INIT_DONE, &ha->flags))
532562306a36Sopenharmony_ci		return;
532662306a36Sopenharmony_ci
532762306a36Sopenharmony_ci	if (test_bit(AF_EEH_BUSY, &ha->flags)) {
532862306a36Sopenharmony_ci		DEBUG2(printk(KERN_INFO "scsi%ld: %s: flags = %lx\n",
532962306a36Sopenharmony_ci		    ha->host_no, __func__, ha->flags));
533062306a36Sopenharmony_ci		return;
533162306a36Sopenharmony_ci	}
533262306a36Sopenharmony_ci
533362306a36Sopenharmony_ci	/* post events to application */
533462306a36Sopenharmony_ci	qla4xxx_do_work(ha);
533562306a36Sopenharmony_ci
533662306a36Sopenharmony_ci	if (is_qla80XX(ha)) {
533762306a36Sopenharmony_ci		if (test_bit(DPC_HA_UNRECOVERABLE, &ha->dpc_flags)) {
533862306a36Sopenharmony_ci			if (is_qla8032(ha) || is_qla8042(ha)) {
533962306a36Sopenharmony_ci				ql4_printk(KERN_INFO, ha, "%s: disabling pause transmit on port 0 & 1.\n",
534062306a36Sopenharmony_ci					   __func__);
534162306a36Sopenharmony_ci				/* disable pause frame for ISP83xx */
534262306a36Sopenharmony_ci				qla4_83xx_disable_pause(ha);
534362306a36Sopenharmony_ci			}
534462306a36Sopenharmony_ci
534562306a36Sopenharmony_ci			ha->isp_ops->idc_lock(ha);
534662306a36Sopenharmony_ci			qla4_8xxx_wr_direct(ha, QLA8XXX_CRB_DEV_STATE,
534762306a36Sopenharmony_ci					    QLA8XXX_DEV_FAILED);
534862306a36Sopenharmony_ci			ha->isp_ops->idc_unlock(ha);
534962306a36Sopenharmony_ci			ql4_printk(KERN_INFO, ha, "HW State: FAILED\n");
535062306a36Sopenharmony_ci			qla4_8xxx_device_state_handler(ha);
535162306a36Sopenharmony_ci		}
535262306a36Sopenharmony_ci
535362306a36Sopenharmony_ci		if (test_bit(DPC_POST_IDC_ACK, &ha->dpc_flags)) {
535462306a36Sopenharmony_ci			if (is_qla8042(ha)) {
535562306a36Sopenharmony_ci				if (ha->idc_info.info2 &
535662306a36Sopenharmony_ci				    ENABLE_INTERNAL_LOOPBACK) {
535762306a36Sopenharmony_ci					ql4_printk(KERN_INFO, ha, "%s: Disabling ACB\n",
535862306a36Sopenharmony_ci						   __func__);
535962306a36Sopenharmony_ci					status = qla4_84xx_config_acb(ha,
536062306a36Sopenharmony_ci							    ACB_CONFIG_DISABLE);
536162306a36Sopenharmony_ci					if (status != QLA_SUCCESS) {
536262306a36Sopenharmony_ci						ql4_printk(KERN_INFO, ha, "%s: ACB config failed\n",
536362306a36Sopenharmony_ci							   __func__);
536462306a36Sopenharmony_ci					}
536562306a36Sopenharmony_ci				}
536662306a36Sopenharmony_ci			}
536762306a36Sopenharmony_ci			qla4_83xx_post_idc_ack(ha);
536862306a36Sopenharmony_ci			clear_bit(DPC_POST_IDC_ACK, &ha->dpc_flags);
536962306a36Sopenharmony_ci		}
537062306a36Sopenharmony_ci
537162306a36Sopenharmony_ci		if (is_qla8042(ha) &&
537262306a36Sopenharmony_ci		    test_bit(DPC_RESTORE_ACB, &ha->dpc_flags)) {
537362306a36Sopenharmony_ci			ql4_printk(KERN_INFO, ha, "%s: Restoring ACB\n",
537462306a36Sopenharmony_ci				   __func__);
537562306a36Sopenharmony_ci			if (qla4_84xx_config_acb(ha, ACB_CONFIG_SET) !=
537662306a36Sopenharmony_ci			    QLA_SUCCESS) {
537762306a36Sopenharmony_ci				ql4_printk(KERN_INFO, ha, "%s: ACB config failed ",
537862306a36Sopenharmony_ci					   __func__);
537962306a36Sopenharmony_ci			}
538062306a36Sopenharmony_ci			clear_bit(DPC_RESTORE_ACB, &ha->dpc_flags);
538162306a36Sopenharmony_ci		}
538262306a36Sopenharmony_ci
538362306a36Sopenharmony_ci		if (test_and_clear_bit(DPC_HA_NEED_QUIESCENT, &ha->dpc_flags)) {
538462306a36Sopenharmony_ci			qla4_8xxx_need_qsnt_handler(ha);
538562306a36Sopenharmony_ci		}
538662306a36Sopenharmony_ci	}
538762306a36Sopenharmony_ci
538862306a36Sopenharmony_ci	if (!test_bit(DPC_RESET_ACTIVE, &ha->dpc_flags) &&
538962306a36Sopenharmony_ci	    (test_bit(DPC_RESET_HA, &ha->dpc_flags) ||
539062306a36Sopenharmony_ci	    test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags) ||
539162306a36Sopenharmony_ci	    test_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags))) {
539262306a36Sopenharmony_ci		if ((is_qla8022(ha) && ql4xdontresethba) ||
539362306a36Sopenharmony_ci		    ((is_qla8032(ha) || is_qla8042(ha)) &&
539462306a36Sopenharmony_ci		     qla4_83xx_idc_dontreset(ha))) {
539562306a36Sopenharmony_ci			DEBUG2(printk("scsi%ld: %s: Don't Reset HBA\n",
539662306a36Sopenharmony_ci			    ha->host_no, __func__));
539762306a36Sopenharmony_ci			clear_bit(DPC_RESET_HA, &ha->dpc_flags);
539862306a36Sopenharmony_ci			clear_bit(DPC_RESET_HA_INTR, &ha->dpc_flags);
539962306a36Sopenharmony_ci			clear_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags);
540062306a36Sopenharmony_ci			goto dpc_post_reset_ha;
540162306a36Sopenharmony_ci		}
540262306a36Sopenharmony_ci		if (test_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags) ||
540362306a36Sopenharmony_ci		    test_bit(DPC_RESET_HA, &ha->dpc_flags))
540462306a36Sopenharmony_ci			qla4xxx_recover_adapter(ha);
540562306a36Sopenharmony_ci
540662306a36Sopenharmony_ci		if (test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags)) {
540762306a36Sopenharmony_ci			uint8_t wait_time = RESET_INTR_TOV;
540862306a36Sopenharmony_ci
540962306a36Sopenharmony_ci			while ((readw(&ha->reg->ctrl_status) &
541062306a36Sopenharmony_ci				(CSR_SOFT_RESET | CSR_FORCE_SOFT_RESET)) != 0) {
541162306a36Sopenharmony_ci				if (--wait_time == 0)
541262306a36Sopenharmony_ci					break;
541362306a36Sopenharmony_ci				msleep(1000);
541462306a36Sopenharmony_ci			}
541562306a36Sopenharmony_ci			if (wait_time == 0)
541662306a36Sopenharmony_ci				DEBUG2(printk("scsi%ld: %s: SR|FSR "
541762306a36Sopenharmony_ci					      "bit not cleared-- resetting\n",
541862306a36Sopenharmony_ci					      ha->host_no, __func__));
541962306a36Sopenharmony_ci			qla4xxx_abort_active_cmds(ha, DID_RESET << 16);
542062306a36Sopenharmony_ci			if (ql4xxx_lock_drvr_wait(ha) == QLA_SUCCESS) {
542162306a36Sopenharmony_ci				qla4xxx_process_aen(ha, FLUSH_DDB_CHANGED_AENS);
542262306a36Sopenharmony_ci				status = qla4xxx_recover_adapter(ha);
542362306a36Sopenharmony_ci			}
542462306a36Sopenharmony_ci			clear_bit(DPC_RESET_HA_INTR, &ha->dpc_flags);
542562306a36Sopenharmony_ci			if (status == QLA_SUCCESS)
542662306a36Sopenharmony_ci				ha->isp_ops->enable_intrs(ha);
542762306a36Sopenharmony_ci		}
542862306a36Sopenharmony_ci	}
542962306a36Sopenharmony_ci
543062306a36Sopenharmony_cidpc_post_reset_ha:
543162306a36Sopenharmony_ci	/* ---- process AEN? --- */
543262306a36Sopenharmony_ci	if (test_and_clear_bit(DPC_AEN, &ha->dpc_flags))
543362306a36Sopenharmony_ci		qla4xxx_process_aen(ha, PROCESS_ALL_AENS);
543462306a36Sopenharmony_ci
543562306a36Sopenharmony_ci	/* ---- Get DHCP IP Address? --- */
543662306a36Sopenharmony_ci	if (test_and_clear_bit(DPC_GET_DHCP_IP_ADDR, &ha->dpc_flags))
543762306a36Sopenharmony_ci		qla4xxx_get_dhcp_ip_address(ha);
543862306a36Sopenharmony_ci
543962306a36Sopenharmony_ci	/* ---- relogin device? --- */
544062306a36Sopenharmony_ci	if (adapter_up(ha) &&
544162306a36Sopenharmony_ci	    test_and_clear_bit(DPC_RELOGIN_DEVICE, &ha->dpc_flags)) {
544262306a36Sopenharmony_ci		iscsi_host_for_each_session(ha->host, qla4xxx_dpc_relogin);
544362306a36Sopenharmony_ci	}
544462306a36Sopenharmony_ci
544562306a36Sopenharmony_ci	/* ---- link change? --- */
544662306a36Sopenharmony_ci	if (!test_bit(AF_LOOPBACK, &ha->flags) &&
544762306a36Sopenharmony_ci	    test_and_clear_bit(DPC_LINK_CHANGED, &ha->dpc_flags)) {
544862306a36Sopenharmony_ci		if (!test_bit(AF_LINK_UP, &ha->flags)) {
544962306a36Sopenharmony_ci			/* ---- link down? --- */
545062306a36Sopenharmony_ci			qla4xxx_mark_all_devices_missing(ha);
545162306a36Sopenharmony_ci		} else {
545262306a36Sopenharmony_ci			/* ---- link up? --- *
545362306a36Sopenharmony_ci			 * F/W will auto login to all devices ONLY ONCE after
545462306a36Sopenharmony_ci			 * link up during driver initialization and runtime
545562306a36Sopenharmony_ci			 * fatal error recovery.  Therefore, the driver must
545662306a36Sopenharmony_ci			 * manually relogin to devices when recovering from
545762306a36Sopenharmony_ci			 * connection failures, logouts, expired KATO, etc. */
545862306a36Sopenharmony_ci			if (test_and_clear_bit(AF_BUILD_DDB_LIST, &ha->flags)) {
545962306a36Sopenharmony_ci				qla4xxx_build_ddb_list(ha, ha->is_reset);
546062306a36Sopenharmony_ci				iscsi_host_for_each_session(ha->host,
546162306a36Sopenharmony_ci						qla4xxx_login_flash_ddb);
546262306a36Sopenharmony_ci			} else
546362306a36Sopenharmony_ci				qla4xxx_relogin_all_devices(ha);
546462306a36Sopenharmony_ci		}
546562306a36Sopenharmony_ci	}
546662306a36Sopenharmony_ci	if (test_and_clear_bit(DPC_SYSFS_DDB_EXPORT, &ha->dpc_flags)) {
546762306a36Sopenharmony_ci		if (qla4xxx_sysfs_ddb_export(ha))
546862306a36Sopenharmony_ci			ql4_printk(KERN_ERR, ha, "%s: Error exporting ddb to sysfs\n",
546962306a36Sopenharmony_ci				   __func__);
547062306a36Sopenharmony_ci	}
547162306a36Sopenharmony_ci}
547262306a36Sopenharmony_ci
547362306a36Sopenharmony_ci/**
547462306a36Sopenharmony_ci * qla4xxx_free_adapter - release the adapter
547562306a36Sopenharmony_ci * @ha: pointer to adapter structure
547662306a36Sopenharmony_ci **/
547762306a36Sopenharmony_cistatic void qla4xxx_free_adapter(struct scsi_qla_host *ha)
547862306a36Sopenharmony_ci{
547962306a36Sopenharmony_ci	qla4xxx_abort_active_cmds(ha, DID_NO_CONNECT << 16);
548062306a36Sopenharmony_ci
548162306a36Sopenharmony_ci	/* Turn-off interrupts on the card. */
548262306a36Sopenharmony_ci	ha->isp_ops->disable_intrs(ha);
548362306a36Sopenharmony_ci
548462306a36Sopenharmony_ci	if (is_qla40XX(ha)) {
548562306a36Sopenharmony_ci		writel(set_rmask(CSR_SCSI_PROCESSOR_INTR),
548662306a36Sopenharmony_ci		       &ha->reg->ctrl_status);
548762306a36Sopenharmony_ci		readl(&ha->reg->ctrl_status);
548862306a36Sopenharmony_ci	} else if (is_qla8022(ha)) {
548962306a36Sopenharmony_ci		writel(0, &ha->qla4_82xx_reg->host_int);
549062306a36Sopenharmony_ci		readl(&ha->qla4_82xx_reg->host_int);
549162306a36Sopenharmony_ci	} else if (is_qla8032(ha) || is_qla8042(ha)) {
549262306a36Sopenharmony_ci		writel(0, &ha->qla4_83xx_reg->risc_intr);
549362306a36Sopenharmony_ci		readl(&ha->qla4_83xx_reg->risc_intr);
549462306a36Sopenharmony_ci	}
549562306a36Sopenharmony_ci
549662306a36Sopenharmony_ci	/* Remove timer thread, if present */
549762306a36Sopenharmony_ci	if (ha->timer_active)
549862306a36Sopenharmony_ci		qla4xxx_stop_timer(ha);
549962306a36Sopenharmony_ci
550062306a36Sopenharmony_ci	/* Kill the kernel thread for this host */
550162306a36Sopenharmony_ci	if (ha->dpc_thread)
550262306a36Sopenharmony_ci		destroy_workqueue(ha->dpc_thread);
550362306a36Sopenharmony_ci
550462306a36Sopenharmony_ci	/* Kill the kernel thread for this host */
550562306a36Sopenharmony_ci	if (ha->task_wq)
550662306a36Sopenharmony_ci		destroy_workqueue(ha->task_wq);
550762306a36Sopenharmony_ci
550862306a36Sopenharmony_ci	/* Put firmware in known state */
550962306a36Sopenharmony_ci	ha->isp_ops->reset_firmware(ha);
551062306a36Sopenharmony_ci
551162306a36Sopenharmony_ci	if (is_qla80XX(ha)) {
551262306a36Sopenharmony_ci		ha->isp_ops->idc_lock(ha);
551362306a36Sopenharmony_ci		qla4_8xxx_clear_drv_active(ha);
551462306a36Sopenharmony_ci		ha->isp_ops->idc_unlock(ha);
551562306a36Sopenharmony_ci	}
551662306a36Sopenharmony_ci
551762306a36Sopenharmony_ci	/* Detach interrupts */
551862306a36Sopenharmony_ci	qla4xxx_free_irqs(ha);
551962306a36Sopenharmony_ci
552062306a36Sopenharmony_ci	/* free extra memory */
552162306a36Sopenharmony_ci	qla4xxx_mem_free(ha);
552262306a36Sopenharmony_ci}
552362306a36Sopenharmony_ci
552462306a36Sopenharmony_ciint qla4_8xxx_iospace_config(struct scsi_qla_host *ha)
552562306a36Sopenharmony_ci{
552662306a36Sopenharmony_ci	int status = 0;
552762306a36Sopenharmony_ci	unsigned long mem_base, mem_len;
552862306a36Sopenharmony_ci	struct pci_dev *pdev = ha->pdev;
552962306a36Sopenharmony_ci
553062306a36Sopenharmony_ci	status = pci_request_regions(pdev, DRIVER_NAME);
553162306a36Sopenharmony_ci	if (status) {
553262306a36Sopenharmony_ci		printk(KERN_WARNING
553362306a36Sopenharmony_ci		    "scsi(%ld) Failed to reserve PIO regions (%s) "
553462306a36Sopenharmony_ci		    "status=%d\n", ha->host_no, pci_name(pdev), status);
553562306a36Sopenharmony_ci		goto iospace_error_exit;
553662306a36Sopenharmony_ci	}
553762306a36Sopenharmony_ci
553862306a36Sopenharmony_ci	DEBUG2(printk(KERN_INFO "%s: revision-id=%d\n",
553962306a36Sopenharmony_ci	    __func__, pdev->revision));
554062306a36Sopenharmony_ci	ha->revision_id = pdev->revision;
554162306a36Sopenharmony_ci
554262306a36Sopenharmony_ci	/* remap phys address */
554362306a36Sopenharmony_ci	mem_base = pci_resource_start(pdev, 0); /* 0 is for BAR 0 */
554462306a36Sopenharmony_ci	mem_len = pci_resource_len(pdev, 0);
554562306a36Sopenharmony_ci	DEBUG2(printk(KERN_INFO "%s: ioremap from %lx a size of %lx\n",
554662306a36Sopenharmony_ci	    __func__, mem_base, mem_len));
554762306a36Sopenharmony_ci
554862306a36Sopenharmony_ci	/* mapping of pcibase pointer */
554962306a36Sopenharmony_ci	ha->nx_pcibase = (unsigned long)ioremap(mem_base, mem_len);
555062306a36Sopenharmony_ci	if (!ha->nx_pcibase) {
555162306a36Sopenharmony_ci		printk(KERN_ERR
555262306a36Sopenharmony_ci		    "cannot remap MMIO (%s), aborting\n", pci_name(pdev));
555362306a36Sopenharmony_ci		pci_release_regions(ha->pdev);
555462306a36Sopenharmony_ci		goto iospace_error_exit;
555562306a36Sopenharmony_ci	}
555662306a36Sopenharmony_ci
555762306a36Sopenharmony_ci	/* Mapping of IO base pointer, door bell read and write pointer */
555862306a36Sopenharmony_ci
555962306a36Sopenharmony_ci	/* mapping of IO base pointer */
556062306a36Sopenharmony_ci	if (is_qla8022(ha)) {
556162306a36Sopenharmony_ci		ha->qla4_82xx_reg = (struct device_reg_82xx  __iomem *)
556262306a36Sopenharmony_ci				    ((uint8_t *)ha->nx_pcibase + 0xbc000 +
556362306a36Sopenharmony_ci				     (ha->pdev->devfn << 11));
556462306a36Sopenharmony_ci		ha->nx_db_wr_ptr = (ha->pdev->devfn == 4 ? QLA82XX_CAM_RAM_DB1 :
556562306a36Sopenharmony_ci				    QLA82XX_CAM_RAM_DB2);
556662306a36Sopenharmony_ci	} else if (is_qla8032(ha) || is_qla8042(ha)) {
556762306a36Sopenharmony_ci		ha->qla4_83xx_reg = (struct device_reg_83xx __iomem *)
556862306a36Sopenharmony_ci				    ((uint8_t *)ha->nx_pcibase);
556962306a36Sopenharmony_ci	}
557062306a36Sopenharmony_ci
557162306a36Sopenharmony_ci	return 0;
557262306a36Sopenharmony_ciiospace_error_exit:
557362306a36Sopenharmony_ci	return -ENOMEM;
557462306a36Sopenharmony_ci}
557562306a36Sopenharmony_ci
557662306a36Sopenharmony_ci/***
557762306a36Sopenharmony_ci * qla4xxx_iospace_config - maps registers
557862306a36Sopenharmony_ci * @ha: pointer to adapter structure
557962306a36Sopenharmony_ci *
558062306a36Sopenharmony_ci * This routines maps HBA's registers from the pci address space
558162306a36Sopenharmony_ci * into the kernel virtual address space for memory mapped i/o.
558262306a36Sopenharmony_ci **/
558362306a36Sopenharmony_ciint qla4xxx_iospace_config(struct scsi_qla_host *ha)
558462306a36Sopenharmony_ci{
558562306a36Sopenharmony_ci	unsigned long pio, pio_len, pio_flags;
558662306a36Sopenharmony_ci	unsigned long mmio, mmio_len, mmio_flags;
558762306a36Sopenharmony_ci
558862306a36Sopenharmony_ci	pio = pci_resource_start(ha->pdev, 0);
558962306a36Sopenharmony_ci	pio_len = pci_resource_len(ha->pdev, 0);
559062306a36Sopenharmony_ci	pio_flags = pci_resource_flags(ha->pdev, 0);
559162306a36Sopenharmony_ci	if (pio_flags & IORESOURCE_IO) {
559262306a36Sopenharmony_ci		if (pio_len < MIN_IOBASE_LEN) {
559362306a36Sopenharmony_ci			ql4_printk(KERN_WARNING, ha,
559462306a36Sopenharmony_ci				"Invalid PCI I/O region size\n");
559562306a36Sopenharmony_ci			pio = 0;
559662306a36Sopenharmony_ci		}
559762306a36Sopenharmony_ci	} else {
559862306a36Sopenharmony_ci		ql4_printk(KERN_WARNING, ha, "region #0 not a PIO resource\n");
559962306a36Sopenharmony_ci		pio = 0;
560062306a36Sopenharmony_ci	}
560162306a36Sopenharmony_ci
560262306a36Sopenharmony_ci	/* Use MMIO operations for all accesses. */
560362306a36Sopenharmony_ci	mmio = pci_resource_start(ha->pdev, 1);
560462306a36Sopenharmony_ci	mmio_len = pci_resource_len(ha->pdev, 1);
560562306a36Sopenharmony_ci	mmio_flags = pci_resource_flags(ha->pdev, 1);
560662306a36Sopenharmony_ci
560762306a36Sopenharmony_ci	if (!(mmio_flags & IORESOURCE_MEM)) {
560862306a36Sopenharmony_ci		ql4_printk(KERN_ERR, ha,
560962306a36Sopenharmony_ci		    "region #0 not an MMIO resource, aborting\n");
561062306a36Sopenharmony_ci
561162306a36Sopenharmony_ci		goto iospace_error_exit;
561262306a36Sopenharmony_ci	}
561362306a36Sopenharmony_ci
561462306a36Sopenharmony_ci	if (mmio_len < MIN_IOBASE_LEN) {
561562306a36Sopenharmony_ci		ql4_printk(KERN_ERR, ha,
561662306a36Sopenharmony_ci		    "Invalid PCI mem region size, aborting\n");
561762306a36Sopenharmony_ci		goto iospace_error_exit;
561862306a36Sopenharmony_ci	}
561962306a36Sopenharmony_ci
562062306a36Sopenharmony_ci	if (pci_request_regions(ha->pdev, DRIVER_NAME)) {
562162306a36Sopenharmony_ci		ql4_printk(KERN_WARNING, ha,
562262306a36Sopenharmony_ci		    "Failed to reserve PIO/MMIO regions\n");
562362306a36Sopenharmony_ci
562462306a36Sopenharmony_ci		goto iospace_error_exit;
562562306a36Sopenharmony_ci	}
562662306a36Sopenharmony_ci
562762306a36Sopenharmony_ci	ha->pio_address = pio;
562862306a36Sopenharmony_ci	ha->pio_length = pio_len;
562962306a36Sopenharmony_ci	ha->reg = ioremap(mmio, MIN_IOBASE_LEN);
563062306a36Sopenharmony_ci	if (!ha->reg) {
563162306a36Sopenharmony_ci		ql4_printk(KERN_ERR, ha,
563262306a36Sopenharmony_ci		    "cannot remap MMIO, aborting\n");
563362306a36Sopenharmony_ci
563462306a36Sopenharmony_ci		goto iospace_error_exit;
563562306a36Sopenharmony_ci	}
563662306a36Sopenharmony_ci
563762306a36Sopenharmony_ci	return 0;
563862306a36Sopenharmony_ci
563962306a36Sopenharmony_ciiospace_error_exit:
564062306a36Sopenharmony_ci	return -ENOMEM;
564162306a36Sopenharmony_ci}
564262306a36Sopenharmony_ci
564362306a36Sopenharmony_cistatic struct isp_operations qla4xxx_isp_ops = {
564462306a36Sopenharmony_ci	.iospace_config         = qla4xxx_iospace_config,
564562306a36Sopenharmony_ci	.pci_config             = qla4xxx_pci_config,
564662306a36Sopenharmony_ci	.disable_intrs          = qla4xxx_disable_intrs,
564762306a36Sopenharmony_ci	.enable_intrs           = qla4xxx_enable_intrs,
564862306a36Sopenharmony_ci	.start_firmware         = qla4xxx_start_firmware,
564962306a36Sopenharmony_ci	.intr_handler           = qla4xxx_intr_handler,
565062306a36Sopenharmony_ci	.interrupt_service_routine = qla4xxx_interrupt_service_routine,
565162306a36Sopenharmony_ci	.reset_chip             = qla4xxx_soft_reset,
565262306a36Sopenharmony_ci	.reset_firmware         = qla4xxx_hw_reset,
565362306a36Sopenharmony_ci	.queue_iocb             = qla4xxx_queue_iocb,
565462306a36Sopenharmony_ci	.complete_iocb          = qla4xxx_complete_iocb,
565562306a36Sopenharmony_ci	.rd_shdw_req_q_out      = qla4xxx_rd_shdw_req_q_out,
565662306a36Sopenharmony_ci	.rd_shdw_rsp_q_in       = qla4xxx_rd_shdw_rsp_q_in,
565762306a36Sopenharmony_ci	.get_sys_info           = qla4xxx_get_sys_info,
565862306a36Sopenharmony_ci	.queue_mailbox_command	= qla4xxx_queue_mbox_cmd,
565962306a36Sopenharmony_ci	.process_mailbox_interrupt = qla4xxx_process_mbox_intr,
566062306a36Sopenharmony_ci};
566162306a36Sopenharmony_ci
566262306a36Sopenharmony_cistatic struct isp_operations qla4_82xx_isp_ops = {
566362306a36Sopenharmony_ci	.iospace_config         = qla4_8xxx_iospace_config,
566462306a36Sopenharmony_ci	.pci_config             = qla4_8xxx_pci_config,
566562306a36Sopenharmony_ci	.disable_intrs          = qla4_82xx_disable_intrs,
566662306a36Sopenharmony_ci	.enable_intrs           = qla4_82xx_enable_intrs,
566762306a36Sopenharmony_ci	.start_firmware         = qla4_8xxx_load_risc,
566862306a36Sopenharmony_ci	.restart_firmware	= qla4_82xx_try_start_fw,
566962306a36Sopenharmony_ci	.intr_handler           = qla4_82xx_intr_handler,
567062306a36Sopenharmony_ci	.interrupt_service_routine = qla4_82xx_interrupt_service_routine,
567162306a36Sopenharmony_ci	.need_reset		= qla4_8xxx_need_reset,
567262306a36Sopenharmony_ci	.reset_chip             = qla4_82xx_isp_reset,
567362306a36Sopenharmony_ci	.reset_firmware         = qla4_8xxx_stop_firmware,
567462306a36Sopenharmony_ci	.queue_iocb             = qla4_82xx_queue_iocb,
567562306a36Sopenharmony_ci	.complete_iocb          = qla4_82xx_complete_iocb,
567662306a36Sopenharmony_ci	.rd_shdw_req_q_out      = qla4_82xx_rd_shdw_req_q_out,
567762306a36Sopenharmony_ci	.rd_shdw_rsp_q_in       = qla4_82xx_rd_shdw_rsp_q_in,
567862306a36Sopenharmony_ci	.get_sys_info           = qla4_8xxx_get_sys_info,
567962306a36Sopenharmony_ci	.rd_reg_direct		= qla4_82xx_rd_32,
568062306a36Sopenharmony_ci	.wr_reg_direct		= qla4_82xx_wr_32,
568162306a36Sopenharmony_ci	.rd_reg_indirect	= qla4_82xx_md_rd_32,
568262306a36Sopenharmony_ci	.wr_reg_indirect	= qla4_82xx_md_wr_32,
568362306a36Sopenharmony_ci	.idc_lock		= qla4_82xx_idc_lock,
568462306a36Sopenharmony_ci	.idc_unlock		= qla4_82xx_idc_unlock,
568562306a36Sopenharmony_ci	.rom_lock_recovery	= qla4_82xx_rom_lock_recovery,
568662306a36Sopenharmony_ci	.queue_mailbox_command	= qla4_82xx_queue_mbox_cmd,
568762306a36Sopenharmony_ci	.process_mailbox_interrupt = qla4_82xx_process_mbox_intr,
568862306a36Sopenharmony_ci};
568962306a36Sopenharmony_ci
569062306a36Sopenharmony_cistatic struct isp_operations qla4_83xx_isp_ops = {
569162306a36Sopenharmony_ci	.iospace_config		= qla4_8xxx_iospace_config,
569262306a36Sopenharmony_ci	.pci_config		= qla4_8xxx_pci_config,
569362306a36Sopenharmony_ci	.disable_intrs		= qla4_83xx_disable_intrs,
569462306a36Sopenharmony_ci	.enable_intrs		= qla4_83xx_enable_intrs,
569562306a36Sopenharmony_ci	.start_firmware		= qla4_8xxx_load_risc,
569662306a36Sopenharmony_ci	.restart_firmware	= qla4_83xx_start_firmware,
569762306a36Sopenharmony_ci	.intr_handler		= qla4_83xx_intr_handler,
569862306a36Sopenharmony_ci	.interrupt_service_routine = qla4_83xx_interrupt_service_routine,
569962306a36Sopenharmony_ci	.need_reset		= qla4_8xxx_need_reset,
570062306a36Sopenharmony_ci	.reset_chip		= qla4_83xx_isp_reset,
570162306a36Sopenharmony_ci	.reset_firmware		= qla4_8xxx_stop_firmware,
570262306a36Sopenharmony_ci	.queue_iocb		= qla4_83xx_queue_iocb,
570362306a36Sopenharmony_ci	.complete_iocb		= qla4_83xx_complete_iocb,
570462306a36Sopenharmony_ci	.rd_shdw_req_q_out	= qla4xxx_rd_shdw_req_q_out,
570562306a36Sopenharmony_ci	.rd_shdw_rsp_q_in	= qla4xxx_rd_shdw_rsp_q_in,
570662306a36Sopenharmony_ci	.get_sys_info		= qla4_8xxx_get_sys_info,
570762306a36Sopenharmony_ci	.rd_reg_direct		= qla4_83xx_rd_reg,
570862306a36Sopenharmony_ci	.wr_reg_direct		= qla4_83xx_wr_reg,
570962306a36Sopenharmony_ci	.rd_reg_indirect	= qla4_83xx_rd_reg_indirect,
571062306a36Sopenharmony_ci	.wr_reg_indirect	= qla4_83xx_wr_reg_indirect,
571162306a36Sopenharmony_ci	.idc_lock		= qla4_83xx_drv_lock,
571262306a36Sopenharmony_ci	.idc_unlock		= qla4_83xx_drv_unlock,
571362306a36Sopenharmony_ci	.rom_lock_recovery	= qla4_83xx_rom_lock_recovery,
571462306a36Sopenharmony_ci	.queue_mailbox_command	= qla4_83xx_queue_mbox_cmd,
571562306a36Sopenharmony_ci	.process_mailbox_interrupt = qla4_83xx_process_mbox_intr,
571662306a36Sopenharmony_ci};
571762306a36Sopenharmony_ci
571862306a36Sopenharmony_ciuint16_t qla4xxx_rd_shdw_req_q_out(struct scsi_qla_host *ha)
571962306a36Sopenharmony_ci{
572062306a36Sopenharmony_ci	return (uint16_t)le32_to_cpu(ha->shadow_regs->req_q_out);
572162306a36Sopenharmony_ci}
572262306a36Sopenharmony_ci
572362306a36Sopenharmony_ciuint16_t qla4_82xx_rd_shdw_req_q_out(struct scsi_qla_host *ha)
572462306a36Sopenharmony_ci{
572562306a36Sopenharmony_ci	return (uint16_t)le32_to_cpu(readl(&ha->qla4_82xx_reg->req_q_out));
572662306a36Sopenharmony_ci}
572762306a36Sopenharmony_ci
572862306a36Sopenharmony_ciuint16_t qla4xxx_rd_shdw_rsp_q_in(struct scsi_qla_host *ha)
572962306a36Sopenharmony_ci{
573062306a36Sopenharmony_ci	return (uint16_t)le32_to_cpu(ha->shadow_regs->rsp_q_in);
573162306a36Sopenharmony_ci}
573262306a36Sopenharmony_ci
573362306a36Sopenharmony_ciuint16_t qla4_82xx_rd_shdw_rsp_q_in(struct scsi_qla_host *ha)
573462306a36Sopenharmony_ci{
573562306a36Sopenharmony_ci	return (uint16_t)le32_to_cpu(readl(&ha->qla4_82xx_reg->rsp_q_in));
573662306a36Sopenharmony_ci}
573762306a36Sopenharmony_ci
573862306a36Sopenharmony_cistatic ssize_t qla4xxx_show_boot_eth_info(void *data, int type, char *buf)
573962306a36Sopenharmony_ci{
574062306a36Sopenharmony_ci	struct scsi_qla_host *ha = data;
574162306a36Sopenharmony_ci	char *str = buf;
574262306a36Sopenharmony_ci	int rc;
574362306a36Sopenharmony_ci
574462306a36Sopenharmony_ci	switch (type) {
574562306a36Sopenharmony_ci	case ISCSI_BOOT_ETH_FLAGS:
574662306a36Sopenharmony_ci		rc = sprintf(str, "%d\n", (char)SYSFS_FLAG_FW_SEL_BOOT);
574762306a36Sopenharmony_ci		break;
574862306a36Sopenharmony_ci	case ISCSI_BOOT_ETH_INDEX:
574962306a36Sopenharmony_ci		rc = sprintf(str, "0\n");
575062306a36Sopenharmony_ci		break;
575162306a36Sopenharmony_ci	case ISCSI_BOOT_ETH_MAC:
575262306a36Sopenharmony_ci		rc = sysfs_format_mac(str, ha->my_mac,
575362306a36Sopenharmony_ci				      MAC_ADDR_LEN);
575462306a36Sopenharmony_ci		break;
575562306a36Sopenharmony_ci	default:
575662306a36Sopenharmony_ci		rc = -ENOSYS;
575762306a36Sopenharmony_ci		break;
575862306a36Sopenharmony_ci	}
575962306a36Sopenharmony_ci	return rc;
576062306a36Sopenharmony_ci}
576162306a36Sopenharmony_ci
576262306a36Sopenharmony_cistatic umode_t qla4xxx_eth_get_attr_visibility(void *data, int type)
576362306a36Sopenharmony_ci{
576462306a36Sopenharmony_ci	int rc;
576562306a36Sopenharmony_ci
576662306a36Sopenharmony_ci	switch (type) {
576762306a36Sopenharmony_ci	case ISCSI_BOOT_ETH_FLAGS:
576862306a36Sopenharmony_ci	case ISCSI_BOOT_ETH_MAC:
576962306a36Sopenharmony_ci	case ISCSI_BOOT_ETH_INDEX:
577062306a36Sopenharmony_ci		rc = S_IRUGO;
577162306a36Sopenharmony_ci		break;
577262306a36Sopenharmony_ci	default:
577362306a36Sopenharmony_ci		rc = 0;
577462306a36Sopenharmony_ci		break;
577562306a36Sopenharmony_ci	}
577662306a36Sopenharmony_ci	return rc;
577762306a36Sopenharmony_ci}
577862306a36Sopenharmony_ci
577962306a36Sopenharmony_cistatic ssize_t qla4xxx_show_boot_ini_info(void *data, int type, char *buf)
578062306a36Sopenharmony_ci{
578162306a36Sopenharmony_ci	struct scsi_qla_host *ha = data;
578262306a36Sopenharmony_ci	char *str = buf;
578362306a36Sopenharmony_ci	int rc;
578462306a36Sopenharmony_ci
578562306a36Sopenharmony_ci	switch (type) {
578662306a36Sopenharmony_ci	case ISCSI_BOOT_INI_INITIATOR_NAME:
578762306a36Sopenharmony_ci		rc = sprintf(str, "%s\n", ha->name_string);
578862306a36Sopenharmony_ci		break;
578962306a36Sopenharmony_ci	default:
579062306a36Sopenharmony_ci		rc = -ENOSYS;
579162306a36Sopenharmony_ci		break;
579262306a36Sopenharmony_ci	}
579362306a36Sopenharmony_ci	return rc;
579462306a36Sopenharmony_ci}
579562306a36Sopenharmony_ci
579662306a36Sopenharmony_cistatic umode_t qla4xxx_ini_get_attr_visibility(void *data, int type)
579762306a36Sopenharmony_ci{
579862306a36Sopenharmony_ci	int rc;
579962306a36Sopenharmony_ci
580062306a36Sopenharmony_ci	switch (type) {
580162306a36Sopenharmony_ci	case ISCSI_BOOT_INI_INITIATOR_NAME:
580262306a36Sopenharmony_ci		rc = S_IRUGO;
580362306a36Sopenharmony_ci		break;
580462306a36Sopenharmony_ci	default:
580562306a36Sopenharmony_ci		rc = 0;
580662306a36Sopenharmony_ci		break;
580762306a36Sopenharmony_ci	}
580862306a36Sopenharmony_ci	return rc;
580962306a36Sopenharmony_ci}
581062306a36Sopenharmony_ci
581162306a36Sopenharmony_cistatic ssize_t
581262306a36Sopenharmony_ciqla4xxx_show_boot_tgt_info(struct ql4_boot_session_info *boot_sess, int type,
581362306a36Sopenharmony_ci			   char *buf)
581462306a36Sopenharmony_ci{
581562306a36Sopenharmony_ci	struct ql4_conn_info *boot_conn = &boot_sess->conn_list[0];
581662306a36Sopenharmony_ci	char *str = buf;
581762306a36Sopenharmony_ci	int rc;
581862306a36Sopenharmony_ci
581962306a36Sopenharmony_ci	switch (type) {
582062306a36Sopenharmony_ci	case ISCSI_BOOT_TGT_NAME:
582162306a36Sopenharmony_ci		rc = sprintf(buf, "%s\n", (char *)&boot_sess->target_name);
582262306a36Sopenharmony_ci		break;
582362306a36Sopenharmony_ci	case ISCSI_BOOT_TGT_IP_ADDR:
582462306a36Sopenharmony_ci		if (boot_sess->conn_list[0].dest_ipaddr.ip_type == 0x1)
582562306a36Sopenharmony_ci			rc = sprintf(buf, "%pI4\n",
582662306a36Sopenharmony_ci				     &boot_conn->dest_ipaddr.ip_address);
582762306a36Sopenharmony_ci		else
582862306a36Sopenharmony_ci			rc = sprintf(str, "%pI6\n",
582962306a36Sopenharmony_ci				     &boot_conn->dest_ipaddr.ip_address);
583062306a36Sopenharmony_ci		break;
583162306a36Sopenharmony_ci	case ISCSI_BOOT_TGT_PORT:
583262306a36Sopenharmony_ci			rc = sprintf(str, "%d\n", boot_conn->dest_port);
583362306a36Sopenharmony_ci		break;
583462306a36Sopenharmony_ci	case ISCSI_BOOT_TGT_CHAP_NAME:
583562306a36Sopenharmony_ci		rc = sprintf(str,  "%.*s\n",
583662306a36Sopenharmony_ci			     boot_conn->chap.target_chap_name_length,
583762306a36Sopenharmony_ci			     (char *)&boot_conn->chap.target_chap_name);
583862306a36Sopenharmony_ci		break;
583962306a36Sopenharmony_ci	case ISCSI_BOOT_TGT_CHAP_SECRET:
584062306a36Sopenharmony_ci		rc = sprintf(str,  "%.*s\n",
584162306a36Sopenharmony_ci			     boot_conn->chap.target_secret_length,
584262306a36Sopenharmony_ci			     (char *)&boot_conn->chap.target_secret);
584362306a36Sopenharmony_ci		break;
584462306a36Sopenharmony_ci	case ISCSI_BOOT_TGT_REV_CHAP_NAME:
584562306a36Sopenharmony_ci		rc = sprintf(str,  "%.*s\n",
584662306a36Sopenharmony_ci			     boot_conn->chap.intr_chap_name_length,
584762306a36Sopenharmony_ci			     (char *)&boot_conn->chap.intr_chap_name);
584862306a36Sopenharmony_ci		break;
584962306a36Sopenharmony_ci	case ISCSI_BOOT_TGT_REV_CHAP_SECRET:
585062306a36Sopenharmony_ci		rc = sprintf(str,  "%.*s\n",
585162306a36Sopenharmony_ci			     boot_conn->chap.intr_secret_length,
585262306a36Sopenharmony_ci			     (char *)&boot_conn->chap.intr_secret);
585362306a36Sopenharmony_ci		break;
585462306a36Sopenharmony_ci	case ISCSI_BOOT_TGT_FLAGS:
585562306a36Sopenharmony_ci		rc = sprintf(str, "%d\n", (char)SYSFS_FLAG_FW_SEL_BOOT);
585662306a36Sopenharmony_ci		break;
585762306a36Sopenharmony_ci	case ISCSI_BOOT_TGT_NIC_ASSOC:
585862306a36Sopenharmony_ci		rc = sprintf(str, "0\n");
585962306a36Sopenharmony_ci		break;
586062306a36Sopenharmony_ci	default:
586162306a36Sopenharmony_ci		rc = -ENOSYS;
586262306a36Sopenharmony_ci		break;
586362306a36Sopenharmony_ci	}
586462306a36Sopenharmony_ci	return rc;
586562306a36Sopenharmony_ci}
586662306a36Sopenharmony_ci
586762306a36Sopenharmony_cistatic ssize_t qla4xxx_show_boot_tgt_pri_info(void *data, int type, char *buf)
586862306a36Sopenharmony_ci{
586962306a36Sopenharmony_ci	struct scsi_qla_host *ha = data;
587062306a36Sopenharmony_ci	struct ql4_boot_session_info *boot_sess = &(ha->boot_tgt.boot_pri_sess);
587162306a36Sopenharmony_ci
587262306a36Sopenharmony_ci	return qla4xxx_show_boot_tgt_info(boot_sess, type, buf);
587362306a36Sopenharmony_ci}
587462306a36Sopenharmony_ci
587562306a36Sopenharmony_cistatic ssize_t qla4xxx_show_boot_tgt_sec_info(void *data, int type, char *buf)
587662306a36Sopenharmony_ci{
587762306a36Sopenharmony_ci	struct scsi_qla_host *ha = data;
587862306a36Sopenharmony_ci	struct ql4_boot_session_info *boot_sess = &(ha->boot_tgt.boot_sec_sess);
587962306a36Sopenharmony_ci
588062306a36Sopenharmony_ci	return qla4xxx_show_boot_tgt_info(boot_sess, type, buf);
588162306a36Sopenharmony_ci}
588262306a36Sopenharmony_ci
588362306a36Sopenharmony_cistatic umode_t qla4xxx_tgt_get_attr_visibility(void *data, int type)
588462306a36Sopenharmony_ci{
588562306a36Sopenharmony_ci	int rc;
588662306a36Sopenharmony_ci
588762306a36Sopenharmony_ci	switch (type) {
588862306a36Sopenharmony_ci	case ISCSI_BOOT_TGT_NAME:
588962306a36Sopenharmony_ci	case ISCSI_BOOT_TGT_IP_ADDR:
589062306a36Sopenharmony_ci	case ISCSI_BOOT_TGT_PORT:
589162306a36Sopenharmony_ci	case ISCSI_BOOT_TGT_CHAP_NAME:
589262306a36Sopenharmony_ci	case ISCSI_BOOT_TGT_CHAP_SECRET:
589362306a36Sopenharmony_ci	case ISCSI_BOOT_TGT_REV_CHAP_NAME:
589462306a36Sopenharmony_ci	case ISCSI_BOOT_TGT_REV_CHAP_SECRET:
589562306a36Sopenharmony_ci	case ISCSI_BOOT_TGT_NIC_ASSOC:
589662306a36Sopenharmony_ci	case ISCSI_BOOT_TGT_FLAGS:
589762306a36Sopenharmony_ci		rc = S_IRUGO;
589862306a36Sopenharmony_ci		break;
589962306a36Sopenharmony_ci	default:
590062306a36Sopenharmony_ci		rc = 0;
590162306a36Sopenharmony_ci		break;
590262306a36Sopenharmony_ci	}
590362306a36Sopenharmony_ci	return rc;
590462306a36Sopenharmony_ci}
590562306a36Sopenharmony_ci
590662306a36Sopenharmony_cistatic void qla4xxx_boot_release(void *data)
590762306a36Sopenharmony_ci{
590862306a36Sopenharmony_ci	struct scsi_qla_host *ha = data;
590962306a36Sopenharmony_ci
591062306a36Sopenharmony_ci	scsi_host_put(ha->host);
591162306a36Sopenharmony_ci}
591262306a36Sopenharmony_ci
591362306a36Sopenharmony_cistatic int get_fw_boot_info(struct scsi_qla_host *ha, uint16_t ddb_index[])
591462306a36Sopenharmony_ci{
591562306a36Sopenharmony_ci	dma_addr_t buf_dma;
591662306a36Sopenharmony_ci	uint32_t addr, pri_addr, sec_addr;
591762306a36Sopenharmony_ci	uint32_t offset;
591862306a36Sopenharmony_ci	uint16_t func_num;
591962306a36Sopenharmony_ci	uint8_t val;
592062306a36Sopenharmony_ci	uint8_t *buf = NULL;
592162306a36Sopenharmony_ci	size_t size = 13 * sizeof(uint8_t);
592262306a36Sopenharmony_ci	int ret = QLA_SUCCESS;
592362306a36Sopenharmony_ci
592462306a36Sopenharmony_ci	func_num = PCI_FUNC(ha->pdev->devfn);
592562306a36Sopenharmony_ci
592662306a36Sopenharmony_ci	ql4_printk(KERN_INFO, ha, "%s: Get FW boot info for 0x%x func %d\n",
592762306a36Sopenharmony_ci		   __func__, ha->pdev->device, func_num);
592862306a36Sopenharmony_ci
592962306a36Sopenharmony_ci	if (is_qla40XX(ha)) {
593062306a36Sopenharmony_ci		if (func_num == 1) {
593162306a36Sopenharmony_ci			addr = NVRAM_PORT0_BOOT_MODE;
593262306a36Sopenharmony_ci			pri_addr = NVRAM_PORT0_BOOT_PRI_TGT;
593362306a36Sopenharmony_ci			sec_addr = NVRAM_PORT0_BOOT_SEC_TGT;
593462306a36Sopenharmony_ci		} else if (func_num == 3) {
593562306a36Sopenharmony_ci			addr = NVRAM_PORT1_BOOT_MODE;
593662306a36Sopenharmony_ci			pri_addr = NVRAM_PORT1_BOOT_PRI_TGT;
593762306a36Sopenharmony_ci			sec_addr = NVRAM_PORT1_BOOT_SEC_TGT;
593862306a36Sopenharmony_ci		} else {
593962306a36Sopenharmony_ci			ret = QLA_ERROR;
594062306a36Sopenharmony_ci			goto exit_boot_info;
594162306a36Sopenharmony_ci		}
594262306a36Sopenharmony_ci
594362306a36Sopenharmony_ci		/* Check Boot Mode */
594462306a36Sopenharmony_ci		val = rd_nvram_byte(ha, addr);
594562306a36Sopenharmony_ci		if (!(val & 0x07)) {
594662306a36Sopenharmony_ci			DEBUG2(ql4_printk(KERN_INFO, ha, "%s: Adapter boot "
594762306a36Sopenharmony_ci					  "options : 0x%x\n", __func__, val));
594862306a36Sopenharmony_ci			ret = QLA_ERROR;
594962306a36Sopenharmony_ci			goto exit_boot_info;
595062306a36Sopenharmony_ci		}
595162306a36Sopenharmony_ci
595262306a36Sopenharmony_ci		/* get primary valid target index */
595362306a36Sopenharmony_ci		val = rd_nvram_byte(ha, pri_addr);
595462306a36Sopenharmony_ci		if (val & BIT_7)
595562306a36Sopenharmony_ci			ddb_index[0] = (val & 0x7f);
595662306a36Sopenharmony_ci
595762306a36Sopenharmony_ci		/* get secondary valid target index */
595862306a36Sopenharmony_ci		val = rd_nvram_byte(ha, sec_addr);
595962306a36Sopenharmony_ci		if (val & BIT_7)
596062306a36Sopenharmony_ci			ddb_index[1] = (val & 0x7f);
596162306a36Sopenharmony_ci		goto exit_boot_info;
596262306a36Sopenharmony_ci	} else if (is_qla80XX(ha)) {
596362306a36Sopenharmony_ci		buf = dma_alloc_coherent(&ha->pdev->dev, size,
596462306a36Sopenharmony_ci					 &buf_dma, GFP_KERNEL);
596562306a36Sopenharmony_ci		if (!buf) {
596662306a36Sopenharmony_ci			DEBUG2(ql4_printk(KERN_ERR, ha,
596762306a36Sopenharmony_ci					  "%s: Unable to allocate dma buffer\n",
596862306a36Sopenharmony_ci					   __func__));
596962306a36Sopenharmony_ci			ret = QLA_ERROR;
597062306a36Sopenharmony_ci			goto exit_boot_info;
597162306a36Sopenharmony_ci		}
597262306a36Sopenharmony_ci
597362306a36Sopenharmony_ci		if (ha->port_num == 0)
597462306a36Sopenharmony_ci			offset = BOOT_PARAM_OFFSET_PORT0;
597562306a36Sopenharmony_ci		else if (ha->port_num == 1)
597662306a36Sopenharmony_ci			offset = BOOT_PARAM_OFFSET_PORT1;
597762306a36Sopenharmony_ci		else {
597862306a36Sopenharmony_ci			ret = QLA_ERROR;
597962306a36Sopenharmony_ci			goto exit_boot_info_free;
598062306a36Sopenharmony_ci		}
598162306a36Sopenharmony_ci		addr = FLASH_RAW_ACCESS_ADDR + (ha->hw.flt_iscsi_param * 4) +
598262306a36Sopenharmony_ci		       offset;
598362306a36Sopenharmony_ci		if (qla4xxx_get_flash(ha, buf_dma, addr,
598462306a36Sopenharmony_ci				      13 * sizeof(uint8_t)) != QLA_SUCCESS) {
598562306a36Sopenharmony_ci			DEBUG2(ql4_printk(KERN_ERR, ha, "scsi%ld: %s: Get Flash"
598662306a36Sopenharmony_ci					  " failed\n", ha->host_no, __func__));
598762306a36Sopenharmony_ci			ret = QLA_ERROR;
598862306a36Sopenharmony_ci			goto exit_boot_info_free;
598962306a36Sopenharmony_ci		}
599062306a36Sopenharmony_ci		/* Check Boot Mode */
599162306a36Sopenharmony_ci		if (!(buf[1] & 0x07)) {
599262306a36Sopenharmony_ci			DEBUG2(ql4_printk(KERN_INFO, ha, "Firmware boot options"
599362306a36Sopenharmony_ci					  " : 0x%x\n", buf[1]));
599462306a36Sopenharmony_ci			ret = QLA_ERROR;
599562306a36Sopenharmony_ci			goto exit_boot_info_free;
599662306a36Sopenharmony_ci		}
599762306a36Sopenharmony_ci
599862306a36Sopenharmony_ci		/* get primary valid target index */
599962306a36Sopenharmony_ci		if (buf[2] & BIT_7)
600062306a36Sopenharmony_ci			ddb_index[0] = buf[2] & 0x7f;
600162306a36Sopenharmony_ci
600262306a36Sopenharmony_ci		/* get secondary valid target index */
600362306a36Sopenharmony_ci		if (buf[11] & BIT_7)
600462306a36Sopenharmony_ci			ddb_index[1] = buf[11] & 0x7f;
600562306a36Sopenharmony_ci	} else {
600662306a36Sopenharmony_ci		ret = QLA_ERROR;
600762306a36Sopenharmony_ci		goto exit_boot_info;
600862306a36Sopenharmony_ci	}
600962306a36Sopenharmony_ci
601062306a36Sopenharmony_ci	DEBUG2(ql4_printk(KERN_INFO, ha, "%s: Primary target ID %d, Secondary"
601162306a36Sopenharmony_ci			  " target ID %d\n", __func__, ddb_index[0],
601262306a36Sopenharmony_ci			  ddb_index[1]));
601362306a36Sopenharmony_ci
601462306a36Sopenharmony_ciexit_boot_info_free:
601562306a36Sopenharmony_ci	dma_free_coherent(&ha->pdev->dev, size, buf, buf_dma);
601662306a36Sopenharmony_ciexit_boot_info:
601762306a36Sopenharmony_ci	ha->pri_ddb_idx = ddb_index[0];
601862306a36Sopenharmony_ci	ha->sec_ddb_idx = ddb_index[1];
601962306a36Sopenharmony_ci	return ret;
602062306a36Sopenharmony_ci}
602162306a36Sopenharmony_ci
602262306a36Sopenharmony_ci/**
602362306a36Sopenharmony_ci * qla4xxx_get_bidi_chap - Get a BIDI CHAP user and password
602462306a36Sopenharmony_ci * @ha: pointer to adapter structure
602562306a36Sopenharmony_ci * @username: CHAP username to be returned
602662306a36Sopenharmony_ci * @password: CHAP password to be returned
602762306a36Sopenharmony_ci *
602862306a36Sopenharmony_ci * If a boot entry has BIDI CHAP enabled then we need to set the BIDI CHAP
602962306a36Sopenharmony_ci * user and password in the sysfs entry in /sys/firmware/iscsi_boot#/.
603062306a36Sopenharmony_ci * So from the CHAP cache find the first BIDI CHAP entry and set it
603162306a36Sopenharmony_ci * to the boot record in sysfs.
603262306a36Sopenharmony_ci **/
603362306a36Sopenharmony_cistatic int qla4xxx_get_bidi_chap(struct scsi_qla_host *ha, char *username,
603462306a36Sopenharmony_ci			    char *password)
603562306a36Sopenharmony_ci{
603662306a36Sopenharmony_ci	int i, ret = -EINVAL;
603762306a36Sopenharmony_ci	int max_chap_entries = 0;
603862306a36Sopenharmony_ci	struct ql4_chap_table *chap_table;
603962306a36Sopenharmony_ci
604062306a36Sopenharmony_ci	if (is_qla80XX(ha))
604162306a36Sopenharmony_ci		max_chap_entries = (ha->hw.flt_chap_size / 2) /
604262306a36Sopenharmony_ci						sizeof(struct ql4_chap_table);
604362306a36Sopenharmony_ci	else
604462306a36Sopenharmony_ci		max_chap_entries = MAX_CHAP_ENTRIES_40XX;
604562306a36Sopenharmony_ci
604662306a36Sopenharmony_ci	if (!ha->chap_list) {
604762306a36Sopenharmony_ci		ql4_printk(KERN_ERR, ha, "Do not have CHAP table cache\n");
604862306a36Sopenharmony_ci		return ret;
604962306a36Sopenharmony_ci	}
605062306a36Sopenharmony_ci
605162306a36Sopenharmony_ci	mutex_lock(&ha->chap_sem);
605262306a36Sopenharmony_ci	for (i = 0; i < max_chap_entries; i++) {
605362306a36Sopenharmony_ci		chap_table = (struct ql4_chap_table *)ha->chap_list + i;
605462306a36Sopenharmony_ci		if (chap_table->cookie !=
605562306a36Sopenharmony_ci		    cpu_to_le16(CHAP_VALID_COOKIE)) {
605662306a36Sopenharmony_ci			continue;
605762306a36Sopenharmony_ci		}
605862306a36Sopenharmony_ci
605962306a36Sopenharmony_ci		if (chap_table->flags & BIT_7) /* local */
606062306a36Sopenharmony_ci			continue;
606162306a36Sopenharmony_ci
606262306a36Sopenharmony_ci		if (!(chap_table->flags & BIT_6)) /* Not BIDI */
606362306a36Sopenharmony_ci			continue;
606462306a36Sopenharmony_ci
606562306a36Sopenharmony_ci		strscpy(password, chap_table->secret, QL4_CHAP_MAX_SECRET_LEN);
606662306a36Sopenharmony_ci		strscpy(username, chap_table->name, QL4_CHAP_MAX_NAME_LEN);
606762306a36Sopenharmony_ci		ret = 0;
606862306a36Sopenharmony_ci		break;
606962306a36Sopenharmony_ci	}
607062306a36Sopenharmony_ci	mutex_unlock(&ha->chap_sem);
607162306a36Sopenharmony_ci
607262306a36Sopenharmony_ci	return ret;
607362306a36Sopenharmony_ci}
607462306a36Sopenharmony_ci
607562306a36Sopenharmony_ci
607662306a36Sopenharmony_cistatic int qla4xxx_get_boot_target(struct scsi_qla_host *ha,
607762306a36Sopenharmony_ci				   struct ql4_boot_session_info *boot_sess,
607862306a36Sopenharmony_ci				   uint16_t ddb_index)
607962306a36Sopenharmony_ci{
608062306a36Sopenharmony_ci	struct ql4_conn_info *boot_conn = &boot_sess->conn_list[0];
608162306a36Sopenharmony_ci	struct dev_db_entry *fw_ddb_entry;
608262306a36Sopenharmony_ci	dma_addr_t fw_ddb_entry_dma;
608362306a36Sopenharmony_ci	uint16_t idx;
608462306a36Sopenharmony_ci	uint16_t options;
608562306a36Sopenharmony_ci	int ret = QLA_SUCCESS;
608662306a36Sopenharmony_ci
608762306a36Sopenharmony_ci	fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
608862306a36Sopenharmony_ci					  &fw_ddb_entry_dma, GFP_KERNEL);
608962306a36Sopenharmony_ci	if (!fw_ddb_entry) {
609062306a36Sopenharmony_ci		DEBUG2(ql4_printk(KERN_ERR, ha,
609162306a36Sopenharmony_ci				  "%s: Unable to allocate dma buffer.\n",
609262306a36Sopenharmony_ci				  __func__));
609362306a36Sopenharmony_ci		ret = QLA_ERROR;
609462306a36Sopenharmony_ci		return ret;
609562306a36Sopenharmony_ci	}
609662306a36Sopenharmony_ci
609762306a36Sopenharmony_ci	if (qla4xxx_bootdb_by_index(ha, fw_ddb_entry,
609862306a36Sopenharmony_ci				   fw_ddb_entry_dma, ddb_index)) {
609962306a36Sopenharmony_ci		DEBUG2(ql4_printk(KERN_INFO, ha, "%s: No Flash DDB found at "
610062306a36Sopenharmony_ci				  "index [%d]\n", __func__, ddb_index));
610162306a36Sopenharmony_ci		ret = QLA_ERROR;
610262306a36Sopenharmony_ci		goto exit_boot_target;
610362306a36Sopenharmony_ci	}
610462306a36Sopenharmony_ci
610562306a36Sopenharmony_ci	/* Update target name and IP from DDB */
610662306a36Sopenharmony_ci	memcpy(boot_sess->target_name, fw_ddb_entry->iscsi_name,
610762306a36Sopenharmony_ci	       min(sizeof(boot_sess->target_name),
610862306a36Sopenharmony_ci		   sizeof(fw_ddb_entry->iscsi_name)));
610962306a36Sopenharmony_ci
611062306a36Sopenharmony_ci	options = le16_to_cpu(fw_ddb_entry->options);
611162306a36Sopenharmony_ci	if (options & DDB_OPT_IPV6_DEVICE) {
611262306a36Sopenharmony_ci		memcpy(&boot_conn->dest_ipaddr.ip_address,
611362306a36Sopenharmony_ci		       &fw_ddb_entry->ip_addr[0], IPv6_ADDR_LEN);
611462306a36Sopenharmony_ci	} else {
611562306a36Sopenharmony_ci		boot_conn->dest_ipaddr.ip_type = 0x1;
611662306a36Sopenharmony_ci		memcpy(&boot_conn->dest_ipaddr.ip_address,
611762306a36Sopenharmony_ci		       &fw_ddb_entry->ip_addr[0], IP_ADDR_LEN);
611862306a36Sopenharmony_ci	}
611962306a36Sopenharmony_ci
612062306a36Sopenharmony_ci	boot_conn->dest_port = le16_to_cpu(fw_ddb_entry->port);
612162306a36Sopenharmony_ci
612262306a36Sopenharmony_ci	/* update chap information */
612362306a36Sopenharmony_ci	idx = __le16_to_cpu(fw_ddb_entry->chap_tbl_idx);
612462306a36Sopenharmony_ci
612562306a36Sopenharmony_ci	if (BIT_7 & le16_to_cpu(fw_ddb_entry->iscsi_options))	{
612662306a36Sopenharmony_ci
612762306a36Sopenharmony_ci		DEBUG2(ql4_printk(KERN_INFO, ha, "Setting chap\n"));
612862306a36Sopenharmony_ci
612962306a36Sopenharmony_ci		ret = qla4xxx_get_chap(ha, (char *)&boot_conn->chap.
613062306a36Sopenharmony_ci				       target_chap_name,
613162306a36Sopenharmony_ci				       (char *)&boot_conn->chap.target_secret,
613262306a36Sopenharmony_ci				       idx);
613362306a36Sopenharmony_ci		if (ret) {
613462306a36Sopenharmony_ci			ql4_printk(KERN_ERR, ha, "Failed to set chap\n");
613562306a36Sopenharmony_ci			ret = QLA_ERROR;
613662306a36Sopenharmony_ci			goto exit_boot_target;
613762306a36Sopenharmony_ci		}
613862306a36Sopenharmony_ci
613962306a36Sopenharmony_ci		boot_conn->chap.target_chap_name_length = QL4_CHAP_MAX_NAME_LEN;
614062306a36Sopenharmony_ci		boot_conn->chap.target_secret_length = QL4_CHAP_MAX_SECRET_LEN;
614162306a36Sopenharmony_ci	}
614262306a36Sopenharmony_ci
614362306a36Sopenharmony_ci	if (BIT_4 & le16_to_cpu(fw_ddb_entry->iscsi_options)) {
614462306a36Sopenharmony_ci
614562306a36Sopenharmony_ci		DEBUG2(ql4_printk(KERN_INFO, ha, "Setting BIDI chap\n"));
614662306a36Sopenharmony_ci
614762306a36Sopenharmony_ci		ret = qla4xxx_get_bidi_chap(ha,
614862306a36Sopenharmony_ci				    (char *)&boot_conn->chap.intr_chap_name,
614962306a36Sopenharmony_ci				    (char *)&boot_conn->chap.intr_secret);
615062306a36Sopenharmony_ci
615162306a36Sopenharmony_ci		if (ret) {
615262306a36Sopenharmony_ci			ql4_printk(KERN_ERR, ha, "Failed to set BIDI chap\n");
615362306a36Sopenharmony_ci			ret = QLA_ERROR;
615462306a36Sopenharmony_ci			goto exit_boot_target;
615562306a36Sopenharmony_ci		}
615662306a36Sopenharmony_ci
615762306a36Sopenharmony_ci		boot_conn->chap.intr_chap_name_length = QL4_CHAP_MAX_NAME_LEN;
615862306a36Sopenharmony_ci		boot_conn->chap.intr_secret_length = QL4_CHAP_MAX_SECRET_LEN;
615962306a36Sopenharmony_ci	}
616062306a36Sopenharmony_ci
616162306a36Sopenharmony_ciexit_boot_target:
616262306a36Sopenharmony_ci	dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
616362306a36Sopenharmony_ci			  fw_ddb_entry, fw_ddb_entry_dma);
616462306a36Sopenharmony_ci	return ret;
616562306a36Sopenharmony_ci}
616662306a36Sopenharmony_ci
616762306a36Sopenharmony_cistatic int qla4xxx_get_boot_info(struct scsi_qla_host *ha)
616862306a36Sopenharmony_ci{
616962306a36Sopenharmony_ci	uint16_t ddb_index[2];
617062306a36Sopenharmony_ci	int ret = QLA_ERROR;
617162306a36Sopenharmony_ci	int rval;
617262306a36Sopenharmony_ci
617362306a36Sopenharmony_ci	memset(ddb_index, 0, sizeof(ddb_index));
617462306a36Sopenharmony_ci	ddb_index[0] = 0xffff;
617562306a36Sopenharmony_ci	ddb_index[1] = 0xffff;
617662306a36Sopenharmony_ci	ret = get_fw_boot_info(ha, ddb_index);
617762306a36Sopenharmony_ci	if (ret != QLA_SUCCESS) {
617862306a36Sopenharmony_ci		DEBUG2(ql4_printk(KERN_INFO, ha,
617962306a36Sopenharmony_ci				"%s: No boot target configured.\n", __func__));
618062306a36Sopenharmony_ci		return ret;
618162306a36Sopenharmony_ci	}
618262306a36Sopenharmony_ci
618362306a36Sopenharmony_ci	if (ql4xdisablesysfsboot)
618462306a36Sopenharmony_ci		return QLA_SUCCESS;
618562306a36Sopenharmony_ci
618662306a36Sopenharmony_ci	if (ddb_index[0] == 0xffff)
618762306a36Sopenharmony_ci		goto sec_target;
618862306a36Sopenharmony_ci
618962306a36Sopenharmony_ci	rval = qla4xxx_get_boot_target(ha, &(ha->boot_tgt.boot_pri_sess),
619062306a36Sopenharmony_ci				      ddb_index[0]);
619162306a36Sopenharmony_ci	if (rval != QLA_SUCCESS) {
619262306a36Sopenharmony_ci		DEBUG2(ql4_printk(KERN_INFO, ha, "%s: Primary boot target not "
619362306a36Sopenharmony_ci				  "configured\n", __func__));
619462306a36Sopenharmony_ci	} else
619562306a36Sopenharmony_ci		ret = QLA_SUCCESS;
619662306a36Sopenharmony_ci
619762306a36Sopenharmony_cisec_target:
619862306a36Sopenharmony_ci	if (ddb_index[1] == 0xffff)
619962306a36Sopenharmony_ci		goto exit_get_boot_info;
620062306a36Sopenharmony_ci
620162306a36Sopenharmony_ci	rval = qla4xxx_get_boot_target(ha, &(ha->boot_tgt.boot_sec_sess),
620262306a36Sopenharmony_ci				      ddb_index[1]);
620362306a36Sopenharmony_ci	if (rval != QLA_SUCCESS) {
620462306a36Sopenharmony_ci		DEBUG2(ql4_printk(KERN_INFO, ha, "%s: Secondary boot target not"
620562306a36Sopenharmony_ci				  " configured\n", __func__));
620662306a36Sopenharmony_ci	} else
620762306a36Sopenharmony_ci		ret = QLA_SUCCESS;
620862306a36Sopenharmony_ci
620962306a36Sopenharmony_ciexit_get_boot_info:
621062306a36Sopenharmony_ci	return ret;
621162306a36Sopenharmony_ci}
621262306a36Sopenharmony_ci
621362306a36Sopenharmony_cistatic int qla4xxx_setup_boot_info(struct scsi_qla_host *ha)
621462306a36Sopenharmony_ci{
621562306a36Sopenharmony_ci	struct iscsi_boot_kobj *boot_kobj;
621662306a36Sopenharmony_ci
621762306a36Sopenharmony_ci	if (qla4xxx_get_boot_info(ha) != QLA_SUCCESS)
621862306a36Sopenharmony_ci		return QLA_ERROR;
621962306a36Sopenharmony_ci
622062306a36Sopenharmony_ci	if (ql4xdisablesysfsboot) {
622162306a36Sopenharmony_ci		ql4_printk(KERN_INFO, ha,
622262306a36Sopenharmony_ci			   "%s: syfsboot disabled - driver will trigger login "
622362306a36Sopenharmony_ci			   "and publish session for discovery .\n", __func__);
622462306a36Sopenharmony_ci		return QLA_SUCCESS;
622562306a36Sopenharmony_ci	}
622662306a36Sopenharmony_ci
622762306a36Sopenharmony_ci
622862306a36Sopenharmony_ci	ha->boot_kset = iscsi_boot_create_host_kset(ha->host->host_no);
622962306a36Sopenharmony_ci	if (!ha->boot_kset)
623062306a36Sopenharmony_ci		goto kset_free;
623162306a36Sopenharmony_ci
623262306a36Sopenharmony_ci	if (!scsi_host_get(ha->host))
623362306a36Sopenharmony_ci		goto kset_free;
623462306a36Sopenharmony_ci	boot_kobj = iscsi_boot_create_target(ha->boot_kset, 0, ha,
623562306a36Sopenharmony_ci					     qla4xxx_show_boot_tgt_pri_info,
623662306a36Sopenharmony_ci					     qla4xxx_tgt_get_attr_visibility,
623762306a36Sopenharmony_ci					     qla4xxx_boot_release);
623862306a36Sopenharmony_ci	if (!boot_kobj)
623962306a36Sopenharmony_ci		goto put_host;
624062306a36Sopenharmony_ci
624162306a36Sopenharmony_ci	if (!scsi_host_get(ha->host))
624262306a36Sopenharmony_ci		goto kset_free;
624362306a36Sopenharmony_ci	boot_kobj = iscsi_boot_create_target(ha->boot_kset, 1, ha,
624462306a36Sopenharmony_ci					     qla4xxx_show_boot_tgt_sec_info,
624562306a36Sopenharmony_ci					     qla4xxx_tgt_get_attr_visibility,
624662306a36Sopenharmony_ci					     qla4xxx_boot_release);
624762306a36Sopenharmony_ci	if (!boot_kobj)
624862306a36Sopenharmony_ci		goto put_host;
624962306a36Sopenharmony_ci
625062306a36Sopenharmony_ci	if (!scsi_host_get(ha->host))
625162306a36Sopenharmony_ci		goto kset_free;
625262306a36Sopenharmony_ci	boot_kobj = iscsi_boot_create_initiator(ha->boot_kset, 0, ha,
625362306a36Sopenharmony_ci					       qla4xxx_show_boot_ini_info,
625462306a36Sopenharmony_ci					       qla4xxx_ini_get_attr_visibility,
625562306a36Sopenharmony_ci					       qla4xxx_boot_release);
625662306a36Sopenharmony_ci	if (!boot_kobj)
625762306a36Sopenharmony_ci		goto put_host;
625862306a36Sopenharmony_ci
625962306a36Sopenharmony_ci	if (!scsi_host_get(ha->host))
626062306a36Sopenharmony_ci		goto kset_free;
626162306a36Sopenharmony_ci	boot_kobj = iscsi_boot_create_ethernet(ha->boot_kset, 0, ha,
626262306a36Sopenharmony_ci					       qla4xxx_show_boot_eth_info,
626362306a36Sopenharmony_ci					       qla4xxx_eth_get_attr_visibility,
626462306a36Sopenharmony_ci					       qla4xxx_boot_release);
626562306a36Sopenharmony_ci	if (!boot_kobj)
626662306a36Sopenharmony_ci		goto put_host;
626762306a36Sopenharmony_ci
626862306a36Sopenharmony_ci	return QLA_SUCCESS;
626962306a36Sopenharmony_ci
627062306a36Sopenharmony_ciput_host:
627162306a36Sopenharmony_ci	scsi_host_put(ha->host);
627262306a36Sopenharmony_cikset_free:
627362306a36Sopenharmony_ci	iscsi_boot_destroy_kset(ha->boot_kset);
627462306a36Sopenharmony_ci	return -ENOMEM;
627562306a36Sopenharmony_ci}
627662306a36Sopenharmony_ci
627762306a36Sopenharmony_ci
627862306a36Sopenharmony_cistatic void qla4xxx_get_param_ddb(struct ddb_entry *ddb_entry,
627962306a36Sopenharmony_ci				  struct ql4_tuple_ddb *tddb)
628062306a36Sopenharmony_ci{
628162306a36Sopenharmony_ci	struct iscsi_cls_session *cls_sess;
628262306a36Sopenharmony_ci	struct iscsi_cls_conn *cls_conn;
628362306a36Sopenharmony_ci	struct iscsi_session *sess;
628462306a36Sopenharmony_ci	struct iscsi_conn *conn;
628562306a36Sopenharmony_ci
628662306a36Sopenharmony_ci	DEBUG2(printk(KERN_INFO "Func: %s\n", __func__));
628762306a36Sopenharmony_ci	cls_sess = ddb_entry->sess;
628862306a36Sopenharmony_ci	sess = cls_sess->dd_data;
628962306a36Sopenharmony_ci	cls_conn = ddb_entry->conn;
629062306a36Sopenharmony_ci	conn = cls_conn->dd_data;
629162306a36Sopenharmony_ci
629262306a36Sopenharmony_ci	tddb->tpgt = sess->tpgt;
629362306a36Sopenharmony_ci	tddb->port = conn->persistent_port;
629462306a36Sopenharmony_ci	strscpy(tddb->iscsi_name, sess->targetname, ISCSI_NAME_SIZE);
629562306a36Sopenharmony_ci	strscpy(tddb->ip_addr, conn->persistent_address, DDB_IPADDR_LEN);
629662306a36Sopenharmony_ci}
629762306a36Sopenharmony_ci
629862306a36Sopenharmony_cistatic void qla4xxx_convert_param_ddb(struct dev_db_entry *fw_ddb_entry,
629962306a36Sopenharmony_ci				      struct ql4_tuple_ddb *tddb,
630062306a36Sopenharmony_ci				      uint8_t *flash_isid)
630162306a36Sopenharmony_ci{
630262306a36Sopenharmony_ci	uint16_t options = 0;
630362306a36Sopenharmony_ci
630462306a36Sopenharmony_ci	tddb->tpgt = le32_to_cpu(fw_ddb_entry->tgt_portal_grp);
630562306a36Sopenharmony_ci	memcpy(&tddb->iscsi_name[0], &fw_ddb_entry->iscsi_name[0],
630662306a36Sopenharmony_ci	       min(sizeof(tddb->iscsi_name), sizeof(fw_ddb_entry->iscsi_name)));
630762306a36Sopenharmony_ci
630862306a36Sopenharmony_ci	options = le16_to_cpu(fw_ddb_entry->options);
630962306a36Sopenharmony_ci	if (options & DDB_OPT_IPV6_DEVICE)
631062306a36Sopenharmony_ci		sprintf(tddb->ip_addr, "%pI6", fw_ddb_entry->ip_addr);
631162306a36Sopenharmony_ci	else
631262306a36Sopenharmony_ci		sprintf(tddb->ip_addr, "%pI4", fw_ddb_entry->ip_addr);
631362306a36Sopenharmony_ci
631462306a36Sopenharmony_ci	tddb->port = le16_to_cpu(fw_ddb_entry->port);
631562306a36Sopenharmony_ci
631662306a36Sopenharmony_ci	if (flash_isid == NULL)
631762306a36Sopenharmony_ci		memcpy(&tddb->isid[0], &fw_ddb_entry->isid[0],
631862306a36Sopenharmony_ci		       sizeof(tddb->isid));
631962306a36Sopenharmony_ci	else
632062306a36Sopenharmony_ci		memcpy(&tddb->isid[0], &flash_isid[0], sizeof(tddb->isid));
632162306a36Sopenharmony_ci}
632262306a36Sopenharmony_ci
632362306a36Sopenharmony_cistatic int qla4xxx_compare_tuple_ddb(struct scsi_qla_host *ha,
632462306a36Sopenharmony_ci				     struct ql4_tuple_ddb *old_tddb,
632562306a36Sopenharmony_ci				     struct ql4_tuple_ddb *new_tddb,
632662306a36Sopenharmony_ci				     uint8_t is_isid_compare)
632762306a36Sopenharmony_ci{
632862306a36Sopenharmony_ci	if (strcmp(old_tddb->iscsi_name, new_tddb->iscsi_name))
632962306a36Sopenharmony_ci		return QLA_ERROR;
633062306a36Sopenharmony_ci
633162306a36Sopenharmony_ci	if (strcmp(old_tddb->ip_addr, new_tddb->ip_addr))
633262306a36Sopenharmony_ci		return QLA_ERROR;
633362306a36Sopenharmony_ci
633462306a36Sopenharmony_ci	if (old_tddb->port != new_tddb->port)
633562306a36Sopenharmony_ci		return QLA_ERROR;
633662306a36Sopenharmony_ci
633762306a36Sopenharmony_ci	/* For multi sessions, driver generates the ISID, so do not compare
633862306a36Sopenharmony_ci	 * ISID in reset path since it would be a comparison between the
633962306a36Sopenharmony_ci	 * driver generated ISID and firmware generated ISID. This could
634062306a36Sopenharmony_ci	 * lead to adding duplicated DDBs in the list as driver generated
634162306a36Sopenharmony_ci	 * ISID would not match firmware generated ISID.
634262306a36Sopenharmony_ci	 */
634362306a36Sopenharmony_ci	if (is_isid_compare) {
634462306a36Sopenharmony_ci		DEBUG2(ql4_printk(KERN_INFO, ha,
634562306a36Sopenharmony_ci			"%s: old ISID [%pmR] New ISID [%pmR]\n",
634662306a36Sopenharmony_ci			__func__, old_tddb->isid, new_tddb->isid));
634762306a36Sopenharmony_ci
634862306a36Sopenharmony_ci		if (memcmp(&old_tddb->isid[0], &new_tddb->isid[0],
634962306a36Sopenharmony_ci			   sizeof(old_tddb->isid)))
635062306a36Sopenharmony_ci			return QLA_ERROR;
635162306a36Sopenharmony_ci	}
635262306a36Sopenharmony_ci
635362306a36Sopenharmony_ci	DEBUG2(ql4_printk(KERN_INFO, ha,
635462306a36Sopenharmony_ci			  "Match Found, fw[%d,%d,%s,%s], [%d,%d,%s,%s]",
635562306a36Sopenharmony_ci			  old_tddb->port, old_tddb->tpgt, old_tddb->ip_addr,
635662306a36Sopenharmony_ci			  old_tddb->iscsi_name, new_tddb->port, new_tddb->tpgt,
635762306a36Sopenharmony_ci			  new_tddb->ip_addr, new_tddb->iscsi_name));
635862306a36Sopenharmony_ci
635962306a36Sopenharmony_ci	return QLA_SUCCESS;
636062306a36Sopenharmony_ci}
636162306a36Sopenharmony_ci
636262306a36Sopenharmony_cistatic int qla4xxx_is_session_exists(struct scsi_qla_host *ha,
636362306a36Sopenharmony_ci				     struct dev_db_entry *fw_ddb_entry,
636462306a36Sopenharmony_ci				     uint32_t *index)
636562306a36Sopenharmony_ci{
636662306a36Sopenharmony_ci	struct ddb_entry *ddb_entry;
636762306a36Sopenharmony_ci	struct ql4_tuple_ddb *fw_tddb = NULL;
636862306a36Sopenharmony_ci	struct ql4_tuple_ddb *tmp_tddb = NULL;
636962306a36Sopenharmony_ci	int idx;
637062306a36Sopenharmony_ci	int ret = QLA_ERROR;
637162306a36Sopenharmony_ci
637262306a36Sopenharmony_ci	fw_tddb = vzalloc(sizeof(*fw_tddb));
637362306a36Sopenharmony_ci	if (!fw_tddb) {
637462306a36Sopenharmony_ci		DEBUG2(ql4_printk(KERN_WARNING, ha,
637562306a36Sopenharmony_ci				  "Memory Allocation failed.\n"));
637662306a36Sopenharmony_ci		ret = QLA_SUCCESS;
637762306a36Sopenharmony_ci		goto exit_check;
637862306a36Sopenharmony_ci	}
637962306a36Sopenharmony_ci
638062306a36Sopenharmony_ci	tmp_tddb = vzalloc(sizeof(*tmp_tddb));
638162306a36Sopenharmony_ci	if (!tmp_tddb) {
638262306a36Sopenharmony_ci		DEBUG2(ql4_printk(KERN_WARNING, ha,
638362306a36Sopenharmony_ci				  "Memory Allocation failed.\n"));
638462306a36Sopenharmony_ci		ret = QLA_SUCCESS;
638562306a36Sopenharmony_ci		goto exit_check;
638662306a36Sopenharmony_ci	}
638762306a36Sopenharmony_ci
638862306a36Sopenharmony_ci	qla4xxx_convert_param_ddb(fw_ddb_entry, fw_tddb, NULL);
638962306a36Sopenharmony_ci
639062306a36Sopenharmony_ci	for (idx = 0; idx < MAX_DDB_ENTRIES; idx++) {
639162306a36Sopenharmony_ci		ddb_entry = qla4xxx_lookup_ddb_by_fw_index(ha, idx);
639262306a36Sopenharmony_ci		if (ddb_entry == NULL)
639362306a36Sopenharmony_ci			continue;
639462306a36Sopenharmony_ci
639562306a36Sopenharmony_ci		qla4xxx_get_param_ddb(ddb_entry, tmp_tddb);
639662306a36Sopenharmony_ci		if (!qla4xxx_compare_tuple_ddb(ha, fw_tddb, tmp_tddb, false)) {
639762306a36Sopenharmony_ci			ret = QLA_SUCCESS; /* found */
639862306a36Sopenharmony_ci			if (index != NULL)
639962306a36Sopenharmony_ci				*index = idx;
640062306a36Sopenharmony_ci			goto exit_check;
640162306a36Sopenharmony_ci		}
640262306a36Sopenharmony_ci	}
640362306a36Sopenharmony_ci
640462306a36Sopenharmony_ciexit_check:
640562306a36Sopenharmony_ci	vfree(fw_tddb);
640662306a36Sopenharmony_ci	vfree(tmp_tddb);
640762306a36Sopenharmony_ci	return ret;
640862306a36Sopenharmony_ci}
640962306a36Sopenharmony_ci
641062306a36Sopenharmony_ci/**
641162306a36Sopenharmony_ci * qla4xxx_check_existing_isid - check if target with same isid exist
641262306a36Sopenharmony_ci *				 in target list
641362306a36Sopenharmony_ci * @list_nt: list of target
641462306a36Sopenharmony_ci * @isid: isid to check
641562306a36Sopenharmony_ci *
641662306a36Sopenharmony_ci * This routine return QLA_SUCCESS if target with same isid exist
641762306a36Sopenharmony_ci **/
641862306a36Sopenharmony_cistatic int qla4xxx_check_existing_isid(struct list_head *list_nt, uint8_t *isid)
641962306a36Sopenharmony_ci{
642062306a36Sopenharmony_ci	struct qla_ddb_index *nt_ddb_idx, *nt_ddb_idx_tmp;
642162306a36Sopenharmony_ci	struct dev_db_entry *fw_ddb_entry;
642262306a36Sopenharmony_ci
642362306a36Sopenharmony_ci	list_for_each_entry_safe(nt_ddb_idx, nt_ddb_idx_tmp, list_nt, list) {
642462306a36Sopenharmony_ci		fw_ddb_entry = &nt_ddb_idx->fw_ddb;
642562306a36Sopenharmony_ci
642662306a36Sopenharmony_ci		if (memcmp(&fw_ddb_entry->isid[0], &isid[0],
642762306a36Sopenharmony_ci			   sizeof(nt_ddb_idx->fw_ddb.isid)) == 0) {
642862306a36Sopenharmony_ci			return QLA_SUCCESS;
642962306a36Sopenharmony_ci		}
643062306a36Sopenharmony_ci	}
643162306a36Sopenharmony_ci	return QLA_ERROR;
643262306a36Sopenharmony_ci}
643362306a36Sopenharmony_ci
643462306a36Sopenharmony_ci/**
643562306a36Sopenharmony_ci * qla4xxx_update_isid - compare ddbs and updated isid
643662306a36Sopenharmony_ci * @ha: Pointer to host adapter structure.
643762306a36Sopenharmony_ci * @list_nt: list of nt target
643862306a36Sopenharmony_ci * @fw_ddb_entry: firmware ddb entry
643962306a36Sopenharmony_ci *
644062306a36Sopenharmony_ci * This routine update isid if ddbs have same iqn, same isid and
644162306a36Sopenharmony_ci * different IP addr.
644262306a36Sopenharmony_ci * Return QLA_SUCCESS if isid is updated.
644362306a36Sopenharmony_ci **/
644462306a36Sopenharmony_cistatic int qla4xxx_update_isid(struct scsi_qla_host *ha,
644562306a36Sopenharmony_ci			       struct list_head *list_nt,
644662306a36Sopenharmony_ci			       struct dev_db_entry *fw_ddb_entry)
644762306a36Sopenharmony_ci{
644862306a36Sopenharmony_ci	uint8_t base_value, i;
644962306a36Sopenharmony_ci
645062306a36Sopenharmony_ci	base_value = fw_ddb_entry->isid[1] & 0x1f;
645162306a36Sopenharmony_ci	for (i = 0; i < 8; i++) {
645262306a36Sopenharmony_ci		fw_ddb_entry->isid[1] = (base_value | (i << 5));
645362306a36Sopenharmony_ci		if (qla4xxx_check_existing_isid(list_nt, fw_ddb_entry->isid))
645462306a36Sopenharmony_ci			break;
645562306a36Sopenharmony_ci	}
645662306a36Sopenharmony_ci
645762306a36Sopenharmony_ci	if (!qla4xxx_check_existing_isid(list_nt, fw_ddb_entry->isid))
645862306a36Sopenharmony_ci		return QLA_ERROR;
645962306a36Sopenharmony_ci
646062306a36Sopenharmony_ci	return QLA_SUCCESS;
646162306a36Sopenharmony_ci}
646262306a36Sopenharmony_ci
646362306a36Sopenharmony_ci/**
646462306a36Sopenharmony_ci * qla4xxx_should_update_isid - check if isid need to update
646562306a36Sopenharmony_ci * @ha: Pointer to host adapter structure.
646662306a36Sopenharmony_ci * @old_tddb: ddb tuple
646762306a36Sopenharmony_ci * @new_tddb: ddb tuple
646862306a36Sopenharmony_ci *
646962306a36Sopenharmony_ci * Return QLA_SUCCESS if different IP, different PORT, same iqn,
647062306a36Sopenharmony_ci * same isid
647162306a36Sopenharmony_ci **/
647262306a36Sopenharmony_cistatic int qla4xxx_should_update_isid(struct scsi_qla_host *ha,
647362306a36Sopenharmony_ci				      struct ql4_tuple_ddb *old_tddb,
647462306a36Sopenharmony_ci				      struct ql4_tuple_ddb *new_tddb)
647562306a36Sopenharmony_ci{
647662306a36Sopenharmony_ci	if (strcmp(old_tddb->ip_addr, new_tddb->ip_addr) == 0) {
647762306a36Sopenharmony_ci		/* Same ip */
647862306a36Sopenharmony_ci		if (old_tddb->port == new_tddb->port)
647962306a36Sopenharmony_ci			return QLA_ERROR;
648062306a36Sopenharmony_ci	}
648162306a36Sopenharmony_ci
648262306a36Sopenharmony_ci	if (strcmp(old_tddb->iscsi_name, new_tddb->iscsi_name))
648362306a36Sopenharmony_ci		/* different iqn */
648462306a36Sopenharmony_ci		return QLA_ERROR;
648562306a36Sopenharmony_ci
648662306a36Sopenharmony_ci	if (memcmp(&old_tddb->isid[0], &new_tddb->isid[0],
648762306a36Sopenharmony_ci		   sizeof(old_tddb->isid)))
648862306a36Sopenharmony_ci		/* different isid */
648962306a36Sopenharmony_ci		return QLA_ERROR;
649062306a36Sopenharmony_ci
649162306a36Sopenharmony_ci	return QLA_SUCCESS;
649262306a36Sopenharmony_ci}
649362306a36Sopenharmony_ci
649462306a36Sopenharmony_ci/**
649562306a36Sopenharmony_ci * qla4xxx_is_flash_ddb_exists - check if fw_ddb_entry already exists in list_nt
649662306a36Sopenharmony_ci * @ha: Pointer to host adapter structure.
649762306a36Sopenharmony_ci * @list_nt: list of nt target.
649862306a36Sopenharmony_ci * @fw_ddb_entry: firmware ddb entry.
649962306a36Sopenharmony_ci *
650062306a36Sopenharmony_ci * This routine check if fw_ddb_entry already exists in list_nt to avoid
650162306a36Sopenharmony_ci * duplicate ddb in list_nt.
650262306a36Sopenharmony_ci * Return QLA_SUCCESS if duplicate ddb exit in list_nl.
650362306a36Sopenharmony_ci * Note: This function also update isid of DDB if required.
650462306a36Sopenharmony_ci **/
650562306a36Sopenharmony_ci
650662306a36Sopenharmony_cistatic int qla4xxx_is_flash_ddb_exists(struct scsi_qla_host *ha,
650762306a36Sopenharmony_ci				       struct list_head *list_nt,
650862306a36Sopenharmony_ci				       struct dev_db_entry *fw_ddb_entry)
650962306a36Sopenharmony_ci{
651062306a36Sopenharmony_ci	struct qla_ddb_index  *nt_ddb_idx, *nt_ddb_idx_tmp;
651162306a36Sopenharmony_ci	struct ql4_tuple_ddb *fw_tddb = NULL;
651262306a36Sopenharmony_ci	struct ql4_tuple_ddb *tmp_tddb = NULL;
651362306a36Sopenharmony_ci	int rval, ret = QLA_ERROR;
651462306a36Sopenharmony_ci
651562306a36Sopenharmony_ci	fw_tddb = vzalloc(sizeof(*fw_tddb));
651662306a36Sopenharmony_ci	if (!fw_tddb) {
651762306a36Sopenharmony_ci		DEBUG2(ql4_printk(KERN_WARNING, ha,
651862306a36Sopenharmony_ci				  "Memory Allocation failed.\n"));
651962306a36Sopenharmony_ci		ret = QLA_SUCCESS;
652062306a36Sopenharmony_ci		goto exit_check;
652162306a36Sopenharmony_ci	}
652262306a36Sopenharmony_ci
652362306a36Sopenharmony_ci	tmp_tddb = vzalloc(sizeof(*tmp_tddb));
652462306a36Sopenharmony_ci	if (!tmp_tddb) {
652562306a36Sopenharmony_ci		DEBUG2(ql4_printk(KERN_WARNING, ha,
652662306a36Sopenharmony_ci				  "Memory Allocation failed.\n"));
652762306a36Sopenharmony_ci		ret = QLA_SUCCESS;
652862306a36Sopenharmony_ci		goto exit_check;
652962306a36Sopenharmony_ci	}
653062306a36Sopenharmony_ci
653162306a36Sopenharmony_ci	qla4xxx_convert_param_ddb(fw_ddb_entry, fw_tddb, NULL);
653262306a36Sopenharmony_ci
653362306a36Sopenharmony_ci	list_for_each_entry_safe(nt_ddb_idx, nt_ddb_idx_tmp, list_nt, list) {
653462306a36Sopenharmony_ci		qla4xxx_convert_param_ddb(&nt_ddb_idx->fw_ddb, tmp_tddb,
653562306a36Sopenharmony_ci					  nt_ddb_idx->flash_isid);
653662306a36Sopenharmony_ci		ret = qla4xxx_compare_tuple_ddb(ha, fw_tddb, tmp_tddb, true);
653762306a36Sopenharmony_ci		/* found duplicate ddb */
653862306a36Sopenharmony_ci		if (ret == QLA_SUCCESS)
653962306a36Sopenharmony_ci			goto exit_check;
654062306a36Sopenharmony_ci	}
654162306a36Sopenharmony_ci
654262306a36Sopenharmony_ci	list_for_each_entry_safe(nt_ddb_idx, nt_ddb_idx_tmp, list_nt, list) {
654362306a36Sopenharmony_ci		qla4xxx_convert_param_ddb(&nt_ddb_idx->fw_ddb, tmp_tddb, NULL);
654462306a36Sopenharmony_ci
654562306a36Sopenharmony_ci		ret = qla4xxx_should_update_isid(ha, tmp_tddb, fw_tddb);
654662306a36Sopenharmony_ci		if (ret == QLA_SUCCESS) {
654762306a36Sopenharmony_ci			rval = qla4xxx_update_isid(ha, list_nt, fw_ddb_entry);
654862306a36Sopenharmony_ci			if (rval == QLA_SUCCESS)
654962306a36Sopenharmony_ci				ret = QLA_ERROR;
655062306a36Sopenharmony_ci			else
655162306a36Sopenharmony_ci				ret = QLA_SUCCESS;
655262306a36Sopenharmony_ci
655362306a36Sopenharmony_ci			goto exit_check;
655462306a36Sopenharmony_ci		}
655562306a36Sopenharmony_ci	}
655662306a36Sopenharmony_ci
655762306a36Sopenharmony_ciexit_check:
655862306a36Sopenharmony_ci	vfree(fw_tddb);
655962306a36Sopenharmony_ci	vfree(tmp_tddb);
656062306a36Sopenharmony_ci	return ret;
656162306a36Sopenharmony_ci}
656262306a36Sopenharmony_ci
656362306a36Sopenharmony_cistatic void qla4xxx_free_ddb_list(struct list_head *list_ddb)
656462306a36Sopenharmony_ci{
656562306a36Sopenharmony_ci	struct qla_ddb_index  *ddb_idx, *ddb_idx_tmp;
656662306a36Sopenharmony_ci
656762306a36Sopenharmony_ci	list_for_each_entry_safe(ddb_idx, ddb_idx_tmp, list_ddb, list) {
656862306a36Sopenharmony_ci		list_del_init(&ddb_idx->list);
656962306a36Sopenharmony_ci		vfree(ddb_idx);
657062306a36Sopenharmony_ci	}
657162306a36Sopenharmony_ci}
657262306a36Sopenharmony_ci
657362306a36Sopenharmony_cistatic struct iscsi_endpoint *qla4xxx_get_ep_fwdb(struct scsi_qla_host *ha,
657462306a36Sopenharmony_ci					struct dev_db_entry *fw_ddb_entry)
657562306a36Sopenharmony_ci{
657662306a36Sopenharmony_ci	struct iscsi_endpoint *ep;
657762306a36Sopenharmony_ci	struct sockaddr_in *addr;
657862306a36Sopenharmony_ci	struct sockaddr_in6 *addr6;
657962306a36Sopenharmony_ci	struct sockaddr *t_addr;
658062306a36Sopenharmony_ci	struct sockaddr_storage *dst_addr;
658162306a36Sopenharmony_ci	char *ip;
658262306a36Sopenharmony_ci
658362306a36Sopenharmony_ci	/* TODO: need to destroy on unload iscsi_endpoint*/
658462306a36Sopenharmony_ci	dst_addr = vmalloc(sizeof(*dst_addr));
658562306a36Sopenharmony_ci	if (!dst_addr)
658662306a36Sopenharmony_ci		return NULL;
658762306a36Sopenharmony_ci
658862306a36Sopenharmony_ci	if (fw_ddb_entry->options & DDB_OPT_IPV6_DEVICE) {
658962306a36Sopenharmony_ci		t_addr = (struct sockaddr *)dst_addr;
659062306a36Sopenharmony_ci		t_addr->sa_family = AF_INET6;
659162306a36Sopenharmony_ci		addr6 = (struct sockaddr_in6 *)dst_addr;
659262306a36Sopenharmony_ci		ip = (char *)&addr6->sin6_addr;
659362306a36Sopenharmony_ci		memcpy(ip, fw_ddb_entry->ip_addr, IPv6_ADDR_LEN);
659462306a36Sopenharmony_ci		addr6->sin6_port = htons(le16_to_cpu(fw_ddb_entry->port));
659562306a36Sopenharmony_ci
659662306a36Sopenharmony_ci	} else {
659762306a36Sopenharmony_ci		t_addr = (struct sockaddr *)dst_addr;
659862306a36Sopenharmony_ci		t_addr->sa_family = AF_INET;
659962306a36Sopenharmony_ci		addr = (struct sockaddr_in *)dst_addr;
660062306a36Sopenharmony_ci		ip = (char *)&addr->sin_addr;
660162306a36Sopenharmony_ci		memcpy(ip, fw_ddb_entry->ip_addr, IP_ADDR_LEN);
660262306a36Sopenharmony_ci		addr->sin_port = htons(le16_to_cpu(fw_ddb_entry->port));
660362306a36Sopenharmony_ci	}
660462306a36Sopenharmony_ci
660562306a36Sopenharmony_ci	ep = qla4xxx_ep_connect(ha->host, (struct sockaddr *)dst_addr, 0);
660662306a36Sopenharmony_ci	vfree(dst_addr);
660762306a36Sopenharmony_ci	return ep;
660862306a36Sopenharmony_ci}
660962306a36Sopenharmony_ci
661062306a36Sopenharmony_cistatic int qla4xxx_verify_boot_idx(struct scsi_qla_host *ha, uint16_t idx)
661162306a36Sopenharmony_ci{
661262306a36Sopenharmony_ci	if (ql4xdisablesysfsboot)
661362306a36Sopenharmony_ci		return QLA_SUCCESS;
661462306a36Sopenharmony_ci	if (idx == ha->pri_ddb_idx || idx == ha->sec_ddb_idx)
661562306a36Sopenharmony_ci		return QLA_ERROR;
661662306a36Sopenharmony_ci	return QLA_SUCCESS;
661762306a36Sopenharmony_ci}
661862306a36Sopenharmony_ci
661962306a36Sopenharmony_cistatic void qla4xxx_setup_flash_ddb_entry(struct scsi_qla_host *ha,
662062306a36Sopenharmony_ci					  struct ddb_entry *ddb_entry,
662162306a36Sopenharmony_ci					  uint16_t idx)
662262306a36Sopenharmony_ci{
662362306a36Sopenharmony_ci	uint16_t def_timeout;
662462306a36Sopenharmony_ci
662562306a36Sopenharmony_ci	ddb_entry->ddb_type = FLASH_DDB;
662662306a36Sopenharmony_ci	ddb_entry->fw_ddb_index = INVALID_ENTRY;
662762306a36Sopenharmony_ci	ddb_entry->fw_ddb_device_state = DDB_DS_NO_CONNECTION_ACTIVE;
662862306a36Sopenharmony_ci	ddb_entry->ha = ha;
662962306a36Sopenharmony_ci	ddb_entry->unblock_sess = qla4xxx_unblock_flash_ddb;
663062306a36Sopenharmony_ci	ddb_entry->ddb_change = qla4xxx_flash_ddb_change;
663162306a36Sopenharmony_ci	ddb_entry->chap_tbl_idx = INVALID_ENTRY;
663262306a36Sopenharmony_ci
663362306a36Sopenharmony_ci	atomic_set(&ddb_entry->retry_relogin_timer, INVALID_ENTRY);
663462306a36Sopenharmony_ci	atomic_set(&ddb_entry->relogin_timer, 0);
663562306a36Sopenharmony_ci	atomic_set(&ddb_entry->relogin_retry_count, 0);
663662306a36Sopenharmony_ci	def_timeout = le16_to_cpu(ddb_entry->fw_ddb_entry.def_timeout);
663762306a36Sopenharmony_ci	ddb_entry->default_relogin_timeout =
663862306a36Sopenharmony_ci		(def_timeout > LOGIN_TOV) && (def_timeout < LOGIN_TOV * 10) ?
663962306a36Sopenharmony_ci		def_timeout : LOGIN_TOV;
664062306a36Sopenharmony_ci	ddb_entry->default_time2wait =
664162306a36Sopenharmony_ci		le16_to_cpu(ddb_entry->fw_ddb_entry.iscsi_def_time2wait);
664262306a36Sopenharmony_ci
664362306a36Sopenharmony_ci	if (ql4xdisablesysfsboot &&
664462306a36Sopenharmony_ci	    (idx == ha->pri_ddb_idx || idx == ha->sec_ddb_idx))
664562306a36Sopenharmony_ci		set_bit(DF_BOOT_TGT, &ddb_entry->flags);
664662306a36Sopenharmony_ci}
664762306a36Sopenharmony_ci
664862306a36Sopenharmony_cistatic void qla4xxx_wait_for_ip_configuration(struct scsi_qla_host *ha)
664962306a36Sopenharmony_ci{
665062306a36Sopenharmony_ci	uint32_t idx = 0;
665162306a36Sopenharmony_ci	uint32_t ip_idx[IP_ADDR_COUNT] = {0, 1, 2, 3}; /* 4 IP interfaces */
665262306a36Sopenharmony_ci	uint32_t sts[MBOX_REG_COUNT];
665362306a36Sopenharmony_ci	uint32_t ip_state;
665462306a36Sopenharmony_ci	unsigned long wtime;
665562306a36Sopenharmony_ci	int ret;
665662306a36Sopenharmony_ci
665762306a36Sopenharmony_ci	wtime = jiffies + (HZ * IP_CONFIG_TOV);
665862306a36Sopenharmony_ci	do {
665962306a36Sopenharmony_ci		for (idx = 0; idx < IP_ADDR_COUNT; idx++) {
666062306a36Sopenharmony_ci			if (ip_idx[idx] == -1)
666162306a36Sopenharmony_ci				continue;
666262306a36Sopenharmony_ci
666362306a36Sopenharmony_ci			ret = qla4xxx_get_ip_state(ha, 0, ip_idx[idx], sts);
666462306a36Sopenharmony_ci
666562306a36Sopenharmony_ci			if (ret == QLA_ERROR) {
666662306a36Sopenharmony_ci				ip_idx[idx] = -1;
666762306a36Sopenharmony_ci				continue;
666862306a36Sopenharmony_ci			}
666962306a36Sopenharmony_ci
667062306a36Sopenharmony_ci			ip_state = (sts[1] & IP_STATE_MASK) >> IP_STATE_SHIFT;
667162306a36Sopenharmony_ci
667262306a36Sopenharmony_ci			DEBUG2(ql4_printk(KERN_INFO, ha,
667362306a36Sopenharmony_ci					  "Waiting for IP state for idx = %d, state = 0x%x\n",
667462306a36Sopenharmony_ci					  ip_idx[idx], ip_state));
667562306a36Sopenharmony_ci			if (ip_state == IP_ADDRSTATE_UNCONFIGURED ||
667662306a36Sopenharmony_ci			    ip_state == IP_ADDRSTATE_INVALID ||
667762306a36Sopenharmony_ci			    ip_state == IP_ADDRSTATE_PREFERRED ||
667862306a36Sopenharmony_ci			    ip_state == IP_ADDRSTATE_DEPRICATED ||
667962306a36Sopenharmony_ci			    ip_state == IP_ADDRSTATE_DISABLING)
668062306a36Sopenharmony_ci				ip_idx[idx] = -1;
668162306a36Sopenharmony_ci		}
668262306a36Sopenharmony_ci
668362306a36Sopenharmony_ci		/* Break if all IP states checked */
668462306a36Sopenharmony_ci		if ((ip_idx[0] == -1) &&
668562306a36Sopenharmony_ci		    (ip_idx[1] == -1) &&
668662306a36Sopenharmony_ci		    (ip_idx[2] == -1) &&
668762306a36Sopenharmony_ci		    (ip_idx[3] == -1))
668862306a36Sopenharmony_ci			break;
668962306a36Sopenharmony_ci		schedule_timeout_uninterruptible(HZ);
669062306a36Sopenharmony_ci	} while (time_after(wtime, jiffies));
669162306a36Sopenharmony_ci}
669262306a36Sopenharmony_ci
669362306a36Sopenharmony_cistatic int qla4xxx_cmp_fw_stentry(struct dev_db_entry *fw_ddb_entry,
669462306a36Sopenharmony_ci				  struct dev_db_entry *flash_ddb_entry)
669562306a36Sopenharmony_ci{
669662306a36Sopenharmony_ci	uint16_t options = 0;
669762306a36Sopenharmony_ci	size_t ip_len = IP_ADDR_LEN;
669862306a36Sopenharmony_ci
669962306a36Sopenharmony_ci	options = le16_to_cpu(fw_ddb_entry->options);
670062306a36Sopenharmony_ci	if (options & DDB_OPT_IPV6_DEVICE)
670162306a36Sopenharmony_ci		ip_len = IPv6_ADDR_LEN;
670262306a36Sopenharmony_ci
670362306a36Sopenharmony_ci	if (memcmp(fw_ddb_entry->ip_addr, flash_ddb_entry->ip_addr, ip_len))
670462306a36Sopenharmony_ci		return QLA_ERROR;
670562306a36Sopenharmony_ci
670662306a36Sopenharmony_ci	if (memcmp(&fw_ddb_entry->isid[0], &flash_ddb_entry->isid[0],
670762306a36Sopenharmony_ci		   sizeof(fw_ddb_entry->isid)))
670862306a36Sopenharmony_ci		return QLA_ERROR;
670962306a36Sopenharmony_ci
671062306a36Sopenharmony_ci	if (memcmp(&fw_ddb_entry->port, &flash_ddb_entry->port,
671162306a36Sopenharmony_ci		   sizeof(fw_ddb_entry->port)))
671262306a36Sopenharmony_ci		return QLA_ERROR;
671362306a36Sopenharmony_ci
671462306a36Sopenharmony_ci	return QLA_SUCCESS;
671562306a36Sopenharmony_ci}
671662306a36Sopenharmony_ci
671762306a36Sopenharmony_cistatic int qla4xxx_find_flash_st_idx(struct scsi_qla_host *ha,
671862306a36Sopenharmony_ci				     struct dev_db_entry *fw_ddb_entry,
671962306a36Sopenharmony_ci				     uint32_t fw_idx, uint32_t *flash_index)
672062306a36Sopenharmony_ci{
672162306a36Sopenharmony_ci	struct dev_db_entry *flash_ddb_entry;
672262306a36Sopenharmony_ci	dma_addr_t flash_ddb_entry_dma;
672362306a36Sopenharmony_ci	uint32_t idx = 0;
672462306a36Sopenharmony_ci	int max_ddbs;
672562306a36Sopenharmony_ci	int ret = QLA_ERROR, status;
672662306a36Sopenharmony_ci
672762306a36Sopenharmony_ci	max_ddbs =  is_qla40XX(ha) ? MAX_DEV_DB_ENTRIES_40XX :
672862306a36Sopenharmony_ci				     MAX_DEV_DB_ENTRIES;
672962306a36Sopenharmony_ci
673062306a36Sopenharmony_ci	flash_ddb_entry = dma_pool_alloc(ha->fw_ddb_dma_pool, GFP_KERNEL,
673162306a36Sopenharmony_ci					 &flash_ddb_entry_dma);
673262306a36Sopenharmony_ci	if (flash_ddb_entry == NULL || fw_ddb_entry == NULL) {
673362306a36Sopenharmony_ci		ql4_printk(KERN_ERR, ha, "Out of memory\n");
673462306a36Sopenharmony_ci		goto exit_find_st_idx;
673562306a36Sopenharmony_ci	}
673662306a36Sopenharmony_ci
673762306a36Sopenharmony_ci	status = qla4xxx_flashdb_by_index(ha, flash_ddb_entry,
673862306a36Sopenharmony_ci					  flash_ddb_entry_dma, fw_idx);
673962306a36Sopenharmony_ci	if (status == QLA_SUCCESS) {
674062306a36Sopenharmony_ci		status = qla4xxx_cmp_fw_stentry(fw_ddb_entry, flash_ddb_entry);
674162306a36Sopenharmony_ci		if (status == QLA_SUCCESS) {
674262306a36Sopenharmony_ci			*flash_index = fw_idx;
674362306a36Sopenharmony_ci			ret = QLA_SUCCESS;
674462306a36Sopenharmony_ci			goto exit_find_st_idx;
674562306a36Sopenharmony_ci		}
674662306a36Sopenharmony_ci	}
674762306a36Sopenharmony_ci
674862306a36Sopenharmony_ci	for (idx = 0; idx < max_ddbs; idx++) {
674962306a36Sopenharmony_ci		status = qla4xxx_flashdb_by_index(ha, flash_ddb_entry,
675062306a36Sopenharmony_ci						  flash_ddb_entry_dma, idx);
675162306a36Sopenharmony_ci		if (status == QLA_ERROR)
675262306a36Sopenharmony_ci			continue;
675362306a36Sopenharmony_ci
675462306a36Sopenharmony_ci		status = qla4xxx_cmp_fw_stentry(fw_ddb_entry, flash_ddb_entry);
675562306a36Sopenharmony_ci		if (status == QLA_SUCCESS) {
675662306a36Sopenharmony_ci			*flash_index = idx;
675762306a36Sopenharmony_ci			ret = QLA_SUCCESS;
675862306a36Sopenharmony_ci			goto exit_find_st_idx;
675962306a36Sopenharmony_ci		}
676062306a36Sopenharmony_ci	}
676162306a36Sopenharmony_ci
676262306a36Sopenharmony_ci	if (idx == max_ddbs)
676362306a36Sopenharmony_ci		ql4_printk(KERN_ERR, ha, "Failed to find ST [%d] in flash\n",
676462306a36Sopenharmony_ci			   fw_idx);
676562306a36Sopenharmony_ci
676662306a36Sopenharmony_ciexit_find_st_idx:
676762306a36Sopenharmony_ci	if (flash_ddb_entry)
676862306a36Sopenharmony_ci		dma_pool_free(ha->fw_ddb_dma_pool, flash_ddb_entry,
676962306a36Sopenharmony_ci			      flash_ddb_entry_dma);
677062306a36Sopenharmony_ci
677162306a36Sopenharmony_ci	return ret;
677262306a36Sopenharmony_ci}
677362306a36Sopenharmony_ci
677462306a36Sopenharmony_cistatic void qla4xxx_build_st_list(struct scsi_qla_host *ha,
677562306a36Sopenharmony_ci				  struct list_head *list_st)
677662306a36Sopenharmony_ci{
677762306a36Sopenharmony_ci	struct qla_ddb_index  *st_ddb_idx;
677862306a36Sopenharmony_ci	int max_ddbs;
677962306a36Sopenharmony_ci	int fw_idx_size;
678062306a36Sopenharmony_ci	struct dev_db_entry *fw_ddb_entry;
678162306a36Sopenharmony_ci	dma_addr_t fw_ddb_dma;
678262306a36Sopenharmony_ci	int ret;
678362306a36Sopenharmony_ci	uint32_t idx = 0, next_idx = 0;
678462306a36Sopenharmony_ci	uint32_t state = 0, conn_err = 0;
678562306a36Sopenharmony_ci	uint32_t flash_index = -1;
678662306a36Sopenharmony_ci	uint16_t conn_id = 0;
678762306a36Sopenharmony_ci
678862306a36Sopenharmony_ci	fw_ddb_entry = dma_pool_alloc(ha->fw_ddb_dma_pool, GFP_KERNEL,
678962306a36Sopenharmony_ci				      &fw_ddb_dma);
679062306a36Sopenharmony_ci	if (fw_ddb_entry == NULL) {
679162306a36Sopenharmony_ci		DEBUG2(ql4_printk(KERN_ERR, ha, "Out of memory\n"));
679262306a36Sopenharmony_ci		goto exit_st_list;
679362306a36Sopenharmony_ci	}
679462306a36Sopenharmony_ci
679562306a36Sopenharmony_ci	max_ddbs =  is_qla40XX(ha) ? MAX_DEV_DB_ENTRIES_40XX :
679662306a36Sopenharmony_ci				     MAX_DEV_DB_ENTRIES;
679762306a36Sopenharmony_ci	fw_idx_size = sizeof(struct qla_ddb_index);
679862306a36Sopenharmony_ci
679962306a36Sopenharmony_ci	for (idx = 0; idx < max_ddbs; idx = next_idx) {
680062306a36Sopenharmony_ci		ret = qla4xxx_get_fwddb_entry(ha, idx, fw_ddb_entry, fw_ddb_dma,
680162306a36Sopenharmony_ci					      NULL, &next_idx, &state,
680262306a36Sopenharmony_ci					      &conn_err, NULL, &conn_id);
680362306a36Sopenharmony_ci		if (ret == QLA_ERROR)
680462306a36Sopenharmony_ci			break;
680562306a36Sopenharmony_ci
680662306a36Sopenharmony_ci		/* Ignore DDB if invalid state (unassigned) */
680762306a36Sopenharmony_ci		if (state == DDB_DS_UNASSIGNED)
680862306a36Sopenharmony_ci			goto continue_next_st;
680962306a36Sopenharmony_ci
681062306a36Sopenharmony_ci		/* Check if ST, add to the list_st */
681162306a36Sopenharmony_ci		if (strlen((char *) fw_ddb_entry->iscsi_name) != 0)
681262306a36Sopenharmony_ci			goto continue_next_st;
681362306a36Sopenharmony_ci
681462306a36Sopenharmony_ci		st_ddb_idx = vzalloc(fw_idx_size);
681562306a36Sopenharmony_ci		if (!st_ddb_idx)
681662306a36Sopenharmony_ci			break;
681762306a36Sopenharmony_ci
681862306a36Sopenharmony_ci		ret = qla4xxx_find_flash_st_idx(ha, fw_ddb_entry, idx,
681962306a36Sopenharmony_ci						&flash_index);
682062306a36Sopenharmony_ci		if (ret == QLA_ERROR) {
682162306a36Sopenharmony_ci			ql4_printk(KERN_ERR, ha,
682262306a36Sopenharmony_ci				   "No flash entry for ST at idx [%d]\n", idx);
682362306a36Sopenharmony_ci			st_ddb_idx->flash_ddb_idx = idx;
682462306a36Sopenharmony_ci		} else {
682562306a36Sopenharmony_ci			ql4_printk(KERN_INFO, ha,
682662306a36Sopenharmony_ci				   "ST at idx [%d] is stored at flash [%d]\n",
682762306a36Sopenharmony_ci				   idx, flash_index);
682862306a36Sopenharmony_ci			st_ddb_idx->flash_ddb_idx = flash_index;
682962306a36Sopenharmony_ci		}
683062306a36Sopenharmony_ci
683162306a36Sopenharmony_ci		st_ddb_idx->fw_ddb_idx = idx;
683262306a36Sopenharmony_ci
683362306a36Sopenharmony_ci		list_add_tail(&st_ddb_idx->list, list_st);
683462306a36Sopenharmony_cicontinue_next_st:
683562306a36Sopenharmony_ci		if (next_idx == 0)
683662306a36Sopenharmony_ci			break;
683762306a36Sopenharmony_ci	}
683862306a36Sopenharmony_ci
683962306a36Sopenharmony_ciexit_st_list:
684062306a36Sopenharmony_ci	if (fw_ddb_entry)
684162306a36Sopenharmony_ci		dma_pool_free(ha->fw_ddb_dma_pool, fw_ddb_entry, fw_ddb_dma);
684262306a36Sopenharmony_ci}
684362306a36Sopenharmony_ci
684462306a36Sopenharmony_ci/**
684562306a36Sopenharmony_ci * qla4xxx_remove_failed_ddb - Remove inactive or failed ddb from list
684662306a36Sopenharmony_ci * @ha: pointer to adapter structure
684762306a36Sopenharmony_ci * @list_ddb: List from which failed ddb to be removed
684862306a36Sopenharmony_ci *
684962306a36Sopenharmony_ci * Iterate over the list of DDBs and find and remove DDBs that are either in
685062306a36Sopenharmony_ci * no connection active state or failed state
685162306a36Sopenharmony_ci **/
685262306a36Sopenharmony_cistatic void qla4xxx_remove_failed_ddb(struct scsi_qla_host *ha,
685362306a36Sopenharmony_ci				      struct list_head *list_ddb)
685462306a36Sopenharmony_ci{
685562306a36Sopenharmony_ci	struct qla_ddb_index  *ddb_idx, *ddb_idx_tmp;
685662306a36Sopenharmony_ci	uint32_t next_idx = 0;
685762306a36Sopenharmony_ci	uint32_t state = 0, conn_err = 0;
685862306a36Sopenharmony_ci	int ret;
685962306a36Sopenharmony_ci
686062306a36Sopenharmony_ci	list_for_each_entry_safe(ddb_idx, ddb_idx_tmp, list_ddb, list) {
686162306a36Sopenharmony_ci		ret = qla4xxx_get_fwddb_entry(ha, ddb_idx->fw_ddb_idx,
686262306a36Sopenharmony_ci					      NULL, 0, NULL, &next_idx, &state,
686362306a36Sopenharmony_ci					      &conn_err, NULL, NULL);
686462306a36Sopenharmony_ci		if (ret == QLA_ERROR)
686562306a36Sopenharmony_ci			continue;
686662306a36Sopenharmony_ci
686762306a36Sopenharmony_ci		if (state == DDB_DS_NO_CONNECTION_ACTIVE ||
686862306a36Sopenharmony_ci		    state == DDB_DS_SESSION_FAILED) {
686962306a36Sopenharmony_ci			list_del_init(&ddb_idx->list);
687062306a36Sopenharmony_ci			vfree(ddb_idx);
687162306a36Sopenharmony_ci		}
687262306a36Sopenharmony_ci	}
687362306a36Sopenharmony_ci}
687462306a36Sopenharmony_ci
687562306a36Sopenharmony_cistatic void qla4xxx_update_sess_disc_idx(struct scsi_qla_host *ha,
687662306a36Sopenharmony_ci					 struct ddb_entry *ddb_entry,
687762306a36Sopenharmony_ci					 struct dev_db_entry *fw_ddb_entry)
687862306a36Sopenharmony_ci{
687962306a36Sopenharmony_ci	struct iscsi_cls_session *cls_sess;
688062306a36Sopenharmony_ci	struct iscsi_session *sess;
688162306a36Sopenharmony_ci	uint32_t max_ddbs = 0;
688262306a36Sopenharmony_ci	uint16_t ddb_link = -1;
688362306a36Sopenharmony_ci
688462306a36Sopenharmony_ci	max_ddbs =  is_qla40XX(ha) ? MAX_DEV_DB_ENTRIES_40XX :
688562306a36Sopenharmony_ci				     MAX_DEV_DB_ENTRIES;
688662306a36Sopenharmony_ci
688762306a36Sopenharmony_ci	cls_sess = ddb_entry->sess;
688862306a36Sopenharmony_ci	sess = cls_sess->dd_data;
688962306a36Sopenharmony_ci
689062306a36Sopenharmony_ci	ddb_link = le16_to_cpu(fw_ddb_entry->ddb_link);
689162306a36Sopenharmony_ci	if (ddb_link < max_ddbs)
689262306a36Sopenharmony_ci		sess->discovery_parent_idx = ddb_link;
689362306a36Sopenharmony_ci	else
689462306a36Sopenharmony_ci		sess->discovery_parent_idx = DDB_NO_LINK;
689562306a36Sopenharmony_ci}
689662306a36Sopenharmony_ci
689762306a36Sopenharmony_cistatic int qla4xxx_sess_conn_setup(struct scsi_qla_host *ha,
689862306a36Sopenharmony_ci				   struct dev_db_entry *fw_ddb_entry,
689962306a36Sopenharmony_ci				   int is_reset, uint16_t idx)
690062306a36Sopenharmony_ci{
690162306a36Sopenharmony_ci	struct iscsi_cls_session *cls_sess;
690262306a36Sopenharmony_ci	struct iscsi_session *sess;
690362306a36Sopenharmony_ci	struct iscsi_cls_conn *cls_conn;
690462306a36Sopenharmony_ci	struct iscsi_endpoint *ep;
690562306a36Sopenharmony_ci	uint16_t cmds_max = 32;
690662306a36Sopenharmony_ci	uint16_t conn_id = 0;
690762306a36Sopenharmony_ci	uint32_t initial_cmdsn = 0;
690862306a36Sopenharmony_ci	int ret = QLA_SUCCESS;
690962306a36Sopenharmony_ci
691062306a36Sopenharmony_ci	struct ddb_entry *ddb_entry = NULL;
691162306a36Sopenharmony_ci
691262306a36Sopenharmony_ci	/* Create session object, with INVALID_ENTRY,
691362306a36Sopenharmony_ci	 * the targer_id would get set when we issue the login
691462306a36Sopenharmony_ci	 */
691562306a36Sopenharmony_ci	cls_sess = iscsi_session_setup(&qla4xxx_iscsi_transport, ha->host,
691662306a36Sopenharmony_ci				       cmds_max, sizeof(struct ddb_entry),
691762306a36Sopenharmony_ci				       sizeof(struct ql4_task_data),
691862306a36Sopenharmony_ci				       initial_cmdsn, INVALID_ENTRY);
691962306a36Sopenharmony_ci	if (!cls_sess) {
692062306a36Sopenharmony_ci		ret = QLA_ERROR;
692162306a36Sopenharmony_ci		goto exit_setup;
692262306a36Sopenharmony_ci	}
692362306a36Sopenharmony_ci
692462306a36Sopenharmony_ci	/*
692562306a36Sopenharmony_ci	 * so calling module_put function to decrement the
692662306a36Sopenharmony_ci	 * reference count.
692762306a36Sopenharmony_ci	 **/
692862306a36Sopenharmony_ci	module_put(qla4xxx_iscsi_transport.owner);
692962306a36Sopenharmony_ci	sess = cls_sess->dd_data;
693062306a36Sopenharmony_ci	ddb_entry = sess->dd_data;
693162306a36Sopenharmony_ci	ddb_entry->sess = cls_sess;
693262306a36Sopenharmony_ci
693362306a36Sopenharmony_ci	cls_sess->recovery_tmo = ql4xsess_recovery_tmo;
693462306a36Sopenharmony_ci	memcpy(&ddb_entry->fw_ddb_entry, fw_ddb_entry,
693562306a36Sopenharmony_ci	       sizeof(struct dev_db_entry));
693662306a36Sopenharmony_ci
693762306a36Sopenharmony_ci	qla4xxx_setup_flash_ddb_entry(ha, ddb_entry, idx);
693862306a36Sopenharmony_ci
693962306a36Sopenharmony_ci	cls_conn = iscsi_conn_setup(cls_sess, sizeof(struct qla_conn), conn_id);
694062306a36Sopenharmony_ci
694162306a36Sopenharmony_ci	if (!cls_conn) {
694262306a36Sopenharmony_ci		ret = QLA_ERROR;
694362306a36Sopenharmony_ci		goto exit_setup;
694462306a36Sopenharmony_ci	}
694562306a36Sopenharmony_ci
694662306a36Sopenharmony_ci	ddb_entry->conn = cls_conn;
694762306a36Sopenharmony_ci
694862306a36Sopenharmony_ci	/* Setup ep, for displaying attributes in sysfs */
694962306a36Sopenharmony_ci	ep = qla4xxx_get_ep_fwdb(ha, fw_ddb_entry);
695062306a36Sopenharmony_ci	if (ep) {
695162306a36Sopenharmony_ci		ep->conn = cls_conn;
695262306a36Sopenharmony_ci		cls_conn->ep = ep;
695362306a36Sopenharmony_ci	} else {
695462306a36Sopenharmony_ci		DEBUG2(ql4_printk(KERN_ERR, ha, "Unable to get ep\n"));
695562306a36Sopenharmony_ci		ret = QLA_ERROR;
695662306a36Sopenharmony_ci		goto exit_setup;
695762306a36Sopenharmony_ci	}
695862306a36Sopenharmony_ci
695962306a36Sopenharmony_ci	/* Update sess/conn params */
696062306a36Sopenharmony_ci	qla4xxx_copy_fwddb_param(ha, fw_ddb_entry, cls_sess, cls_conn);
696162306a36Sopenharmony_ci	qla4xxx_update_sess_disc_idx(ha, ddb_entry, fw_ddb_entry);
696262306a36Sopenharmony_ci
696362306a36Sopenharmony_ci	if (is_reset == RESET_ADAPTER) {
696462306a36Sopenharmony_ci		iscsi_block_session(cls_sess);
696562306a36Sopenharmony_ci		/* Use the relogin path to discover new devices
696662306a36Sopenharmony_ci		 *  by short-circuiting the logic of setting
696762306a36Sopenharmony_ci		 *  timer to relogin - instead set the flags
696862306a36Sopenharmony_ci		 *  to initiate login right away.
696962306a36Sopenharmony_ci		 */
697062306a36Sopenharmony_ci		set_bit(DPC_RELOGIN_DEVICE, &ha->dpc_flags);
697162306a36Sopenharmony_ci		set_bit(DF_RELOGIN, &ddb_entry->flags);
697262306a36Sopenharmony_ci	}
697362306a36Sopenharmony_ci
697462306a36Sopenharmony_ciexit_setup:
697562306a36Sopenharmony_ci	return ret;
697662306a36Sopenharmony_ci}
697762306a36Sopenharmony_ci
697862306a36Sopenharmony_cistatic void qla4xxx_update_fw_ddb_link(struct scsi_qla_host *ha,
697962306a36Sopenharmony_ci				       struct list_head *list_ddb,
698062306a36Sopenharmony_ci				       struct dev_db_entry *fw_ddb_entry)
698162306a36Sopenharmony_ci{
698262306a36Sopenharmony_ci	struct qla_ddb_index  *ddb_idx, *ddb_idx_tmp;
698362306a36Sopenharmony_ci	uint16_t ddb_link;
698462306a36Sopenharmony_ci
698562306a36Sopenharmony_ci	ddb_link = le16_to_cpu(fw_ddb_entry->ddb_link);
698662306a36Sopenharmony_ci
698762306a36Sopenharmony_ci	list_for_each_entry_safe(ddb_idx, ddb_idx_tmp, list_ddb, list) {
698862306a36Sopenharmony_ci		if (ddb_idx->fw_ddb_idx == ddb_link) {
698962306a36Sopenharmony_ci			DEBUG2(ql4_printk(KERN_INFO, ha,
699062306a36Sopenharmony_ci					  "Updating NT parent idx from [%d] to [%d]\n",
699162306a36Sopenharmony_ci					  ddb_link, ddb_idx->flash_ddb_idx));
699262306a36Sopenharmony_ci			fw_ddb_entry->ddb_link =
699362306a36Sopenharmony_ci					    cpu_to_le16(ddb_idx->flash_ddb_idx);
699462306a36Sopenharmony_ci			return;
699562306a36Sopenharmony_ci		}
699662306a36Sopenharmony_ci	}
699762306a36Sopenharmony_ci}
699862306a36Sopenharmony_ci
699962306a36Sopenharmony_cistatic void qla4xxx_build_nt_list(struct scsi_qla_host *ha,
700062306a36Sopenharmony_ci				  struct list_head *list_nt,
700162306a36Sopenharmony_ci				  struct list_head *list_st,
700262306a36Sopenharmony_ci				  int is_reset)
700362306a36Sopenharmony_ci{
700462306a36Sopenharmony_ci	struct dev_db_entry *fw_ddb_entry;
700562306a36Sopenharmony_ci	struct ddb_entry *ddb_entry = NULL;
700662306a36Sopenharmony_ci	dma_addr_t fw_ddb_dma;
700762306a36Sopenharmony_ci	int max_ddbs;
700862306a36Sopenharmony_ci	int fw_idx_size;
700962306a36Sopenharmony_ci	int ret;
701062306a36Sopenharmony_ci	uint32_t idx = 0, next_idx = 0;
701162306a36Sopenharmony_ci	uint32_t state = 0, conn_err = 0;
701262306a36Sopenharmony_ci	uint32_t ddb_idx = -1;
701362306a36Sopenharmony_ci	uint16_t conn_id = 0;
701462306a36Sopenharmony_ci	uint16_t ddb_link = -1;
701562306a36Sopenharmony_ci	struct qla_ddb_index  *nt_ddb_idx;
701662306a36Sopenharmony_ci
701762306a36Sopenharmony_ci	fw_ddb_entry = dma_pool_alloc(ha->fw_ddb_dma_pool, GFP_KERNEL,
701862306a36Sopenharmony_ci				      &fw_ddb_dma);
701962306a36Sopenharmony_ci	if (fw_ddb_entry == NULL) {
702062306a36Sopenharmony_ci		DEBUG2(ql4_printk(KERN_ERR, ha, "Out of memory\n"));
702162306a36Sopenharmony_ci		goto exit_nt_list;
702262306a36Sopenharmony_ci	}
702362306a36Sopenharmony_ci	max_ddbs =  is_qla40XX(ha) ? MAX_DEV_DB_ENTRIES_40XX :
702462306a36Sopenharmony_ci				     MAX_DEV_DB_ENTRIES;
702562306a36Sopenharmony_ci	fw_idx_size = sizeof(struct qla_ddb_index);
702662306a36Sopenharmony_ci
702762306a36Sopenharmony_ci	for (idx = 0; idx < max_ddbs; idx = next_idx) {
702862306a36Sopenharmony_ci		ret = qla4xxx_get_fwddb_entry(ha, idx, fw_ddb_entry, fw_ddb_dma,
702962306a36Sopenharmony_ci					      NULL, &next_idx, &state,
703062306a36Sopenharmony_ci					      &conn_err, NULL, &conn_id);
703162306a36Sopenharmony_ci		if (ret == QLA_ERROR)
703262306a36Sopenharmony_ci			break;
703362306a36Sopenharmony_ci
703462306a36Sopenharmony_ci		if (qla4xxx_verify_boot_idx(ha, idx) != QLA_SUCCESS)
703562306a36Sopenharmony_ci			goto continue_next_nt;
703662306a36Sopenharmony_ci
703762306a36Sopenharmony_ci		/* Check if NT, then add to list it */
703862306a36Sopenharmony_ci		if (strlen((char *) fw_ddb_entry->iscsi_name) == 0)
703962306a36Sopenharmony_ci			goto continue_next_nt;
704062306a36Sopenharmony_ci
704162306a36Sopenharmony_ci		ddb_link = le16_to_cpu(fw_ddb_entry->ddb_link);
704262306a36Sopenharmony_ci		if (ddb_link < max_ddbs)
704362306a36Sopenharmony_ci			qla4xxx_update_fw_ddb_link(ha, list_st, fw_ddb_entry);
704462306a36Sopenharmony_ci
704562306a36Sopenharmony_ci		if (!(state == DDB_DS_NO_CONNECTION_ACTIVE ||
704662306a36Sopenharmony_ci		    state == DDB_DS_SESSION_FAILED) &&
704762306a36Sopenharmony_ci		    (is_reset == INIT_ADAPTER))
704862306a36Sopenharmony_ci			goto continue_next_nt;
704962306a36Sopenharmony_ci
705062306a36Sopenharmony_ci		DEBUG2(ql4_printk(KERN_INFO, ha,
705162306a36Sopenharmony_ci				  "Adding  DDB to session = 0x%x\n", idx));
705262306a36Sopenharmony_ci
705362306a36Sopenharmony_ci		if (is_reset == INIT_ADAPTER) {
705462306a36Sopenharmony_ci			nt_ddb_idx = vmalloc(fw_idx_size);
705562306a36Sopenharmony_ci			if (!nt_ddb_idx)
705662306a36Sopenharmony_ci				break;
705762306a36Sopenharmony_ci
705862306a36Sopenharmony_ci			nt_ddb_idx->fw_ddb_idx = idx;
705962306a36Sopenharmony_ci
706062306a36Sopenharmony_ci			/* Copy original isid as it may get updated in function
706162306a36Sopenharmony_ci			 * qla4xxx_update_isid(). We need original isid in
706262306a36Sopenharmony_ci			 * function qla4xxx_compare_tuple_ddb to find duplicate
706362306a36Sopenharmony_ci			 * target */
706462306a36Sopenharmony_ci			memcpy(&nt_ddb_idx->flash_isid[0],
706562306a36Sopenharmony_ci			       &fw_ddb_entry->isid[0],
706662306a36Sopenharmony_ci			       sizeof(nt_ddb_idx->flash_isid));
706762306a36Sopenharmony_ci
706862306a36Sopenharmony_ci			ret = qla4xxx_is_flash_ddb_exists(ha, list_nt,
706962306a36Sopenharmony_ci							  fw_ddb_entry);
707062306a36Sopenharmony_ci			if (ret == QLA_SUCCESS) {
707162306a36Sopenharmony_ci				/* free nt_ddb_idx and do not add to list_nt */
707262306a36Sopenharmony_ci				vfree(nt_ddb_idx);
707362306a36Sopenharmony_ci				goto continue_next_nt;
707462306a36Sopenharmony_ci			}
707562306a36Sopenharmony_ci
707662306a36Sopenharmony_ci			/* Copy updated isid */
707762306a36Sopenharmony_ci			memcpy(&nt_ddb_idx->fw_ddb, fw_ddb_entry,
707862306a36Sopenharmony_ci			       sizeof(struct dev_db_entry));
707962306a36Sopenharmony_ci
708062306a36Sopenharmony_ci			list_add_tail(&nt_ddb_idx->list, list_nt);
708162306a36Sopenharmony_ci		} else if (is_reset == RESET_ADAPTER) {
708262306a36Sopenharmony_ci			ret = qla4xxx_is_session_exists(ha, fw_ddb_entry,
708362306a36Sopenharmony_ci							&ddb_idx);
708462306a36Sopenharmony_ci			if (ret == QLA_SUCCESS) {
708562306a36Sopenharmony_ci				ddb_entry = qla4xxx_lookup_ddb_by_fw_index(ha,
708662306a36Sopenharmony_ci								       ddb_idx);
708762306a36Sopenharmony_ci				if (ddb_entry != NULL)
708862306a36Sopenharmony_ci					qla4xxx_update_sess_disc_idx(ha,
708962306a36Sopenharmony_ci								     ddb_entry,
709062306a36Sopenharmony_ci								  fw_ddb_entry);
709162306a36Sopenharmony_ci				goto continue_next_nt;
709262306a36Sopenharmony_ci			}
709362306a36Sopenharmony_ci		}
709462306a36Sopenharmony_ci
709562306a36Sopenharmony_ci		ret = qla4xxx_sess_conn_setup(ha, fw_ddb_entry, is_reset, idx);
709662306a36Sopenharmony_ci		if (ret == QLA_ERROR)
709762306a36Sopenharmony_ci			goto exit_nt_list;
709862306a36Sopenharmony_ci
709962306a36Sopenharmony_cicontinue_next_nt:
710062306a36Sopenharmony_ci		if (next_idx == 0)
710162306a36Sopenharmony_ci			break;
710262306a36Sopenharmony_ci	}
710362306a36Sopenharmony_ci
710462306a36Sopenharmony_ciexit_nt_list:
710562306a36Sopenharmony_ci	if (fw_ddb_entry)
710662306a36Sopenharmony_ci		dma_pool_free(ha->fw_ddb_dma_pool, fw_ddb_entry, fw_ddb_dma);
710762306a36Sopenharmony_ci}
710862306a36Sopenharmony_ci
710962306a36Sopenharmony_cistatic void qla4xxx_build_new_nt_list(struct scsi_qla_host *ha,
711062306a36Sopenharmony_ci				      struct list_head *list_nt,
711162306a36Sopenharmony_ci				      uint16_t target_id)
711262306a36Sopenharmony_ci{
711362306a36Sopenharmony_ci	struct dev_db_entry *fw_ddb_entry;
711462306a36Sopenharmony_ci	dma_addr_t fw_ddb_dma;
711562306a36Sopenharmony_ci	int max_ddbs;
711662306a36Sopenharmony_ci	int fw_idx_size;
711762306a36Sopenharmony_ci	int ret;
711862306a36Sopenharmony_ci	uint32_t idx = 0, next_idx = 0;
711962306a36Sopenharmony_ci	uint32_t state = 0, conn_err = 0;
712062306a36Sopenharmony_ci	uint16_t conn_id = 0;
712162306a36Sopenharmony_ci	struct qla_ddb_index  *nt_ddb_idx;
712262306a36Sopenharmony_ci
712362306a36Sopenharmony_ci	fw_ddb_entry = dma_pool_alloc(ha->fw_ddb_dma_pool, GFP_KERNEL,
712462306a36Sopenharmony_ci				      &fw_ddb_dma);
712562306a36Sopenharmony_ci	if (fw_ddb_entry == NULL) {
712662306a36Sopenharmony_ci		DEBUG2(ql4_printk(KERN_ERR, ha, "Out of memory\n"));
712762306a36Sopenharmony_ci		goto exit_new_nt_list;
712862306a36Sopenharmony_ci	}
712962306a36Sopenharmony_ci	max_ddbs =  is_qla40XX(ha) ? MAX_DEV_DB_ENTRIES_40XX :
713062306a36Sopenharmony_ci				     MAX_DEV_DB_ENTRIES;
713162306a36Sopenharmony_ci	fw_idx_size = sizeof(struct qla_ddb_index);
713262306a36Sopenharmony_ci
713362306a36Sopenharmony_ci	for (idx = 0; idx < max_ddbs; idx = next_idx) {
713462306a36Sopenharmony_ci		ret = qla4xxx_get_fwddb_entry(ha, idx, fw_ddb_entry, fw_ddb_dma,
713562306a36Sopenharmony_ci					      NULL, &next_idx, &state,
713662306a36Sopenharmony_ci					      &conn_err, NULL, &conn_id);
713762306a36Sopenharmony_ci		if (ret == QLA_ERROR)
713862306a36Sopenharmony_ci			break;
713962306a36Sopenharmony_ci
714062306a36Sopenharmony_ci		/* Check if NT, then add it to list */
714162306a36Sopenharmony_ci		if (strlen((char *)fw_ddb_entry->iscsi_name) == 0)
714262306a36Sopenharmony_ci			goto continue_next_new_nt;
714362306a36Sopenharmony_ci
714462306a36Sopenharmony_ci		if (!(state == DDB_DS_NO_CONNECTION_ACTIVE))
714562306a36Sopenharmony_ci			goto continue_next_new_nt;
714662306a36Sopenharmony_ci
714762306a36Sopenharmony_ci		DEBUG2(ql4_printk(KERN_INFO, ha,
714862306a36Sopenharmony_ci				  "Adding  DDB to session = 0x%x\n", idx));
714962306a36Sopenharmony_ci
715062306a36Sopenharmony_ci		nt_ddb_idx = vmalloc(fw_idx_size);
715162306a36Sopenharmony_ci		if (!nt_ddb_idx)
715262306a36Sopenharmony_ci			break;
715362306a36Sopenharmony_ci
715462306a36Sopenharmony_ci		nt_ddb_idx->fw_ddb_idx = idx;
715562306a36Sopenharmony_ci
715662306a36Sopenharmony_ci		ret = qla4xxx_is_session_exists(ha, fw_ddb_entry, NULL);
715762306a36Sopenharmony_ci		if (ret == QLA_SUCCESS) {
715862306a36Sopenharmony_ci			/* free nt_ddb_idx and do not add to list_nt */
715962306a36Sopenharmony_ci			vfree(nt_ddb_idx);
716062306a36Sopenharmony_ci			goto continue_next_new_nt;
716162306a36Sopenharmony_ci		}
716262306a36Sopenharmony_ci
716362306a36Sopenharmony_ci		if (target_id < max_ddbs)
716462306a36Sopenharmony_ci			fw_ddb_entry->ddb_link = cpu_to_le16(target_id);
716562306a36Sopenharmony_ci
716662306a36Sopenharmony_ci		list_add_tail(&nt_ddb_idx->list, list_nt);
716762306a36Sopenharmony_ci
716862306a36Sopenharmony_ci		ret = qla4xxx_sess_conn_setup(ha, fw_ddb_entry, RESET_ADAPTER,
716962306a36Sopenharmony_ci					      idx);
717062306a36Sopenharmony_ci		if (ret == QLA_ERROR)
717162306a36Sopenharmony_ci			goto exit_new_nt_list;
717262306a36Sopenharmony_ci
717362306a36Sopenharmony_cicontinue_next_new_nt:
717462306a36Sopenharmony_ci		if (next_idx == 0)
717562306a36Sopenharmony_ci			break;
717662306a36Sopenharmony_ci	}
717762306a36Sopenharmony_ci
717862306a36Sopenharmony_ciexit_new_nt_list:
717962306a36Sopenharmony_ci	if (fw_ddb_entry)
718062306a36Sopenharmony_ci		dma_pool_free(ha->fw_ddb_dma_pool, fw_ddb_entry, fw_ddb_dma);
718162306a36Sopenharmony_ci}
718262306a36Sopenharmony_ci
718362306a36Sopenharmony_ci/**
718462306a36Sopenharmony_ci * qla4xxx_sysfs_ddb_is_non_persistent - check for non-persistence of ddb entry
718562306a36Sopenharmony_ci * @dev: dev associated with the sysfs entry
718662306a36Sopenharmony_ci * @data: pointer to flashnode session object
718762306a36Sopenharmony_ci *
718862306a36Sopenharmony_ci * Returns:
718962306a36Sopenharmony_ci *	1: if flashnode entry is non-persistent
719062306a36Sopenharmony_ci *	0: if flashnode entry is persistent
719162306a36Sopenharmony_ci **/
719262306a36Sopenharmony_cistatic int qla4xxx_sysfs_ddb_is_non_persistent(struct device *dev, void *data)
719362306a36Sopenharmony_ci{
719462306a36Sopenharmony_ci	struct iscsi_bus_flash_session *fnode_sess;
719562306a36Sopenharmony_ci
719662306a36Sopenharmony_ci	if (!iscsi_flashnode_bus_match(dev, NULL))
719762306a36Sopenharmony_ci		return 0;
719862306a36Sopenharmony_ci
719962306a36Sopenharmony_ci	fnode_sess = iscsi_dev_to_flash_session(dev);
720062306a36Sopenharmony_ci
720162306a36Sopenharmony_ci	return (fnode_sess->flash_state == DEV_DB_NON_PERSISTENT);
720262306a36Sopenharmony_ci}
720362306a36Sopenharmony_ci
720462306a36Sopenharmony_ci/**
720562306a36Sopenharmony_ci * qla4xxx_sysfs_ddb_tgt_create - Create sysfs entry for target
720662306a36Sopenharmony_ci * @ha: pointer to host
720762306a36Sopenharmony_ci * @fw_ddb_entry: flash ddb data
720862306a36Sopenharmony_ci * @idx: target index
720962306a36Sopenharmony_ci * @user: if set then this call is made from userland else from kernel
721062306a36Sopenharmony_ci *
721162306a36Sopenharmony_ci * Returns:
721262306a36Sopenharmony_ci * On sucess: QLA_SUCCESS
721362306a36Sopenharmony_ci * On failure: QLA_ERROR
721462306a36Sopenharmony_ci *
721562306a36Sopenharmony_ci * This create separate sysfs entries for session and connection attributes of
721662306a36Sopenharmony_ci * the given fw ddb entry.
721762306a36Sopenharmony_ci * If this is invoked as a result of a userspace call then the entry is marked
721862306a36Sopenharmony_ci * as nonpersistent using flash_state field.
721962306a36Sopenharmony_ci **/
722062306a36Sopenharmony_cistatic int qla4xxx_sysfs_ddb_tgt_create(struct scsi_qla_host *ha,
722162306a36Sopenharmony_ci					struct dev_db_entry *fw_ddb_entry,
722262306a36Sopenharmony_ci					uint16_t *idx, int user)
722362306a36Sopenharmony_ci{
722462306a36Sopenharmony_ci	struct iscsi_bus_flash_session *fnode_sess = NULL;
722562306a36Sopenharmony_ci	struct iscsi_bus_flash_conn *fnode_conn = NULL;
722662306a36Sopenharmony_ci	int rc = QLA_ERROR;
722762306a36Sopenharmony_ci
722862306a36Sopenharmony_ci	fnode_sess = iscsi_create_flashnode_sess(ha->host, *idx,
722962306a36Sopenharmony_ci						 &qla4xxx_iscsi_transport, 0);
723062306a36Sopenharmony_ci	if (!fnode_sess) {
723162306a36Sopenharmony_ci		ql4_printk(KERN_ERR, ha,
723262306a36Sopenharmony_ci			   "%s: Unable to create session sysfs entry for flashnode %d of host%lu\n",
723362306a36Sopenharmony_ci			   __func__, *idx, ha->host_no);
723462306a36Sopenharmony_ci		goto exit_tgt_create;
723562306a36Sopenharmony_ci	}
723662306a36Sopenharmony_ci
723762306a36Sopenharmony_ci	fnode_conn = iscsi_create_flashnode_conn(ha->host, fnode_sess,
723862306a36Sopenharmony_ci						 &qla4xxx_iscsi_transport, 0);
723962306a36Sopenharmony_ci	if (!fnode_conn) {
724062306a36Sopenharmony_ci		ql4_printk(KERN_ERR, ha,
724162306a36Sopenharmony_ci			   "%s: Unable to create conn sysfs entry for flashnode %d of host%lu\n",
724262306a36Sopenharmony_ci			   __func__, *idx, ha->host_no);
724362306a36Sopenharmony_ci		goto free_sess;
724462306a36Sopenharmony_ci	}
724562306a36Sopenharmony_ci
724662306a36Sopenharmony_ci	if (user) {
724762306a36Sopenharmony_ci		fnode_sess->flash_state = DEV_DB_NON_PERSISTENT;
724862306a36Sopenharmony_ci	} else {
724962306a36Sopenharmony_ci		fnode_sess->flash_state = DEV_DB_PERSISTENT;
725062306a36Sopenharmony_ci
725162306a36Sopenharmony_ci		if (*idx == ha->pri_ddb_idx || *idx == ha->sec_ddb_idx)
725262306a36Sopenharmony_ci			fnode_sess->is_boot_target = 1;
725362306a36Sopenharmony_ci		else
725462306a36Sopenharmony_ci			fnode_sess->is_boot_target = 0;
725562306a36Sopenharmony_ci	}
725662306a36Sopenharmony_ci
725762306a36Sopenharmony_ci	rc = qla4xxx_copy_from_fwddb_param(fnode_sess, fnode_conn,
725862306a36Sopenharmony_ci					   fw_ddb_entry);
725962306a36Sopenharmony_ci	if (rc)
726062306a36Sopenharmony_ci		goto free_sess;
726162306a36Sopenharmony_ci
726262306a36Sopenharmony_ci	ql4_printk(KERN_INFO, ha, "%s: sysfs entry %s created\n",
726362306a36Sopenharmony_ci		   __func__, fnode_sess->dev.kobj.name);
726462306a36Sopenharmony_ci
726562306a36Sopenharmony_ci	ql4_printk(KERN_INFO, ha, "%s: sysfs entry %s created\n",
726662306a36Sopenharmony_ci		   __func__, fnode_conn->dev.kobj.name);
726762306a36Sopenharmony_ci
726862306a36Sopenharmony_ci	return QLA_SUCCESS;
726962306a36Sopenharmony_ci
727062306a36Sopenharmony_cifree_sess:
727162306a36Sopenharmony_ci	iscsi_destroy_flashnode_sess(fnode_sess);
727262306a36Sopenharmony_ci
727362306a36Sopenharmony_ciexit_tgt_create:
727462306a36Sopenharmony_ci	return QLA_ERROR;
727562306a36Sopenharmony_ci}
727662306a36Sopenharmony_ci
727762306a36Sopenharmony_ci/**
727862306a36Sopenharmony_ci * qla4xxx_sysfs_ddb_add - Add new ddb entry in flash
727962306a36Sopenharmony_ci * @shost: pointer to host
728062306a36Sopenharmony_ci * @buf: type of ddb entry (ipv4/ipv6)
728162306a36Sopenharmony_ci * @len: length of buf
728262306a36Sopenharmony_ci *
728362306a36Sopenharmony_ci * This creates new ddb entry in the flash by finding first free index and
728462306a36Sopenharmony_ci * storing default ddb there. And then create sysfs entry for the new ddb entry.
728562306a36Sopenharmony_ci **/
728662306a36Sopenharmony_cistatic int qla4xxx_sysfs_ddb_add(struct Scsi_Host *shost, const char *buf,
728762306a36Sopenharmony_ci				 int len)
728862306a36Sopenharmony_ci{
728962306a36Sopenharmony_ci	struct scsi_qla_host *ha = to_qla_host(shost);
729062306a36Sopenharmony_ci	struct dev_db_entry *fw_ddb_entry = NULL;
729162306a36Sopenharmony_ci	dma_addr_t fw_ddb_entry_dma;
729262306a36Sopenharmony_ci	struct device *dev;
729362306a36Sopenharmony_ci	uint16_t idx = 0;
729462306a36Sopenharmony_ci	uint16_t max_ddbs = 0;
729562306a36Sopenharmony_ci	uint32_t options = 0;
729662306a36Sopenharmony_ci	uint32_t rval = QLA_ERROR;
729762306a36Sopenharmony_ci
729862306a36Sopenharmony_ci	if (strncasecmp(PORTAL_TYPE_IPV4, buf, 4) &&
729962306a36Sopenharmony_ci	    strncasecmp(PORTAL_TYPE_IPV6, buf, 4)) {
730062306a36Sopenharmony_ci		DEBUG2(ql4_printk(KERN_ERR, ha, "%s: Invalid portal type\n",
730162306a36Sopenharmony_ci				  __func__));
730262306a36Sopenharmony_ci		goto exit_ddb_add;
730362306a36Sopenharmony_ci	}
730462306a36Sopenharmony_ci
730562306a36Sopenharmony_ci	max_ddbs =  is_qla40XX(ha) ? MAX_PRST_DEV_DB_ENTRIES :
730662306a36Sopenharmony_ci				     MAX_DEV_DB_ENTRIES;
730762306a36Sopenharmony_ci
730862306a36Sopenharmony_ci	fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
730962306a36Sopenharmony_ci					  &fw_ddb_entry_dma, GFP_KERNEL);
731062306a36Sopenharmony_ci	if (!fw_ddb_entry) {
731162306a36Sopenharmony_ci		DEBUG2(ql4_printk(KERN_ERR, ha,
731262306a36Sopenharmony_ci				  "%s: Unable to allocate dma buffer\n",
731362306a36Sopenharmony_ci				  __func__));
731462306a36Sopenharmony_ci		goto exit_ddb_add;
731562306a36Sopenharmony_ci	}
731662306a36Sopenharmony_ci
731762306a36Sopenharmony_ci	dev = iscsi_find_flashnode_sess(ha->host, NULL,
731862306a36Sopenharmony_ci					qla4xxx_sysfs_ddb_is_non_persistent);
731962306a36Sopenharmony_ci	if (dev) {
732062306a36Sopenharmony_ci		ql4_printk(KERN_ERR, ha,
732162306a36Sopenharmony_ci			   "%s: A non-persistent entry %s found\n",
732262306a36Sopenharmony_ci			   __func__, dev->kobj.name);
732362306a36Sopenharmony_ci		put_device(dev);
732462306a36Sopenharmony_ci		goto exit_ddb_add;
732562306a36Sopenharmony_ci	}
732662306a36Sopenharmony_ci
732762306a36Sopenharmony_ci	/* Index 0 and 1 are reserved for boot target entries */
732862306a36Sopenharmony_ci	for (idx = 2; idx < max_ddbs; idx++) {
732962306a36Sopenharmony_ci		if (qla4xxx_flashdb_by_index(ha, fw_ddb_entry,
733062306a36Sopenharmony_ci					     fw_ddb_entry_dma, idx))
733162306a36Sopenharmony_ci			break;
733262306a36Sopenharmony_ci	}
733362306a36Sopenharmony_ci
733462306a36Sopenharmony_ci	if (idx == max_ddbs)
733562306a36Sopenharmony_ci		goto exit_ddb_add;
733662306a36Sopenharmony_ci
733762306a36Sopenharmony_ci	if (!strncasecmp("ipv6", buf, 4))
733862306a36Sopenharmony_ci		options |= IPV6_DEFAULT_DDB_ENTRY;
733962306a36Sopenharmony_ci
734062306a36Sopenharmony_ci	rval = qla4xxx_get_default_ddb(ha, options, fw_ddb_entry_dma);
734162306a36Sopenharmony_ci	if (rval == QLA_ERROR)
734262306a36Sopenharmony_ci		goto exit_ddb_add;
734362306a36Sopenharmony_ci
734462306a36Sopenharmony_ci	rval = qla4xxx_sysfs_ddb_tgt_create(ha, fw_ddb_entry, &idx, 1);
734562306a36Sopenharmony_ci
734662306a36Sopenharmony_ciexit_ddb_add:
734762306a36Sopenharmony_ci	if (fw_ddb_entry)
734862306a36Sopenharmony_ci		dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
734962306a36Sopenharmony_ci				  fw_ddb_entry, fw_ddb_entry_dma);
735062306a36Sopenharmony_ci	if (rval == QLA_SUCCESS)
735162306a36Sopenharmony_ci		return idx;
735262306a36Sopenharmony_ci	else
735362306a36Sopenharmony_ci		return -EIO;
735462306a36Sopenharmony_ci}
735562306a36Sopenharmony_ci
735662306a36Sopenharmony_ci/**
735762306a36Sopenharmony_ci * qla4xxx_sysfs_ddb_apply - write the target ddb contents to Flash
735862306a36Sopenharmony_ci * @fnode_sess: pointer to session attrs of flash ddb entry
735962306a36Sopenharmony_ci * @fnode_conn: pointer to connection attrs of flash ddb entry
736062306a36Sopenharmony_ci *
736162306a36Sopenharmony_ci * This writes the contents of target ddb buffer to Flash with a valid cookie
736262306a36Sopenharmony_ci * value in order to make the ddb entry persistent.
736362306a36Sopenharmony_ci **/
736462306a36Sopenharmony_cistatic int  qla4xxx_sysfs_ddb_apply(struct iscsi_bus_flash_session *fnode_sess,
736562306a36Sopenharmony_ci				    struct iscsi_bus_flash_conn *fnode_conn)
736662306a36Sopenharmony_ci{
736762306a36Sopenharmony_ci	struct Scsi_Host *shost = iscsi_flash_session_to_shost(fnode_sess);
736862306a36Sopenharmony_ci	struct scsi_qla_host *ha = to_qla_host(shost);
736962306a36Sopenharmony_ci	uint32_t dev_db_start_offset = FLASH_OFFSET_DB_INFO;
737062306a36Sopenharmony_ci	struct dev_db_entry *fw_ddb_entry = NULL;
737162306a36Sopenharmony_ci	dma_addr_t fw_ddb_entry_dma;
737262306a36Sopenharmony_ci	uint32_t options = 0;
737362306a36Sopenharmony_ci	int rval = 0;
737462306a36Sopenharmony_ci
737562306a36Sopenharmony_ci	fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
737662306a36Sopenharmony_ci					  &fw_ddb_entry_dma, GFP_KERNEL);
737762306a36Sopenharmony_ci	if (!fw_ddb_entry) {
737862306a36Sopenharmony_ci		DEBUG2(ql4_printk(KERN_ERR, ha,
737962306a36Sopenharmony_ci				  "%s: Unable to allocate dma buffer\n",
738062306a36Sopenharmony_ci				  __func__));
738162306a36Sopenharmony_ci		rval = -ENOMEM;
738262306a36Sopenharmony_ci		goto exit_ddb_apply;
738362306a36Sopenharmony_ci	}
738462306a36Sopenharmony_ci
738562306a36Sopenharmony_ci	if (!strncasecmp(fnode_sess->portal_type, PORTAL_TYPE_IPV6, 4))
738662306a36Sopenharmony_ci		options |= IPV6_DEFAULT_DDB_ENTRY;
738762306a36Sopenharmony_ci
738862306a36Sopenharmony_ci	rval = qla4xxx_get_default_ddb(ha, options, fw_ddb_entry_dma);
738962306a36Sopenharmony_ci	if (rval == QLA_ERROR)
739062306a36Sopenharmony_ci		goto exit_ddb_apply;
739162306a36Sopenharmony_ci
739262306a36Sopenharmony_ci	dev_db_start_offset += (fnode_sess->target_id *
739362306a36Sopenharmony_ci				sizeof(*fw_ddb_entry));
739462306a36Sopenharmony_ci
739562306a36Sopenharmony_ci	qla4xxx_copy_to_fwddb_param(fnode_sess, fnode_conn, fw_ddb_entry);
739662306a36Sopenharmony_ci	fw_ddb_entry->cookie = DDB_VALID_COOKIE;
739762306a36Sopenharmony_ci
739862306a36Sopenharmony_ci	rval = qla4xxx_set_flash(ha, fw_ddb_entry_dma, dev_db_start_offset,
739962306a36Sopenharmony_ci				 sizeof(*fw_ddb_entry), FLASH_OPT_RMW_COMMIT);
740062306a36Sopenharmony_ci
740162306a36Sopenharmony_ci	if (rval == QLA_SUCCESS) {
740262306a36Sopenharmony_ci		fnode_sess->flash_state = DEV_DB_PERSISTENT;
740362306a36Sopenharmony_ci		ql4_printk(KERN_INFO, ha,
740462306a36Sopenharmony_ci			   "%s: flash node %u of host %lu written to flash\n",
740562306a36Sopenharmony_ci			   __func__, fnode_sess->target_id, ha->host_no);
740662306a36Sopenharmony_ci	} else {
740762306a36Sopenharmony_ci		rval = -EIO;
740862306a36Sopenharmony_ci		ql4_printk(KERN_ERR, ha,
740962306a36Sopenharmony_ci			   "%s: Error while writing flash node %u of host %lu to flash\n",
741062306a36Sopenharmony_ci			   __func__, fnode_sess->target_id, ha->host_no);
741162306a36Sopenharmony_ci	}
741262306a36Sopenharmony_ci
741362306a36Sopenharmony_ciexit_ddb_apply:
741462306a36Sopenharmony_ci	if (fw_ddb_entry)
741562306a36Sopenharmony_ci		dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
741662306a36Sopenharmony_ci				  fw_ddb_entry, fw_ddb_entry_dma);
741762306a36Sopenharmony_ci	return rval;
741862306a36Sopenharmony_ci}
741962306a36Sopenharmony_ci
742062306a36Sopenharmony_cistatic ssize_t qla4xxx_sysfs_ddb_conn_open(struct scsi_qla_host *ha,
742162306a36Sopenharmony_ci					   struct dev_db_entry *fw_ddb_entry,
742262306a36Sopenharmony_ci					   uint16_t idx)
742362306a36Sopenharmony_ci{
742462306a36Sopenharmony_ci	struct dev_db_entry *ddb_entry = NULL;
742562306a36Sopenharmony_ci	dma_addr_t ddb_entry_dma;
742662306a36Sopenharmony_ci	unsigned long wtime;
742762306a36Sopenharmony_ci	uint32_t mbx_sts = 0;
742862306a36Sopenharmony_ci	uint32_t state = 0, conn_err = 0;
742962306a36Sopenharmony_ci	uint16_t tmo = 0;
743062306a36Sopenharmony_ci	int ret = 0;
743162306a36Sopenharmony_ci
743262306a36Sopenharmony_ci	ddb_entry = dma_alloc_coherent(&ha->pdev->dev, sizeof(*ddb_entry),
743362306a36Sopenharmony_ci				       &ddb_entry_dma, GFP_KERNEL);
743462306a36Sopenharmony_ci	if (!ddb_entry) {
743562306a36Sopenharmony_ci		DEBUG2(ql4_printk(KERN_ERR, ha,
743662306a36Sopenharmony_ci				  "%s: Unable to allocate dma buffer\n",
743762306a36Sopenharmony_ci				  __func__));
743862306a36Sopenharmony_ci		return QLA_ERROR;
743962306a36Sopenharmony_ci	}
744062306a36Sopenharmony_ci
744162306a36Sopenharmony_ci	memcpy(ddb_entry, fw_ddb_entry, sizeof(*ddb_entry));
744262306a36Sopenharmony_ci
744362306a36Sopenharmony_ci	ret = qla4xxx_set_ddb_entry(ha, idx, ddb_entry_dma, &mbx_sts);
744462306a36Sopenharmony_ci	if (ret != QLA_SUCCESS) {
744562306a36Sopenharmony_ci		DEBUG2(ql4_printk(KERN_ERR, ha,
744662306a36Sopenharmony_ci				  "%s: Unable to set ddb entry for index %d\n",
744762306a36Sopenharmony_ci				  __func__, idx));
744862306a36Sopenharmony_ci		goto exit_ddb_conn_open;
744962306a36Sopenharmony_ci	}
745062306a36Sopenharmony_ci
745162306a36Sopenharmony_ci	qla4xxx_conn_open(ha, idx);
745262306a36Sopenharmony_ci
745362306a36Sopenharmony_ci	/* To ensure that sendtargets is done, wait for at least 12 secs */
745462306a36Sopenharmony_ci	tmo = ((ha->def_timeout > LOGIN_TOV) &&
745562306a36Sopenharmony_ci	       (ha->def_timeout < LOGIN_TOV * 10) ?
745662306a36Sopenharmony_ci	       ha->def_timeout : LOGIN_TOV);
745762306a36Sopenharmony_ci
745862306a36Sopenharmony_ci	DEBUG2(ql4_printk(KERN_INFO, ha,
745962306a36Sopenharmony_ci			  "Default time to wait for login to ddb %d\n", tmo));
746062306a36Sopenharmony_ci
746162306a36Sopenharmony_ci	wtime = jiffies + (HZ * tmo);
746262306a36Sopenharmony_ci	do {
746362306a36Sopenharmony_ci		ret = qla4xxx_get_fwddb_entry(ha, idx, NULL, 0, NULL,
746462306a36Sopenharmony_ci					      NULL, &state, &conn_err, NULL,
746562306a36Sopenharmony_ci					      NULL);
746662306a36Sopenharmony_ci		if (ret == QLA_ERROR)
746762306a36Sopenharmony_ci			continue;
746862306a36Sopenharmony_ci
746962306a36Sopenharmony_ci		if (state == DDB_DS_NO_CONNECTION_ACTIVE ||
747062306a36Sopenharmony_ci		    state == DDB_DS_SESSION_FAILED)
747162306a36Sopenharmony_ci			break;
747262306a36Sopenharmony_ci
747362306a36Sopenharmony_ci		schedule_timeout_uninterruptible(HZ / 10);
747462306a36Sopenharmony_ci	} while (time_after(wtime, jiffies));
747562306a36Sopenharmony_ci
747662306a36Sopenharmony_ciexit_ddb_conn_open:
747762306a36Sopenharmony_ci	if (ddb_entry)
747862306a36Sopenharmony_ci		dma_free_coherent(&ha->pdev->dev, sizeof(*ddb_entry),
747962306a36Sopenharmony_ci				  ddb_entry, ddb_entry_dma);
748062306a36Sopenharmony_ci	return ret;
748162306a36Sopenharmony_ci}
748262306a36Sopenharmony_ci
748362306a36Sopenharmony_cistatic int qla4xxx_ddb_login_st(struct scsi_qla_host *ha,
748462306a36Sopenharmony_ci				struct dev_db_entry *fw_ddb_entry,
748562306a36Sopenharmony_ci				uint16_t target_id)
748662306a36Sopenharmony_ci{
748762306a36Sopenharmony_ci	struct qla_ddb_index *ddb_idx, *ddb_idx_tmp;
748862306a36Sopenharmony_ci	struct list_head list_nt;
748962306a36Sopenharmony_ci	uint16_t ddb_index;
749062306a36Sopenharmony_ci	int ret = 0;
749162306a36Sopenharmony_ci
749262306a36Sopenharmony_ci	if (test_bit(AF_ST_DISCOVERY_IN_PROGRESS, &ha->flags)) {
749362306a36Sopenharmony_ci		ql4_printk(KERN_WARNING, ha,
749462306a36Sopenharmony_ci			   "%s: A discovery already in progress!\n", __func__);
749562306a36Sopenharmony_ci		return QLA_ERROR;
749662306a36Sopenharmony_ci	}
749762306a36Sopenharmony_ci
749862306a36Sopenharmony_ci	INIT_LIST_HEAD(&list_nt);
749962306a36Sopenharmony_ci
750062306a36Sopenharmony_ci	set_bit(AF_ST_DISCOVERY_IN_PROGRESS, &ha->flags);
750162306a36Sopenharmony_ci
750262306a36Sopenharmony_ci	ret = qla4xxx_get_ddb_index(ha, &ddb_index);
750362306a36Sopenharmony_ci	if (ret == QLA_ERROR)
750462306a36Sopenharmony_ci		goto exit_login_st_clr_bit;
750562306a36Sopenharmony_ci
750662306a36Sopenharmony_ci	ret = qla4xxx_sysfs_ddb_conn_open(ha, fw_ddb_entry, ddb_index);
750762306a36Sopenharmony_ci	if (ret == QLA_ERROR)
750862306a36Sopenharmony_ci		goto exit_login_st;
750962306a36Sopenharmony_ci
751062306a36Sopenharmony_ci	qla4xxx_build_new_nt_list(ha, &list_nt, target_id);
751162306a36Sopenharmony_ci
751262306a36Sopenharmony_ci	list_for_each_entry_safe(ddb_idx, ddb_idx_tmp, &list_nt, list) {
751362306a36Sopenharmony_ci		list_del_init(&ddb_idx->list);
751462306a36Sopenharmony_ci		qla4xxx_clear_ddb_entry(ha, ddb_idx->fw_ddb_idx);
751562306a36Sopenharmony_ci		vfree(ddb_idx);
751662306a36Sopenharmony_ci	}
751762306a36Sopenharmony_ci
751862306a36Sopenharmony_ciexit_login_st:
751962306a36Sopenharmony_ci	if (qla4xxx_clear_ddb_entry(ha, ddb_index) == QLA_ERROR) {
752062306a36Sopenharmony_ci		ql4_printk(KERN_ERR, ha,
752162306a36Sopenharmony_ci			   "Unable to clear DDB index = 0x%x\n", ddb_index);
752262306a36Sopenharmony_ci	}
752362306a36Sopenharmony_ci
752462306a36Sopenharmony_ci	clear_bit(ddb_index, ha->ddb_idx_map);
752562306a36Sopenharmony_ci
752662306a36Sopenharmony_ciexit_login_st_clr_bit:
752762306a36Sopenharmony_ci	clear_bit(AF_ST_DISCOVERY_IN_PROGRESS, &ha->flags);
752862306a36Sopenharmony_ci	return ret;
752962306a36Sopenharmony_ci}
753062306a36Sopenharmony_ci
753162306a36Sopenharmony_cistatic int qla4xxx_ddb_login_nt(struct scsi_qla_host *ha,
753262306a36Sopenharmony_ci				struct dev_db_entry *fw_ddb_entry,
753362306a36Sopenharmony_ci				uint16_t idx)
753462306a36Sopenharmony_ci{
753562306a36Sopenharmony_ci	int ret = QLA_ERROR;
753662306a36Sopenharmony_ci
753762306a36Sopenharmony_ci	ret = qla4xxx_is_session_exists(ha, fw_ddb_entry, NULL);
753862306a36Sopenharmony_ci	if (ret != QLA_SUCCESS)
753962306a36Sopenharmony_ci		ret = qla4xxx_sess_conn_setup(ha, fw_ddb_entry, RESET_ADAPTER,
754062306a36Sopenharmony_ci					      idx);
754162306a36Sopenharmony_ci	else
754262306a36Sopenharmony_ci		ret = -EPERM;
754362306a36Sopenharmony_ci
754462306a36Sopenharmony_ci	return ret;
754562306a36Sopenharmony_ci}
754662306a36Sopenharmony_ci
754762306a36Sopenharmony_ci/**
754862306a36Sopenharmony_ci * qla4xxx_sysfs_ddb_login - Login to the specified target
754962306a36Sopenharmony_ci * @fnode_sess: pointer to session attrs of flash ddb entry
755062306a36Sopenharmony_ci * @fnode_conn: pointer to connection attrs of flash ddb entry
755162306a36Sopenharmony_ci *
755262306a36Sopenharmony_ci * This logs in to the specified target
755362306a36Sopenharmony_ci **/
755462306a36Sopenharmony_cistatic int qla4xxx_sysfs_ddb_login(struct iscsi_bus_flash_session *fnode_sess,
755562306a36Sopenharmony_ci				   struct iscsi_bus_flash_conn *fnode_conn)
755662306a36Sopenharmony_ci{
755762306a36Sopenharmony_ci	struct Scsi_Host *shost = iscsi_flash_session_to_shost(fnode_sess);
755862306a36Sopenharmony_ci	struct scsi_qla_host *ha = to_qla_host(shost);
755962306a36Sopenharmony_ci	struct dev_db_entry *fw_ddb_entry = NULL;
756062306a36Sopenharmony_ci	dma_addr_t fw_ddb_entry_dma;
756162306a36Sopenharmony_ci	uint32_t options = 0;
756262306a36Sopenharmony_ci	int ret = 0;
756362306a36Sopenharmony_ci
756462306a36Sopenharmony_ci	if (fnode_sess->flash_state == DEV_DB_NON_PERSISTENT) {
756562306a36Sopenharmony_ci		ql4_printk(KERN_ERR, ha,
756662306a36Sopenharmony_ci			   "%s: Target info is not persistent\n", __func__);
756762306a36Sopenharmony_ci		ret = -EIO;
756862306a36Sopenharmony_ci		goto exit_ddb_login;
756962306a36Sopenharmony_ci	}
757062306a36Sopenharmony_ci
757162306a36Sopenharmony_ci	fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
757262306a36Sopenharmony_ci					  &fw_ddb_entry_dma, GFP_KERNEL);
757362306a36Sopenharmony_ci	if (!fw_ddb_entry) {
757462306a36Sopenharmony_ci		DEBUG2(ql4_printk(KERN_ERR, ha,
757562306a36Sopenharmony_ci				  "%s: Unable to allocate dma buffer\n",
757662306a36Sopenharmony_ci				  __func__));
757762306a36Sopenharmony_ci		ret = -ENOMEM;
757862306a36Sopenharmony_ci		goto exit_ddb_login;
757962306a36Sopenharmony_ci	}
758062306a36Sopenharmony_ci
758162306a36Sopenharmony_ci	if (!strncasecmp(fnode_sess->portal_type, PORTAL_TYPE_IPV6, 4))
758262306a36Sopenharmony_ci		options |= IPV6_DEFAULT_DDB_ENTRY;
758362306a36Sopenharmony_ci
758462306a36Sopenharmony_ci	ret = qla4xxx_get_default_ddb(ha, options, fw_ddb_entry_dma);
758562306a36Sopenharmony_ci	if (ret == QLA_ERROR)
758662306a36Sopenharmony_ci		goto exit_ddb_login;
758762306a36Sopenharmony_ci
758862306a36Sopenharmony_ci	qla4xxx_copy_to_fwddb_param(fnode_sess, fnode_conn, fw_ddb_entry);
758962306a36Sopenharmony_ci	fw_ddb_entry->cookie = DDB_VALID_COOKIE;
759062306a36Sopenharmony_ci
759162306a36Sopenharmony_ci	if (strlen((char *)fw_ddb_entry->iscsi_name) == 0)
759262306a36Sopenharmony_ci		ret = qla4xxx_ddb_login_st(ha, fw_ddb_entry,
759362306a36Sopenharmony_ci					   fnode_sess->target_id);
759462306a36Sopenharmony_ci	else
759562306a36Sopenharmony_ci		ret = qla4xxx_ddb_login_nt(ha, fw_ddb_entry,
759662306a36Sopenharmony_ci					   fnode_sess->target_id);
759762306a36Sopenharmony_ci
759862306a36Sopenharmony_ci	if (ret > 0)
759962306a36Sopenharmony_ci		ret = -EIO;
760062306a36Sopenharmony_ci
760162306a36Sopenharmony_ciexit_ddb_login:
760262306a36Sopenharmony_ci	if (fw_ddb_entry)
760362306a36Sopenharmony_ci		dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
760462306a36Sopenharmony_ci				  fw_ddb_entry, fw_ddb_entry_dma);
760562306a36Sopenharmony_ci	return ret;
760662306a36Sopenharmony_ci}
760762306a36Sopenharmony_ci
760862306a36Sopenharmony_ci/**
760962306a36Sopenharmony_ci * qla4xxx_sysfs_ddb_logout_sid - Logout session for the specified target
761062306a36Sopenharmony_ci * @cls_sess: pointer to session to be logged out
761162306a36Sopenharmony_ci *
761262306a36Sopenharmony_ci * This performs session log out from the specified target
761362306a36Sopenharmony_ci **/
761462306a36Sopenharmony_cistatic int qla4xxx_sysfs_ddb_logout_sid(struct iscsi_cls_session *cls_sess)
761562306a36Sopenharmony_ci{
761662306a36Sopenharmony_ci	struct iscsi_session *sess;
761762306a36Sopenharmony_ci	struct ddb_entry *ddb_entry = NULL;
761862306a36Sopenharmony_ci	struct scsi_qla_host *ha;
761962306a36Sopenharmony_ci	struct dev_db_entry *fw_ddb_entry = NULL;
762062306a36Sopenharmony_ci	dma_addr_t fw_ddb_entry_dma;
762162306a36Sopenharmony_ci	unsigned long flags;
762262306a36Sopenharmony_ci	unsigned long wtime;
762362306a36Sopenharmony_ci	uint32_t ddb_state;
762462306a36Sopenharmony_ci	int options;
762562306a36Sopenharmony_ci	int ret = 0;
762662306a36Sopenharmony_ci
762762306a36Sopenharmony_ci	sess = cls_sess->dd_data;
762862306a36Sopenharmony_ci	ddb_entry = sess->dd_data;
762962306a36Sopenharmony_ci	ha = ddb_entry->ha;
763062306a36Sopenharmony_ci
763162306a36Sopenharmony_ci	if (ddb_entry->ddb_type != FLASH_DDB) {
763262306a36Sopenharmony_ci		ql4_printk(KERN_ERR, ha, "%s: Not a flash node session\n",
763362306a36Sopenharmony_ci			   __func__);
763462306a36Sopenharmony_ci		ret = -ENXIO;
763562306a36Sopenharmony_ci		goto exit_ddb_logout;
763662306a36Sopenharmony_ci	}
763762306a36Sopenharmony_ci
763862306a36Sopenharmony_ci	if (test_bit(DF_BOOT_TGT, &ddb_entry->flags)) {
763962306a36Sopenharmony_ci		ql4_printk(KERN_ERR, ha,
764062306a36Sopenharmony_ci			   "%s: Logout from boot target entry is not permitted.\n",
764162306a36Sopenharmony_ci			   __func__);
764262306a36Sopenharmony_ci		ret = -EPERM;
764362306a36Sopenharmony_ci		goto exit_ddb_logout;
764462306a36Sopenharmony_ci	}
764562306a36Sopenharmony_ci
764662306a36Sopenharmony_ci	fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
764762306a36Sopenharmony_ci					  &fw_ddb_entry_dma, GFP_KERNEL);
764862306a36Sopenharmony_ci	if (!fw_ddb_entry) {
764962306a36Sopenharmony_ci		ql4_printk(KERN_ERR, ha,
765062306a36Sopenharmony_ci			   "%s: Unable to allocate dma buffer\n", __func__);
765162306a36Sopenharmony_ci		ret = -ENOMEM;
765262306a36Sopenharmony_ci		goto exit_ddb_logout;
765362306a36Sopenharmony_ci	}
765462306a36Sopenharmony_ci
765562306a36Sopenharmony_ci	if (test_and_set_bit(DF_DISABLE_RELOGIN, &ddb_entry->flags))
765662306a36Sopenharmony_ci		goto ddb_logout_init;
765762306a36Sopenharmony_ci
765862306a36Sopenharmony_ci	ret = qla4xxx_get_fwddb_entry(ha, ddb_entry->fw_ddb_index,
765962306a36Sopenharmony_ci				      fw_ddb_entry, fw_ddb_entry_dma,
766062306a36Sopenharmony_ci				      NULL, NULL, &ddb_state, NULL,
766162306a36Sopenharmony_ci				      NULL, NULL);
766262306a36Sopenharmony_ci	if (ret == QLA_ERROR)
766362306a36Sopenharmony_ci		goto ddb_logout_init;
766462306a36Sopenharmony_ci
766562306a36Sopenharmony_ci	if (ddb_state == DDB_DS_SESSION_ACTIVE)
766662306a36Sopenharmony_ci		goto ddb_logout_init;
766762306a36Sopenharmony_ci
766862306a36Sopenharmony_ci	/* wait until next relogin is triggered using DF_RELOGIN and
766962306a36Sopenharmony_ci	 * clear DF_RELOGIN to avoid invocation of further relogin
767062306a36Sopenharmony_ci	 */
767162306a36Sopenharmony_ci	wtime = jiffies + (HZ * RELOGIN_TOV);
767262306a36Sopenharmony_ci	do {
767362306a36Sopenharmony_ci		if (test_and_clear_bit(DF_RELOGIN, &ddb_entry->flags))
767462306a36Sopenharmony_ci			goto ddb_logout_init;
767562306a36Sopenharmony_ci
767662306a36Sopenharmony_ci		schedule_timeout_uninterruptible(HZ);
767762306a36Sopenharmony_ci	} while ((time_after(wtime, jiffies)));
767862306a36Sopenharmony_ci
767962306a36Sopenharmony_ciddb_logout_init:
768062306a36Sopenharmony_ci	atomic_set(&ddb_entry->retry_relogin_timer, INVALID_ENTRY);
768162306a36Sopenharmony_ci	atomic_set(&ddb_entry->relogin_timer, 0);
768262306a36Sopenharmony_ci
768362306a36Sopenharmony_ci	options = LOGOUT_OPTION_CLOSE_SESSION;
768462306a36Sopenharmony_ci	qla4xxx_session_logout_ddb(ha, ddb_entry, options);
768562306a36Sopenharmony_ci
768662306a36Sopenharmony_ci	memset(fw_ddb_entry, 0, sizeof(*fw_ddb_entry));
768762306a36Sopenharmony_ci	wtime = jiffies + (HZ * LOGOUT_TOV);
768862306a36Sopenharmony_ci	do {
768962306a36Sopenharmony_ci		ret = qla4xxx_get_fwddb_entry(ha, ddb_entry->fw_ddb_index,
769062306a36Sopenharmony_ci					      fw_ddb_entry, fw_ddb_entry_dma,
769162306a36Sopenharmony_ci					      NULL, NULL, &ddb_state, NULL,
769262306a36Sopenharmony_ci					      NULL, NULL);
769362306a36Sopenharmony_ci		if (ret == QLA_ERROR)
769462306a36Sopenharmony_ci			goto ddb_logout_clr_sess;
769562306a36Sopenharmony_ci
769662306a36Sopenharmony_ci		if ((ddb_state == DDB_DS_NO_CONNECTION_ACTIVE) ||
769762306a36Sopenharmony_ci		    (ddb_state == DDB_DS_SESSION_FAILED))
769862306a36Sopenharmony_ci			goto ddb_logout_clr_sess;
769962306a36Sopenharmony_ci
770062306a36Sopenharmony_ci		schedule_timeout_uninterruptible(HZ);
770162306a36Sopenharmony_ci	} while ((time_after(wtime, jiffies)));
770262306a36Sopenharmony_ci
770362306a36Sopenharmony_ciddb_logout_clr_sess:
770462306a36Sopenharmony_ci	qla4xxx_clear_ddb_entry(ha, ddb_entry->fw_ddb_index);
770562306a36Sopenharmony_ci	/*
770662306a36Sopenharmony_ci	 * we have decremented the reference count of the driver
770762306a36Sopenharmony_ci	 * when we setup the session to have the driver unload
770862306a36Sopenharmony_ci	 * to be seamless without actually destroying the
770962306a36Sopenharmony_ci	 * session
771062306a36Sopenharmony_ci	 **/
771162306a36Sopenharmony_ci	try_module_get(qla4xxx_iscsi_transport.owner);
771262306a36Sopenharmony_ci	iscsi_destroy_endpoint(ddb_entry->conn->ep);
771362306a36Sopenharmony_ci
771462306a36Sopenharmony_ci	spin_lock_irqsave(&ha->hardware_lock, flags);
771562306a36Sopenharmony_ci	qla4xxx_free_ddb(ha, ddb_entry);
771662306a36Sopenharmony_ci	clear_bit(ddb_entry->fw_ddb_index, ha->ddb_idx_map);
771762306a36Sopenharmony_ci	spin_unlock_irqrestore(&ha->hardware_lock, flags);
771862306a36Sopenharmony_ci
771962306a36Sopenharmony_ci	iscsi_session_teardown(ddb_entry->sess);
772062306a36Sopenharmony_ci
772162306a36Sopenharmony_ci	clear_bit(DF_DISABLE_RELOGIN, &ddb_entry->flags);
772262306a36Sopenharmony_ci	ret = QLA_SUCCESS;
772362306a36Sopenharmony_ci
772462306a36Sopenharmony_ciexit_ddb_logout:
772562306a36Sopenharmony_ci	if (fw_ddb_entry)
772662306a36Sopenharmony_ci		dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
772762306a36Sopenharmony_ci				  fw_ddb_entry, fw_ddb_entry_dma);
772862306a36Sopenharmony_ci	return ret;
772962306a36Sopenharmony_ci}
773062306a36Sopenharmony_ci
773162306a36Sopenharmony_ci/**
773262306a36Sopenharmony_ci * qla4xxx_sysfs_ddb_logout - Logout from the specified target
773362306a36Sopenharmony_ci * @fnode_sess: pointer to session attrs of flash ddb entry
773462306a36Sopenharmony_ci * @fnode_conn: pointer to connection attrs of flash ddb entry
773562306a36Sopenharmony_ci *
773662306a36Sopenharmony_ci * This performs log out from the specified target
773762306a36Sopenharmony_ci **/
773862306a36Sopenharmony_cistatic int qla4xxx_sysfs_ddb_logout(struct iscsi_bus_flash_session *fnode_sess,
773962306a36Sopenharmony_ci				    struct iscsi_bus_flash_conn *fnode_conn)
774062306a36Sopenharmony_ci{
774162306a36Sopenharmony_ci	struct Scsi_Host *shost = iscsi_flash_session_to_shost(fnode_sess);
774262306a36Sopenharmony_ci	struct scsi_qla_host *ha = to_qla_host(shost);
774362306a36Sopenharmony_ci	struct ql4_tuple_ddb *flash_tddb = NULL;
774462306a36Sopenharmony_ci	struct ql4_tuple_ddb *tmp_tddb = NULL;
774562306a36Sopenharmony_ci	struct dev_db_entry *fw_ddb_entry = NULL;
774662306a36Sopenharmony_ci	struct ddb_entry *ddb_entry = NULL;
774762306a36Sopenharmony_ci	dma_addr_t fw_ddb_dma;
774862306a36Sopenharmony_ci	uint32_t next_idx = 0;
774962306a36Sopenharmony_ci	uint32_t state = 0, conn_err = 0;
775062306a36Sopenharmony_ci	uint16_t conn_id = 0;
775162306a36Sopenharmony_ci	int idx, index;
775262306a36Sopenharmony_ci	int status, ret = 0;
775362306a36Sopenharmony_ci
775462306a36Sopenharmony_ci	fw_ddb_entry = dma_pool_alloc(ha->fw_ddb_dma_pool, GFP_KERNEL,
775562306a36Sopenharmony_ci				      &fw_ddb_dma);
775662306a36Sopenharmony_ci	if (fw_ddb_entry == NULL) {
775762306a36Sopenharmony_ci		ql4_printk(KERN_ERR, ha, "%s:Out of memory\n", __func__);
775862306a36Sopenharmony_ci		ret = -ENOMEM;
775962306a36Sopenharmony_ci		goto exit_ddb_logout;
776062306a36Sopenharmony_ci	}
776162306a36Sopenharmony_ci
776262306a36Sopenharmony_ci	flash_tddb = vzalloc(sizeof(*flash_tddb));
776362306a36Sopenharmony_ci	if (!flash_tddb) {
776462306a36Sopenharmony_ci		ql4_printk(KERN_WARNING, ha,
776562306a36Sopenharmony_ci			   "%s:Memory Allocation failed.\n", __func__);
776662306a36Sopenharmony_ci		ret = -ENOMEM;
776762306a36Sopenharmony_ci		goto exit_ddb_logout;
776862306a36Sopenharmony_ci	}
776962306a36Sopenharmony_ci
777062306a36Sopenharmony_ci	tmp_tddb = vzalloc(sizeof(*tmp_tddb));
777162306a36Sopenharmony_ci	if (!tmp_tddb) {
777262306a36Sopenharmony_ci		ql4_printk(KERN_WARNING, ha,
777362306a36Sopenharmony_ci			   "%s:Memory Allocation failed.\n", __func__);
777462306a36Sopenharmony_ci		ret = -ENOMEM;
777562306a36Sopenharmony_ci		goto exit_ddb_logout;
777662306a36Sopenharmony_ci	}
777762306a36Sopenharmony_ci
777862306a36Sopenharmony_ci	if (!fnode_sess->targetname) {
777962306a36Sopenharmony_ci		ql4_printk(KERN_ERR, ha,
778062306a36Sopenharmony_ci			   "%s:Cannot logout from SendTarget entry\n",
778162306a36Sopenharmony_ci			   __func__);
778262306a36Sopenharmony_ci		ret = -EPERM;
778362306a36Sopenharmony_ci		goto exit_ddb_logout;
778462306a36Sopenharmony_ci	}
778562306a36Sopenharmony_ci
778662306a36Sopenharmony_ci	if (fnode_sess->is_boot_target) {
778762306a36Sopenharmony_ci		ql4_printk(KERN_ERR, ha,
778862306a36Sopenharmony_ci			   "%s: Logout from boot target entry is not permitted.\n",
778962306a36Sopenharmony_ci			   __func__);
779062306a36Sopenharmony_ci		ret = -EPERM;
779162306a36Sopenharmony_ci		goto exit_ddb_logout;
779262306a36Sopenharmony_ci	}
779362306a36Sopenharmony_ci
779462306a36Sopenharmony_ci	strscpy(flash_tddb->iscsi_name, fnode_sess->targetname,
779562306a36Sopenharmony_ci		ISCSI_NAME_SIZE);
779662306a36Sopenharmony_ci
779762306a36Sopenharmony_ci	if (!strncmp(fnode_sess->portal_type, PORTAL_TYPE_IPV6, 4))
779862306a36Sopenharmony_ci		sprintf(flash_tddb->ip_addr, "%pI6", fnode_conn->ipaddress);
779962306a36Sopenharmony_ci	else
780062306a36Sopenharmony_ci		sprintf(flash_tddb->ip_addr, "%pI4", fnode_conn->ipaddress);
780162306a36Sopenharmony_ci
780262306a36Sopenharmony_ci	flash_tddb->tpgt = fnode_sess->tpgt;
780362306a36Sopenharmony_ci	flash_tddb->port = fnode_conn->port;
780462306a36Sopenharmony_ci
780562306a36Sopenharmony_ci	COPY_ISID(flash_tddb->isid, fnode_sess->isid);
780662306a36Sopenharmony_ci
780762306a36Sopenharmony_ci	for (idx = 0; idx < MAX_DDB_ENTRIES; idx++) {
780862306a36Sopenharmony_ci		ddb_entry = qla4xxx_lookup_ddb_by_fw_index(ha, idx);
780962306a36Sopenharmony_ci		if (ddb_entry == NULL)
781062306a36Sopenharmony_ci			continue;
781162306a36Sopenharmony_ci
781262306a36Sopenharmony_ci		if (ddb_entry->ddb_type != FLASH_DDB)
781362306a36Sopenharmony_ci			continue;
781462306a36Sopenharmony_ci
781562306a36Sopenharmony_ci		index = ddb_entry->sess->target_id;
781662306a36Sopenharmony_ci		status = qla4xxx_get_fwddb_entry(ha, index, fw_ddb_entry,
781762306a36Sopenharmony_ci						 fw_ddb_dma, NULL, &next_idx,
781862306a36Sopenharmony_ci						 &state, &conn_err, NULL,
781962306a36Sopenharmony_ci						 &conn_id);
782062306a36Sopenharmony_ci		if (status == QLA_ERROR) {
782162306a36Sopenharmony_ci			ret = -ENOMEM;
782262306a36Sopenharmony_ci			break;
782362306a36Sopenharmony_ci		}
782462306a36Sopenharmony_ci
782562306a36Sopenharmony_ci		qla4xxx_convert_param_ddb(fw_ddb_entry, tmp_tddb, NULL);
782662306a36Sopenharmony_ci
782762306a36Sopenharmony_ci		status = qla4xxx_compare_tuple_ddb(ha, flash_tddb, tmp_tddb,
782862306a36Sopenharmony_ci						   true);
782962306a36Sopenharmony_ci		if (status == QLA_SUCCESS) {
783062306a36Sopenharmony_ci			ret = qla4xxx_sysfs_ddb_logout_sid(ddb_entry->sess);
783162306a36Sopenharmony_ci			break;
783262306a36Sopenharmony_ci		}
783362306a36Sopenharmony_ci	}
783462306a36Sopenharmony_ci
783562306a36Sopenharmony_ci	if (idx == MAX_DDB_ENTRIES)
783662306a36Sopenharmony_ci		ret = -ESRCH;
783762306a36Sopenharmony_ci
783862306a36Sopenharmony_ciexit_ddb_logout:
783962306a36Sopenharmony_ci	vfree(flash_tddb);
784062306a36Sopenharmony_ci	vfree(tmp_tddb);
784162306a36Sopenharmony_ci	if (fw_ddb_entry)
784262306a36Sopenharmony_ci		dma_pool_free(ha->fw_ddb_dma_pool, fw_ddb_entry, fw_ddb_dma);
784362306a36Sopenharmony_ci
784462306a36Sopenharmony_ci	return ret;
784562306a36Sopenharmony_ci}
784662306a36Sopenharmony_ci
784762306a36Sopenharmony_cistatic int
784862306a36Sopenharmony_ciqla4xxx_sysfs_ddb_get_param(struct iscsi_bus_flash_session *fnode_sess,
784962306a36Sopenharmony_ci			    int param, char *buf)
785062306a36Sopenharmony_ci{
785162306a36Sopenharmony_ci	struct Scsi_Host *shost = iscsi_flash_session_to_shost(fnode_sess);
785262306a36Sopenharmony_ci	struct scsi_qla_host *ha = to_qla_host(shost);
785362306a36Sopenharmony_ci	struct iscsi_bus_flash_conn *fnode_conn;
785462306a36Sopenharmony_ci	struct ql4_chap_table chap_tbl;
785562306a36Sopenharmony_ci	struct device *dev;
785662306a36Sopenharmony_ci	int parent_type;
785762306a36Sopenharmony_ci	int rc = 0;
785862306a36Sopenharmony_ci
785962306a36Sopenharmony_ci	dev = iscsi_find_flashnode_conn(fnode_sess);
786062306a36Sopenharmony_ci	if (!dev)
786162306a36Sopenharmony_ci		return -EIO;
786262306a36Sopenharmony_ci
786362306a36Sopenharmony_ci	fnode_conn = iscsi_dev_to_flash_conn(dev);
786462306a36Sopenharmony_ci
786562306a36Sopenharmony_ci	switch (param) {
786662306a36Sopenharmony_ci	case ISCSI_FLASHNODE_IS_FW_ASSIGNED_IPV6:
786762306a36Sopenharmony_ci		rc = sprintf(buf, "%u\n", fnode_conn->is_fw_assigned_ipv6);
786862306a36Sopenharmony_ci		break;
786962306a36Sopenharmony_ci	case ISCSI_FLASHNODE_PORTAL_TYPE:
787062306a36Sopenharmony_ci		rc = sprintf(buf, "%s\n", fnode_sess->portal_type);
787162306a36Sopenharmony_ci		break;
787262306a36Sopenharmony_ci	case ISCSI_FLASHNODE_AUTO_SND_TGT_DISABLE:
787362306a36Sopenharmony_ci		rc = sprintf(buf, "%u\n", fnode_sess->auto_snd_tgt_disable);
787462306a36Sopenharmony_ci		break;
787562306a36Sopenharmony_ci	case ISCSI_FLASHNODE_DISCOVERY_SESS:
787662306a36Sopenharmony_ci		rc = sprintf(buf, "%u\n", fnode_sess->discovery_sess);
787762306a36Sopenharmony_ci		break;
787862306a36Sopenharmony_ci	case ISCSI_FLASHNODE_ENTRY_EN:
787962306a36Sopenharmony_ci		rc = sprintf(buf, "%u\n", fnode_sess->entry_state);
788062306a36Sopenharmony_ci		break;
788162306a36Sopenharmony_ci	case ISCSI_FLASHNODE_HDR_DGST_EN:
788262306a36Sopenharmony_ci		rc = sprintf(buf, "%u\n", fnode_conn->hdrdgst_en);
788362306a36Sopenharmony_ci		break;
788462306a36Sopenharmony_ci	case ISCSI_FLASHNODE_DATA_DGST_EN:
788562306a36Sopenharmony_ci		rc = sprintf(buf, "%u\n", fnode_conn->datadgst_en);
788662306a36Sopenharmony_ci		break;
788762306a36Sopenharmony_ci	case ISCSI_FLASHNODE_IMM_DATA_EN:
788862306a36Sopenharmony_ci		rc = sprintf(buf, "%u\n", fnode_sess->imm_data_en);
788962306a36Sopenharmony_ci		break;
789062306a36Sopenharmony_ci	case ISCSI_FLASHNODE_INITIAL_R2T_EN:
789162306a36Sopenharmony_ci		rc = sprintf(buf, "%u\n", fnode_sess->initial_r2t_en);
789262306a36Sopenharmony_ci		break;
789362306a36Sopenharmony_ci	case ISCSI_FLASHNODE_DATASEQ_INORDER:
789462306a36Sopenharmony_ci		rc = sprintf(buf, "%u\n", fnode_sess->dataseq_inorder_en);
789562306a36Sopenharmony_ci		break;
789662306a36Sopenharmony_ci	case ISCSI_FLASHNODE_PDU_INORDER:
789762306a36Sopenharmony_ci		rc = sprintf(buf, "%u\n", fnode_sess->pdu_inorder_en);
789862306a36Sopenharmony_ci		break;
789962306a36Sopenharmony_ci	case ISCSI_FLASHNODE_CHAP_AUTH_EN:
790062306a36Sopenharmony_ci		rc = sprintf(buf, "%u\n", fnode_sess->chap_auth_en);
790162306a36Sopenharmony_ci		break;
790262306a36Sopenharmony_ci	case ISCSI_FLASHNODE_SNACK_REQ_EN:
790362306a36Sopenharmony_ci		rc = sprintf(buf, "%u\n", fnode_conn->snack_req_en);
790462306a36Sopenharmony_ci		break;
790562306a36Sopenharmony_ci	case ISCSI_FLASHNODE_DISCOVERY_LOGOUT_EN:
790662306a36Sopenharmony_ci		rc = sprintf(buf, "%u\n", fnode_sess->discovery_logout_en);
790762306a36Sopenharmony_ci		break;
790862306a36Sopenharmony_ci	case ISCSI_FLASHNODE_BIDI_CHAP_EN:
790962306a36Sopenharmony_ci		rc = sprintf(buf, "%u\n", fnode_sess->bidi_chap_en);
791062306a36Sopenharmony_ci		break;
791162306a36Sopenharmony_ci	case ISCSI_FLASHNODE_DISCOVERY_AUTH_OPTIONAL:
791262306a36Sopenharmony_ci		rc = sprintf(buf, "%u\n", fnode_sess->discovery_auth_optional);
791362306a36Sopenharmony_ci		break;
791462306a36Sopenharmony_ci	case ISCSI_FLASHNODE_ERL:
791562306a36Sopenharmony_ci		rc = sprintf(buf, "%u\n", fnode_sess->erl);
791662306a36Sopenharmony_ci		break;
791762306a36Sopenharmony_ci	case ISCSI_FLASHNODE_TCP_TIMESTAMP_STAT:
791862306a36Sopenharmony_ci		rc = sprintf(buf, "%u\n", fnode_conn->tcp_timestamp_stat);
791962306a36Sopenharmony_ci		break;
792062306a36Sopenharmony_ci	case ISCSI_FLASHNODE_TCP_NAGLE_DISABLE:
792162306a36Sopenharmony_ci		rc = sprintf(buf, "%u\n", fnode_conn->tcp_nagle_disable);
792262306a36Sopenharmony_ci		break;
792362306a36Sopenharmony_ci	case ISCSI_FLASHNODE_TCP_WSF_DISABLE:
792462306a36Sopenharmony_ci		rc = sprintf(buf, "%u\n", fnode_conn->tcp_wsf_disable);
792562306a36Sopenharmony_ci		break;
792662306a36Sopenharmony_ci	case ISCSI_FLASHNODE_TCP_TIMER_SCALE:
792762306a36Sopenharmony_ci		rc = sprintf(buf, "%u\n", fnode_conn->tcp_timer_scale);
792862306a36Sopenharmony_ci		break;
792962306a36Sopenharmony_ci	case ISCSI_FLASHNODE_TCP_TIMESTAMP_EN:
793062306a36Sopenharmony_ci		rc = sprintf(buf, "%u\n", fnode_conn->tcp_timestamp_en);
793162306a36Sopenharmony_ci		break;
793262306a36Sopenharmony_ci	case ISCSI_FLASHNODE_IP_FRAG_DISABLE:
793362306a36Sopenharmony_ci		rc = sprintf(buf, "%u\n", fnode_conn->fragment_disable);
793462306a36Sopenharmony_ci		break;
793562306a36Sopenharmony_ci	case ISCSI_FLASHNODE_MAX_RECV_DLENGTH:
793662306a36Sopenharmony_ci		rc = sprintf(buf, "%u\n", fnode_conn->max_recv_dlength);
793762306a36Sopenharmony_ci		break;
793862306a36Sopenharmony_ci	case ISCSI_FLASHNODE_MAX_XMIT_DLENGTH:
793962306a36Sopenharmony_ci		rc = sprintf(buf, "%u\n", fnode_conn->max_xmit_dlength);
794062306a36Sopenharmony_ci		break;
794162306a36Sopenharmony_ci	case ISCSI_FLASHNODE_FIRST_BURST:
794262306a36Sopenharmony_ci		rc = sprintf(buf, "%u\n", fnode_sess->first_burst);
794362306a36Sopenharmony_ci		break;
794462306a36Sopenharmony_ci	case ISCSI_FLASHNODE_DEF_TIME2WAIT:
794562306a36Sopenharmony_ci		rc = sprintf(buf, "%u\n", fnode_sess->time2wait);
794662306a36Sopenharmony_ci		break;
794762306a36Sopenharmony_ci	case ISCSI_FLASHNODE_DEF_TIME2RETAIN:
794862306a36Sopenharmony_ci		rc = sprintf(buf, "%u\n", fnode_sess->time2retain);
794962306a36Sopenharmony_ci		break;
795062306a36Sopenharmony_ci	case ISCSI_FLASHNODE_MAX_R2T:
795162306a36Sopenharmony_ci		rc = sprintf(buf, "%u\n", fnode_sess->max_r2t);
795262306a36Sopenharmony_ci		break;
795362306a36Sopenharmony_ci	case ISCSI_FLASHNODE_KEEPALIVE_TMO:
795462306a36Sopenharmony_ci		rc = sprintf(buf, "%u\n", fnode_conn->keepalive_timeout);
795562306a36Sopenharmony_ci		break;
795662306a36Sopenharmony_ci	case ISCSI_FLASHNODE_ISID:
795762306a36Sopenharmony_ci		rc = sprintf(buf, "%pm\n", fnode_sess->isid);
795862306a36Sopenharmony_ci		break;
795962306a36Sopenharmony_ci	case ISCSI_FLASHNODE_TSID:
796062306a36Sopenharmony_ci		rc = sprintf(buf, "%u\n", fnode_sess->tsid);
796162306a36Sopenharmony_ci		break;
796262306a36Sopenharmony_ci	case ISCSI_FLASHNODE_PORT:
796362306a36Sopenharmony_ci		rc = sprintf(buf, "%d\n", fnode_conn->port);
796462306a36Sopenharmony_ci		break;
796562306a36Sopenharmony_ci	case ISCSI_FLASHNODE_MAX_BURST:
796662306a36Sopenharmony_ci		rc = sprintf(buf, "%u\n", fnode_sess->max_burst);
796762306a36Sopenharmony_ci		break;
796862306a36Sopenharmony_ci	case ISCSI_FLASHNODE_DEF_TASKMGMT_TMO:
796962306a36Sopenharmony_ci		rc = sprintf(buf, "%u\n",
797062306a36Sopenharmony_ci			     fnode_sess->default_taskmgmt_timeout);
797162306a36Sopenharmony_ci		break;
797262306a36Sopenharmony_ci	case ISCSI_FLASHNODE_IPADDR:
797362306a36Sopenharmony_ci		if (!strncmp(fnode_sess->portal_type, PORTAL_TYPE_IPV6, 4))
797462306a36Sopenharmony_ci			rc = sprintf(buf, "%pI6\n", fnode_conn->ipaddress);
797562306a36Sopenharmony_ci		else
797662306a36Sopenharmony_ci			rc = sprintf(buf, "%pI4\n", fnode_conn->ipaddress);
797762306a36Sopenharmony_ci		break;
797862306a36Sopenharmony_ci	case ISCSI_FLASHNODE_ALIAS:
797962306a36Sopenharmony_ci		if (fnode_sess->targetalias)
798062306a36Sopenharmony_ci			rc = sprintf(buf, "%s\n", fnode_sess->targetalias);
798162306a36Sopenharmony_ci		else
798262306a36Sopenharmony_ci			rc = sprintf(buf, "\n");
798362306a36Sopenharmony_ci		break;
798462306a36Sopenharmony_ci	case ISCSI_FLASHNODE_REDIRECT_IPADDR:
798562306a36Sopenharmony_ci		if (!strncmp(fnode_sess->portal_type, PORTAL_TYPE_IPV6, 4))
798662306a36Sopenharmony_ci			rc = sprintf(buf, "%pI6\n",
798762306a36Sopenharmony_ci				     fnode_conn->redirect_ipaddr);
798862306a36Sopenharmony_ci		else
798962306a36Sopenharmony_ci			rc = sprintf(buf, "%pI4\n",
799062306a36Sopenharmony_ci				     fnode_conn->redirect_ipaddr);
799162306a36Sopenharmony_ci		break;
799262306a36Sopenharmony_ci	case ISCSI_FLASHNODE_MAX_SEGMENT_SIZE:
799362306a36Sopenharmony_ci		rc = sprintf(buf, "%u\n", fnode_conn->max_segment_size);
799462306a36Sopenharmony_ci		break;
799562306a36Sopenharmony_ci	case ISCSI_FLASHNODE_LOCAL_PORT:
799662306a36Sopenharmony_ci		rc = sprintf(buf, "%u\n", fnode_conn->local_port);
799762306a36Sopenharmony_ci		break;
799862306a36Sopenharmony_ci	case ISCSI_FLASHNODE_IPV4_TOS:
799962306a36Sopenharmony_ci		rc = sprintf(buf, "%u\n", fnode_conn->ipv4_tos);
800062306a36Sopenharmony_ci		break;
800162306a36Sopenharmony_ci	case ISCSI_FLASHNODE_IPV6_TC:
800262306a36Sopenharmony_ci		if (!strncmp(fnode_sess->portal_type, PORTAL_TYPE_IPV6, 4))
800362306a36Sopenharmony_ci			rc = sprintf(buf, "%u\n",
800462306a36Sopenharmony_ci				     fnode_conn->ipv6_traffic_class);
800562306a36Sopenharmony_ci		else
800662306a36Sopenharmony_ci			rc = sprintf(buf, "\n");
800762306a36Sopenharmony_ci		break;
800862306a36Sopenharmony_ci	case ISCSI_FLASHNODE_IPV6_FLOW_LABEL:
800962306a36Sopenharmony_ci		rc = sprintf(buf, "%u\n", fnode_conn->ipv6_flow_label);
801062306a36Sopenharmony_ci		break;
801162306a36Sopenharmony_ci	case ISCSI_FLASHNODE_LINK_LOCAL_IPV6:
801262306a36Sopenharmony_ci		if (!strncmp(fnode_sess->portal_type, PORTAL_TYPE_IPV6, 4))
801362306a36Sopenharmony_ci			rc = sprintf(buf, "%pI6\n",
801462306a36Sopenharmony_ci				     fnode_conn->link_local_ipv6_addr);
801562306a36Sopenharmony_ci		else
801662306a36Sopenharmony_ci			rc = sprintf(buf, "\n");
801762306a36Sopenharmony_ci		break;
801862306a36Sopenharmony_ci	case ISCSI_FLASHNODE_DISCOVERY_PARENT_IDX:
801962306a36Sopenharmony_ci		rc = sprintf(buf, "%u\n", fnode_sess->discovery_parent_idx);
802062306a36Sopenharmony_ci		break;
802162306a36Sopenharmony_ci	case ISCSI_FLASHNODE_DISCOVERY_PARENT_TYPE:
802262306a36Sopenharmony_ci		if (fnode_sess->discovery_parent_type == DDB_ISNS)
802362306a36Sopenharmony_ci			parent_type = ISCSI_DISC_PARENT_ISNS;
802462306a36Sopenharmony_ci		else if (fnode_sess->discovery_parent_type == DDB_NO_LINK)
802562306a36Sopenharmony_ci			parent_type = ISCSI_DISC_PARENT_UNKNOWN;
802662306a36Sopenharmony_ci		else if (fnode_sess->discovery_parent_type < MAX_DDB_ENTRIES)
802762306a36Sopenharmony_ci			parent_type = ISCSI_DISC_PARENT_SENDTGT;
802862306a36Sopenharmony_ci		else
802962306a36Sopenharmony_ci			parent_type = ISCSI_DISC_PARENT_UNKNOWN;
803062306a36Sopenharmony_ci
803162306a36Sopenharmony_ci		rc = sprintf(buf, "%s\n",
803262306a36Sopenharmony_ci			     iscsi_get_discovery_parent_name(parent_type));
803362306a36Sopenharmony_ci		break;
803462306a36Sopenharmony_ci	case ISCSI_FLASHNODE_NAME:
803562306a36Sopenharmony_ci		if (fnode_sess->targetname)
803662306a36Sopenharmony_ci			rc = sprintf(buf, "%s\n", fnode_sess->targetname);
803762306a36Sopenharmony_ci		else
803862306a36Sopenharmony_ci			rc = sprintf(buf, "\n");
803962306a36Sopenharmony_ci		break;
804062306a36Sopenharmony_ci	case ISCSI_FLASHNODE_TPGT:
804162306a36Sopenharmony_ci		rc = sprintf(buf, "%u\n", fnode_sess->tpgt);
804262306a36Sopenharmony_ci		break;
804362306a36Sopenharmony_ci	case ISCSI_FLASHNODE_TCP_XMIT_WSF:
804462306a36Sopenharmony_ci		rc = sprintf(buf, "%u\n", fnode_conn->tcp_xmit_wsf);
804562306a36Sopenharmony_ci		break;
804662306a36Sopenharmony_ci	case ISCSI_FLASHNODE_TCP_RECV_WSF:
804762306a36Sopenharmony_ci		rc = sprintf(buf, "%u\n", fnode_conn->tcp_recv_wsf);
804862306a36Sopenharmony_ci		break;
804962306a36Sopenharmony_ci	case ISCSI_FLASHNODE_CHAP_OUT_IDX:
805062306a36Sopenharmony_ci		rc = sprintf(buf, "%u\n", fnode_sess->chap_out_idx);
805162306a36Sopenharmony_ci		break;
805262306a36Sopenharmony_ci	case ISCSI_FLASHNODE_USERNAME:
805362306a36Sopenharmony_ci		if (fnode_sess->chap_auth_en) {
805462306a36Sopenharmony_ci			qla4xxx_get_uni_chap_at_index(ha,
805562306a36Sopenharmony_ci						      chap_tbl.name,
805662306a36Sopenharmony_ci						      chap_tbl.secret,
805762306a36Sopenharmony_ci						      fnode_sess->chap_out_idx);
805862306a36Sopenharmony_ci			rc = sprintf(buf, "%s\n", chap_tbl.name);
805962306a36Sopenharmony_ci		} else {
806062306a36Sopenharmony_ci			rc = sprintf(buf, "\n");
806162306a36Sopenharmony_ci		}
806262306a36Sopenharmony_ci		break;
806362306a36Sopenharmony_ci	case ISCSI_FLASHNODE_PASSWORD:
806462306a36Sopenharmony_ci		if (fnode_sess->chap_auth_en) {
806562306a36Sopenharmony_ci			qla4xxx_get_uni_chap_at_index(ha,
806662306a36Sopenharmony_ci						      chap_tbl.name,
806762306a36Sopenharmony_ci						      chap_tbl.secret,
806862306a36Sopenharmony_ci						      fnode_sess->chap_out_idx);
806962306a36Sopenharmony_ci			rc = sprintf(buf, "%s\n", chap_tbl.secret);
807062306a36Sopenharmony_ci		} else {
807162306a36Sopenharmony_ci			rc = sprintf(buf, "\n");
807262306a36Sopenharmony_ci		}
807362306a36Sopenharmony_ci		break;
807462306a36Sopenharmony_ci	case ISCSI_FLASHNODE_STATSN:
807562306a36Sopenharmony_ci		rc = sprintf(buf, "%u\n", fnode_conn->statsn);
807662306a36Sopenharmony_ci		break;
807762306a36Sopenharmony_ci	case ISCSI_FLASHNODE_EXP_STATSN:
807862306a36Sopenharmony_ci		rc = sprintf(buf, "%u\n", fnode_conn->exp_statsn);
807962306a36Sopenharmony_ci		break;
808062306a36Sopenharmony_ci	case ISCSI_FLASHNODE_IS_BOOT_TGT:
808162306a36Sopenharmony_ci		rc = sprintf(buf, "%u\n", fnode_sess->is_boot_target);
808262306a36Sopenharmony_ci		break;
808362306a36Sopenharmony_ci	default:
808462306a36Sopenharmony_ci		rc = -ENOSYS;
808562306a36Sopenharmony_ci		break;
808662306a36Sopenharmony_ci	}
808762306a36Sopenharmony_ci
808862306a36Sopenharmony_ci	put_device(dev);
808962306a36Sopenharmony_ci	return rc;
809062306a36Sopenharmony_ci}
809162306a36Sopenharmony_ci
809262306a36Sopenharmony_ci/**
809362306a36Sopenharmony_ci * qla4xxx_sysfs_ddb_set_param - Set parameter for firmware DDB entry
809462306a36Sopenharmony_ci * @fnode_sess: pointer to session attrs of flash ddb entry
809562306a36Sopenharmony_ci * @fnode_conn: pointer to connection attrs of flash ddb entry
809662306a36Sopenharmony_ci * @data: Parameters and their values to update
809762306a36Sopenharmony_ci * @len: len of data
809862306a36Sopenharmony_ci *
809962306a36Sopenharmony_ci * This sets the parameter of flash ddb entry and writes them to flash
810062306a36Sopenharmony_ci **/
810162306a36Sopenharmony_cistatic int
810262306a36Sopenharmony_ciqla4xxx_sysfs_ddb_set_param(struct iscsi_bus_flash_session *fnode_sess,
810362306a36Sopenharmony_ci			    struct iscsi_bus_flash_conn *fnode_conn,
810462306a36Sopenharmony_ci			    void *data, int len)
810562306a36Sopenharmony_ci{
810662306a36Sopenharmony_ci	struct Scsi_Host *shost = iscsi_flash_session_to_shost(fnode_sess);
810762306a36Sopenharmony_ci	struct scsi_qla_host *ha = to_qla_host(shost);
810862306a36Sopenharmony_ci	struct iscsi_flashnode_param_info *fnode_param;
810962306a36Sopenharmony_ci	struct ql4_chap_table chap_tbl;
811062306a36Sopenharmony_ci	struct nlattr *attr;
811162306a36Sopenharmony_ci	uint16_t chap_out_idx = INVALID_ENTRY;
811262306a36Sopenharmony_ci	int rc = QLA_ERROR;
811362306a36Sopenharmony_ci	uint32_t rem = len;
811462306a36Sopenharmony_ci
811562306a36Sopenharmony_ci	memset((void *)&chap_tbl, 0, sizeof(chap_tbl));
811662306a36Sopenharmony_ci	nla_for_each_attr(attr, data, len, rem) {
811762306a36Sopenharmony_ci		if (nla_len(attr) < sizeof(*fnode_param)) {
811862306a36Sopenharmony_ci			rc = -EINVAL;
811962306a36Sopenharmony_ci			goto exit_set_param;
812062306a36Sopenharmony_ci		}
812162306a36Sopenharmony_ci
812262306a36Sopenharmony_ci		fnode_param = nla_data(attr);
812362306a36Sopenharmony_ci
812462306a36Sopenharmony_ci		switch (fnode_param->param) {
812562306a36Sopenharmony_ci		case ISCSI_FLASHNODE_IS_FW_ASSIGNED_IPV6:
812662306a36Sopenharmony_ci			fnode_conn->is_fw_assigned_ipv6 = fnode_param->value[0];
812762306a36Sopenharmony_ci			break;
812862306a36Sopenharmony_ci		case ISCSI_FLASHNODE_PORTAL_TYPE:
812962306a36Sopenharmony_ci			memcpy(fnode_sess->portal_type, fnode_param->value,
813062306a36Sopenharmony_ci			       strlen(fnode_sess->portal_type));
813162306a36Sopenharmony_ci			break;
813262306a36Sopenharmony_ci		case ISCSI_FLASHNODE_AUTO_SND_TGT_DISABLE:
813362306a36Sopenharmony_ci			fnode_sess->auto_snd_tgt_disable =
813462306a36Sopenharmony_ci							fnode_param->value[0];
813562306a36Sopenharmony_ci			break;
813662306a36Sopenharmony_ci		case ISCSI_FLASHNODE_DISCOVERY_SESS:
813762306a36Sopenharmony_ci			fnode_sess->discovery_sess = fnode_param->value[0];
813862306a36Sopenharmony_ci			break;
813962306a36Sopenharmony_ci		case ISCSI_FLASHNODE_ENTRY_EN:
814062306a36Sopenharmony_ci			fnode_sess->entry_state = fnode_param->value[0];
814162306a36Sopenharmony_ci			break;
814262306a36Sopenharmony_ci		case ISCSI_FLASHNODE_HDR_DGST_EN:
814362306a36Sopenharmony_ci			fnode_conn->hdrdgst_en = fnode_param->value[0];
814462306a36Sopenharmony_ci			break;
814562306a36Sopenharmony_ci		case ISCSI_FLASHNODE_DATA_DGST_EN:
814662306a36Sopenharmony_ci			fnode_conn->datadgst_en = fnode_param->value[0];
814762306a36Sopenharmony_ci			break;
814862306a36Sopenharmony_ci		case ISCSI_FLASHNODE_IMM_DATA_EN:
814962306a36Sopenharmony_ci			fnode_sess->imm_data_en = fnode_param->value[0];
815062306a36Sopenharmony_ci			break;
815162306a36Sopenharmony_ci		case ISCSI_FLASHNODE_INITIAL_R2T_EN:
815262306a36Sopenharmony_ci			fnode_sess->initial_r2t_en = fnode_param->value[0];
815362306a36Sopenharmony_ci			break;
815462306a36Sopenharmony_ci		case ISCSI_FLASHNODE_DATASEQ_INORDER:
815562306a36Sopenharmony_ci			fnode_sess->dataseq_inorder_en = fnode_param->value[0];
815662306a36Sopenharmony_ci			break;
815762306a36Sopenharmony_ci		case ISCSI_FLASHNODE_PDU_INORDER:
815862306a36Sopenharmony_ci			fnode_sess->pdu_inorder_en = fnode_param->value[0];
815962306a36Sopenharmony_ci			break;
816062306a36Sopenharmony_ci		case ISCSI_FLASHNODE_CHAP_AUTH_EN:
816162306a36Sopenharmony_ci			fnode_sess->chap_auth_en = fnode_param->value[0];
816262306a36Sopenharmony_ci			/* Invalidate chap index if chap auth is disabled */
816362306a36Sopenharmony_ci			if (!fnode_sess->chap_auth_en)
816462306a36Sopenharmony_ci				fnode_sess->chap_out_idx = INVALID_ENTRY;
816562306a36Sopenharmony_ci
816662306a36Sopenharmony_ci			break;
816762306a36Sopenharmony_ci		case ISCSI_FLASHNODE_SNACK_REQ_EN:
816862306a36Sopenharmony_ci			fnode_conn->snack_req_en = fnode_param->value[0];
816962306a36Sopenharmony_ci			break;
817062306a36Sopenharmony_ci		case ISCSI_FLASHNODE_DISCOVERY_LOGOUT_EN:
817162306a36Sopenharmony_ci			fnode_sess->discovery_logout_en = fnode_param->value[0];
817262306a36Sopenharmony_ci			break;
817362306a36Sopenharmony_ci		case ISCSI_FLASHNODE_BIDI_CHAP_EN:
817462306a36Sopenharmony_ci			fnode_sess->bidi_chap_en = fnode_param->value[0];
817562306a36Sopenharmony_ci			break;
817662306a36Sopenharmony_ci		case ISCSI_FLASHNODE_DISCOVERY_AUTH_OPTIONAL:
817762306a36Sopenharmony_ci			fnode_sess->discovery_auth_optional =
817862306a36Sopenharmony_ci							fnode_param->value[0];
817962306a36Sopenharmony_ci			break;
818062306a36Sopenharmony_ci		case ISCSI_FLASHNODE_ERL:
818162306a36Sopenharmony_ci			fnode_sess->erl = fnode_param->value[0];
818262306a36Sopenharmony_ci			break;
818362306a36Sopenharmony_ci		case ISCSI_FLASHNODE_TCP_TIMESTAMP_STAT:
818462306a36Sopenharmony_ci			fnode_conn->tcp_timestamp_stat = fnode_param->value[0];
818562306a36Sopenharmony_ci			break;
818662306a36Sopenharmony_ci		case ISCSI_FLASHNODE_TCP_NAGLE_DISABLE:
818762306a36Sopenharmony_ci			fnode_conn->tcp_nagle_disable = fnode_param->value[0];
818862306a36Sopenharmony_ci			break;
818962306a36Sopenharmony_ci		case ISCSI_FLASHNODE_TCP_WSF_DISABLE:
819062306a36Sopenharmony_ci			fnode_conn->tcp_wsf_disable = fnode_param->value[0];
819162306a36Sopenharmony_ci			break;
819262306a36Sopenharmony_ci		case ISCSI_FLASHNODE_TCP_TIMER_SCALE:
819362306a36Sopenharmony_ci			fnode_conn->tcp_timer_scale = fnode_param->value[0];
819462306a36Sopenharmony_ci			break;
819562306a36Sopenharmony_ci		case ISCSI_FLASHNODE_TCP_TIMESTAMP_EN:
819662306a36Sopenharmony_ci			fnode_conn->tcp_timestamp_en = fnode_param->value[0];
819762306a36Sopenharmony_ci			break;
819862306a36Sopenharmony_ci		case ISCSI_FLASHNODE_IP_FRAG_DISABLE:
819962306a36Sopenharmony_ci			fnode_conn->fragment_disable = fnode_param->value[0];
820062306a36Sopenharmony_ci			break;
820162306a36Sopenharmony_ci		case ISCSI_FLASHNODE_MAX_RECV_DLENGTH:
820262306a36Sopenharmony_ci			fnode_conn->max_recv_dlength =
820362306a36Sopenharmony_ci					*(unsigned *)fnode_param->value;
820462306a36Sopenharmony_ci			break;
820562306a36Sopenharmony_ci		case ISCSI_FLASHNODE_MAX_XMIT_DLENGTH:
820662306a36Sopenharmony_ci			fnode_conn->max_xmit_dlength =
820762306a36Sopenharmony_ci					*(unsigned *)fnode_param->value;
820862306a36Sopenharmony_ci			break;
820962306a36Sopenharmony_ci		case ISCSI_FLASHNODE_FIRST_BURST:
821062306a36Sopenharmony_ci			fnode_sess->first_burst =
821162306a36Sopenharmony_ci					*(unsigned *)fnode_param->value;
821262306a36Sopenharmony_ci			break;
821362306a36Sopenharmony_ci		case ISCSI_FLASHNODE_DEF_TIME2WAIT:
821462306a36Sopenharmony_ci			fnode_sess->time2wait = *(uint16_t *)fnode_param->value;
821562306a36Sopenharmony_ci			break;
821662306a36Sopenharmony_ci		case ISCSI_FLASHNODE_DEF_TIME2RETAIN:
821762306a36Sopenharmony_ci			fnode_sess->time2retain =
821862306a36Sopenharmony_ci						*(uint16_t *)fnode_param->value;
821962306a36Sopenharmony_ci			break;
822062306a36Sopenharmony_ci		case ISCSI_FLASHNODE_MAX_R2T:
822162306a36Sopenharmony_ci			fnode_sess->max_r2t =
822262306a36Sopenharmony_ci					*(uint16_t *)fnode_param->value;
822362306a36Sopenharmony_ci			break;
822462306a36Sopenharmony_ci		case ISCSI_FLASHNODE_KEEPALIVE_TMO:
822562306a36Sopenharmony_ci			fnode_conn->keepalive_timeout =
822662306a36Sopenharmony_ci				*(uint16_t *)fnode_param->value;
822762306a36Sopenharmony_ci			break;
822862306a36Sopenharmony_ci		case ISCSI_FLASHNODE_ISID:
822962306a36Sopenharmony_ci			memcpy(fnode_sess->isid, fnode_param->value,
823062306a36Sopenharmony_ci			       sizeof(fnode_sess->isid));
823162306a36Sopenharmony_ci			break;
823262306a36Sopenharmony_ci		case ISCSI_FLASHNODE_TSID:
823362306a36Sopenharmony_ci			fnode_sess->tsid = *(uint16_t *)fnode_param->value;
823462306a36Sopenharmony_ci			break;
823562306a36Sopenharmony_ci		case ISCSI_FLASHNODE_PORT:
823662306a36Sopenharmony_ci			fnode_conn->port = *(uint16_t *)fnode_param->value;
823762306a36Sopenharmony_ci			break;
823862306a36Sopenharmony_ci		case ISCSI_FLASHNODE_MAX_BURST:
823962306a36Sopenharmony_ci			fnode_sess->max_burst = *(unsigned *)fnode_param->value;
824062306a36Sopenharmony_ci			break;
824162306a36Sopenharmony_ci		case ISCSI_FLASHNODE_DEF_TASKMGMT_TMO:
824262306a36Sopenharmony_ci			fnode_sess->default_taskmgmt_timeout =
824362306a36Sopenharmony_ci						*(uint16_t *)fnode_param->value;
824462306a36Sopenharmony_ci			break;
824562306a36Sopenharmony_ci		case ISCSI_FLASHNODE_IPADDR:
824662306a36Sopenharmony_ci			memcpy(fnode_conn->ipaddress, fnode_param->value,
824762306a36Sopenharmony_ci			       IPv6_ADDR_LEN);
824862306a36Sopenharmony_ci			break;
824962306a36Sopenharmony_ci		case ISCSI_FLASHNODE_ALIAS:
825062306a36Sopenharmony_ci			rc = iscsi_switch_str_param(&fnode_sess->targetalias,
825162306a36Sopenharmony_ci						    (char *)fnode_param->value);
825262306a36Sopenharmony_ci			break;
825362306a36Sopenharmony_ci		case ISCSI_FLASHNODE_REDIRECT_IPADDR:
825462306a36Sopenharmony_ci			memcpy(fnode_conn->redirect_ipaddr, fnode_param->value,
825562306a36Sopenharmony_ci			       IPv6_ADDR_LEN);
825662306a36Sopenharmony_ci			break;
825762306a36Sopenharmony_ci		case ISCSI_FLASHNODE_MAX_SEGMENT_SIZE:
825862306a36Sopenharmony_ci			fnode_conn->max_segment_size =
825962306a36Sopenharmony_ci					*(unsigned *)fnode_param->value;
826062306a36Sopenharmony_ci			break;
826162306a36Sopenharmony_ci		case ISCSI_FLASHNODE_LOCAL_PORT:
826262306a36Sopenharmony_ci			fnode_conn->local_port =
826362306a36Sopenharmony_ci						*(uint16_t *)fnode_param->value;
826462306a36Sopenharmony_ci			break;
826562306a36Sopenharmony_ci		case ISCSI_FLASHNODE_IPV4_TOS:
826662306a36Sopenharmony_ci			fnode_conn->ipv4_tos = fnode_param->value[0];
826762306a36Sopenharmony_ci			break;
826862306a36Sopenharmony_ci		case ISCSI_FLASHNODE_IPV6_TC:
826962306a36Sopenharmony_ci			fnode_conn->ipv6_traffic_class = fnode_param->value[0];
827062306a36Sopenharmony_ci			break;
827162306a36Sopenharmony_ci		case ISCSI_FLASHNODE_IPV6_FLOW_LABEL:
827262306a36Sopenharmony_ci			fnode_conn->ipv6_flow_label = fnode_param->value[0];
827362306a36Sopenharmony_ci			break;
827462306a36Sopenharmony_ci		case ISCSI_FLASHNODE_NAME:
827562306a36Sopenharmony_ci			rc = iscsi_switch_str_param(&fnode_sess->targetname,
827662306a36Sopenharmony_ci						    (char *)fnode_param->value);
827762306a36Sopenharmony_ci			break;
827862306a36Sopenharmony_ci		case ISCSI_FLASHNODE_TPGT:
827962306a36Sopenharmony_ci			fnode_sess->tpgt = *(uint16_t *)fnode_param->value;
828062306a36Sopenharmony_ci			break;
828162306a36Sopenharmony_ci		case ISCSI_FLASHNODE_LINK_LOCAL_IPV6:
828262306a36Sopenharmony_ci			memcpy(fnode_conn->link_local_ipv6_addr,
828362306a36Sopenharmony_ci			       fnode_param->value, IPv6_ADDR_LEN);
828462306a36Sopenharmony_ci			break;
828562306a36Sopenharmony_ci		case ISCSI_FLASHNODE_DISCOVERY_PARENT_IDX:
828662306a36Sopenharmony_ci			fnode_sess->discovery_parent_idx =
828762306a36Sopenharmony_ci						*(uint16_t *)fnode_param->value;
828862306a36Sopenharmony_ci			break;
828962306a36Sopenharmony_ci		case ISCSI_FLASHNODE_TCP_XMIT_WSF:
829062306a36Sopenharmony_ci			fnode_conn->tcp_xmit_wsf =
829162306a36Sopenharmony_ci						*(uint8_t *)fnode_param->value;
829262306a36Sopenharmony_ci			break;
829362306a36Sopenharmony_ci		case ISCSI_FLASHNODE_TCP_RECV_WSF:
829462306a36Sopenharmony_ci			fnode_conn->tcp_recv_wsf =
829562306a36Sopenharmony_ci						*(uint8_t *)fnode_param->value;
829662306a36Sopenharmony_ci			break;
829762306a36Sopenharmony_ci		case ISCSI_FLASHNODE_STATSN:
829862306a36Sopenharmony_ci			fnode_conn->statsn = *(uint32_t *)fnode_param->value;
829962306a36Sopenharmony_ci			break;
830062306a36Sopenharmony_ci		case ISCSI_FLASHNODE_EXP_STATSN:
830162306a36Sopenharmony_ci			fnode_conn->exp_statsn =
830262306a36Sopenharmony_ci						*(uint32_t *)fnode_param->value;
830362306a36Sopenharmony_ci			break;
830462306a36Sopenharmony_ci		case ISCSI_FLASHNODE_CHAP_OUT_IDX:
830562306a36Sopenharmony_ci			chap_out_idx = *(uint16_t *)fnode_param->value;
830662306a36Sopenharmony_ci			if (!qla4xxx_get_uni_chap_at_index(ha,
830762306a36Sopenharmony_ci							   chap_tbl.name,
830862306a36Sopenharmony_ci							   chap_tbl.secret,
830962306a36Sopenharmony_ci							   chap_out_idx)) {
831062306a36Sopenharmony_ci				fnode_sess->chap_out_idx = chap_out_idx;
831162306a36Sopenharmony_ci				/* Enable chap auth if chap index is valid */
831262306a36Sopenharmony_ci				fnode_sess->chap_auth_en = QL4_PARAM_ENABLE;
831362306a36Sopenharmony_ci			}
831462306a36Sopenharmony_ci			break;
831562306a36Sopenharmony_ci		default:
831662306a36Sopenharmony_ci			ql4_printk(KERN_ERR, ha,
831762306a36Sopenharmony_ci				   "%s: No such sysfs attribute\n", __func__);
831862306a36Sopenharmony_ci			rc = -ENOSYS;
831962306a36Sopenharmony_ci			goto exit_set_param;
832062306a36Sopenharmony_ci		}
832162306a36Sopenharmony_ci	}
832262306a36Sopenharmony_ci
832362306a36Sopenharmony_ci	rc = qla4xxx_sysfs_ddb_apply(fnode_sess, fnode_conn);
832462306a36Sopenharmony_ci
832562306a36Sopenharmony_ciexit_set_param:
832662306a36Sopenharmony_ci	return rc;
832762306a36Sopenharmony_ci}
832862306a36Sopenharmony_ci
832962306a36Sopenharmony_ci/**
833062306a36Sopenharmony_ci * qla4xxx_sysfs_ddb_delete - Delete firmware DDB entry
833162306a36Sopenharmony_ci * @fnode_sess: pointer to session attrs of flash ddb entry
833262306a36Sopenharmony_ci *
833362306a36Sopenharmony_ci * This invalidates the flash ddb entry at the given index
833462306a36Sopenharmony_ci **/
833562306a36Sopenharmony_cistatic int qla4xxx_sysfs_ddb_delete(struct iscsi_bus_flash_session *fnode_sess)
833662306a36Sopenharmony_ci{
833762306a36Sopenharmony_ci	struct Scsi_Host *shost = iscsi_flash_session_to_shost(fnode_sess);
833862306a36Sopenharmony_ci	struct scsi_qla_host *ha = to_qla_host(shost);
833962306a36Sopenharmony_ci	uint32_t dev_db_start_offset;
834062306a36Sopenharmony_ci	uint32_t dev_db_end_offset;
834162306a36Sopenharmony_ci	struct dev_db_entry *fw_ddb_entry = NULL;
834262306a36Sopenharmony_ci	dma_addr_t fw_ddb_entry_dma;
834362306a36Sopenharmony_ci	uint16_t *ddb_cookie = NULL;
834462306a36Sopenharmony_ci	size_t ddb_size = 0;
834562306a36Sopenharmony_ci	void *pddb = NULL;
834662306a36Sopenharmony_ci	int target_id;
834762306a36Sopenharmony_ci	int rc = 0;
834862306a36Sopenharmony_ci
834962306a36Sopenharmony_ci	if (fnode_sess->is_boot_target) {
835062306a36Sopenharmony_ci		rc = -EPERM;
835162306a36Sopenharmony_ci		DEBUG2(ql4_printk(KERN_ERR, ha,
835262306a36Sopenharmony_ci				  "%s: Deletion of boot target entry is not permitted.\n",
835362306a36Sopenharmony_ci				  __func__));
835462306a36Sopenharmony_ci		goto exit_ddb_del;
835562306a36Sopenharmony_ci	}
835662306a36Sopenharmony_ci
835762306a36Sopenharmony_ci	if (fnode_sess->flash_state == DEV_DB_NON_PERSISTENT)
835862306a36Sopenharmony_ci		goto sysfs_ddb_del;
835962306a36Sopenharmony_ci
836062306a36Sopenharmony_ci	if (is_qla40XX(ha)) {
836162306a36Sopenharmony_ci		dev_db_start_offset = FLASH_OFFSET_DB_INFO;
836262306a36Sopenharmony_ci		dev_db_end_offset = FLASH_OFFSET_DB_END;
836362306a36Sopenharmony_ci		dev_db_start_offset += (fnode_sess->target_id *
836462306a36Sopenharmony_ci				       sizeof(*fw_ddb_entry));
836562306a36Sopenharmony_ci		ddb_size = sizeof(*fw_ddb_entry);
836662306a36Sopenharmony_ci	} else {
836762306a36Sopenharmony_ci		dev_db_start_offset = FLASH_RAW_ACCESS_ADDR +
836862306a36Sopenharmony_ci				      (ha->hw.flt_region_ddb << 2);
836962306a36Sopenharmony_ci		/* flt_ddb_size is DDB table size for both ports
837062306a36Sopenharmony_ci		 * so divide it by 2 to calculate the offset for second port
837162306a36Sopenharmony_ci		 */
837262306a36Sopenharmony_ci		if (ha->port_num == 1)
837362306a36Sopenharmony_ci			dev_db_start_offset += (ha->hw.flt_ddb_size / 2);
837462306a36Sopenharmony_ci
837562306a36Sopenharmony_ci		dev_db_end_offset = dev_db_start_offset +
837662306a36Sopenharmony_ci				    (ha->hw.flt_ddb_size / 2);
837762306a36Sopenharmony_ci
837862306a36Sopenharmony_ci		dev_db_start_offset += (fnode_sess->target_id *
837962306a36Sopenharmony_ci				       sizeof(*fw_ddb_entry));
838062306a36Sopenharmony_ci		dev_db_start_offset += offsetof(struct dev_db_entry, cookie);
838162306a36Sopenharmony_ci
838262306a36Sopenharmony_ci		ddb_size = sizeof(*ddb_cookie);
838362306a36Sopenharmony_ci	}
838462306a36Sopenharmony_ci
838562306a36Sopenharmony_ci	DEBUG2(ql4_printk(KERN_ERR, ha, "%s: start offset=%u, end offset=%u\n",
838662306a36Sopenharmony_ci			  __func__, dev_db_start_offset, dev_db_end_offset));
838762306a36Sopenharmony_ci
838862306a36Sopenharmony_ci	if (dev_db_start_offset > dev_db_end_offset) {
838962306a36Sopenharmony_ci		rc = -EIO;
839062306a36Sopenharmony_ci		DEBUG2(ql4_printk(KERN_ERR, ha, "%s:Invalid DDB index %u\n",
839162306a36Sopenharmony_ci				  __func__, fnode_sess->target_id));
839262306a36Sopenharmony_ci		goto exit_ddb_del;
839362306a36Sopenharmony_ci	}
839462306a36Sopenharmony_ci
839562306a36Sopenharmony_ci	pddb = dma_alloc_coherent(&ha->pdev->dev, ddb_size,
839662306a36Sopenharmony_ci				  &fw_ddb_entry_dma, GFP_KERNEL);
839762306a36Sopenharmony_ci	if (!pddb) {
839862306a36Sopenharmony_ci		rc = -ENOMEM;
839962306a36Sopenharmony_ci		DEBUG2(ql4_printk(KERN_ERR, ha,
840062306a36Sopenharmony_ci				  "%s: Unable to allocate dma buffer\n",
840162306a36Sopenharmony_ci				  __func__));
840262306a36Sopenharmony_ci		goto exit_ddb_del;
840362306a36Sopenharmony_ci	}
840462306a36Sopenharmony_ci
840562306a36Sopenharmony_ci	if (is_qla40XX(ha)) {
840662306a36Sopenharmony_ci		fw_ddb_entry = pddb;
840762306a36Sopenharmony_ci		memset(fw_ddb_entry, 0, ddb_size);
840862306a36Sopenharmony_ci		ddb_cookie = &fw_ddb_entry->cookie;
840962306a36Sopenharmony_ci	} else {
841062306a36Sopenharmony_ci		ddb_cookie = pddb;
841162306a36Sopenharmony_ci	}
841262306a36Sopenharmony_ci
841362306a36Sopenharmony_ci	/* invalidate the cookie */
841462306a36Sopenharmony_ci	*ddb_cookie = 0xFFEE;
841562306a36Sopenharmony_ci	qla4xxx_set_flash(ha, fw_ddb_entry_dma, dev_db_start_offset,
841662306a36Sopenharmony_ci			  ddb_size, FLASH_OPT_RMW_COMMIT);
841762306a36Sopenharmony_ci
841862306a36Sopenharmony_cisysfs_ddb_del:
841962306a36Sopenharmony_ci	target_id = fnode_sess->target_id;
842062306a36Sopenharmony_ci	iscsi_destroy_flashnode_sess(fnode_sess);
842162306a36Sopenharmony_ci	ql4_printk(KERN_INFO, ha,
842262306a36Sopenharmony_ci		   "%s: session and conn entries for flashnode %u of host %lu deleted\n",
842362306a36Sopenharmony_ci		   __func__, target_id, ha->host_no);
842462306a36Sopenharmony_ciexit_ddb_del:
842562306a36Sopenharmony_ci	if (pddb)
842662306a36Sopenharmony_ci		dma_free_coherent(&ha->pdev->dev, ddb_size, pddb,
842762306a36Sopenharmony_ci				  fw_ddb_entry_dma);
842862306a36Sopenharmony_ci	return rc;
842962306a36Sopenharmony_ci}
843062306a36Sopenharmony_ci
843162306a36Sopenharmony_ci/**
843262306a36Sopenharmony_ci * qla4xxx_sysfs_ddb_export - Create sysfs entries for firmware DDBs
843362306a36Sopenharmony_ci * @ha: pointer to adapter structure
843462306a36Sopenharmony_ci *
843562306a36Sopenharmony_ci * Export the firmware DDB for all send targets and normal targets to sysfs.
843662306a36Sopenharmony_ci **/
843762306a36Sopenharmony_ciint qla4xxx_sysfs_ddb_export(struct scsi_qla_host *ha)
843862306a36Sopenharmony_ci{
843962306a36Sopenharmony_ci	struct dev_db_entry *fw_ddb_entry = NULL;
844062306a36Sopenharmony_ci	dma_addr_t fw_ddb_entry_dma;
844162306a36Sopenharmony_ci	uint16_t max_ddbs;
844262306a36Sopenharmony_ci	uint16_t idx = 0;
844362306a36Sopenharmony_ci	int ret = QLA_SUCCESS;
844462306a36Sopenharmony_ci
844562306a36Sopenharmony_ci	fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev,
844662306a36Sopenharmony_ci					  sizeof(*fw_ddb_entry),
844762306a36Sopenharmony_ci					  &fw_ddb_entry_dma, GFP_KERNEL);
844862306a36Sopenharmony_ci	if (!fw_ddb_entry) {
844962306a36Sopenharmony_ci		DEBUG2(ql4_printk(KERN_ERR, ha,
845062306a36Sopenharmony_ci				  "%s: Unable to allocate dma buffer\n",
845162306a36Sopenharmony_ci				  __func__));
845262306a36Sopenharmony_ci		return -ENOMEM;
845362306a36Sopenharmony_ci	}
845462306a36Sopenharmony_ci
845562306a36Sopenharmony_ci	max_ddbs =  is_qla40XX(ha) ? MAX_PRST_DEV_DB_ENTRIES :
845662306a36Sopenharmony_ci				     MAX_DEV_DB_ENTRIES;
845762306a36Sopenharmony_ci
845862306a36Sopenharmony_ci	for (idx = 0; idx < max_ddbs; idx++) {
845962306a36Sopenharmony_ci		if (qla4xxx_flashdb_by_index(ha, fw_ddb_entry, fw_ddb_entry_dma,
846062306a36Sopenharmony_ci					     idx))
846162306a36Sopenharmony_ci			continue;
846262306a36Sopenharmony_ci
846362306a36Sopenharmony_ci		ret = qla4xxx_sysfs_ddb_tgt_create(ha, fw_ddb_entry, &idx, 0);
846462306a36Sopenharmony_ci		if (ret) {
846562306a36Sopenharmony_ci			ret = -EIO;
846662306a36Sopenharmony_ci			break;
846762306a36Sopenharmony_ci		}
846862306a36Sopenharmony_ci	}
846962306a36Sopenharmony_ci
847062306a36Sopenharmony_ci	dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), fw_ddb_entry,
847162306a36Sopenharmony_ci			  fw_ddb_entry_dma);
847262306a36Sopenharmony_ci
847362306a36Sopenharmony_ci	return ret;
847462306a36Sopenharmony_ci}
847562306a36Sopenharmony_ci
847662306a36Sopenharmony_cistatic void qla4xxx_sysfs_ddb_remove(struct scsi_qla_host *ha)
847762306a36Sopenharmony_ci{
847862306a36Sopenharmony_ci	iscsi_destroy_all_flashnode(ha->host);
847962306a36Sopenharmony_ci}
848062306a36Sopenharmony_ci
848162306a36Sopenharmony_ci/**
848262306a36Sopenharmony_ci * qla4xxx_build_ddb_list - Build ddb list and setup sessions
848362306a36Sopenharmony_ci * @ha: pointer to adapter structure
848462306a36Sopenharmony_ci * @is_reset: Is this init path or reset path
848562306a36Sopenharmony_ci *
848662306a36Sopenharmony_ci * Create a list of sendtargets (st) from firmware DDBs, issue send targets
848762306a36Sopenharmony_ci * using connection open, then create the list of normal targets (nt)
848862306a36Sopenharmony_ci * from firmware DDBs. Based on the list of nt setup session and connection
848962306a36Sopenharmony_ci * objects.
849062306a36Sopenharmony_ci **/
849162306a36Sopenharmony_civoid qla4xxx_build_ddb_list(struct scsi_qla_host *ha, int is_reset)
849262306a36Sopenharmony_ci{
849362306a36Sopenharmony_ci	uint16_t tmo = 0;
849462306a36Sopenharmony_ci	struct list_head list_st, list_nt;
849562306a36Sopenharmony_ci	struct qla_ddb_index  *st_ddb_idx, *st_ddb_idx_tmp;
849662306a36Sopenharmony_ci	unsigned long wtime;
849762306a36Sopenharmony_ci
849862306a36Sopenharmony_ci	if (!test_bit(AF_LINK_UP, &ha->flags)) {
849962306a36Sopenharmony_ci		set_bit(AF_BUILD_DDB_LIST, &ha->flags);
850062306a36Sopenharmony_ci		ha->is_reset = is_reset;
850162306a36Sopenharmony_ci		return;
850262306a36Sopenharmony_ci	}
850362306a36Sopenharmony_ci
850462306a36Sopenharmony_ci	INIT_LIST_HEAD(&list_st);
850562306a36Sopenharmony_ci	INIT_LIST_HEAD(&list_nt);
850662306a36Sopenharmony_ci
850762306a36Sopenharmony_ci	qla4xxx_build_st_list(ha, &list_st);
850862306a36Sopenharmony_ci
850962306a36Sopenharmony_ci	/* Before issuing conn open mbox, ensure all IPs states are configured
851062306a36Sopenharmony_ci	 * Note, conn open fails if IPs are not configured
851162306a36Sopenharmony_ci	 */
851262306a36Sopenharmony_ci	qla4xxx_wait_for_ip_configuration(ha);
851362306a36Sopenharmony_ci
851462306a36Sopenharmony_ci	/* Go thru the STs and fire the sendtargets by issuing conn open mbx */
851562306a36Sopenharmony_ci	list_for_each_entry_safe(st_ddb_idx, st_ddb_idx_tmp, &list_st, list) {
851662306a36Sopenharmony_ci		qla4xxx_conn_open(ha, st_ddb_idx->fw_ddb_idx);
851762306a36Sopenharmony_ci	}
851862306a36Sopenharmony_ci
851962306a36Sopenharmony_ci	/* Wait to ensure all sendtargets are done for min 12 sec wait */
852062306a36Sopenharmony_ci	tmo = ((ha->def_timeout > LOGIN_TOV) &&
852162306a36Sopenharmony_ci	       (ha->def_timeout < LOGIN_TOV * 10) ?
852262306a36Sopenharmony_ci	       ha->def_timeout : LOGIN_TOV);
852362306a36Sopenharmony_ci
852462306a36Sopenharmony_ci	DEBUG2(ql4_printk(KERN_INFO, ha,
852562306a36Sopenharmony_ci			  "Default time to wait for build ddb %d\n", tmo));
852662306a36Sopenharmony_ci
852762306a36Sopenharmony_ci	wtime = jiffies + (HZ * tmo);
852862306a36Sopenharmony_ci	do {
852962306a36Sopenharmony_ci		if (list_empty(&list_st))
853062306a36Sopenharmony_ci			break;
853162306a36Sopenharmony_ci
853262306a36Sopenharmony_ci		qla4xxx_remove_failed_ddb(ha, &list_st);
853362306a36Sopenharmony_ci		schedule_timeout_uninterruptible(HZ / 10);
853462306a36Sopenharmony_ci	} while (time_after(wtime, jiffies));
853562306a36Sopenharmony_ci
853662306a36Sopenharmony_ci
853762306a36Sopenharmony_ci	qla4xxx_build_nt_list(ha, &list_nt, &list_st, is_reset);
853862306a36Sopenharmony_ci
853962306a36Sopenharmony_ci	qla4xxx_free_ddb_list(&list_st);
854062306a36Sopenharmony_ci	qla4xxx_free_ddb_list(&list_nt);
854162306a36Sopenharmony_ci
854262306a36Sopenharmony_ci	qla4xxx_free_ddb_index(ha);
854362306a36Sopenharmony_ci}
854462306a36Sopenharmony_ci
854562306a36Sopenharmony_ci/**
854662306a36Sopenharmony_ci * qla4xxx_wait_login_resp_boot_tgt -  Wait for iSCSI boot target login
854762306a36Sopenharmony_ci * response.
854862306a36Sopenharmony_ci * @ha: pointer to adapter structure
854962306a36Sopenharmony_ci *
855062306a36Sopenharmony_ci * When the boot entry is normal iSCSI target then DF_BOOT_TGT flag will be
855162306a36Sopenharmony_ci * set in DDB and we will wait for login response of boot targets during
855262306a36Sopenharmony_ci * probe.
855362306a36Sopenharmony_ci **/
855462306a36Sopenharmony_cistatic void qla4xxx_wait_login_resp_boot_tgt(struct scsi_qla_host *ha)
855562306a36Sopenharmony_ci{
855662306a36Sopenharmony_ci	struct ddb_entry *ddb_entry;
855762306a36Sopenharmony_ci	struct dev_db_entry *fw_ddb_entry = NULL;
855862306a36Sopenharmony_ci	dma_addr_t fw_ddb_entry_dma;
855962306a36Sopenharmony_ci	unsigned long wtime;
856062306a36Sopenharmony_ci	uint32_t ddb_state;
856162306a36Sopenharmony_ci	int max_ddbs, idx, ret;
856262306a36Sopenharmony_ci
856362306a36Sopenharmony_ci	max_ddbs =  is_qla40XX(ha) ? MAX_DEV_DB_ENTRIES_40XX :
856462306a36Sopenharmony_ci				     MAX_DEV_DB_ENTRIES;
856562306a36Sopenharmony_ci
856662306a36Sopenharmony_ci	fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
856762306a36Sopenharmony_ci					  &fw_ddb_entry_dma, GFP_KERNEL);
856862306a36Sopenharmony_ci	if (!fw_ddb_entry) {
856962306a36Sopenharmony_ci		ql4_printk(KERN_ERR, ha,
857062306a36Sopenharmony_ci			   "%s: Unable to allocate dma buffer\n", __func__);
857162306a36Sopenharmony_ci		goto exit_login_resp;
857262306a36Sopenharmony_ci	}
857362306a36Sopenharmony_ci
857462306a36Sopenharmony_ci	wtime = jiffies + (HZ * BOOT_LOGIN_RESP_TOV);
857562306a36Sopenharmony_ci
857662306a36Sopenharmony_ci	for (idx = 0; idx < max_ddbs; idx++) {
857762306a36Sopenharmony_ci		ddb_entry = qla4xxx_lookup_ddb_by_fw_index(ha, idx);
857862306a36Sopenharmony_ci		if (ddb_entry == NULL)
857962306a36Sopenharmony_ci			continue;
858062306a36Sopenharmony_ci
858162306a36Sopenharmony_ci		if (test_bit(DF_BOOT_TGT, &ddb_entry->flags)) {
858262306a36Sopenharmony_ci			DEBUG2(ql4_printk(KERN_INFO, ha,
858362306a36Sopenharmony_ci					  "%s: DDB index [%d]\n", __func__,
858462306a36Sopenharmony_ci					  ddb_entry->fw_ddb_index));
858562306a36Sopenharmony_ci			do {
858662306a36Sopenharmony_ci				ret = qla4xxx_get_fwddb_entry(ha,
858762306a36Sopenharmony_ci						ddb_entry->fw_ddb_index,
858862306a36Sopenharmony_ci						fw_ddb_entry, fw_ddb_entry_dma,
858962306a36Sopenharmony_ci						NULL, NULL, &ddb_state, NULL,
859062306a36Sopenharmony_ci						NULL, NULL);
859162306a36Sopenharmony_ci				if (ret == QLA_ERROR)
859262306a36Sopenharmony_ci					goto exit_login_resp;
859362306a36Sopenharmony_ci
859462306a36Sopenharmony_ci				if ((ddb_state == DDB_DS_SESSION_ACTIVE) ||
859562306a36Sopenharmony_ci				    (ddb_state == DDB_DS_SESSION_FAILED))
859662306a36Sopenharmony_ci					break;
859762306a36Sopenharmony_ci
859862306a36Sopenharmony_ci				schedule_timeout_uninterruptible(HZ);
859962306a36Sopenharmony_ci
860062306a36Sopenharmony_ci			} while ((time_after(wtime, jiffies)));
860162306a36Sopenharmony_ci
860262306a36Sopenharmony_ci			if (!time_after(wtime, jiffies)) {
860362306a36Sopenharmony_ci				DEBUG2(ql4_printk(KERN_INFO, ha,
860462306a36Sopenharmony_ci						  "%s: Login response wait timer expired\n",
860562306a36Sopenharmony_ci						  __func__));
860662306a36Sopenharmony_ci				 goto exit_login_resp;
860762306a36Sopenharmony_ci			}
860862306a36Sopenharmony_ci		}
860962306a36Sopenharmony_ci	}
861062306a36Sopenharmony_ci
861162306a36Sopenharmony_ciexit_login_resp:
861262306a36Sopenharmony_ci	if (fw_ddb_entry)
861362306a36Sopenharmony_ci		dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
861462306a36Sopenharmony_ci				  fw_ddb_entry, fw_ddb_entry_dma);
861562306a36Sopenharmony_ci}
861662306a36Sopenharmony_ci
861762306a36Sopenharmony_ci/**
861862306a36Sopenharmony_ci * qla4xxx_probe_adapter - callback function to probe HBA
861962306a36Sopenharmony_ci * @pdev: pointer to pci_dev structure
862062306a36Sopenharmony_ci * @ent: pointer to pci_device entry
862162306a36Sopenharmony_ci *
862262306a36Sopenharmony_ci * This routine will probe for Qlogic 4xxx iSCSI host adapters.
862362306a36Sopenharmony_ci * It returns zero if successful. It also initializes all data necessary for
862462306a36Sopenharmony_ci * the driver.
862562306a36Sopenharmony_ci **/
862662306a36Sopenharmony_cistatic int qla4xxx_probe_adapter(struct pci_dev *pdev,
862762306a36Sopenharmony_ci				 const struct pci_device_id *ent)
862862306a36Sopenharmony_ci{
862962306a36Sopenharmony_ci	int ret = -ENODEV, status;
863062306a36Sopenharmony_ci	struct Scsi_Host *host;
863162306a36Sopenharmony_ci	struct scsi_qla_host *ha;
863262306a36Sopenharmony_ci	uint8_t init_retry_count = 0;
863362306a36Sopenharmony_ci	char buf[34];
863462306a36Sopenharmony_ci	struct qla4_8xxx_legacy_intr_set *nx_legacy_intr;
863562306a36Sopenharmony_ci	uint32_t dev_state;
863662306a36Sopenharmony_ci
863762306a36Sopenharmony_ci	if (pci_enable_device(pdev))
863862306a36Sopenharmony_ci		return -1;
863962306a36Sopenharmony_ci
864062306a36Sopenharmony_ci	host = iscsi_host_alloc(&qla4xxx_driver_template, sizeof(*ha), 0);
864162306a36Sopenharmony_ci	if (host == NULL) {
864262306a36Sopenharmony_ci		printk(KERN_WARNING
864362306a36Sopenharmony_ci		       "qla4xxx: Couldn't allocate host from scsi layer!\n");
864462306a36Sopenharmony_ci		goto probe_disable_device;
864562306a36Sopenharmony_ci	}
864662306a36Sopenharmony_ci
864762306a36Sopenharmony_ci	/* Clear our data area */
864862306a36Sopenharmony_ci	ha = to_qla_host(host);
864962306a36Sopenharmony_ci	memset(ha, 0, sizeof(*ha));
865062306a36Sopenharmony_ci
865162306a36Sopenharmony_ci	/* Save the information from PCI BIOS.	*/
865262306a36Sopenharmony_ci	ha->pdev = pdev;
865362306a36Sopenharmony_ci	ha->host = host;
865462306a36Sopenharmony_ci	ha->host_no = host->host_no;
865562306a36Sopenharmony_ci	ha->func_num = PCI_FUNC(ha->pdev->devfn);
865662306a36Sopenharmony_ci
865762306a36Sopenharmony_ci	/* Setup Runtime configurable options */
865862306a36Sopenharmony_ci	if (is_qla8022(ha)) {
865962306a36Sopenharmony_ci		ha->isp_ops = &qla4_82xx_isp_ops;
866062306a36Sopenharmony_ci		ha->reg_tbl = (uint32_t *) qla4_82xx_reg_tbl;
866162306a36Sopenharmony_ci		ha->qdr_sn_window = -1;
866262306a36Sopenharmony_ci		ha->ddr_mn_window = -1;
866362306a36Sopenharmony_ci		ha->curr_window = 255;
866462306a36Sopenharmony_ci		nx_legacy_intr = &legacy_intr[ha->func_num];
866562306a36Sopenharmony_ci		ha->nx_legacy_intr.int_vec_bit = nx_legacy_intr->int_vec_bit;
866662306a36Sopenharmony_ci		ha->nx_legacy_intr.tgt_status_reg =
866762306a36Sopenharmony_ci			nx_legacy_intr->tgt_status_reg;
866862306a36Sopenharmony_ci		ha->nx_legacy_intr.tgt_mask_reg = nx_legacy_intr->tgt_mask_reg;
866962306a36Sopenharmony_ci		ha->nx_legacy_intr.pci_int_reg = nx_legacy_intr->pci_int_reg;
867062306a36Sopenharmony_ci	} else if (is_qla8032(ha) || is_qla8042(ha)) {
867162306a36Sopenharmony_ci		ha->isp_ops = &qla4_83xx_isp_ops;
867262306a36Sopenharmony_ci		ha->reg_tbl = (uint32_t *)qla4_83xx_reg_tbl;
867362306a36Sopenharmony_ci	} else {
867462306a36Sopenharmony_ci		ha->isp_ops = &qla4xxx_isp_ops;
867562306a36Sopenharmony_ci	}
867662306a36Sopenharmony_ci
867762306a36Sopenharmony_ci	if (is_qla80XX(ha)) {
867862306a36Sopenharmony_ci		rwlock_init(&ha->hw_lock);
867962306a36Sopenharmony_ci		ha->pf_bit = ha->func_num << 16;
868062306a36Sopenharmony_ci		/* Set EEH reset type to fundamental if required by hba */
868162306a36Sopenharmony_ci		pdev->needs_freset = 1;
868262306a36Sopenharmony_ci	}
868362306a36Sopenharmony_ci
868462306a36Sopenharmony_ci	/* Configure PCI I/O space. */
868562306a36Sopenharmony_ci	ret = ha->isp_ops->iospace_config(ha);
868662306a36Sopenharmony_ci	if (ret)
868762306a36Sopenharmony_ci		goto probe_failed_ioconfig;
868862306a36Sopenharmony_ci
868962306a36Sopenharmony_ci	ql4_printk(KERN_INFO, ha, "Found an ISP%04x, irq %d, iobase 0x%p\n",
869062306a36Sopenharmony_ci		   pdev->device, pdev->irq, ha->reg);
869162306a36Sopenharmony_ci
869262306a36Sopenharmony_ci	qla4xxx_config_dma_addressing(ha);
869362306a36Sopenharmony_ci
869462306a36Sopenharmony_ci	/* Initialize lists and spinlocks. */
869562306a36Sopenharmony_ci	INIT_LIST_HEAD(&ha->free_srb_q);
869662306a36Sopenharmony_ci
869762306a36Sopenharmony_ci	mutex_init(&ha->mbox_sem);
869862306a36Sopenharmony_ci	mutex_init(&ha->chap_sem);
869962306a36Sopenharmony_ci	init_completion(&ha->mbx_intr_comp);
870062306a36Sopenharmony_ci	init_completion(&ha->disable_acb_comp);
870162306a36Sopenharmony_ci	init_completion(&ha->idc_comp);
870262306a36Sopenharmony_ci	init_completion(&ha->link_up_comp);
870362306a36Sopenharmony_ci
870462306a36Sopenharmony_ci	spin_lock_init(&ha->hardware_lock);
870562306a36Sopenharmony_ci	spin_lock_init(&ha->work_lock);
870662306a36Sopenharmony_ci
870762306a36Sopenharmony_ci	/* Initialize work list */
870862306a36Sopenharmony_ci	INIT_LIST_HEAD(&ha->work_list);
870962306a36Sopenharmony_ci
871062306a36Sopenharmony_ci	/* Allocate dma buffers */
871162306a36Sopenharmony_ci	if (qla4xxx_mem_alloc(ha)) {
871262306a36Sopenharmony_ci		ql4_printk(KERN_WARNING, ha,
871362306a36Sopenharmony_ci		    "[ERROR] Failed to allocate memory for adapter\n");
871462306a36Sopenharmony_ci
871562306a36Sopenharmony_ci		ret = -ENOMEM;
871662306a36Sopenharmony_ci		goto probe_failed;
871762306a36Sopenharmony_ci	}
871862306a36Sopenharmony_ci
871962306a36Sopenharmony_ci	host->cmd_per_lun = 3;
872062306a36Sopenharmony_ci	host->max_channel = 0;
872162306a36Sopenharmony_ci	host->max_lun = MAX_LUNS - 1;
872262306a36Sopenharmony_ci	host->max_id = MAX_TARGETS;
872362306a36Sopenharmony_ci	host->max_cmd_len = IOCB_MAX_CDB_LEN;
872462306a36Sopenharmony_ci	host->can_queue = MAX_SRBS ;
872562306a36Sopenharmony_ci	host->transportt = qla4xxx_scsi_transport;
872662306a36Sopenharmony_ci
872762306a36Sopenharmony_ci	pci_set_drvdata(pdev, ha);
872862306a36Sopenharmony_ci
872962306a36Sopenharmony_ci	ret = scsi_add_host(host, &pdev->dev);
873062306a36Sopenharmony_ci	if (ret)
873162306a36Sopenharmony_ci		goto probe_failed;
873262306a36Sopenharmony_ci
873362306a36Sopenharmony_ci	if (is_qla80XX(ha))
873462306a36Sopenharmony_ci		qla4_8xxx_get_flash_info(ha);
873562306a36Sopenharmony_ci
873662306a36Sopenharmony_ci	if (is_qla8032(ha) || is_qla8042(ha)) {
873762306a36Sopenharmony_ci		qla4_83xx_read_reset_template(ha);
873862306a36Sopenharmony_ci		/*
873962306a36Sopenharmony_ci		 * NOTE: If ql4dontresethba==1, set IDC_CTRL DONTRESET_BIT0.
874062306a36Sopenharmony_ci		 * If DONRESET_BIT0 is set, drivers should not set dev_state
874162306a36Sopenharmony_ci		 * to NEED_RESET. But if NEED_RESET is set, drivers should
874262306a36Sopenharmony_ci		 * should honor the reset.
874362306a36Sopenharmony_ci		 */
874462306a36Sopenharmony_ci		if (ql4xdontresethba == 1)
874562306a36Sopenharmony_ci			qla4_83xx_set_idc_dontreset(ha);
874662306a36Sopenharmony_ci	}
874762306a36Sopenharmony_ci
874862306a36Sopenharmony_ci	/*
874962306a36Sopenharmony_ci	 * Initialize the Host adapter request/response queues and
875062306a36Sopenharmony_ci	 * firmware
875162306a36Sopenharmony_ci	 * NOTE: interrupts enabled upon successful completion
875262306a36Sopenharmony_ci	 */
875362306a36Sopenharmony_ci	status = qla4xxx_initialize_adapter(ha, INIT_ADAPTER);
875462306a36Sopenharmony_ci
875562306a36Sopenharmony_ci	/* Dont retry adapter initialization if IRQ allocation failed */
875662306a36Sopenharmony_ci	if (is_qla80XX(ha) && (status == QLA_ERROR))
875762306a36Sopenharmony_ci		goto skip_retry_init;
875862306a36Sopenharmony_ci
875962306a36Sopenharmony_ci	while ((!test_bit(AF_ONLINE, &ha->flags)) &&
876062306a36Sopenharmony_ci	    init_retry_count++ < MAX_INIT_RETRIES) {
876162306a36Sopenharmony_ci
876262306a36Sopenharmony_ci		if (is_qla80XX(ha)) {
876362306a36Sopenharmony_ci			ha->isp_ops->idc_lock(ha);
876462306a36Sopenharmony_ci			dev_state = qla4_8xxx_rd_direct(ha,
876562306a36Sopenharmony_ci							QLA8XXX_CRB_DEV_STATE);
876662306a36Sopenharmony_ci			ha->isp_ops->idc_unlock(ha);
876762306a36Sopenharmony_ci			if (dev_state == QLA8XXX_DEV_FAILED) {
876862306a36Sopenharmony_ci				ql4_printk(KERN_WARNING, ha, "%s: don't retry "
876962306a36Sopenharmony_ci				    "initialize adapter. H/W is in failed state\n",
877062306a36Sopenharmony_ci				    __func__);
877162306a36Sopenharmony_ci				break;
877262306a36Sopenharmony_ci			}
877362306a36Sopenharmony_ci		}
877462306a36Sopenharmony_ci		DEBUG2(printk("scsi: %s: retrying adapter initialization "
877562306a36Sopenharmony_ci			      "(%d)\n", __func__, init_retry_count));
877662306a36Sopenharmony_ci
877762306a36Sopenharmony_ci		if (ha->isp_ops->reset_chip(ha) == QLA_ERROR)
877862306a36Sopenharmony_ci			continue;
877962306a36Sopenharmony_ci
878062306a36Sopenharmony_ci		status = qla4xxx_initialize_adapter(ha, INIT_ADAPTER);
878162306a36Sopenharmony_ci		if (is_qla80XX(ha) && (status == QLA_ERROR)) {
878262306a36Sopenharmony_ci			if (qla4_8xxx_check_init_adapter_retry(ha) == QLA_ERROR)
878362306a36Sopenharmony_ci				goto skip_retry_init;
878462306a36Sopenharmony_ci		}
878562306a36Sopenharmony_ci	}
878662306a36Sopenharmony_ci
878762306a36Sopenharmony_ciskip_retry_init:
878862306a36Sopenharmony_ci	if (!test_bit(AF_ONLINE, &ha->flags)) {
878962306a36Sopenharmony_ci		ql4_printk(KERN_WARNING, ha, "Failed to initialize adapter\n");
879062306a36Sopenharmony_ci
879162306a36Sopenharmony_ci		if ((is_qla8022(ha) && ql4xdontresethba) ||
879262306a36Sopenharmony_ci		    ((is_qla8032(ha) || is_qla8042(ha)) &&
879362306a36Sopenharmony_ci		     qla4_83xx_idc_dontreset(ha))) {
879462306a36Sopenharmony_ci			/* Put the device in failed state. */
879562306a36Sopenharmony_ci			DEBUG2(printk(KERN_ERR "HW STATE: FAILED\n"));
879662306a36Sopenharmony_ci			ha->isp_ops->idc_lock(ha);
879762306a36Sopenharmony_ci			qla4_8xxx_wr_direct(ha, QLA8XXX_CRB_DEV_STATE,
879862306a36Sopenharmony_ci					    QLA8XXX_DEV_FAILED);
879962306a36Sopenharmony_ci			ha->isp_ops->idc_unlock(ha);
880062306a36Sopenharmony_ci		}
880162306a36Sopenharmony_ci		ret = -ENODEV;
880262306a36Sopenharmony_ci		goto remove_host;
880362306a36Sopenharmony_ci	}
880462306a36Sopenharmony_ci
880562306a36Sopenharmony_ci	/* Startup the kernel thread for this host adapter. */
880662306a36Sopenharmony_ci	DEBUG2(printk("scsi: %s: Starting kernel thread for "
880762306a36Sopenharmony_ci		      "qla4xxx_dpc\n", __func__));
880862306a36Sopenharmony_ci	sprintf(buf, "qla4xxx_%lu_dpc", ha->host_no);
880962306a36Sopenharmony_ci	ha->dpc_thread = create_singlethread_workqueue(buf);
881062306a36Sopenharmony_ci	if (!ha->dpc_thread) {
881162306a36Sopenharmony_ci		ql4_printk(KERN_WARNING, ha, "Unable to start DPC thread!\n");
881262306a36Sopenharmony_ci		ret = -ENODEV;
881362306a36Sopenharmony_ci		goto remove_host;
881462306a36Sopenharmony_ci	}
881562306a36Sopenharmony_ci	INIT_WORK(&ha->dpc_work, qla4xxx_do_dpc);
881662306a36Sopenharmony_ci
881762306a36Sopenharmony_ci	ha->task_wq = alloc_workqueue("qla4xxx_%lu_task", WQ_MEM_RECLAIM, 1,
881862306a36Sopenharmony_ci				      ha->host_no);
881962306a36Sopenharmony_ci	if (!ha->task_wq) {
882062306a36Sopenharmony_ci		ql4_printk(KERN_WARNING, ha, "Unable to start task thread!\n");
882162306a36Sopenharmony_ci		ret = -ENODEV;
882262306a36Sopenharmony_ci		goto remove_host;
882362306a36Sopenharmony_ci	}
882462306a36Sopenharmony_ci
882562306a36Sopenharmony_ci	/*
882662306a36Sopenharmony_ci	 * For ISP-8XXX, request_irqs is called in qla4_8xxx_load_risc
882762306a36Sopenharmony_ci	 * (which is called indirectly by qla4xxx_initialize_adapter),
882862306a36Sopenharmony_ci	 * so that irqs will be registered after crbinit but before
882962306a36Sopenharmony_ci	 * mbx_intr_enable.
883062306a36Sopenharmony_ci	 */
883162306a36Sopenharmony_ci	if (is_qla40XX(ha)) {
883262306a36Sopenharmony_ci		ret = qla4xxx_request_irqs(ha);
883362306a36Sopenharmony_ci		if (ret) {
883462306a36Sopenharmony_ci			ql4_printk(KERN_WARNING, ha, "Failed to reserve "
883562306a36Sopenharmony_ci			    "interrupt %d already in use.\n", pdev->irq);
883662306a36Sopenharmony_ci			goto remove_host;
883762306a36Sopenharmony_ci		}
883862306a36Sopenharmony_ci	}
883962306a36Sopenharmony_ci
884062306a36Sopenharmony_ci	pci_save_state(ha->pdev);
884162306a36Sopenharmony_ci	ha->isp_ops->enable_intrs(ha);
884262306a36Sopenharmony_ci
884362306a36Sopenharmony_ci	/* Start timer thread. */
884462306a36Sopenharmony_ci	qla4xxx_start_timer(ha, 1);
884562306a36Sopenharmony_ci
884662306a36Sopenharmony_ci	set_bit(AF_INIT_DONE, &ha->flags);
884762306a36Sopenharmony_ci
884862306a36Sopenharmony_ci	qla4_8xxx_alloc_sysfs_attr(ha);
884962306a36Sopenharmony_ci
885062306a36Sopenharmony_ci	printk(KERN_INFO
885162306a36Sopenharmony_ci	       " QLogic iSCSI HBA Driver version: %s\n"
885262306a36Sopenharmony_ci	       "  QLogic ISP%04x @ %s, host#=%ld, fw=%02d.%02d.%02d.%02d\n",
885362306a36Sopenharmony_ci	       qla4xxx_version_str, ha->pdev->device, pci_name(ha->pdev),
885462306a36Sopenharmony_ci	       ha->host_no, ha->fw_info.fw_major, ha->fw_info.fw_minor,
885562306a36Sopenharmony_ci	       ha->fw_info.fw_patch, ha->fw_info.fw_build);
885662306a36Sopenharmony_ci
885762306a36Sopenharmony_ci	/* Set the driver version */
885862306a36Sopenharmony_ci	if (is_qla80XX(ha))
885962306a36Sopenharmony_ci		qla4_8xxx_set_param(ha, SET_DRVR_VERSION);
886062306a36Sopenharmony_ci
886162306a36Sopenharmony_ci	if (qla4xxx_setup_boot_info(ha))
886262306a36Sopenharmony_ci		ql4_printk(KERN_ERR, ha,
886362306a36Sopenharmony_ci			   "%s: No iSCSI boot target configured\n", __func__);
886462306a36Sopenharmony_ci
886562306a36Sopenharmony_ci	set_bit(DPC_SYSFS_DDB_EXPORT, &ha->dpc_flags);
886662306a36Sopenharmony_ci	/* Perform the build ddb list and login to each */
886762306a36Sopenharmony_ci	qla4xxx_build_ddb_list(ha, INIT_ADAPTER);
886862306a36Sopenharmony_ci	iscsi_host_for_each_session(ha->host, qla4xxx_login_flash_ddb);
886962306a36Sopenharmony_ci	qla4xxx_wait_login_resp_boot_tgt(ha);
887062306a36Sopenharmony_ci
887162306a36Sopenharmony_ci	qla4xxx_create_chap_list(ha);
887262306a36Sopenharmony_ci
887362306a36Sopenharmony_ci	qla4xxx_create_ifaces(ha);
887462306a36Sopenharmony_ci	return 0;
887562306a36Sopenharmony_ci
887662306a36Sopenharmony_ciremove_host:
887762306a36Sopenharmony_ci	scsi_remove_host(ha->host);
887862306a36Sopenharmony_ci
887962306a36Sopenharmony_ciprobe_failed:
888062306a36Sopenharmony_ci	qla4xxx_free_adapter(ha);
888162306a36Sopenharmony_ci
888262306a36Sopenharmony_ciprobe_failed_ioconfig:
888362306a36Sopenharmony_ci	scsi_host_put(ha->host);
888462306a36Sopenharmony_ci
888562306a36Sopenharmony_ciprobe_disable_device:
888662306a36Sopenharmony_ci	pci_disable_device(pdev);
888762306a36Sopenharmony_ci
888862306a36Sopenharmony_ci	return ret;
888962306a36Sopenharmony_ci}
889062306a36Sopenharmony_ci
889162306a36Sopenharmony_ci/**
889262306a36Sopenharmony_ci * qla4xxx_prevent_other_port_reinit - prevent other port from re-initialize
889362306a36Sopenharmony_ci * @ha: pointer to adapter structure
889462306a36Sopenharmony_ci *
889562306a36Sopenharmony_ci * Mark the other ISP-4xxx port to indicate that the driver is being removed,
889662306a36Sopenharmony_ci * so that the other port will not re-initialize while in the process of
889762306a36Sopenharmony_ci * removing the ha due to driver unload or hba hotplug.
889862306a36Sopenharmony_ci **/
889962306a36Sopenharmony_cistatic void qla4xxx_prevent_other_port_reinit(struct scsi_qla_host *ha)
890062306a36Sopenharmony_ci{
890162306a36Sopenharmony_ci	struct scsi_qla_host *other_ha = NULL;
890262306a36Sopenharmony_ci	struct pci_dev *other_pdev = NULL;
890362306a36Sopenharmony_ci	int fn = ISP4XXX_PCI_FN_2;
890462306a36Sopenharmony_ci
890562306a36Sopenharmony_ci	/*iscsi function numbers for ISP4xxx is 1 and 3*/
890662306a36Sopenharmony_ci	if (PCI_FUNC(ha->pdev->devfn) & BIT_1)
890762306a36Sopenharmony_ci		fn = ISP4XXX_PCI_FN_1;
890862306a36Sopenharmony_ci
890962306a36Sopenharmony_ci	other_pdev =
891062306a36Sopenharmony_ci		pci_get_domain_bus_and_slot(pci_domain_nr(ha->pdev->bus),
891162306a36Sopenharmony_ci		ha->pdev->bus->number, PCI_DEVFN(PCI_SLOT(ha->pdev->devfn),
891262306a36Sopenharmony_ci		fn));
891362306a36Sopenharmony_ci
891462306a36Sopenharmony_ci	/* Get other_ha if other_pdev is valid and state is enable*/
891562306a36Sopenharmony_ci	if (other_pdev) {
891662306a36Sopenharmony_ci		if (atomic_read(&other_pdev->enable_cnt)) {
891762306a36Sopenharmony_ci			other_ha = pci_get_drvdata(other_pdev);
891862306a36Sopenharmony_ci			if (other_ha) {
891962306a36Sopenharmony_ci				set_bit(AF_HA_REMOVAL, &other_ha->flags);
892062306a36Sopenharmony_ci				DEBUG2(ql4_printk(KERN_INFO, ha, "%s: "
892162306a36Sopenharmony_ci				    "Prevent %s reinit\n", __func__,
892262306a36Sopenharmony_ci				    dev_name(&other_ha->pdev->dev)));
892362306a36Sopenharmony_ci			}
892462306a36Sopenharmony_ci		}
892562306a36Sopenharmony_ci		pci_dev_put(other_pdev);
892662306a36Sopenharmony_ci	}
892762306a36Sopenharmony_ci}
892862306a36Sopenharmony_ci
892962306a36Sopenharmony_cistatic void qla4xxx_destroy_ddb(struct scsi_qla_host *ha,
893062306a36Sopenharmony_ci		struct ddb_entry *ddb_entry)
893162306a36Sopenharmony_ci{
893262306a36Sopenharmony_ci	struct dev_db_entry *fw_ddb_entry = NULL;
893362306a36Sopenharmony_ci	dma_addr_t fw_ddb_entry_dma;
893462306a36Sopenharmony_ci	unsigned long wtime;
893562306a36Sopenharmony_ci	uint32_t ddb_state;
893662306a36Sopenharmony_ci	int options;
893762306a36Sopenharmony_ci	int status;
893862306a36Sopenharmony_ci
893962306a36Sopenharmony_ci	options = LOGOUT_OPTION_CLOSE_SESSION;
894062306a36Sopenharmony_ci	if (qla4xxx_session_logout_ddb(ha, ddb_entry, options) == QLA_ERROR) {
894162306a36Sopenharmony_ci		ql4_printk(KERN_ERR, ha, "%s: Logout failed\n", __func__);
894262306a36Sopenharmony_ci		goto clear_ddb;
894362306a36Sopenharmony_ci	}
894462306a36Sopenharmony_ci
894562306a36Sopenharmony_ci	fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
894662306a36Sopenharmony_ci					  &fw_ddb_entry_dma, GFP_KERNEL);
894762306a36Sopenharmony_ci	if (!fw_ddb_entry) {
894862306a36Sopenharmony_ci		ql4_printk(KERN_ERR, ha,
894962306a36Sopenharmony_ci			   "%s: Unable to allocate dma buffer\n", __func__);
895062306a36Sopenharmony_ci		goto clear_ddb;
895162306a36Sopenharmony_ci	}
895262306a36Sopenharmony_ci
895362306a36Sopenharmony_ci	wtime = jiffies + (HZ * LOGOUT_TOV);
895462306a36Sopenharmony_ci	do {
895562306a36Sopenharmony_ci		status = qla4xxx_get_fwddb_entry(ha, ddb_entry->fw_ddb_index,
895662306a36Sopenharmony_ci						 fw_ddb_entry, fw_ddb_entry_dma,
895762306a36Sopenharmony_ci						 NULL, NULL, &ddb_state, NULL,
895862306a36Sopenharmony_ci						 NULL, NULL);
895962306a36Sopenharmony_ci		if (status == QLA_ERROR)
896062306a36Sopenharmony_ci			goto free_ddb;
896162306a36Sopenharmony_ci
896262306a36Sopenharmony_ci		if ((ddb_state == DDB_DS_NO_CONNECTION_ACTIVE) ||
896362306a36Sopenharmony_ci		    (ddb_state == DDB_DS_SESSION_FAILED))
896462306a36Sopenharmony_ci			goto free_ddb;
896562306a36Sopenharmony_ci
896662306a36Sopenharmony_ci		schedule_timeout_uninterruptible(HZ);
896762306a36Sopenharmony_ci	} while ((time_after(wtime, jiffies)));
896862306a36Sopenharmony_ci
896962306a36Sopenharmony_cifree_ddb:
897062306a36Sopenharmony_ci	dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
897162306a36Sopenharmony_ci			  fw_ddb_entry, fw_ddb_entry_dma);
897262306a36Sopenharmony_ciclear_ddb:
897362306a36Sopenharmony_ci	qla4xxx_clear_ddb_entry(ha, ddb_entry->fw_ddb_index);
897462306a36Sopenharmony_ci}
897562306a36Sopenharmony_ci
897662306a36Sopenharmony_cistatic void qla4xxx_destroy_fw_ddb_session(struct scsi_qla_host *ha)
897762306a36Sopenharmony_ci{
897862306a36Sopenharmony_ci	struct ddb_entry *ddb_entry;
897962306a36Sopenharmony_ci	int idx;
898062306a36Sopenharmony_ci
898162306a36Sopenharmony_ci	for (idx = 0; idx < MAX_DDB_ENTRIES; idx++) {
898262306a36Sopenharmony_ci
898362306a36Sopenharmony_ci		ddb_entry = qla4xxx_lookup_ddb_by_fw_index(ha, idx);
898462306a36Sopenharmony_ci		if ((ddb_entry != NULL) &&
898562306a36Sopenharmony_ci		    (ddb_entry->ddb_type == FLASH_DDB)) {
898662306a36Sopenharmony_ci
898762306a36Sopenharmony_ci			qla4xxx_destroy_ddb(ha, ddb_entry);
898862306a36Sopenharmony_ci			/*
898962306a36Sopenharmony_ci			 * we have decremented the reference count of the driver
899062306a36Sopenharmony_ci			 * when we setup the session to have the driver unload
899162306a36Sopenharmony_ci			 * to be seamless without actually destroying the
899262306a36Sopenharmony_ci			 * session
899362306a36Sopenharmony_ci			 **/
899462306a36Sopenharmony_ci			try_module_get(qla4xxx_iscsi_transport.owner);
899562306a36Sopenharmony_ci			iscsi_destroy_endpoint(ddb_entry->conn->ep);
899662306a36Sopenharmony_ci			qla4xxx_free_ddb(ha, ddb_entry);
899762306a36Sopenharmony_ci			iscsi_session_teardown(ddb_entry->sess);
899862306a36Sopenharmony_ci		}
899962306a36Sopenharmony_ci	}
900062306a36Sopenharmony_ci}
900162306a36Sopenharmony_ci/**
900262306a36Sopenharmony_ci * qla4xxx_remove_adapter - callback function to remove adapter.
900362306a36Sopenharmony_ci * @pdev: PCI device pointer
900462306a36Sopenharmony_ci **/
900562306a36Sopenharmony_cistatic void qla4xxx_remove_adapter(struct pci_dev *pdev)
900662306a36Sopenharmony_ci{
900762306a36Sopenharmony_ci	struct scsi_qla_host *ha;
900862306a36Sopenharmony_ci
900962306a36Sopenharmony_ci	/*
901062306a36Sopenharmony_ci	 * If the PCI device is disabled then it means probe_adapter had
901162306a36Sopenharmony_ci	 * failed and resources already cleaned up on probe_adapter exit.
901262306a36Sopenharmony_ci	 */
901362306a36Sopenharmony_ci	if (!pci_is_enabled(pdev))
901462306a36Sopenharmony_ci		return;
901562306a36Sopenharmony_ci
901662306a36Sopenharmony_ci	ha = pci_get_drvdata(pdev);
901762306a36Sopenharmony_ci
901862306a36Sopenharmony_ci	if (is_qla40XX(ha))
901962306a36Sopenharmony_ci		qla4xxx_prevent_other_port_reinit(ha);
902062306a36Sopenharmony_ci
902162306a36Sopenharmony_ci	/* destroy iface from sysfs */
902262306a36Sopenharmony_ci	qla4xxx_destroy_ifaces(ha);
902362306a36Sopenharmony_ci
902462306a36Sopenharmony_ci	if ((!ql4xdisablesysfsboot) && ha->boot_kset)
902562306a36Sopenharmony_ci		iscsi_boot_destroy_kset(ha->boot_kset);
902662306a36Sopenharmony_ci
902762306a36Sopenharmony_ci	qla4xxx_destroy_fw_ddb_session(ha);
902862306a36Sopenharmony_ci	qla4_8xxx_free_sysfs_attr(ha);
902962306a36Sopenharmony_ci
903062306a36Sopenharmony_ci	qla4xxx_sysfs_ddb_remove(ha);
903162306a36Sopenharmony_ci	scsi_remove_host(ha->host);
903262306a36Sopenharmony_ci
903362306a36Sopenharmony_ci	qla4xxx_free_adapter(ha);
903462306a36Sopenharmony_ci
903562306a36Sopenharmony_ci	scsi_host_put(ha->host);
903662306a36Sopenharmony_ci
903762306a36Sopenharmony_ci	pci_disable_device(pdev);
903862306a36Sopenharmony_ci}
903962306a36Sopenharmony_ci
904062306a36Sopenharmony_ci/**
904162306a36Sopenharmony_ci * qla4xxx_config_dma_addressing() - Configure OS DMA addressing method.
904262306a36Sopenharmony_ci * @ha: HA context
904362306a36Sopenharmony_ci */
904462306a36Sopenharmony_cistatic void qla4xxx_config_dma_addressing(struct scsi_qla_host *ha)
904562306a36Sopenharmony_ci{
904662306a36Sopenharmony_ci	/* Update our PCI device dma_mask for full 64 bit mask */
904762306a36Sopenharmony_ci	if (dma_set_mask_and_coherent(&ha->pdev->dev, DMA_BIT_MASK(64))) {
904862306a36Sopenharmony_ci		dev_dbg(&ha->pdev->dev,
904962306a36Sopenharmony_ci			  "Failed to set 64 bit PCI consistent mask; "
905062306a36Sopenharmony_ci			   "using 32 bit.\n");
905162306a36Sopenharmony_ci		dma_set_mask_and_coherent(&ha->pdev->dev, DMA_BIT_MASK(32));
905262306a36Sopenharmony_ci	}
905362306a36Sopenharmony_ci}
905462306a36Sopenharmony_ci
905562306a36Sopenharmony_cistatic int qla4xxx_slave_alloc(struct scsi_device *sdev)
905662306a36Sopenharmony_ci{
905762306a36Sopenharmony_ci	struct iscsi_cls_session *cls_sess;
905862306a36Sopenharmony_ci	struct iscsi_session *sess;
905962306a36Sopenharmony_ci	struct ddb_entry *ddb;
906062306a36Sopenharmony_ci	int queue_depth = QL4_DEF_QDEPTH;
906162306a36Sopenharmony_ci
906262306a36Sopenharmony_ci	cls_sess = starget_to_session(sdev->sdev_target);
906362306a36Sopenharmony_ci	sess = cls_sess->dd_data;
906462306a36Sopenharmony_ci	ddb = sess->dd_data;
906562306a36Sopenharmony_ci
906662306a36Sopenharmony_ci	sdev->hostdata = ddb;
906762306a36Sopenharmony_ci
906862306a36Sopenharmony_ci	if (ql4xmaxqdepth != 0 && ql4xmaxqdepth <= 0xffffU)
906962306a36Sopenharmony_ci		queue_depth = ql4xmaxqdepth;
907062306a36Sopenharmony_ci
907162306a36Sopenharmony_ci	scsi_change_queue_depth(sdev, queue_depth);
907262306a36Sopenharmony_ci	return 0;
907362306a36Sopenharmony_ci}
907462306a36Sopenharmony_ci
907562306a36Sopenharmony_ci/**
907662306a36Sopenharmony_ci * qla4xxx_del_from_active_array - returns an active srb
907762306a36Sopenharmony_ci * @ha: Pointer to host adapter structure.
907862306a36Sopenharmony_ci * @index: index into the active_array
907962306a36Sopenharmony_ci *
908062306a36Sopenharmony_ci * This routine removes and returns the srb at the specified index
908162306a36Sopenharmony_ci **/
908262306a36Sopenharmony_cistruct srb *qla4xxx_del_from_active_array(struct scsi_qla_host *ha,
908362306a36Sopenharmony_ci    uint32_t index)
908462306a36Sopenharmony_ci{
908562306a36Sopenharmony_ci	struct srb *srb = NULL;
908662306a36Sopenharmony_ci	struct scsi_cmnd *cmd = NULL;
908762306a36Sopenharmony_ci
908862306a36Sopenharmony_ci	cmd = scsi_host_find_tag(ha->host, index);
908962306a36Sopenharmony_ci	if (!cmd)
909062306a36Sopenharmony_ci		return srb;
909162306a36Sopenharmony_ci
909262306a36Sopenharmony_ci	srb = qla4xxx_cmd_priv(cmd)->srb;
909362306a36Sopenharmony_ci	if (!srb)
909462306a36Sopenharmony_ci		return srb;
909562306a36Sopenharmony_ci
909662306a36Sopenharmony_ci	/* update counters */
909762306a36Sopenharmony_ci	if (srb->flags & SRB_DMA_VALID) {
909862306a36Sopenharmony_ci		ha->iocb_cnt -= srb->iocb_cnt;
909962306a36Sopenharmony_ci		if (srb->cmd)
910062306a36Sopenharmony_ci			srb->cmd->host_scribble =
910162306a36Sopenharmony_ci				(unsigned char *)(unsigned long) MAX_SRBS;
910262306a36Sopenharmony_ci	}
910362306a36Sopenharmony_ci	return srb;
910462306a36Sopenharmony_ci}
910562306a36Sopenharmony_ci
910662306a36Sopenharmony_ci/**
910762306a36Sopenharmony_ci * qla4xxx_eh_wait_on_command - waits for command to be returned by firmware
910862306a36Sopenharmony_ci * @ha: Pointer to host adapter structure.
910962306a36Sopenharmony_ci * @cmd: Scsi Command to wait on.
911062306a36Sopenharmony_ci *
911162306a36Sopenharmony_ci * This routine waits for the command to be returned by the Firmware
911262306a36Sopenharmony_ci * for some max time.
911362306a36Sopenharmony_ci **/
911462306a36Sopenharmony_cistatic int qla4xxx_eh_wait_on_command(struct scsi_qla_host *ha,
911562306a36Sopenharmony_ci				      struct scsi_cmnd *cmd)
911662306a36Sopenharmony_ci{
911762306a36Sopenharmony_ci	int done = 0;
911862306a36Sopenharmony_ci	struct srb *rp;
911962306a36Sopenharmony_ci	uint32_t max_wait_time = EH_WAIT_CMD_TOV;
912062306a36Sopenharmony_ci	int ret = SUCCESS;
912162306a36Sopenharmony_ci
912262306a36Sopenharmony_ci	/* Dont wait on command if PCI error is being handled
912362306a36Sopenharmony_ci	 * by PCI AER driver
912462306a36Sopenharmony_ci	 */
912562306a36Sopenharmony_ci	if (unlikely(pci_channel_offline(ha->pdev)) ||
912662306a36Sopenharmony_ci	    (test_bit(AF_EEH_BUSY, &ha->flags))) {
912762306a36Sopenharmony_ci		ql4_printk(KERN_WARNING, ha, "scsi%ld: Return from %s\n",
912862306a36Sopenharmony_ci		    ha->host_no, __func__);
912962306a36Sopenharmony_ci		return ret;
913062306a36Sopenharmony_ci	}
913162306a36Sopenharmony_ci
913262306a36Sopenharmony_ci	do {
913362306a36Sopenharmony_ci		/* Checking to see if its returned to OS */
913462306a36Sopenharmony_ci		rp = qla4xxx_cmd_priv(cmd)->srb;
913562306a36Sopenharmony_ci		if (rp == NULL) {
913662306a36Sopenharmony_ci			done++;
913762306a36Sopenharmony_ci			break;
913862306a36Sopenharmony_ci		}
913962306a36Sopenharmony_ci
914062306a36Sopenharmony_ci		msleep(2000);
914162306a36Sopenharmony_ci	} while (max_wait_time--);
914262306a36Sopenharmony_ci
914362306a36Sopenharmony_ci	return done;
914462306a36Sopenharmony_ci}
914562306a36Sopenharmony_ci
914662306a36Sopenharmony_ci/**
914762306a36Sopenharmony_ci * qla4xxx_wait_for_hba_online - waits for HBA to come online
914862306a36Sopenharmony_ci * @ha: Pointer to host adapter structure
914962306a36Sopenharmony_ci **/
915062306a36Sopenharmony_cistatic int qla4xxx_wait_for_hba_online(struct scsi_qla_host *ha)
915162306a36Sopenharmony_ci{
915262306a36Sopenharmony_ci	unsigned long wait_online;
915362306a36Sopenharmony_ci
915462306a36Sopenharmony_ci	wait_online = jiffies + (HBA_ONLINE_TOV * HZ);
915562306a36Sopenharmony_ci	while (time_before(jiffies, wait_online)) {
915662306a36Sopenharmony_ci
915762306a36Sopenharmony_ci		if (adapter_up(ha))
915862306a36Sopenharmony_ci			return QLA_SUCCESS;
915962306a36Sopenharmony_ci
916062306a36Sopenharmony_ci		msleep(2000);
916162306a36Sopenharmony_ci	}
916262306a36Sopenharmony_ci
916362306a36Sopenharmony_ci	return QLA_ERROR;
916462306a36Sopenharmony_ci}
916562306a36Sopenharmony_ci
916662306a36Sopenharmony_ci/**
916762306a36Sopenharmony_ci * qla4xxx_eh_wait_for_commands - wait for active cmds to finish.
916862306a36Sopenharmony_ci * @ha: pointer to HBA
916962306a36Sopenharmony_ci * @stgt: pointer to SCSI target
917062306a36Sopenharmony_ci * @sdev: pointer to SCSI device
917162306a36Sopenharmony_ci *
917262306a36Sopenharmony_ci * This function waits for all outstanding commands to a lun to complete. It
917362306a36Sopenharmony_ci * returns 0 if all pending commands are returned and 1 otherwise.
917462306a36Sopenharmony_ci **/
917562306a36Sopenharmony_cistatic int qla4xxx_eh_wait_for_commands(struct scsi_qla_host *ha,
917662306a36Sopenharmony_ci					struct scsi_target *stgt,
917762306a36Sopenharmony_ci					struct scsi_device *sdev)
917862306a36Sopenharmony_ci{
917962306a36Sopenharmony_ci	int cnt;
918062306a36Sopenharmony_ci	int status = 0;
918162306a36Sopenharmony_ci	struct scsi_cmnd *cmd;
918262306a36Sopenharmony_ci
918362306a36Sopenharmony_ci	/*
918462306a36Sopenharmony_ci	 * Waiting for all commands for the designated target or dev
918562306a36Sopenharmony_ci	 * in the active array
918662306a36Sopenharmony_ci	 */
918762306a36Sopenharmony_ci	for (cnt = 0; cnt < ha->host->can_queue; cnt++) {
918862306a36Sopenharmony_ci		cmd = scsi_host_find_tag(ha->host, cnt);
918962306a36Sopenharmony_ci		if (cmd && stgt == scsi_target(cmd->device) &&
919062306a36Sopenharmony_ci		    (!sdev || sdev == cmd->device)) {
919162306a36Sopenharmony_ci			if (!qla4xxx_eh_wait_on_command(ha, cmd)) {
919262306a36Sopenharmony_ci				status++;
919362306a36Sopenharmony_ci				break;
919462306a36Sopenharmony_ci			}
919562306a36Sopenharmony_ci		}
919662306a36Sopenharmony_ci	}
919762306a36Sopenharmony_ci	return status;
919862306a36Sopenharmony_ci}
919962306a36Sopenharmony_ci
920062306a36Sopenharmony_ci/**
920162306a36Sopenharmony_ci * qla4xxx_eh_abort - callback for abort task.
920262306a36Sopenharmony_ci * @cmd: Pointer to Linux's SCSI command structure
920362306a36Sopenharmony_ci *
920462306a36Sopenharmony_ci * This routine is called by the Linux OS to abort the specified
920562306a36Sopenharmony_ci * command.
920662306a36Sopenharmony_ci **/
920762306a36Sopenharmony_cistatic int qla4xxx_eh_abort(struct scsi_cmnd *cmd)
920862306a36Sopenharmony_ci{
920962306a36Sopenharmony_ci	struct scsi_qla_host *ha = to_qla_host(cmd->device->host);
921062306a36Sopenharmony_ci	unsigned int id = cmd->device->id;
921162306a36Sopenharmony_ci	uint64_t lun = cmd->device->lun;
921262306a36Sopenharmony_ci	unsigned long flags;
921362306a36Sopenharmony_ci	struct srb *srb = NULL;
921462306a36Sopenharmony_ci	int ret = SUCCESS;
921562306a36Sopenharmony_ci	int wait = 0;
921662306a36Sopenharmony_ci	int rval;
921762306a36Sopenharmony_ci
921862306a36Sopenharmony_ci	ql4_printk(KERN_INFO, ha, "scsi%ld:%d:%llu: Abort command issued cmd=%p, cdb=0x%x\n",
921962306a36Sopenharmony_ci		   ha->host_no, id, lun, cmd, cmd->cmnd[0]);
922062306a36Sopenharmony_ci
922162306a36Sopenharmony_ci	rval = qla4xxx_isp_check_reg(ha);
922262306a36Sopenharmony_ci	if (rval != QLA_SUCCESS) {
922362306a36Sopenharmony_ci		ql4_printk(KERN_INFO, ha, "PCI/Register disconnect, exiting.\n");
922462306a36Sopenharmony_ci		return FAILED;
922562306a36Sopenharmony_ci	}
922662306a36Sopenharmony_ci
922762306a36Sopenharmony_ci	spin_lock_irqsave(&ha->hardware_lock, flags);
922862306a36Sopenharmony_ci	srb = qla4xxx_cmd_priv(cmd)->srb;
922962306a36Sopenharmony_ci	if (!srb) {
923062306a36Sopenharmony_ci		spin_unlock_irqrestore(&ha->hardware_lock, flags);
923162306a36Sopenharmony_ci		ql4_printk(KERN_INFO, ha, "scsi%ld:%d:%llu: Specified command has already completed.\n",
923262306a36Sopenharmony_ci			   ha->host_no, id, lun);
923362306a36Sopenharmony_ci		return SUCCESS;
923462306a36Sopenharmony_ci	}
923562306a36Sopenharmony_ci	kref_get(&srb->srb_ref);
923662306a36Sopenharmony_ci	spin_unlock_irqrestore(&ha->hardware_lock, flags);
923762306a36Sopenharmony_ci
923862306a36Sopenharmony_ci	if (qla4xxx_abort_task(ha, srb) != QLA_SUCCESS) {
923962306a36Sopenharmony_ci		DEBUG3(printk("scsi%ld:%d:%llu: Abort_task mbx failed.\n",
924062306a36Sopenharmony_ci		    ha->host_no, id, lun));
924162306a36Sopenharmony_ci		ret = FAILED;
924262306a36Sopenharmony_ci	} else {
924362306a36Sopenharmony_ci		DEBUG3(printk("scsi%ld:%d:%llu: Abort_task mbx success.\n",
924462306a36Sopenharmony_ci		    ha->host_no, id, lun));
924562306a36Sopenharmony_ci		wait = 1;
924662306a36Sopenharmony_ci	}
924762306a36Sopenharmony_ci
924862306a36Sopenharmony_ci	kref_put(&srb->srb_ref, qla4xxx_srb_compl);
924962306a36Sopenharmony_ci
925062306a36Sopenharmony_ci	/* Wait for command to complete */
925162306a36Sopenharmony_ci	if (wait) {
925262306a36Sopenharmony_ci		if (!qla4xxx_eh_wait_on_command(ha, cmd)) {
925362306a36Sopenharmony_ci			DEBUG2(printk("scsi%ld:%d:%llu: Abort handler timed out\n",
925462306a36Sopenharmony_ci			    ha->host_no, id, lun));
925562306a36Sopenharmony_ci			ret = FAILED;
925662306a36Sopenharmony_ci		}
925762306a36Sopenharmony_ci	}
925862306a36Sopenharmony_ci
925962306a36Sopenharmony_ci	ql4_printk(KERN_INFO, ha,
926062306a36Sopenharmony_ci	    "scsi%ld:%d:%llu: Abort command - %s\n",
926162306a36Sopenharmony_ci	    ha->host_no, id, lun, (ret == SUCCESS) ? "succeeded" : "failed");
926262306a36Sopenharmony_ci
926362306a36Sopenharmony_ci	return ret;
926462306a36Sopenharmony_ci}
926562306a36Sopenharmony_ci
926662306a36Sopenharmony_ci/**
926762306a36Sopenharmony_ci * qla4xxx_eh_device_reset - callback for target reset.
926862306a36Sopenharmony_ci * @cmd: Pointer to Linux's SCSI command structure
926962306a36Sopenharmony_ci *
927062306a36Sopenharmony_ci * This routine is called by the Linux OS to reset all luns on the
927162306a36Sopenharmony_ci * specified target.
927262306a36Sopenharmony_ci **/
927362306a36Sopenharmony_cistatic int qla4xxx_eh_device_reset(struct scsi_cmnd *cmd)
927462306a36Sopenharmony_ci{
927562306a36Sopenharmony_ci	struct scsi_qla_host *ha = to_qla_host(cmd->device->host);
927662306a36Sopenharmony_ci	struct ddb_entry *ddb_entry = cmd->device->hostdata;
927762306a36Sopenharmony_ci	int ret = FAILED, stat;
927862306a36Sopenharmony_ci	int rval;
927962306a36Sopenharmony_ci
928062306a36Sopenharmony_ci	if (!ddb_entry)
928162306a36Sopenharmony_ci		return ret;
928262306a36Sopenharmony_ci
928362306a36Sopenharmony_ci	ret = iscsi_block_scsi_eh(cmd);
928462306a36Sopenharmony_ci	if (ret)
928562306a36Sopenharmony_ci		return ret;
928662306a36Sopenharmony_ci	ret = FAILED;
928762306a36Sopenharmony_ci
928862306a36Sopenharmony_ci	ql4_printk(KERN_INFO, ha,
928962306a36Sopenharmony_ci		   "scsi%ld:%d:%d:%llu: DEVICE RESET ISSUED.\n", ha->host_no,
929062306a36Sopenharmony_ci		   cmd->device->channel, cmd->device->id, cmd->device->lun);
929162306a36Sopenharmony_ci
929262306a36Sopenharmony_ci	DEBUG2(printk(KERN_INFO
929362306a36Sopenharmony_ci		      "scsi%ld: DEVICE_RESET cmd=%p jiffies = 0x%lx, to=%x,"
929462306a36Sopenharmony_ci		      "dpc_flags=%lx, status=%x allowed=%d\n", ha->host_no,
929562306a36Sopenharmony_ci		      cmd, jiffies, scsi_cmd_to_rq(cmd)->timeout / HZ,
929662306a36Sopenharmony_ci		      ha->dpc_flags, cmd->result, cmd->allowed));
929762306a36Sopenharmony_ci
929862306a36Sopenharmony_ci	rval = qla4xxx_isp_check_reg(ha);
929962306a36Sopenharmony_ci	if (rval != QLA_SUCCESS) {
930062306a36Sopenharmony_ci		ql4_printk(KERN_INFO, ha, "PCI/Register disconnect, exiting.\n");
930162306a36Sopenharmony_ci		return FAILED;
930262306a36Sopenharmony_ci	}
930362306a36Sopenharmony_ci
930462306a36Sopenharmony_ci	/* FIXME: wait for hba to go online */
930562306a36Sopenharmony_ci	stat = qla4xxx_reset_lun(ha, ddb_entry, cmd->device->lun);
930662306a36Sopenharmony_ci	if (stat != QLA_SUCCESS) {
930762306a36Sopenharmony_ci		ql4_printk(KERN_INFO, ha, "DEVICE RESET FAILED. %d\n", stat);
930862306a36Sopenharmony_ci		goto eh_dev_reset_done;
930962306a36Sopenharmony_ci	}
931062306a36Sopenharmony_ci
931162306a36Sopenharmony_ci	if (qla4xxx_eh_wait_for_commands(ha, scsi_target(cmd->device),
931262306a36Sopenharmony_ci					 cmd->device)) {
931362306a36Sopenharmony_ci		ql4_printk(KERN_INFO, ha,
931462306a36Sopenharmony_ci			   "DEVICE RESET FAILED - waiting for "
931562306a36Sopenharmony_ci			   "commands.\n");
931662306a36Sopenharmony_ci		goto eh_dev_reset_done;
931762306a36Sopenharmony_ci	}
931862306a36Sopenharmony_ci
931962306a36Sopenharmony_ci	/* Send marker. */
932062306a36Sopenharmony_ci	if (qla4xxx_send_marker_iocb(ha, ddb_entry, cmd->device->lun,
932162306a36Sopenharmony_ci		MM_LUN_RESET) != QLA_SUCCESS)
932262306a36Sopenharmony_ci		goto eh_dev_reset_done;
932362306a36Sopenharmony_ci
932462306a36Sopenharmony_ci	ql4_printk(KERN_INFO, ha,
932562306a36Sopenharmony_ci		   "scsi(%ld:%d:%d:%llu): DEVICE RESET SUCCEEDED.\n",
932662306a36Sopenharmony_ci		   ha->host_no, cmd->device->channel, cmd->device->id,
932762306a36Sopenharmony_ci		   cmd->device->lun);
932862306a36Sopenharmony_ci
932962306a36Sopenharmony_ci	ret = SUCCESS;
933062306a36Sopenharmony_ci
933162306a36Sopenharmony_cieh_dev_reset_done:
933262306a36Sopenharmony_ci
933362306a36Sopenharmony_ci	return ret;
933462306a36Sopenharmony_ci}
933562306a36Sopenharmony_ci
933662306a36Sopenharmony_ci/**
933762306a36Sopenharmony_ci * qla4xxx_eh_target_reset - callback for target reset.
933862306a36Sopenharmony_ci * @cmd: Pointer to Linux's SCSI command structure
933962306a36Sopenharmony_ci *
934062306a36Sopenharmony_ci * This routine is called by the Linux OS to reset the target.
934162306a36Sopenharmony_ci **/
934262306a36Sopenharmony_cistatic int qla4xxx_eh_target_reset(struct scsi_cmnd *cmd)
934362306a36Sopenharmony_ci{
934462306a36Sopenharmony_ci	struct scsi_qla_host *ha = to_qla_host(cmd->device->host);
934562306a36Sopenharmony_ci	struct ddb_entry *ddb_entry = cmd->device->hostdata;
934662306a36Sopenharmony_ci	int stat, ret;
934762306a36Sopenharmony_ci	int rval;
934862306a36Sopenharmony_ci
934962306a36Sopenharmony_ci	if (!ddb_entry)
935062306a36Sopenharmony_ci		return FAILED;
935162306a36Sopenharmony_ci
935262306a36Sopenharmony_ci	ret = iscsi_block_scsi_eh(cmd);
935362306a36Sopenharmony_ci	if (ret)
935462306a36Sopenharmony_ci		return ret;
935562306a36Sopenharmony_ci
935662306a36Sopenharmony_ci	starget_printk(KERN_INFO, scsi_target(cmd->device),
935762306a36Sopenharmony_ci		       "WARM TARGET RESET ISSUED.\n");
935862306a36Sopenharmony_ci
935962306a36Sopenharmony_ci	DEBUG2(printk(KERN_INFO
936062306a36Sopenharmony_ci		      "scsi%ld: TARGET_DEVICE_RESET cmd=%p jiffies = 0x%lx, "
936162306a36Sopenharmony_ci		      "to=%x,dpc_flags=%lx, status=%x allowed=%d\n",
936262306a36Sopenharmony_ci		      ha->host_no, cmd, jiffies, scsi_cmd_to_rq(cmd)->timeout / HZ,
936362306a36Sopenharmony_ci		      ha->dpc_flags, cmd->result, cmd->allowed));
936462306a36Sopenharmony_ci
936562306a36Sopenharmony_ci	rval = qla4xxx_isp_check_reg(ha);
936662306a36Sopenharmony_ci	if (rval != QLA_SUCCESS) {
936762306a36Sopenharmony_ci		ql4_printk(KERN_INFO, ha, "PCI/Register disconnect, exiting.\n");
936862306a36Sopenharmony_ci		return FAILED;
936962306a36Sopenharmony_ci	}
937062306a36Sopenharmony_ci
937162306a36Sopenharmony_ci	stat = qla4xxx_reset_target(ha, ddb_entry);
937262306a36Sopenharmony_ci	if (stat != QLA_SUCCESS) {
937362306a36Sopenharmony_ci		starget_printk(KERN_INFO, scsi_target(cmd->device),
937462306a36Sopenharmony_ci			       "WARM TARGET RESET FAILED.\n");
937562306a36Sopenharmony_ci		return FAILED;
937662306a36Sopenharmony_ci	}
937762306a36Sopenharmony_ci
937862306a36Sopenharmony_ci	if (qla4xxx_eh_wait_for_commands(ha, scsi_target(cmd->device),
937962306a36Sopenharmony_ci					 NULL)) {
938062306a36Sopenharmony_ci		starget_printk(KERN_INFO, scsi_target(cmd->device),
938162306a36Sopenharmony_ci			       "WARM TARGET DEVICE RESET FAILED - "
938262306a36Sopenharmony_ci			       "waiting for commands.\n");
938362306a36Sopenharmony_ci		return FAILED;
938462306a36Sopenharmony_ci	}
938562306a36Sopenharmony_ci
938662306a36Sopenharmony_ci	/* Send marker. */
938762306a36Sopenharmony_ci	if (qla4xxx_send_marker_iocb(ha, ddb_entry, cmd->device->lun,
938862306a36Sopenharmony_ci		MM_TGT_WARM_RESET) != QLA_SUCCESS) {
938962306a36Sopenharmony_ci		starget_printk(KERN_INFO, scsi_target(cmd->device),
939062306a36Sopenharmony_ci			       "WARM TARGET DEVICE RESET FAILED - "
939162306a36Sopenharmony_ci			       "marker iocb failed.\n");
939262306a36Sopenharmony_ci		return FAILED;
939362306a36Sopenharmony_ci	}
939462306a36Sopenharmony_ci
939562306a36Sopenharmony_ci	starget_printk(KERN_INFO, scsi_target(cmd->device),
939662306a36Sopenharmony_ci		       "WARM TARGET RESET SUCCEEDED.\n");
939762306a36Sopenharmony_ci	return SUCCESS;
939862306a36Sopenharmony_ci}
939962306a36Sopenharmony_ci
940062306a36Sopenharmony_ci/**
940162306a36Sopenharmony_ci * qla4xxx_is_eh_active - check if error handler is running
940262306a36Sopenharmony_ci * @shost: Pointer to SCSI Host struct
940362306a36Sopenharmony_ci *
940462306a36Sopenharmony_ci * This routine finds that if reset host is called in EH
940562306a36Sopenharmony_ci * scenario or from some application like sg_reset
940662306a36Sopenharmony_ci **/
940762306a36Sopenharmony_cistatic int qla4xxx_is_eh_active(struct Scsi_Host *shost)
940862306a36Sopenharmony_ci{
940962306a36Sopenharmony_ci	if (shost->shost_state == SHOST_RECOVERY)
941062306a36Sopenharmony_ci		return 1;
941162306a36Sopenharmony_ci	return 0;
941262306a36Sopenharmony_ci}
941362306a36Sopenharmony_ci
941462306a36Sopenharmony_ci/**
941562306a36Sopenharmony_ci * qla4xxx_eh_host_reset - kernel callback
941662306a36Sopenharmony_ci * @cmd: Pointer to Linux's SCSI command structure
941762306a36Sopenharmony_ci *
941862306a36Sopenharmony_ci * This routine is invoked by the Linux kernel to perform fatal error
941962306a36Sopenharmony_ci * recovery on the specified adapter.
942062306a36Sopenharmony_ci **/
942162306a36Sopenharmony_cistatic int qla4xxx_eh_host_reset(struct scsi_cmnd *cmd)
942262306a36Sopenharmony_ci{
942362306a36Sopenharmony_ci	int return_status = FAILED;
942462306a36Sopenharmony_ci	struct scsi_qla_host *ha;
942562306a36Sopenharmony_ci	int rval;
942662306a36Sopenharmony_ci
942762306a36Sopenharmony_ci	ha = to_qla_host(cmd->device->host);
942862306a36Sopenharmony_ci
942962306a36Sopenharmony_ci	rval = qla4xxx_isp_check_reg(ha);
943062306a36Sopenharmony_ci	if (rval != QLA_SUCCESS) {
943162306a36Sopenharmony_ci		ql4_printk(KERN_INFO, ha, "PCI/Register disconnect, exiting.\n");
943262306a36Sopenharmony_ci		return FAILED;
943362306a36Sopenharmony_ci	}
943462306a36Sopenharmony_ci
943562306a36Sopenharmony_ci	if ((is_qla8032(ha) || is_qla8042(ha)) && ql4xdontresethba)
943662306a36Sopenharmony_ci		qla4_83xx_set_idc_dontreset(ha);
943762306a36Sopenharmony_ci
943862306a36Sopenharmony_ci	/*
943962306a36Sopenharmony_ci	 * For ISP8324 and ISP8042, if IDC_CTRL DONTRESET_BIT0 is set by other
944062306a36Sopenharmony_ci	 * protocol drivers, we should not set device_state to NEED_RESET
944162306a36Sopenharmony_ci	 */
944262306a36Sopenharmony_ci	if (ql4xdontresethba ||
944362306a36Sopenharmony_ci	    ((is_qla8032(ha) || is_qla8042(ha)) &&
944462306a36Sopenharmony_ci	     qla4_83xx_idc_dontreset(ha))) {
944562306a36Sopenharmony_ci		DEBUG2(printk("scsi%ld: %s: Don't Reset HBA\n",
944662306a36Sopenharmony_ci		     ha->host_no, __func__));
944762306a36Sopenharmony_ci
944862306a36Sopenharmony_ci		/* Clear outstanding srb in queues */
944962306a36Sopenharmony_ci		if (qla4xxx_is_eh_active(cmd->device->host))
945062306a36Sopenharmony_ci			qla4xxx_abort_active_cmds(ha, DID_ABORT << 16);
945162306a36Sopenharmony_ci
945262306a36Sopenharmony_ci		return FAILED;
945362306a36Sopenharmony_ci	}
945462306a36Sopenharmony_ci
945562306a36Sopenharmony_ci	ql4_printk(KERN_INFO, ha,
945662306a36Sopenharmony_ci		   "scsi(%ld:%d:%d:%llu): HOST RESET ISSUED.\n", ha->host_no,
945762306a36Sopenharmony_ci		   cmd->device->channel, cmd->device->id, cmd->device->lun);
945862306a36Sopenharmony_ci
945962306a36Sopenharmony_ci	if (qla4xxx_wait_for_hba_online(ha) != QLA_SUCCESS) {
946062306a36Sopenharmony_ci		DEBUG2(printk("scsi%ld:%d: %s: Unable to reset host.  Adapter "
946162306a36Sopenharmony_ci			      "DEAD.\n", ha->host_no, cmd->device->channel,
946262306a36Sopenharmony_ci			      __func__));
946362306a36Sopenharmony_ci
946462306a36Sopenharmony_ci		return FAILED;
946562306a36Sopenharmony_ci	}
946662306a36Sopenharmony_ci
946762306a36Sopenharmony_ci	if (!test_bit(DPC_RESET_HA, &ha->dpc_flags)) {
946862306a36Sopenharmony_ci		if (is_qla80XX(ha))
946962306a36Sopenharmony_ci			set_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags);
947062306a36Sopenharmony_ci		else
947162306a36Sopenharmony_ci			set_bit(DPC_RESET_HA, &ha->dpc_flags);
947262306a36Sopenharmony_ci	}
947362306a36Sopenharmony_ci
947462306a36Sopenharmony_ci	if (qla4xxx_recover_adapter(ha) == QLA_SUCCESS)
947562306a36Sopenharmony_ci		return_status = SUCCESS;
947662306a36Sopenharmony_ci
947762306a36Sopenharmony_ci	ql4_printk(KERN_INFO, ha, "HOST RESET %s.\n",
947862306a36Sopenharmony_ci		   return_status == FAILED ? "FAILED" : "SUCCEEDED");
947962306a36Sopenharmony_ci
948062306a36Sopenharmony_ci	return return_status;
948162306a36Sopenharmony_ci}
948262306a36Sopenharmony_ci
948362306a36Sopenharmony_cistatic int qla4xxx_context_reset(struct scsi_qla_host *ha)
948462306a36Sopenharmony_ci{
948562306a36Sopenharmony_ci	uint32_t mbox_cmd[MBOX_REG_COUNT];
948662306a36Sopenharmony_ci	uint32_t mbox_sts[MBOX_REG_COUNT];
948762306a36Sopenharmony_ci	struct addr_ctrl_blk_def *acb = NULL;
948862306a36Sopenharmony_ci	uint32_t acb_len = sizeof(struct addr_ctrl_blk_def);
948962306a36Sopenharmony_ci	int rval = QLA_SUCCESS;
949062306a36Sopenharmony_ci	dma_addr_t acb_dma;
949162306a36Sopenharmony_ci
949262306a36Sopenharmony_ci	acb = dma_alloc_coherent(&ha->pdev->dev,
949362306a36Sopenharmony_ci				 sizeof(struct addr_ctrl_blk_def),
949462306a36Sopenharmony_ci				 &acb_dma, GFP_KERNEL);
949562306a36Sopenharmony_ci	if (!acb) {
949662306a36Sopenharmony_ci		ql4_printk(KERN_ERR, ha, "%s: Unable to alloc acb\n",
949762306a36Sopenharmony_ci			   __func__);
949862306a36Sopenharmony_ci		rval = -ENOMEM;
949962306a36Sopenharmony_ci		goto exit_port_reset;
950062306a36Sopenharmony_ci	}
950162306a36Sopenharmony_ci
950262306a36Sopenharmony_ci	memset(acb, 0, acb_len);
950362306a36Sopenharmony_ci
950462306a36Sopenharmony_ci	rval = qla4xxx_get_acb(ha, acb_dma, PRIMARI_ACB, acb_len);
950562306a36Sopenharmony_ci	if (rval != QLA_SUCCESS) {
950662306a36Sopenharmony_ci		rval = -EIO;
950762306a36Sopenharmony_ci		goto exit_free_acb;
950862306a36Sopenharmony_ci	}
950962306a36Sopenharmony_ci
951062306a36Sopenharmony_ci	rval = qla4xxx_disable_acb(ha);
951162306a36Sopenharmony_ci	if (rval != QLA_SUCCESS) {
951262306a36Sopenharmony_ci		rval = -EIO;
951362306a36Sopenharmony_ci		goto exit_free_acb;
951462306a36Sopenharmony_ci	}
951562306a36Sopenharmony_ci
951662306a36Sopenharmony_ci	wait_for_completion_timeout(&ha->disable_acb_comp,
951762306a36Sopenharmony_ci				    DISABLE_ACB_TOV * HZ);
951862306a36Sopenharmony_ci
951962306a36Sopenharmony_ci	rval = qla4xxx_set_acb(ha, &mbox_cmd[0], &mbox_sts[0], acb_dma);
952062306a36Sopenharmony_ci	if (rval != QLA_SUCCESS) {
952162306a36Sopenharmony_ci		rval = -EIO;
952262306a36Sopenharmony_ci		goto exit_free_acb;
952362306a36Sopenharmony_ci	}
952462306a36Sopenharmony_ci
952562306a36Sopenharmony_ciexit_free_acb:
952662306a36Sopenharmony_ci	dma_free_coherent(&ha->pdev->dev, sizeof(struct addr_ctrl_blk_def),
952762306a36Sopenharmony_ci			  acb, acb_dma);
952862306a36Sopenharmony_ciexit_port_reset:
952962306a36Sopenharmony_ci	DEBUG2(ql4_printk(KERN_INFO, ha, "%s %s\n", __func__,
953062306a36Sopenharmony_ci			  rval == QLA_SUCCESS ? "SUCCEEDED" : "FAILED"));
953162306a36Sopenharmony_ci	return rval;
953262306a36Sopenharmony_ci}
953362306a36Sopenharmony_ci
953462306a36Sopenharmony_cistatic int qla4xxx_host_reset(struct Scsi_Host *shost, int reset_type)
953562306a36Sopenharmony_ci{
953662306a36Sopenharmony_ci	struct scsi_qla_host *ha = to_qla_host(shost);
953762306a36Sopenharmony_ci	int rval = QLA_SUCCESS;
953862306a36Sopenharmony_ci	uint32_t idc_ctrl;
953962306a36Sopenharmony_ci
954062306a36Sopenharmony_ci	if (ql4xdontresethba) {
954162306a36Sopenharmony_ci		DEBUG2(ql4_printk(KERN_INFO, ha, "%s: Don't Reset HBA\n",
954262306a36Sopenharmony_ci				  __func__));
954362306a36Sopenharmony_ci		rval = -EPERM;
954462306a36Sopenharmony_ci		goto exit_host_reset;
954562306a36Sopenharmony_ci	}
954662306a36Sopenharmony_ci
954762306a36Sopenharmony_ci	if (test_bit(DPC_RESET_HA, &ha->dpc_flags))
954862306a36Sopenharmony_ci		goto recover_adapter;
954962306a36Sopenharmony_ci
955062306a36Sopenharmony_ci	switch (reset_type) {
955162306a36Sopenharmony_ci	case SCSI_ADAPTER_RESET:
955262306a36Sopenharmony_ci		set_bit(DPC_RESET_HA, &ha->dpc_flags);
955362306a36Sopenharmony_ci		break;
955462306a36Sopenharmony_ci	case SCSI_FIRMWARE_RESET:
955562306a36Sopenharmony_ci		if (!test_bit(DPC_RESET_HA, &ha->dpc_flags)) {
955662306a36Sopenharmony_ci			if (is_qla80XX(ha))
955762306a36Sopenharmony_ci				/* set firmware context reset */
955862306a36Sopenharmony_ci				set_bit(DPC_RESET_HA_FW_CONTEXT,
955962306a36Sopenharmony_ci					&ha->dpc_flags);
956062306a36Sopenharmony_ci			else {
956162306a36Sopenharmony_ci				rval = qla4xxx_context_reset(ha);
956262306a36Sopenharmony_ci				goto exit_host_reset;
956362306a36Sopenharmony_ci			}
956462306a36Sopenharmony_ci		}
956562306a36Sopenharmony_ci		break;
956662306a36Sopenharmony_ci	}
956762306a36Sopenharmony_ci
956862306a36Sopenharmony_cirecover_adapter:
956962306a36Sopenharmony_ci	/* For ISP8324 and ISP8042 set graceful reset bit in IDC_DRV_CTRL if
957062306a36Sopenharmony_ci	 * reset is issued by application */
957162306a36Sopenharmony_ci	if ((is_qla8032(ha) || is_qla8042(ha)) &&
957262306a36Sopenharmony_ci	    test_bit(DPC_RESET_HA, &ha->dpc_flags)) {
957362306a36Sopenharmony_ci		idc_ctrl = qla4_83xx_rd_reg(ha, QLA83XX_IDC_DRV_CTRL);
957462306a36Sopenharmony_ci		qla4_83xx_wr_reg(ha, QLA83XX_IDC_DRV_CTRL,
957562306a36Sopenharmony_ci				 (idc_ctrl | GRACEFUL_RESET_BIT1));
957662306a36Sopenharmony_ci	}
957762306a36Sopenharmony_ci
957862306a36Sopenharmony_ci	rval = qla4xxx_recover_adapter(ha);
957962306a36Sopenharmony_ci	if (rval != QLA_SUCCESS) {
958062306a36Sopenharmony_ci		DEBUG2(ql4_printk(KERN_INFO, ha, "%s: recover adapter fail\n",
958162306a36Sopenharmony_ci				  __func__));
958262306a36Sopenharmony_ci		rval = -EIO;
958362306a36Sopenharmony_ci	}
958462306a36Sopenharmony_ci
958562306a36Sopenharmony_ciexit_host_reset:
958662306a36Sopenharmony_ci	return rval;
958762306a36Sopenharmony_ci}
958862306a36Sopenharmony_ci
958962306a36Sopenharmony_ci/* PCI AER driver recovers from all correctable errors w/o
959062306a36Sopenharmony_ci * driver intervention. For uncorrectable errors PCI AER
959162306a36Sopenharmony_ci * driver calls the following device driver's callbacks
959262306a36Sopenharmony_ci *
959362306a36Sopenharmony_ci * - Fatal Errors - link_reset
959462306a36Sopenharmony_ci * - Non-Fatal Errors - driver's error_detected() which
959562306a36Sopenharmony_ci * returns CAN_RECOVER, NEED_RESET or DISCONNECT.
959662306a36Sopenharmony_ci *
959762306a36Sopenharmony_ci * PCI AER driver calls
959862306a36Sopenharmony_ci * CAN_RECOVER - driver's mmio_enabled(), mmio_enabled()
959962306a36Sopenharmony_ci *               returns RECOVERED or NEED_RESET if fw_hung
960062306a36Sopenharmony_ci * NEED_RESET - driver's slot_reset()
960162306a36Sopenharmony_ci * DISCONNECT - device is dead & cannot recover
960262306a36Sopenharmony_ci * RECOVERED - driver's resume()
960362306a36Sopenharmony_ci */
960462306a36Sopenharmony_cistatic pci_ers_result_t
960562306a36Sopenharmony_ciqla4xxx_pci_error_detected(struct pci_dev *pdev, pci_channel_state_t state)
960662306a36Sopenharmony_ci{
960762306a36Sopenharmony_ci	struct scsi_qla_host *ha = pci_get_drvdata(pdev);
960862306a36Sopenharmony_ci
960962306a36Sopenharmony_ci	ql4_printk(KERN_WARNING, ha, "scsi%ld: %s: error detected:state %x\n",
961062306a36Sopenharmony_ci	    ha->host_no, __func__, state);
961162306a36Sopenharmony_ci
961262306a36Sopenharmony_ci	if (!is_aer_supported(ha))
961362306a36Sopenharmony_ci		return PCI_ERS_RESULT_NONE;
961462306a36Sopenharmony_ci
961562306a36Sopenharmony_ci	switch (state) {
961662306a36Sopenharmony_ci	case pci_channel_io_normal:
961762306a36Sopenharmony_ci		clear_bit(AF_EEH_BUSY, &ha->flags);
961862306a36Sopenharmony_ci		return PCI_ERS_RESULT_CAN_RECOVER;
961962306a36Sopenharmony_ci	case pci_channel_io_frozen:
962062306a36Sopenharmony_ci		set_bit(AF_EEH_BUSY, &ha->flags);
962162306a36Sopenharmony_ci		qla4xxx_mailbox_premature_completion(ha);
962262306a36Sopenharmony_ci		qla4xxx_free_irqs(ha);
962362306a36Sopenharmony_ci		pci_disable_device(pdev);
962462306a36Sopenharmony_ci		/* Return back all IOs */
962562306a36Sopenharmony_ci		qla4xxx_abort_active_cmds(ha, DID_RESET << 16);
962662306a36Sopenharmony_ci		return PCI_ERS_RESULT_NEED_RESET;
962762306a36Sopenharmony_ci	case pci_channel_io_perm_failure:
962862306a36Sopenharmony_ci		set_bit(AF_EEH_BUSY, &ha->flags);
962962306a36Sopenharmony_ci		set_bit(AF_PCI_CHANNEL_IO_PERM_FAILURE, &ha->flags);
963062306a36Sopenharmony_ci		qla4xxx_abort_active_cmds(ha, DID_NO_CONNECT << 16);
963162306a36Sopenharmony_ci		return PCI_ERS_RESULT_DISCONNECT;
963262306a36Sopenharmony_ci	}
963362306a36Sopenharmony_ci	return PCI_ERS_RESULT_NEED_RESET;
963462306a36Sopenharmony_ci}
963562306a36Sopenharmony_ci
963662306a36Sopenharmony_ci/**
963762306a36Sopenharmony_ci * qla4xxx_pci_mmio_enabled() - gets called if
963862306a36Sopenharmony_ci * qla4xxx_pci_error_detected() returns PCI_ERS_RESULT_CAN_RECOVER
963962306a36Sopenharmony_ci * and read/write to the device still works.
964062306a36Sopenharmony_ci * @pdev: PCI device pointer
964162306a36Sopenharmony_ci **/
964262306a36Sopenharmony_cistatic pci_ers_result_t
964362306a36Sopenharmony_ciqla4xxx_pci_mmio_enabled(struct pci_dev *pdev)
964462306a36Sopenharmony_ci{
964562306a36Sopenharmony_ci	struct scsi_qla_host *ha = pci_get_drvdata(pdev);
964662306a36Sopenharmony_ci
964762306a36Sopenharmony_ci	if (!is_aer_supported(ha))
964862306a36Sopenharmony_ci		return PCI_ERS_RESULT_NONE;
964962306a36Sopenharmony_ci
965062306a36Sopenharmony_ci	return PCI_ERS_RESULT_RECOVERED;
965162306a36Sopenharmony_ci}
965262306a36Sopenharmony_ci
965362306a36Sopenharmony_cistatic uint32_t qla4_8xxx_error_recovery(struct scsi_qla_host *ha)
965462306a36Sopenharmony_ci{
965562306a36Sopenharmony_ci	uint32_t rval = QLA_ERROR;
965662306a36Sopenharmony_ci	int fn;
965762306a36Sopenharmony_ci	struct pci_dev *other_pdev = NULL;
965862306a36Sopenharmony_ci
965962306a36Sopenharmony_ci	ql4_printk(KERN_WARNING, ha, "scsi%ld: In %s\n", ha->host_no, __func__);
966062306a36Sopenharmony_ci
966162306a36Sopenharmony_ci	set_bit(DPC_RESET_ACTIVE, &ha->dpc_flags);
966262306a36Sopenharmony_ci
966362306a36Sopenharmony_ci	if (test_bit(AF_ONLINE, &ha->flags)) {
966462306a36Sopenharmony_ci		clear_bit(AF_ONLINE, &ha->flags);
966562306a36Sopenharmony_ci		clear_bit(AF_LINK_UP, &ha->flags);
966662306a36Sopenharmony_ci		iscsi_host_for_each_session(ha->host, qla4xxx_fail_session);
966762306a36Sopenharmony_ci		qla4xxx_process_aen(ha, FLUSH_DDB_CHANGED_AENS);
966862306a36Sopenharmony_ci	}
966962306a36Sopenharmony_ci
967062306a36Sopenharmony_ci	fn = PCI_FUNC(ha->pdev->devfn);
967162306a36Sopenharmony_ci	if (is_qla8022(ha)) {
967262306a36Sopenharmony_ci		while (fn > 0) {
967362306a36Sopenharmony_ci			fn--;
967462306a36Sopenharmony_ci			ql4_printk(KERN_INFO, ha, "scsi%ld: %s: Finding PCI device at func %x\n",
967562306a36Sopenharmony_ci				   ha->host_no, __func__, fn);
967662306a36Sopenharmony_ci			/* Get the pci device given the domain, bus,
967762306a36Sopenharmony_ci			 * slot/function number */
967862306a36Sopenharmony_ci			other_pdev = pci_get_domain_bus_and_slot(
967962306a36Sopenharmony_ci					   pci_domain_nr(ha->pdev->bus),
968062306a36Sopenharmony_ci					   ha->pdev->bus->number,
968162306a36Sopenharmony_ci					   PCI_DEVFN(PCI_SLOT(ha->pdev->devfn),
968262306a36Sopenharmony_ci					   fn));
968362306a36Sopenharmony_ci
968462306a36Sopenharmony_ci			if (!other_pdev)
968562306a36Sopenharmony_ci				continue;
968662306a36Sopenharmony_ci
968762306a36Sopenharmony_ci			if (atomic_read(&other_pdev->enable_cnt)) {
968862306a36Sopenharmony_ci				ql4_printk(KERN_INFO, ha, "scsi%ld: %s: Found PCI func in enabled state%x\n",
968962306a36Sopenharmony_ci					   ha->host_no, __func__, fn);
969062306a36Sopenharmony_ci				pci_dev_put(other_pdev);
969162306a36Sopenharmony_ci				break;
969262306a36Sopenharmony_ci			}
969362306a36Sopenharmony_ci			pci_dev_put(other_pdev);
969462306a36Sopenharmony_ci		}
969562306a36Sopenharmony_ci	} else {
969662306a36Sopenharmony_ci		/* this case is meant for ISP83xx/ISP84xx only */
969762306a36Sopenharmony_ci		if (qla4_83xx_can_perform_reset(ha)) {
969862306a36Sopenharmony_ci			/* reset fn as iSCSI is going to perform the reset */
969962306a36Sopenharmony_ci			fn = 0;
970062306a36Sopenharmony_ci		}
970162306a36Sopenharmony_ci	}
970262306a36Sopenharmony_ci
970362306a36Sopenharmony_ci	/* The first function on the card, the reset owner will
970462306a36Sopenharmony_ci	 * start & initialize the firmware. The other functions
970562306a36Sopenharmony_ci	 * on the card will reset the firmware context
970662306a36Sopenharmony_ci	 */
970762306a36Sopenharmony_ci	if (!fn) {
970862306a36Sopenharmony_ci		ql4_printk(KERN_INFO, ha, "scsi%ld: %s: devfn being reset "
970962306a36Sopenharmony_ci		    "0x%x is the owner\n", ha->host_no, __func__,
971062306a36Sopenharmony_ci		    ha->pdev->devfn);
971162306a36Sopenharmony_ci
971262306a36Sopenharmony_ci		ha->isp_ops->idc_lock(ha);
971362306a36Sopenharmony_ci		qla4_8xxx_wr_direct(ha, QLA8XXX_CRB_DEV_STATE,
971462306a36Sopenharmony_ci				    QLA8XXX_DEV_COLD);
971562306a36Sopenharmony_ci		ha->isp_ops->idc_unlock(ha);
971662306a36Sopenharmony_ci
971762306a36Sopenharmony_ci		rval = qla4_8xxx_update_idc_reg(ha);
971862306a36Sopenharmony_ci		if (rval == QLA_ERROR) {
971962306a36Sopenharmony_ci			ql4_printk(KERN_INFO, ha, "scsi%ld: %s: HW State: FAILED\n",
972062306a36Sopenharmony_ci				   ha->host_no, __func__);
972162306a36Sopenharmony_ci			ha->isp_ops->idc_lock(ha);
972262306a36Sopenharmony_ci			qla4_8xxx_wr_direct(ha, QLA8XXX_CRB_DEV_STATE,
972362306a36Sopenharmony_ci					    QLA8XXX_DEV_FAILED);
972462306a36Sopenharmony_ci			ha->isp_ops->idc_unlock(ha);
972562306a36Sopenharmony_ci			goto exit_error_recovery;
972662306a36Sopenharmony_ci		}
972762306a36Sopenharmony_ci
972862306a36Sopenharmony_ci		clear_bit(AF_FW_RECOVERY, &ha->flags);
972962306a36Sopenharmony_ci		rval = qla4xxx_initialize_adapter(ha, RESET_ADAPTER);
973062306a36Sopenharmony_ci
973162306a36Sopenharmony_ci		if (rval != QLA_SUCCESS) {
973262306a36Sopenharmony_ci			ql4_printk(KERN_INFO, ha, "scsi%ld: %s: HW State: "
973362306a36Sopenharmony_ci			    "FAILED\n", ha->host_no, __func__);
973462306a36Sopenharmony_ci			qla4xxx_free_irqs(ha);
973562306a36Sopenharmony_ci			ha->isp_ops->idc_lock(ha);
973662306a36Sopenharmony_ci			qla4_8xxx_clear_drv_active(ha);
973762306a36Sopenharmony_ci			qla4_8xxx_wr_direct(ha, QLA8XXX_CRB_DEV_STATE,
973862306a36Sopenharmony_ci					    QLA8XXX_DEV_FAILED);
973962306a36Sopenharmony_ci			ha->isp_ops->idc_unlock(ha);
974062306a36Sopenharmony_ci		} else {
974162306a36Sopenharmony_ci			ql4_printk(KERN_INFO, ha, "scsi%ld: %s: HW State: "
974262306a36Sopenharmony_ci			    "READY\n", ha->host_no, __func__);
974362306a36Sopenharmony_ci			ha->isp_ops->idc_lock(ha);
974462306a36Sopenharmony_ci			qla4_8xxx_wr_direct(ha, QLA8XXX_CRB_DEV_STATE,
974562306a36Sopenharmony_ci					    QLA8XXX_DEV_READY);
974662306a36Sopenharmony_ci			/* Clear driver state register */
974762306a36Sopenharmony_ci			qla4_8xxx_wr_direct(ha, QLA8XXX_CRB_DRV_STATE, 0);
974862306a36Sopenharmony_ci			qla4_8xxx_set_drv_active(ha);
974962306a36Sopenharmony_ci			ha->isp_ops->idc_unlock(ha);
975062306a36Sopenharmony_ci			ha->isp_ops->enable_intrs(ha);
975162306a36Sopenharmony_ci		}
975262306a36Sopenharmony_ci	} else {
975362306a36Sopenharmony_ci		ql4_printk(KERN_INFO, ha, "scsi%ld: %s: devfn 0x%x is not "
975462306a36Sopenharmony_ci		    "the reset owner\n", ha->host_no, __func__,
975562306a36Sopenharmony_ci		    ha->pdev->devfn);
975662306a36Sopenharmony_ci		if ((qla4_8xxx_rd_direct(ha, QLA8XXX_CRB_DEV_STATE) ==
975762306a36Sopenharmony_ci		     QLA8XXX_DEV_READY)) {
975862306a36Sopenharmony_ci			clear_bit(AF_FW_RECOVERY, &ha->flags);
975962306a36Sopenharmony_ci			rval = qla4xxx_initialize_adapter(ha, RESET_ADAPTER);
976062306a36Sopenharmony_ci			if (rval == QLA_SUCCESS)
976162306a36Sopenharmony_ci				ha->isp_ops->enable_intrs(ha);
976262306a36Sopenharmony_ci			else
976362306a36Sopenharmony_ci				qla4xxx_free_irqs(ha);
976462306a36Sopenharmony_ci
976562306a36Sopenharmony_ci			ha->isp_ops->idc_lock(ha);
976662306a36Sopenharmony_ci			qla4_8xxx_set_drv_active(ha);
976762306a36Sopenharmony_ci			ha->isp_ops->idc_unlock(ha);
976862306a36Sopenharmony_ci		}
976962306a36Sopenharmony_ci	}
977062306a36Sopenharmony_ciexit_error_recovery:
977162306a36Sopenharmony_ci	clear_bit(DPC_RESET_ACTIVE, &ha->dpc_flags);
977262306a36Sopenharmony_ci	return rval;
977362306a36Sopenharmony_ci}
977462306a36Sopenharmony_ci
977562306a36Sopenharmony_cistatic pci_ers_result_t
977662306a36Sopenharmony_ciqla4xxx_pci_slot_reset(struct pci_dev *pdev)
977762306a36Sopenharmony_ci{
977862306a36Sopenharmony_ci	pci_ers_result_t ret = PCI_ERS_RESULT_DISCONNECT;
977962306a36Sopenharmony_ci	struct scsi_qla_host *ha = pci_get_drvdata(pdev);
978062306a36Sopenharmony_ci	int rc;
978162306a36Sopenharmony_ci
978262306a36Sopenharmony_ci	ql4_printk(KERN_WARNING, ha, "scsi%ld: %s: slot_reset\n",
978362306a36Sopenharmony_ci	    ha->host_no, __func__);
978462306a36Sopenharmony_ci
978562306a36Sopenharmony_ci	if (!is_aer_supported(ha))
978662306a36Sopenharmony_ci		return PCI_ERS_RESULT_NONE;
978762306a36Sopenharmony_ci
978862306a36Sopenharmony_ci	/* Restore the saved state of PCIe device -
978962306a36Sopenharmony_ci	 * BAR registers, PCI Config space, PCIX, MSI,
979062306a36Sopenharmony_ci	 * IOV states
979162306a36Sopenharmony_ci	 */
979262306a36Sopenharmony_ci	pci_restore_state(pdev);
979362306a36Sopenharmony_ci
979462306a36Sopenharmony_ci	/* pci_restore_state() clears the saved_state flag of the device
979562306a36Sopenharmony_ci	 * save restored state which resets saved_state flag
979662306a36Sopenharmony_ci	 */
979762306a36Sopenharmony_ci	pci_save_state(pdev);
979862306a36Sopenharmony_ci
979962306a36Sopenharmony_ci	/* Initialize device or resume if in suspended state */
980062306a36Sopenharmony_ci	rc = pci_enable_device(pdev);
980162306a36Sopenharmony_ci	if (rc) {
980262306a36Sopenharmony_ci		ql4_printk(KERN_WARNING, ha, "scsi%ld: %s: Can't re-enable "
980362306a36Sopenharmony_ci		    "device after reset\n", ha->host_no, __func__);
980462306a36Sopenharmony_ci		goto exit_slot_reset;
980562306a36Sopenharmony_ci	}
980662306a36Sopenharmony_ci
980762306a36Sopenharmony_ci	ha->isp_ops->disable_intrs(ha);
980862306a36Sopenharmony_ci
980962306a36Sopenharmony_ci	if (is_qla80XX(ha)) {
981062306a36Sopenharmony_ci		if (qla4_8xxx_error_recovery(ha) == QLA_SUCCESS) {
981162306a36Sopenharmony_ci			ret = PCI_ERS_RESULT_RECOVERED;
981262306a36Sopenharmony_ci			goto exit_slot_reset;
981362306a36Sopenharmony_ci		} else
981462306a36Sopenharmony_ci			goto exit_slot_reset;
981562306a36Sopenharmony_ci	}
981662306a36Sopenharmony_ci
981762306a36Sopenharmony_ciexit_slot_reset:
981862306a36Sopenharmony_ci	ql4_printk(KERN_WARNING, ha, "scsi%ld: %s: Return=%x\n"
981962306a36Sopenharmony_ci	    "device after reset\n", ha->host_no, __func__, ret);
982062306a36Sopenharmony_ci	return ret;
982162306a36Sopenharmony_ci}
982262306a36Sopenharmony_ci
982362306a36Sopenharmony_cistatic void
982462306a36Sopenharmony_ciqla4xxx_pci_resume(struct pci_dev *pdev)
982562306a36Sopenharmony_ci{
982662306a36Sopenharmony_ci	struct scsi_qla_host *ha = pci_get_drvdata(pdev);
982762306a36Sopenharmony_ci	int ret;
982862306a36Sopenharmony_ci
982962306a36Sopenharmony_ci	ql4_printk(KERN_WARNING, ha, "scsi%ld: %s: pci_resume\n",
983062306a36Sopenharmony_ci	    ha->host_no, __func__);
983162306a36Sopenharmony_ci
983262306a36Sopenharmony_ci	ret = qla4xxx_wait_for_hba_online(ha);
983362306a36Sopenharmony_ci	if (ret != QLA_SUCCESS) {
983462306a36Sopenharmony_ci		ql4_printk(KERN_ERR, ha, "scsi%ld: %s: the device failed to "
983562306a36Sopenharmony_ci		    "resume I/O from slot/link_reset\n", ha->host_no,
983662306a36Sopenharmony_ci		     __func__);
983762306a36Sopenharmony_ci	}
983862306a36Sopenharmony_ci
983962306a36Sopenharmony_ci	clear_bit(AF_EEH_BUSY, &ha->flags);
984062306a36Sopenharmony_ci}
984162306a36Sopenharmony_ci
984262306a36Sopenharmony_cistatic const struct pci_error_handlers qla4xxx_err_handler = {
984362306a36Sopenharmony_ci	.error_detected = qla4xxx_pci_error_detected,
984462306a36Sopenharmony_ci	.mmio_enabled = qla4xxx_pci_mmio_enabled,
984562306a36Sopenharmony_ci	.slot_reset = qla4xxx_pci_slot_reset,
984662306a36Sopenharmony_ci	.resume = qla4xxx_pci_resume,
984762306a36Sopenharmony_ci};
984862306a36Sopenharmony_ci
984962306a36Sopenharmony_cistatic struct pci_device_id qla4xxx_pci_tbl[] = {
985062306a36Sopenharmony_ci	{
985162306a36Sopenharmony_ci		.vendor		= PCI_VENDOR_ID_QLOGIC,
985262306a36Sopenharmony_ci		.device		= PCI_DEVICE_ID_QLOGIC_ISP4010,
985362306a36Sopenharmony_ci		.subvendor	= PCI_ANY_ID,
985462306a36Sopenharmony_ci		.subdevice	= PCI_ANY_ID,
985562306a36Sopenharmony_ci	},
985662306a36Sopenharmony_ci	{
985762306a36Sopenharmony_ci		.vendor		= PCI_VENDOR_ID_QLOGIC,
985862306a36Sopenharmony_ci		.device		= PCI_DEVICE_ID_QLOGIC_ISP4022,
985962306a36Sopenharmony_ci		.subvendor	= PCI_ANY_ID,
986062306a36Sopenharmony_ci		.subdevice	= PCI_ANY_ID,
986162306a36Sopenharmony_ci	},
986262306a36Sopenharmony_ci	{
986362306a36Sopenharmony_ci		.vendor		= PCI_VENDOR_ID_QLOGIC,
986462306a36Sopenharmony_ci		.device		= PCI_DEVICE_ID_QLOGIC_ISP4032,
986562306a36Sopenharmony_ci		.subvendor	= PCI_ANY_ID,
986662306a36Sopenharmony_ci		.subdevice	= PCI_ANY_ID,
986762306a36Sopenharmony_ci	},
986862306a36Sopenharmony_ci	{
986962306a36Sopenharmony_ci		.vendor         = PCI_VENDOR_ID_QLOGIC,
987062306a36Sopenharmony_ci		.device         = PCI_DEVICE_ID_QLOGIC_ISP8022,
987162306a36Sopenharmony_ci		.subvendor      = PCI_ANY_ID,
987262306a36Sopenharmony_ci		.subdevice      = PCI_ANY_ID,
987362306a36Sopenharmony_ci	},
987462306a36Sopenharmony_ci	{
987562306a36Sopenharmony_ci		.vendor		= PCI_VENDOR_ID_QLOGIC,
987662306a36Sopenharmony_ci		.device		= PCI_DEVICE_ID_QLOGIC_ISP8324,
987762306a36Sopenharmony_ci		.subvendor	= PCI_ANY_ID,
987862306a36Sopenharmony_ci		.subdevice	= PCI_ANY_ID,
987962306a36Sopenharmony_ci	},
988062306a36Sopenharmony_ci	{
988162306a36Sopenharmony_ci		.vendor		= PCI_VENDOR_ID_QLOGIC,
988262306a36Sopenharmony_ci		.device		= PCI_DEVICE_ID_QLOGIC_ISP8042,
988362306a36Sopenharmony_ci		.subvendor	= PCI_ANY_ID,
988462306a36Sopenharmony_ci		.subdevice	= PCI_ANY_ID,
988562306a36Sopenharmony_ci	},
988662306a36Sopenharmony_ci	{0, 0},
988762306a36Sopenharmony_ci};
988862306a36Sopenharmony_ciMODULE_DEVICE_TABLE(pci, qla4xxx_pci_tbl);
988962306a36Sopenharmony_ci
989062306a36Sopenharmony_cistatic struct pci_driver qla4xxx_pci_driver = {
989162306a36Sopenharmony_ci	.name		= DRIVER_NAME,
989262306a36Sopenharmony_ci	.id_table	= qla4xxx_pci_tbl,
989362306a36Sopenharmony_ci	.probe		= qla4xxx_probe_adapter,
989462306a36Sopenharmony_ci	.remove		= qla4xxx_remove_adapter,
989562306a36Sopenharmony_ci	.err_handler = &qla4xxx_err_handler,
989662306a36Sopenharmony_ci};
989762306a36Sopenharmony_ci
989862306a36Sopenharmony_cistatic int __init qla4xxx_module_init(void)
989962306a36Sopenharmony_ci{
990062306a36Sopenharmony_ci	int ret;
990162306a36Sopenharmony_ci
990262306a36Sopenharmony_ci	if (ql4xqfulltracking)
990362306a36Sopenharmony_ci		qla4xxx_driver_template.track_queue_depth = 1;
990462306a36Sopenharmony_ci
990562306a36Sopenharmony_ci	/* Allocate cache for SRBs. */
990662306a36Sopenharmony_ci	srb_cachep = kmem_cache_create("qla4xxx_srbs", sizeof(struct srb), 0,
990762306a36Sopenharmony_ci				       SLAB_HWCACHE_ALIGN, NULL);
990862306a36Sopenharmony_ci	if (srb_cachep == NULL) {
990962306a36Sopenharmony_ci		printk(KERN_ERR
991062306a36Sopenharmony_ci		       "%s: Unable to allocate SRB cache..."
991162306a36Sopenharmony_ci		       "Failing load!\n", DRIVER_NAME);
991262306a36Sopenharmony_ci		ret = -ENOMEM;
991362306a36Sopenharmony_ci		goto no_srp_cache;
991462306a36Sopenharmony_ci	}
991562306a36Sopenharmony_ci
991662306a36Sopenharmony_ci	/* Derive version string. */
991762306a36Sopenharmony_ci	strcpy(qla4xxx_version_str, QLA4XXX_DRIVER_VERSION);
991862306a36Sopenharmony_ci	if (ql4xextended_error_logging)
991962306a36Sopenharmony_ci		strcat(qla4xxx_version_str, "-debug");
992062306a36Sopenharmony_ci
992162306a36Sopenharmony_ci	qla4xxx_scsi_transport =
992262306a36Sopenharmony_ci		iscsi_register_transport(&qla4xxx_iscsi_transport);
992362306a36Sopenharmony_ci	if (!qla4xxx_scsi_transport){
992462306a36Sopenharmony_ci		ret = -ENODEV;
992562306a36Sopenharmony_ci		goto release_srb_cache;
992662306a36Sopenharmony_ci	}
992762306a36Sopenharmony_ci
992862306a36Sopenharmony_ci	ret = pci_register_driver(&qla4xxx_pci_driver);
992962306a36Sopenharmony_ci	if (ret)
993062306a36Sopenharmony_ci		goto unregister_transport;
993162306a36Sopenharmony_ci
993262306a36Sopenharmony_ci	printk(KERN_INFO "QLogic iSCSI HBA Driver\n");
993362306a36Sopenharmony_ci	return 0;
993462306a36Sopenharmony_ci
993562306a36Sopenharmony_ciunregister_transport:
993662306a36Sopenharmony_ci	iscsi_unregister_transport(&qla4xxx_iscsi_transport);
993762306a36Sopenharmony_cirelease_srb_cache:
993862306a36Sopenharmony_ci	kmem_cache_destroy(srb_cachep);
993962306a36Sopenharmony_cino_srp_cache:
994062306a36Sopenharmony_ci	return ret;
994162306a36Sopenharmony_ci}
994262306a36Sopenharmony_ci
994362306a36Sopenharmony_cistatic void __exit qla4xxx_module_exit(void)
994462306a36Sopenharmony_ci{
994562306a36Sopenharmony_ci	pci_unregister_driver(&qla4xxx_pci_driver);
994662306a36Sopenharmony_ci	iscsi_unregister_transport(&qla4xxx_iscsi_transport);
994762306a36Sopenharmony_ci	kmem_cache_destroy(srb_cachep);
994862306a36Sopenharmony_ci}
994962306a36Sopenharmony_ci
995062306a36Sopenharmony_cimodule_init(qla4xxx_module_init);
995162306a36Sopenharmony_cimodule_exit(qla4xxx_module_exit);
995262306a36Sopenharmony_ci
995362306a36Sopenharmony_ciMODULE_AUTHOR("QLogic Corporation");
995462306a36Sopenharmony_ciMODULE_DESCRIPTION("QLogic iSCSI HBA Driver");
995562306a36Sopenharmony_ciMODULE_LICENSE("GPL");
995662306a36Sopenharmony_ciMODULE_VERSION(QLA4XXX_DRIVER_VERSION);
9957