18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * QLogic iSCSI HBA Driver
48c2ecf20Sopenharmony_ci * Copyright (c)  2003-2013 QLogic Corporation
58c2ecf20Sopenharmony_ci */
68c2ecf20Sopenharmony_ci#include <linux/moduleparam.h>
78c2ecf20Sopenharmony_ci#include <linux/slab.h>
88c2ecf20Sopenharmony_ci#include <linux/blkdev.h>
98c2ecf20Sopenharmony_ci#include <linux/iscsi_boot_sysfs.h>
108c2ecf20Sopenharmony_ci#include <linux/inet.h>
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_ci#include <scsi/scsi_tcq.h>
138c2ecf20Sopenharmony_ci#include <scsi/scsicam.h>
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_ci#include "ql4_def.h"
168c2ecf20Sopenharmony_ci#include "ql4_version.h"
178c2ecf20Sopenharmony_ci#include "ql4_glbl.h"
188c2ecf20Sopenharmony_ci#include "ql4_dbg.h"
198c2ecf20Sopenharmony_ci#include "ql4_inline.h"
208c2ecf20Sopenharmony_ci#include "ql4_83xx.h"
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_ci/*
238c2ecf20Sopenharmony_ci * Driver version
248c2ecf20Sopenharmony_ci */
258c2ecf20Sopenharmony_cistatic char qla4xxx_version_str[40];
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_ci/*
288c2ecf20Sopenharmony_ci * SRB allocation cache
298c2ecf20Sopenharmony_ci */
308c2ecf20Sopenharmony_cistatic struct kmem_cache *srb_cachep;
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_ci/*
338c2ecf20Sopenharmony_ci * Module parameter information and variables
348c2ecf20Sopenharmony_ci */
358c2ecf20Sopenharmony_cistatic int ql4xdisablesysfsboot = 1;
368c2ecf20Sopenharmony_cimodule_param(ql4xdisablesysfsboot, int, S_IRUGO | S_IWUSR);
378c2ecf20Sopenharmony_ciMODULE_PARM_DESC(ql4xdisablesysfsboot,
388c2ecf20Sopenharmony_ci		 " Set to disable exporting boot targets to sysfs.\n"
398c2ecf20Sopenharmony_ci		 "\t\t  0 - Export boot targets\n"
408c2ecf20Sopenharmony_ci		 "\t\t  1 - Do not export boot targets (Default)");
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ciint ql4xdontresethba;
438c2ecf20Sopenharmony_cimodule_param(ql4xdontresethba, int, S_IRUGO | S_IWUSR);
448c2ecf20Sopenharmony_ciMODULE_PARM_DESC(ql4xdontresethba,
458c2ecf20Sopenharmony_ci		 " Don't reset the HBA for driver recovery.\n"
468c2ecf20Sopenharmony_ci		 "\t\t  0 - It will reset HBA (Default)\n"
478c2ecf20Sopenharmony_ci		 "\t\t  1 - It will NOT reset HBA");
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_ciint ql4xextended_error_logging;
508c2ecf20Sopenharmony_cimodule_param(ql4xextended_error_logging, int, S_IRUGO | S_IWUSR);
518c2ecf20Sopenharmony_ciMODULE_PARM_DESC(ql4xextended_error_logging,
528c2ecf20Sopenharmony_ci		 " Option to enable extended error logging.\n"
538c2ecf20Sopenharmony_ci		 "\t\t  0 - no logging (Default)\n"
548c2ecf20Sopenharmony_ci		 "\t\t  2 - debug logging");
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ciint ql4xenablemsix = 1;
578c2ecf20Sopenharmony_cimodule_param(ql4xenablemsix, int, S_IRUGO|S_IWUSR);
588c2ecf20Sopenharmony_ciMODULE_PARM_DESC(ql4xenablemsix,
598c2ecf20Sopenharmony_ci		 " Set to enable MSI or MSI-X interrupt mechanism.\n"
608c2ecf20Sopenharmony_ci		 "\t\t  0 = enable INTx interrupt mechanism.\n"
618c2ecf20Sopenharmony_ci		 "\t\t  1 = enable MSI-X interrupt mechanism (Default).\n"
628c2ecf20Sopenharmony_ci		 "\t\t  2 = enable MSI interrupt mechanism.");
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_ci#define QL4_DEF_QDEPTH 32
658c2ecf20Sopenharmony_cistatic int ql4xmaxqdepth = QL4_DEF_QDEPTH;
668c2ecf20Sopenharmony_cimodule_param(ql4xmaxqdepth, int, S_IRUGO | S_IWUSR);
678c2ecf20Sopenharmony_ciMODULE_PARM_DESC(ql4xmaxqdepth,
688c2ecf20Sopenharmony_ci		 " Maximum queue depth to report for target devices.\n"
698c2ecf20Sopenharmony_ci		 "\t\t  Default: 32.");
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_cistatic int ql4xqfulltracking = 1;
728c2ecf20Sopenharmony_cimodule_param(ql4xqfulltracking, int, S_IRUGO | S_IWUSR);
738c2ecf20Sopenharmony_ciMODULE_PARM_DESC(ql4xqfulltracking,
748c2ecf20Sopenharmony_ci		 " Enable or disable dynamic tracking and adjustment of\n"
758c2ecf20Sopenharmony_ci		 "\t\t scsi device queue depth.\n"
768c2ecf20Sopenharmony_ci		 "\t\t  0 - Disable.\n"
778c2ecf20Sopenharmony_ci		 "\t\t  1 - Enable. (Default)");
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_cistatic int ql4xsess_recovery_tmo = QL4_SESS_RECOVERY_TMO;
808c2ecf20Sopenharmony_cimodule_param(ql4xsess_recovery_tmo, int, S_IRUGO);
818c2ecf20Sopenharmony_ciMODULE_PARM_DESC(ql4xsess_recovery_tmo,
828c2ecf20Sopenharmony_ci		" Target Session Recovery Timeout.\n"
838c2ecf20Sopenharmony_ci		"\t\t  Default: 120 sec.");
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ciint ql4xmdcapmask = 0;
868c2ecf20Sopenharmony_cimodule_param(ql4xmdcapmask, int, S_IRUGO);
878c2ecf20Sopenharmony_ciMODULE_PARM_DESC(ql4xmdcapmask,
888c2ecf20Sopenharmony_ci		 " Set the Minidump driver capture mask level.\n"
898c2ecf20Sopenharmony_ci		 "\t\t  Default is 0 (firmware default capture mask)\n"
908c2ecf20Sopenharmony_ci		 "\t\t  Can be set to 0x3, 0x7, 0xF, 0x1F, 0x3F, 0x7F, 0xFF");
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_ciint ql4xenablemd = 1;
938c2ecf20Sopenharmony_cimodule_param(ql4xenablemd, int, S_IRUGO | S_IWUSR);
948c2ecf20Sopenharmony_ciMODULE_PARM_DESC(ql4xenablemd,
958c2ecf20Sopenharmony_ci		 " Set to enable minidump.\n"
968c2ecf20Sopenharmony_ci		 "\t\t  0 - disable minidump\n"
978c2ecf20Sopenharmony_ci		 "\t\t  1 - enable minidump (Default)");
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_cistatic int qla4xxx_wait_for_hba_online(struct scsi_qla_host *ha);
1008c2ecf20Sopenharmony_ci/*
1018c2ecf20Sopenharmony_ci * SCSI host template entry points
1028c2ecf20Sopenharmony_ci */
1038c2ecf20Sopenharmony_cistatic void qla4xxx_config_dma_addressing(struct scsi_qla_host *ha);
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_ci/*
1068c2ecf20Sopenharmony_ci * iSCSI template entry points
1078c2ecf20Sopenharmony_ci */
1088c2ecf20Sopenharmony_cistatic int qla4xxx_session_get_param(struct iscsi_cls_session *cls_sess,
1098c2ecf20Sopenharmony_ci				     enum iscsi_param param, char *buf);
1108c2ecf20Sopenharmony_cistatic int qla4xxx_conn_get_param(struct iscsi_cls_conn *conn,
1118c2ecf20Sopenharmony_ci				  enum iscsi_param param, char *buf);
1128c2ecf20Sopenharmony_cistatic int qla4xxx_host_get_param(struct Scsi_Host *shost,
1138c2ecf20Sopenharmony_ci				  enum iscsi_host_param param, char *buf);
1148c2ecf20Sopenharmony_cistatic int qla4xxx_iface_set_param(struct Scsi_Host *shost, void *data,
1158c2ecf20Sopenharmony_ci				   uint32_t len);
1168c2ecf20Sopenharmony_cistatic int qla4xxx_get_iface_param(struct iscsi_iface *iface,
1178c2ecf20Sopenharmony_ci				   enum iscsi_param_type param_type,
1188c2ecf20Sopenharmony_ci				   int param, char *buf);
1198c2ecf20Sopenharmony_cistatic enum blk_eh_timer_return qla4xxx_eh_cmd_timed_out(struct scsi_cmnd *sc);
1208c2ecf20Sopenharmony_cistatic struct iscsi_endpoint *qla4xxx_ep_connect(struct Scsi_Host *shost,
1218c2ecf20Sopenharmony_ci						 struct sockaddr *dst_addr,
1228c2ecf20Sopenharmony_ci						 int non_blocking);
1238c2ecf20Sopenharmony_cistatic int qla4xxx_ep_poll(struct iscsi_endpoint *ep, int timeout_ms);
1248c2ecf20Sopenharmony_cistatic void qla4xxx_ep_disconnect(struct iscsi_endpoint *ep);
1258c2ecf20Sopenharmony_cistatic int qla4xxx_get_ep_param(struct iscsi_endpoint *ep,
1268c2ecf20Sopenharmony_ci				enum iscsi_param param, char *buf);
1278c2ecf20Sopenharmony_cistatic int qla4xxx_conn_start(struct iscsi_cls_conn *conn);
1288c2ecf20Sopenharmony_cistatic struct iscsi_cls_conn *
1298c2ecf20Sopenharmony_ciqla4xxx_conn_create(struct iscsi_cls_session *cls_sess, uint32_t conn_idx);
1308c2ecf20Sopenharmony_cistatic int qla4xxx_conn_bind(struct iscsi_cls_session *cls_session,
1318c2ecf20Sopenharmony_ci			     struct iscsi_cls_conn *cls_conn,
1328c2ecf20Sopenharmony_ci			     uint64_t transport_fd, int is_leading);
1338c2ecf20Sopenharmony_cistatic void qla4xxx_conn_destroy(struct iscsi_cls_conn *conn);
1348c2ecf20Sopenharmony_cistatic struct iscsi_cls_session *
1358c2ecf20Sopenharmony_ciqla4xxx_session_create(struct iscsi_endpoint *ep, uint16_t cmds_max,
1368c2ecf20Sopenharmony_ci			uint16_t qdepth, uint32_t initial_cmdsn);
1378c2ecf20Sopenharmony_cistatic void qla4xxx_session_destroy(struct iscsi_cls_session *sess);
1388c2ecf20Sopenharmony_cistatic void qla4xxx_task_work(struct work_struct *wdata);
1398c2ecf20Sopenharmony_cistatic int qla4xxx_alloc_pdu(struct iscsi_task *, uint8_t);
1408c2ecf20Sopenharmony_cistatic int qla4xxx_task_xmit(struct iscsi_task *);
1418c2ecf20Sopenharmony_cistatic void qla4xxx_task_cleanup(struct iscsi_task *);
1428c2ecf20Sopenharmony_cistatic void qla4xxx_fail_session(struct iscsi_cls_session *cls_session);
1438c2ecf20Sopenharmony_cistatic void qla4xxx_conn_get_stats(struct iscsi_cls_conn *cls_conn,
1448c2ecf20Sopenharmony_ci				   struct iscsi_stats *stats);
1458c2ecf20Sopenharmony_cistatic int qla4xxx_send_ping(struct Scsi_Host *shost, uint32_t iface_num,
1468c2ecf20Sopenharmony_ci			     uint32_t iface_type, uint32_t payload_size,
1478c2ecf20Sopenharmony_ci			     uint32_t pid, struct sockaddr *dst_addr);
1488c2ecf20Sopenharmony_cistatic int qla4xxx_get_chap_list(struct Scsi_Host *shost, uint16_t chap_tbl_idx,
1498c2ecf20Sopenharmony_ci				 uint32_t *num_entries, char *buf);
1508c2ecf20Sopenharmony_cistatic int qla4xxx_delete_chap(struct Scsi_Host *shost, uint16_t chap_tbl_idx);
1518c2ecf20Sopenharmony_cistatic int qla4xxx_set_chap_entry(struct Scsi_Host *shost, void  *data,
1528c2ecf20Sopenharmony_ci				  int len);
1538c2ecf20Sopenharmony_cistatic int qla4xxx_get_host_stats(struct Scsi_Host *shost, char *buf, int len);
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_ci/*
1568c2ecf20Sopenharmony_ci * SCSI host template entry points
1578c2ecf20Sopenharmony_ci */
1588c2ecf20Sopenharmony_cistatic int qla4xxx_queuecommand(struct Scsi_Host *h, struct scsi_cmnd *cmd);
1598c2ecf20Sopenharmony_cistatic int qla4xxx_eh_abort(struct scsi_cmnd *cmd);
1608c2ecf20Sopenharmony_cistatic int qla4xxx_eh_device_reset(struct scsi_cmnd *cmd);
1618c2ecf20Sopenharmony_cistatic int qla4xxx_eh_target_reset(struct scsi_cmnd *cmd);
1628c2ecf20Sopenharmony_cistatic int qla4xxx_eh_host_reset(struct scsi_cmnd *cmd);
1638c2ecf20Sopenharmony_cistatic int qla4xxx_slave_alloc(struct scsi_device *device);
1648c2ecf20Sopenharmony_cistatic umode_t qla4_attr_is_visible(int param_type, int param);
1658c2ecf20Sopenharmony_cistatic int qla4xxx_host_reset(struct Scsi_Host *shost, int reset_type);
1668c2ecf20Sopenharmony_ci
1678c2ecf20Sopenharmony_ci/*
1688c2ecf20Sopenharmony_ci * iSCSI Flash DDB sysfs entry points
1698c2ecf20Sopenharmony_ci */
1708c2ecf20Sopenharmony_cistatic int
1718c2ecf20Sopenharmony_ciqla4xxx_sysfs_ddb_set_param(struct iscsi_bus_flash_session *fnode_sess,
1728c2ecf20Sopenharmony_ci			    struct iscsi_bus_flash_conn *fnode_conn,
1738c2ecf20Sopenharmony_ci			    void *data, int len);
1748c2ecf20Sopenharmony_cistatic int
1758c2ecf20Sopenharmony_ciqla4xxx_sysfs_ddb_get_param(struct iscsi_bus_flash_session *fnode_sess,
1768c2ecf20Sopenharmony_ci			    int param, char *buf);
1778c2ecf20Sopenharmony_cistatic int qla4xxx_sysfs_ddb_add(struct Scsi_Host *shost, const char *buf,
1788c2ecf20Sopenharmony_ci				 int len);
1798c2ecf20Sopenharmony_cistatic int
1808c2ecf20Sopenharmony_ciqla4xxx_sysfs_ddb_delete(struct iscsi_bus_flash_session *fnode_sess);
1818c2ecf20Sopenharmony_cistatic int qla4xxx_sysfs_ddb_login(struct iscsi_bus_flash_session *fnode_sess,
1828c2ecf20Sopenharmony_ci				   struct iscsi_bus_flash_conn *fnode_conn);
1838c2ecf20Sopenharmony_cistatic int qla4xxx_sysfs_ddb_logout(struct iscsi_bus_flash_session *fnode_sess,
1848c2ecf20Sopenharmony_ci				    struct iscsi_bus_flash_conn *fnode_conn);
1858c2ecf20Sopenharmony_cistatic int qla4xxx_sysfs_ddb_logout_sid(struct iscsi_cls_session *cls_sess);
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_cistatic struct qla4_8xxx_legacy_intr_set legacy_intr[] =
1888c2ecf20Sopenharmony_ci    QLA82XX_LEGACY_INTR_CONFIG;
1898c2ecf20Sopenharmony_ci
1908c2ecf20Sopenharmony_cistatic const uint32_t qla4_82xx_reg_tbl[] = {
1918c2ecf20Sopenharmony_ci	QLA82XX_PEG_HALT_STATUS1,
1928c2ecf20Sopenharmony_ci	QLA82XX_PEG_HALT_STATUS2,
1938c2ecf20Sopenharmony_ci	QLA82XX_PEG_ALIVE_COUNTER,
1948c2ecf20Sopenharmony_ci	QLA82XX_CRB_DRV_ACTIVE,
1958c2ecf20Sopenharmony_ci	QLA82XX_CRB_DEV_STATE,
1968c2ecf20Sopenharmony_ci	QLA82XX_CRB_DRV_STATE,
1978c2ecf20Sopenharmony_ci	QLA82XX_CRB_DRV_SCRATCH,
1988c2ecf20Sopenharmony_ci	QLA82XX_CRB_DEV_PART_INFO,
1998c2ecf20Sopenharmony_ci	QLA82XX_CRB_DRV_IDC_VERSION,
2008c2ecf20Sopenharmony_ci	QLA82XX_FW_VERSION_MAJOR,
2018c2ecf20Sopenharmony_ci	QLA82XX_FW_VERSION_MINOR,
2028c2ecf20Sopenharmony_ci	QLA82XX_FW_VERSION_SUB,
2038c2ecf20Sopenharmony_ci	CRB_CMDPEG_STATE,
2048c2ecf20Sopenharmony_ci	CRB_TEMP_STATE,
2058c2ecf20Sopenharmony_ci};
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_cistatic const uint32_t qla4_83xx_reg_tbl[] = {
2088c2ecf20Sopenharmony_ci	QLA83XX_PEG_HALT_STATUS1,
2098c2ecf20Sopenharmony_ci	QLA83XX_PEG_HALT_STATUS2,
2108c2ecf20Sopenharmony_ci	QLA83XX_PEG_ALIVE_COUNTER,
2118c2ecf20Sopenharmony_ci	QLA83XX_CRB_DRV_ACTIVE,
2128c2ecf20Sopenharmony_ci	QLA83XX_CRB_DEV_STATE,
2138c2ecf20Sopenharmony_ci	QLA83XX_CRB_DRV_STATE,
2148c2ecf20Sopenharmony_ci	QLA83XX_CRB_DRV_SCRATCH,
2158c2ecf20Sopenharmony_ci	QLA83XX_CRB_DEV_PART_INFO1,
2168c2ecf20Sopenharmony_ci	QLA83XX_CRB_IDC_VER_MAJOR,
2178c2ecf20Sopenharmony_ci	QLA83XX_FW_VER_MAJOR,
2188c2ecf20Sopenharmony_ci	QLA83XX_FW_VER_MINOR,
2198c2ecf20Sopenharmony_ci	QLA83XX_FW_VER_SUB,
2208c2ecf20Sopenharmony_ci	QLA83XX_CMDPEG_STATE,
2218c2ecf20Sopenharmony_ci	QLA83XX_ASIC_TEMP,
2228c2ecf20Sopenharmony_ci};
2238c2ecf20Sopenharmony_ci
2248c2ecf20Sopenharmony_cistatic struct scsi_host_template qla4xxx_driver_template = {
2258c2ecf20Sopenharmony_ci	.module			= THIS_MODULE,
2268c2ecf20Sopenharmony_ci	.name			= DRIVER_NAME,
2278c2ecf20Sopenharmony_ci	.proc_name		= DRIVER_NAME,
2288c2ecf20Sopenharmony_ci	.queuecommand		= qla4xxx_queuecommand,
2298c2ecf20Sopenharmony_ci
2308c2ecf20Sopenharmony_ci	.eh_abort_handler	= qla4xxx_eh_abort,
2318c2ecf20Sopenharmony_ci	.eh_device_reset_handler = qla4xxx_eh_device_reset,
2328c2ecf20Sopenharmony_ci	.eh_target_reset_handler = qla4xxx_eh_target_reset,
2338c2ecf20Sopenharmony_ci	.eh_host_reset_handler	= qla4xxx_eh_host_reset,
2348c2ecf20Sopenharmony_ci	.eh_timed_out		= qla4xxx_eh_cmd_timed_out,
2358c2ecf20Sopenharmony_ci
2368c2ecf20Sopenharmony_ci	.slave_alloc		= qla4xxx_slave_alloc,
2378c2ecf20Sopenharmony_ci	.change_queue_depth	= scsi_change_queue_depth,
2388c2ecf20Sopenharmony_ci
2398c2ecf20Sopenharmony_ci	.this_id		= -1,
2408c2ecf20Sopenharmony_ci	.cmd_per_lun		= 3,
2418c2ecf20Sopenharmony_ci	.sg_tablesize		= SG_ALL,
2428c2ecf20Sopenharmony_ci
2438c2ecf20Sopenharmony_ci	.max_sectors		= 0xFFFF,
2448c2ecf20Sopenharmony_ci	.shost_attrs		= qla4xxx_host_attrs,
2458c2ecf20Sopenharmony_ci	.host_reset		= qla4xxx_host_reset,
2468c2ecf20Sopenharmony_ci	.vendor_id		= SCSI_NL_VID_TYPE_PCI | PCI_VENDOR_ID_QLOGIC,
2478c2ecf20Sopenharmony_ci};
2488c2ecf20Sopenharmony_ci
2498c2ecf20Sopenharmony_cistatic struct iscsi_transport qla4xxx_iscsi_transport = {
2508c2ecf20Sopenharmony_ci	.owner			= THIS_MODULE,
2518c2ecf20Sopenharmony_ci	.name			= DRIVER_NAME,
2528c2ecf20Sopenharmony_ci	.caps			= CAP_TEXT_NEGO |
2538c2ecf20Sopenharmony_ci				  CAP_DATA_PATH_OFFLOAD | CAP_HDRDGST |
2548c2ecf20Sopenharmony_ci				  CAP_DATADGST | CAP_LOGIN_OFFLOAD |
2558c2ecf20Sopenharmony_ci				  CAP_MULTI_R2T,
2568c2ecf20Sopenharmony_ci	.attr_is_visible	= qla4_attr_is_visible,
2578c2ecf20Sopenharmony_ci	.create_session         = qla4xxx_session_create,
2588c2ecf20Sopenharmony_ci	.destroy_session        = qla4xxx_session_destroy,
2598c2ecf20Sopenharmony_ci	.start_conn             = qla4xxx_conn_start,
2608c2ecf20Sopenharmony_ci	.create_conn            = qla4xxx_conn_create,
2618c2ecf20Sopenharmony_ci	.bind_conn              = qla4xxx_conn_bind,
2628c2ecf20Sopenharmony_ci	.unbind_conn		= iscsi_conn_unbind,
2638c2ecf20Sopenharmony_ci	.stop_conn              = iscsi_conn_stop,
2648c2ecf20Sopenharmony_ci	.destroy_conn           = qla4xxx_conn_destroy,
2658c2ecf20Sopenharmony_ci	.set_param              = iscsi_set_param,
2668c2ecf20Sopenharmony_ci	.get_conn_param		= qla4xxx_conn_get_param,
2678c2ecf20Sopenharmony_ci	.get_session_param	= qla4xxx_session_get_param,
2688c2ecf20Sopenharmony_ci	.get_ep_param           = qla4xxx_get_ep_param,
2698c2ecf20Sopenharmony_ci	.ep_connect		= qla4xxx_ep_connect,
2708c2ecf20Sopenharmony_ci	.ep_poll		= qla4xxx_ep_poll,
2718c2ecf20Sopenharmony_ci	.ep_disconnect		= qla4xxx_ep_disconnect,
2728c2ecf20Sopenharmony_ci	.get_stats		= qla4xxx_conn_get_stats,
2738c2ecf20Sopenharmony_ci	.send_pdu		= iscsi_conn_send_pdu,
2748c2ecf20Sopenharmony_ci	.xmit_task		= qla4xxx_task_xmit,
2758c2ecf20Sopenharmony_ci	.cleanup_task		= qla4xxx_task_cleanup,
2768c2ecf20Sopenharmony_ci	.alloc_pdu		= qla4xxx_alloc_pdu,
2778c2ecf20Sopenharmony_ci
2788c2ecf20Sopenharmony_ci	.get_host_param		= qla4xxx_host_get_param,
2798c2ecf20Sopenharmony_ci	.set_iface_param	= qla4xxx_iface_set_param,
2808c2ecf20Sopenharmony_ci	.get_iface_param	= qla4xxx_get_iface_param,
2818c2ecf20Sopenharmony_ci	.bsg_request		= qla4xxx_bsg_request,
2828c2ecf20Sopenharmony_ci	.send_ping		= qla4xxx_send_ping,
2838c2ecf20Sopenharmony_ci	.get_chap		= qla4xxx_get_chap_list,
2848c2ecf20Sopenharmony_ci	.delete_chap		= qla4xxx_delete_chap,
2858c2ecf20Sopenharmony_ci	.set_chap		= qla4xxx_set_chap_entry,
2868c2ecf20Sopenharmony_ci	.get_flashnode_param	= qla4xxx_sysfs_ddb_get_param,
2878c2ecf20Sopenharmony_ci	.set_flashnode_param	= qla4xxx_sysfs_ddb_set_param,
2888c2ecf20Sopenharmony_ci	.new_flashnode		= qla4xxx_sysfs_ddb_add,
2898c2ecf20Sopenharmony_ci	.del_flashnode		= qla4xxx_sysfs_ddb_delete,
2908c2ecf20Sopenharmony_ci	.login_flashnode	= qla4xxx_sysfs_ddb_login,
2918c2ecf20Sopenharmony_ci	.logout_flashnode	= qla4xxx_sysfs_ddb_logout,
2928c2ecf20Sopenharmony_ci	.logout_flashnode_sid	= qla4xxx_sysfs_ddb_logout_sid,
2938c2ecf20Sopenharmony_ci	.get_host_stats		= qla4xxx_get_host_stats,
2948c2ecf20Sopenharmony_ci};
2958c2ecf20Sopenharmony_ci
2968c2ecf20Sopenharmony_cistatic struct scsi_transport_template *qla4xxx_scsi_transport;
2978c2ecf20Sopenharmony_ci
2988c2ecf20Sopenharmony_cistatic int qla4xxx_isp_check_reg(struct scsi_qla_host *ha)
2998c2ecf20Sopenharmony_ci{
3008c2ecf20Sopenharmony_ci	u32 reg_val = 0;
3018c2ecf20Sopenharmony_ci	int rval = QLA_SUCCESS;
3028c2ecf20Sopenharmony_ci
3038c2ecf20Sopenharmony_ci	if (is_qla8022(ha))
3048c2ecf20Sopenharmony_ci		reg_val = readl(&ha->qla4_82xx_reg->host_status);
3058c2ecf20Sopenharmony_ci	else if (is_qla8032(ha) || is_qla8042(ha))
3068c2ecf20Sopenharmony_ci		reg_val = qla4_8xxx_rd_direct(ha, QLA8XXX_PEG_ALIVE_COUNTER);
3078c2ecf20Sopenharmony_ci	else
3088c2ecf20Sopenharmony_ci		reg_val = readw(&ha->reg->ctrl_status);
3098c2ecf20Sopenharmony_ci
3108c2ecf20Sopenharmony_ci	if (reg_val == QL4_ISP_REG_DISCONNECT)
3118c2ecf20Sopenharmony_ci		rval = QLA_ERROR;
3128c2ecf20Sopenharmony_ci
3138c2ecf20Sopenharmony_ci	return rval;
3148c2ecf20Sopenharmony_ci}
3158c2ecf20Sopenharmony_ci
3168c2ecf20Sopenharmony_cistatic int qla4xxx_send_ping(struct Scsi_Host *shost, uint32_t iface_num,
3178c2ecf20Sopenharmony_ci			     uint32_t iface_type, uint32_t payload_size,
3188c2ecf20Sopenharmony_ci			     uint32_t pid, struct sockaddr *dst_addr)
3198c2ecf20Sopenharmony_ci{
3208c2ecf20Sopenharmony_ci	struct scsi_qla_host *ha = to_qla_host(shost);
3218c2ecf20Sopenharmony_ci	struct sockaddr_in *addr;
3228c2ecf20Sopenharmony_ci	struct sockaddr_in6 *addr6;
3238c2ecf20Sopenharmony_ci	uint32_t options = 0;
3248c2ecf20Sopenharmony_ci	uint8_t ipaddr[IPv6_ADDR_LEN];
3258c2ecf20Sopenharmony_ci	int rval;
3268c2ecf20Sopenharmony_ci
3278c2ecf20Sopenharmony_ci	memset(ipaddr, 0, IPv6_ADDR_LEN);
3288c2ecf20Sopenharmony_ci	/* IPv4 to IPv4 */
3298c2ecf20Sopenharmony_ci	if ((iface_type == ISCSI_IFACE_TYPE_IPV4) &&
3308c2ecf20Sopenharmony_ci	    (dst_addr->sa_family == AF_INET)) {
3318c2ecf20Sopenharmony_ci		addr = (struct sockaddr_in *)dst_addr;
3328c2ecf20Sopenharmony_ci		memcpy(ipaddr, &addr->sin_addr.s_addr, IP_ADDR_LEN);
3338c2ecf20Sopenharmony_ci		DEBUG2(ql4_printk(KERN_INFO, ha, "%s: IPv4 Ping src: %pI4 "
3348c2ecf20Sopenharmony_ci				  "dest: %pI4\n", __func__,
3358c2ecf20Sopenharmony_ci				  &ha->ip_config.ip_address, ipaddr));
3368c2ecf20Sopenharmony_ci		rval = qla4xxx_ping_iocb(ha, options, payload_size, pid,
3378c2ecf20Sopenharmony_ci					 ipaddr);
3388c2ecf20Sopenharmony_ci		if (rval)
3398c2ecf20Sopenharmony_ci			rval = -EINVAL;
3408c2ecf20Sopenharmony_ci	} else if ((iface_type == ISCSI_IFACE_TYPE_IPV6) &&
3418c2ecf20Sopenharmony_ci		   (dst_addr->sa_family == AF_INET6)) {
3428c2ecf20Sopenharmony_ci		/* IPv6 to IPv6 */
3438c2ecf20Sopenharmony_ci		addr6 = (struct sockaddr_in6 *)dst_addr;
3448c2ecf20Sopenharmony_ci		memcpy(ipaddr, &addr6->sin6_addr.in6_u.u6_addr8, IPv6_ADDR_LEN);
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_ci		options |= PING_IPV6_PROTOCOL_ENABLE;
3478c2ecf20Sopenharmony_ci
3488c2ecf20Sopenharmony_ci		/* Ping using LinkLocal address */
3498c2ecf20Sopenharmony_ci		if ((iface_num == 0) || (iface_num == 1)) {
3508c2ecf20Sopenharmony_ci			DEBUG2(ql4_printk(KERN_INFO, ha, "%s: LinkLocal Ping "
3518c2ecf20Sopenharmony_ci					  "src: %pI6 dest: %pI6\n", __func__,
3528c2ecf20Sopenharmony_ci					  &ha->ip_config.ipv6_link_local_addr,
3538c2ecf20Sopenharmony_ci					  ipaddr));
3548c2ecf20Sopenharmony_ci			options |= PING_IPV6_LINKLOCAL_ADDR;
3558c2ecf20Sopenharmony_ci			rval = qla4xxx_ping_iocb(ha, options, payload_size,
3568c2ecf20Sopenharmony_ci						 pid, ipaddr);
3578c2ecf20Sopenharmony_ci		} else {
3588c2ecf20Sopenharmony_ci			ql4_printk(KERN_WARNING, ha, "%s: iface num = %d "
3598c2ecf20Sopenharmony_ci				   "not supported\n", __func__, iface_num);
3608c2ecf20Sopenharmony_ci			rval = -ENOSYS;
3618c2ecf20Sopenharmony_ci			goto exit_send_ping;
3628c2ecf20Sopenharmony_ci		}
3638c2ecf20Sopenharmony_ci
3648c2ecf20Sopenharmony_ci		/*
3658c2ecf20Sopenharmony_ci		 * If ping using LinkLocal address fails, try ping using
3668c2ecf20Sopenharmony_ci		 * IPv6 address
3678c2ecf20Sopenharmony_ci		 */
3688c2ecf20Sopenharmony_ci		if (rval != QLA_SUCCESS) {
3698c2ecf20Sopenharmony_ci			options &= ~PING_IPV6_LINKLOCAL_ADDR;
3708c2ecf20Sopenharmony_ci			if (iface_num == 0) {
3718c2ecf20Sopenharmony_ci				options |= PING_IPV6_ADDR0;
3728c2ecf20Sopenharmony_ci				DEBUG2(ql4_printk(KERN_INFO, ha, "%s: IPv6 "
3738c2ecf20Sopenharmony_ci						  "Ping src: %pI6 "
3748c2ecf20Sopenharmony_ci						  "dest: %pI6\n", __func__,
3758c2ecf20Sopenharmony_ci						  &ha->ip_config.ipv6_addr0,
3768c2ecf20Sopenharmony_ci						  ipaddr));
3778c2ecf20Sopenharmony_ci			} else if (iface_num == 1) {
3788c2ecf20Sopenharmony_ci				options |= PING_IPV6_ADDR1;
3798c2ecf20Sopenharmony_ci				DEBUG2(ql4_printk(KERN_INFO, ha, "%s: IPv6 "
3808c2ecf20Sopenharmony_ci						  "Ping src: %pI6 "
3818c2ecf20Sopenharmony_ci						  "dest: %pI6\n", __func__,
3828c2ecf20Sopenharmony_ci						  &ha->ip_config.ipv6_addr1,
3838c2ecf20Sopenharmony_ci						  ipaddr));
3848c2ecf20Sopenharmony_ci			}
3858c2ecf20Sopenharmony_ci			rval = qla4xxx_ping_iocb(ha, options, payload_size,
3868c2ecf20Sopenharmony_ci						 pid, ipaddr);
3878c2ecf20Sopenharmony_ci			if (rval)
3888c2ecf20Sopenharmony_ci				rval = -EINVAL;
3898c2ecf20Sopenharmony_ci		}
3908c2ecf20Sopenharmony_ci	} else
3918c2ecf20Sopenharmony_ci		rval = -ENOSYS;
3928c2ecf20Sopenharmony_ciexit_send_ping:
3938c2ecf20Sopenharmony_ci	return rval;
3948c2ecf20Sopenharmony_ci}
3958c2ecf20Sopenharmony_ci
3968c2ecf20Sopenharmony_cistatic umode_t qla4_attr_is_visible(int param_type, int param)
3978c2ecf20Sopenharmony_ci{
3988c2ecf20Sopenharmony_ci	switch (param_type) {
3998c2ecf20Sopenharmony_ci	case ISCSI_HOST_PARAM:
4008c2ecf20Sopenharmony_ci		switch (param) {
4018c2ecf20Sopenharmony_ci		case ISCSI_HOST_PARAM_HWADDRESS:
4028c2ecf20Sopenharmony_ci		case ISCSI_HOST_PARAM_IPADDRESS:
4038c2ecf20Sopenharmony_ci		case ISCSI_HOST_PARAM_INITIATOR_NAME:
4048c2ecf20Sopenharmony_ci		case ISCSI_HOST_PARAM_PORT_STATE:
4058c2ecf20Sopenharmony_ci		case ISCSI_HOST_PARAM_PORT_SPEED:
4068c2ecf20Sopenharmony_ci			return S_IRUGO;
4078c2ecf20Sopenharmony_ci		default:
4088c2ecf20Sopenharmony_ci			return 0;
4098c2ecf20Sopenharmony_ci		}
4108c2ecf20Sopenharmony_ci	case ISCSI_PARAM:
4118c2ecf20Sopenharmony_ci		switch (param) {
4128c2ecf20Sopenharmony_ci		case ISCSI_PARAM_PERSISTENT_ADDRESS:
4138c2ecf20Sopenharmony_ci		case ISCSI_PARAM_PERSISTENT_PORT:
4148c2ecf20Sopenharmony_ci		case ISCSI_PARAM_CONN_ADDRESS:
4158c2ecf20Sopenharmony_ci		case ISCSI_PARAM_CONN_PORT:
4168c2ecf20Sopenharmony_ci		case ISCSI_PARAM_TARGET_NAME:
4178c2ecf20Sopenharmony_ci		case ISCSI_PARAM_TPGT:
4188c2ecf20Sopenharmony_ci		case ISCSI_PARAM_TARGET_ALIAS:
4198c2ecf20Sopenharmony_ci		case ISCSI_PARAM_MAX_BURST:
4208c2ecf20Sopenharmony_ci		case ISCSI_PARAM_MAX_R2T:
4218c2ecf20Sopenharmony_ci		case ISCSI_PARAM_FIRST_BURST:
4228c2ecf20Sopenharmony_ci		case ISCSI_PARAM_MAX_RECV_DLENGTH:
4238c2ecf20Sopenharmony_ci		case ISCSI_PARAM_MAX_XMIT_DLENGTH:
4248c2ecf20Sopenharmony_ci		case ISCSI_PARAM_IFACE_NAME:
4258c2ecf20Sopenharmony_ci		case ISCSI_PARAM_CHAP_OUT_IDX:
4268c2ecf20Sopenharmony_ci		case ISCSI_PARAM_CHAP_IN_IDX:
4278c2ecf20Sopenharmony_ci		case ISCSI_PARAM_USERNAME:
4288c2ecf20Sopenharmony_ci		case ISCSI_PARAM_PASSWORD:
4298c2ecf20Sopenharmony_ci		case ISCSI_PARAM_USERNAME_IN:
4308c2ecf20Sopenharmony_ci		case ISCSI_PARAM_PASSWORD_IN:
4318c2ecf20Sopenharmony_ci		case ISCSI_PARAM_AUTO_SND_TGT_DISABLE:
4328c2ecf20Sopenharmony_ci		case ISCSI_PARAM_DISCOVERY_SESS:
4338c2ecf20Sopenharmony_ci		case ISCSI_PARAM_PORTAL_TYPE:
4348c2ecf20Sopenharmony_ci		case ISCSI_PARAM_CHAP_AUTH_EN:
4358c2ecf20Sopenharmony_ci		case ISCSI_PARAM_DISCOVERY_LOGOUT_EN:
4368c2ecf20Sopenharmony_ci		case ISCSI_PARAM_BIDI_CHAP_EN:
4378c2ecf20Sopenharmony_ci		case ISCSI_PARAM_DISCOVERY_AUTH_OPTIONAL:
4388c2ecf20Sopenharmony_ci		case ISCSI_PARAM_DEF_TIME2WAIT:
4398c2ecf20Sopenharmony_ci		case ISCSI_PARAM_DEF_TIME2RETAIN:
4408c2ecf20Sopenharmony_ci		case ISCSI_PARAM_HDRDGST_EN:
4418c2ecf20Sopenharmony_ci		case ISCSI_PARAM_DATADGST_EN:
4428c2ecf20Sopenharmony_ci		case ISCSI_PARAM_INITIAL_R2T_EN:
4438c2ecf20Sopenharmony_ci		case ISCSI_PARAM_IMM_DATA_EN:
4448c2ecf20Sopenharmony_ci		case ISCSI_PARAM_PDU_INORDER_EN:
4458c2ecf20Sopenharmony_ci		case ISCSI_PARAM_DATASEQ_INORDER_EN:
4468c2ecf20Sopenharmony_ci		case ISCSI_PARAM_MAX_SEGMENT_SIZE:
4478c2ecf20Sopenharmony_ci		case ISCSI_PARAM_TCP_TIMESTAMP_STAT:
4488c2ecf20Sopenharmony_ci		case ISCSI_PARAM_TCP_WSF_DISABLE:
4498c2ecf20Sopenharmony_ci		case ISCSI_PARAM_TCP_NAGLE_DISABLE:
4508c2ecf20Sopenharmony_ci		case ISCSI_PARAM_TCP_TIMER_SCALE:
4518c2ecf20Sopenharmony_ci		case ISCSI_PARAM_TCP_TIMESTAMP_EN:
4528c2ecf20Sopenharmony_ci		case ISCSI_PARAM_TCP_XMIT_WSF:
4538c2ecf20Sopenharmony_ci		case ISCSI_PARAM_TCP_RECV_WSF:
4548c2ecf20Sopenharmony_ci		case ISCSI_PARAM_IP_FRAGMENT_DISABLE:
4558c2ecf20Sopenharmony_ci		case ISCSI_PARAM_IPV4_TOS:
4568c2ecf20Sopenharmony_ci		case ISCSI_PARAM_IPV6_TC:
4578c2ecf20Sopenharmony_ci		case ISCSI_PARAM_IPV6_FLOW_LABEL:
4588c2ecf20Sopenharmony_ci		case ISCSI_PARAM_IS_FW_ASSIGNED_IPV6:
4598c2ecf20Sopenharmony_ci		case ISCSI_PARAM_KEEPALIVE_TMO:
4608c2ecf20Sopenharmony_ci		case ISCSI_PARAM_LOCAL_PORT:
4618c2ecf20Sopenharmony_ci		case ISCSI_PARAM_ISID:
4628c2ecf20Sopenharmony_ci		case ISCSI_PARAM_TSID:
4638c2ecf20Sopenharmony_ci		case ISCSI_PARAM_DEF_TASKMGMT_TMO:
4648c2ecf20Sopenharmony_ci		case ISCSI_PARAM_ERL:
4658c2ecf20Sopenharmony_ci		case ISCSI_PARAM_STATSN:
4668c2ecf20Sopenharmony_ci		case ISCSI_PARAM_EXP_STATSN:
4678c2ecf20Sopenharmony_ci		case ISCSI_PARAM_DISCOVERY_PARENT_IDX:
4688c2ecf20Sopenharmony_ci		case ISCSI_PARAM_DISCOVERY_PARENT_TYPE:
4698c2ecf20Sopenharmony_ci		case ISCSI_PARAM_LOCAL_IPADDR:
4708c2ecf20Sopenharmony_ci			return S_IRUGO;
4718c2ecf20Sopenharmony_ci		default:
4728c2ecf20Sopenharmony_ci			return 0;
4738c2ecf20Sopenharmony_ci		}
4748c2ecf20Sopenharmony_ci	case ISCSI_NET_PARAM:
4758c2ecf20Sopenharmony_ci		switch (param) {
4768c2ecf20Sopenharmony_ci		case ISCSI_NET_PARAM_IPV4_ADDR:
4778c2ecf20Sopenharmony_ci		case ISCSI_NET_PARAM_IPV4_SUBNET:
4788c2ecf20Sopenharmony_ci		case ISCSI_NET_PARAM_IPV4_GW:
4798c2ecf20Sopenharmony_ci		case ISCSI_NET_PARAM_IPV4_BOOTPROTO:
4808c2ecf20Sopenharmony_ci		case ISCSI_NET_PARAM_IFACE_ENABLE:
4818c2ecf20Sopenharmony_ci		case ISCSI_NET_PARAM_IPV6_LINKLOCAL:
4828c2ecf20Sopenharmony_ci		case ISCSI_NET_PARAM_IPV6_ADDR:
4838c2ecf20Sopenharmony_ci		case ISCSI_NET_PARAM_IPV6_ROUTER:
4848c2ecf20Sopenharmony_ci		case ISCSI_NET_PARAM_IPV6_ADDR_AUTOCFG:
4858c2ecf20Sopenharmony_ci		case ISCSI_NET_PARAM_IPV6_LINKLOCAL_AUTOCFG:
4868c2ecf20Sopenharmony_ci		case ISCSI_NET_PARAM_VLAN_ID:
4878c2ecf20Sopenharmony_ci		case ISCSI_NET_PARAM_VLAN_PRIORITY:
4888c2ecf20Sopenharmony_ci		case ISCSI_NET_PARAM_VLAN_ENABLED:
4898c2ecf20Sopenharmony_ci		case ISCSI_NET_PARAM_MTU:
4908c2ecf20Sopenharmony_ci		case ISCSI_NET_PARAM_PORT:
4918c2ecf20Sopenharmony_ci		case ISCSI_NET_PARAM_IPADDR_STATE:
4928c2ecf20Sopenharmony_ci		case ISCSI_NET_PARAM_IPV6_LINKLOCAL_STATE:
4938c2ecf20Sopenharmony_ci		case ISCSI_NET_PARAM_IPV6_ROUTER_STATE:
4948c2ecf20Sopenharmony_ci		case ISCSI_NET_PARAM_DELAYED_ACK_EN:
4958c2ecf20Sopenharmony_ci		case ISCSI_NET_PARAM_TCP_NAGLE_DISABLE:
4968c2ecf20Sopenharmony_ci		case ISCSI_NET_PARAM_TCP_WSF_DISABLE:
4978c2ecf20Sopenharmony_ci		case ISCSI_NET_PARAM_TCP_WSF:
4988c2ecf20Sopenharmony_ci		case ISCSI_NET_PARAM_TCP_TIMER_SCALE:
4998c2ecf20Sopenharmony_ci		case ISCSI_NET_PARAM_TCP_TIMESTAMP_EN:
5008c2ecf20Sopenharmony_ci		case ISCSI_NET_PARAM_CACHE_ID:
5018c2ecf20Sopenharmony_ci		case ISCSI_NET_PARAM_IPV4_DHCP_DNS_ADDR_EN:
5028c2ecf20Sopenharmony_ci		case ISCSI_NET_PARAM_IPV4_DHCP_SLP_DA_EN:
5038c2ecf20Sopenharmony_ci		case ISCSI_NET_PARAM_IPV4_TOS_EN:
5048c2ecf20Sopenharmony_ci		case ISCSI_NET_PARAM_IPV4_TOS:
5058c2ecf20Sopenharmony_ci		case ISCSI_NET_PARAM_IPV4_GRAT_ARP_EN:
5068c2ecf20Sopenharmony_ci		case ISCSI_NET_PARAM_IPV4_DHCP_ALT_CLIENT_ID_EN:
5078c2ecf20Sopenharmony_ci		case ISCSI_NET_PARAM_IPV4_DHCP_ALT_CLIENT_ID:
5088c2ecf20Sopenharmony_ci		case ISCSI_NET_PARAM_IPV4_DHCP_REQ_VENDOR_ID_EN:
5098c2ecf20Sopenharmony_ci		case ISCSI_NET_PARAM_IPV4_DHCP_USE_VENDOR_ID_EN:
5108c2ecf20Sopenharmony_ci		case ISCSI_NET_PARAM_IPV4_DHCP_VENDOR_ID:
5118c2ecf20Sopenharmony_ci		case ISCSI_NET_PARAM_IPV4_DHCP_LEARN_IQN_EN:
5128c2ecf20Sopenharmony_ci		case ISCSI_NET_PARAM_IPV4_FRAGMENT_DISABLE:
5138c2ecf20Sopenharmony_ci		case ISCSI_NET_PARAM_IPV4_IN_FORWARD_EN:
5148c2ecf20Sopenharmony_ci		case ISCSI_NET_PARAM_REDIRECT_EN:
5158c2ecf20Sopenharmony_ci		case ISCSI_NET_PARAM_IPV4_TTL:
5168c2ecf20Sopenharmony_ci		case ISCSI_NET_PARAM_IPV6_GRAT_NEIGHBOR_ADV_EN:
5178c2ecf20Sopenharmony_ci		case ISCSI_NET_PARAM_IPV6_MLD_EN:
5188c2ecf20Sopenharmony_ci		case ISCSI_NET_PARAM_IPV6_FLOW_LABEL:
5198c2ecf20Sopenharmony_ci		case ISCSI_NET_PARAM_IPV6_TRAFFIC_CLASS:
5208c2ecf20Sopenharmony_ci		case ISCSI_NET_PARAM_IPV6_HOP_LIMIT:
5218c2ecf20Sopenharmony_ci		case ISCSI_NET_PARAM_IPV6_ND_REACHABLE_TMO:
5228c2ecf20Sopenharmony_ci		case ISCSI_NET_PARAM_IPV6_ND_REXMIT_TIME:
5238c2ecf20Sopenharmony_ci		case ISCSI_NET_PARAM_IPV6_ND_STALE_TMO:
5248c2ecf20Sopenharmony_ci		case ISCSI_NET_PARAM_IPV6_DUP_ADDR_DETECT_CNT:
5258c2ecf20Sopenharmony_ci		case ISCSI_NET_PARAM_IPV6_RTR_ADV_LINK_MTU:
5268c2ecf20Sopenharmony_ci			return S_IRUGO;
5278c2ecf20Sopenharmony_ci		default:
5288c2ecf20Sopenharmony_ci			return 0;
5298c2ecf20Sopenharmony_ci		}
5308c2ecf20Sopenharmony_ci	case ISCSI_IFACE_PARAM:
5318c2ecf20Sopenharmony_ci		switch (param) {
5328c2ecf20Sopenharmony_ci		case ISCSI_IFACE_PARAM_DEF_TASKMGMT_TMO:
5338c2ecf20Sopenharmony_ci		case ISCSI_IFACE_PARAM_HDRDGST_EN:
5348c2ecf20Sopenharmony_ci		case ISCSI_IFACE_PARAM_DATADGST_EN:
5358c2ecf20Sopenharmony_ci		case ISCSI_IFACE_PARAM_IMM_DATA_EN:
5368c2ecf20Sopenharmony_ci		case ISCSI_IFACE_PARAM_INITIAL_R2T_EN:
5378c2ecf20Sopenharmony_ci		case ISCSI_IFACE_PARAM_DATASEQ_INORDER_EN:
5388c2ecf20Sopenharmony_ci		case ISCSI_IFACE_PARAM_PDU_INORDER_EN:
5398c2ecf20Sopenharmony_ci		case ISCSI_IFACE_PARAM_ERL:
5408c2ecf20Sopenharmony_ci		case ISCSI_IFACE_PARAM_MAX_RECV_DLENGTH:
5418c2ecf20Sopenharmony_ci		case ISCSI_IFACE_PARAM_FIRST_BURST:
5428c2ecf20Sopenharmony_ci		case ISCSI_IFACE_PARAM_MAX_R2T:
5438c2ecf20Sopenharmony_ci		case ISCSI_IFACE_PARAM_MAX_BURST:
5448c2ecf20Sopenharmony_ci		case ISCSI_IFACE_PARAM_CHAP_AUTH_EN:
5458c2ecf20Sopenharmony_ci		case ISCSI_IFACE_PARAM_BIDI_CHAP_EN:
5468c2ecf20Sopenharmony_ci		case ISCSI_IFACE_PARAM_DISCOVERY_AUTH_OPTIONAL:
5478c2ecf20Sopenharmony_ci		case ISCSI_IFACE_PARAM_DISCOVERY_LOGOUT_EN:
5488c2ecf20Sopenharmony_ci		case ISCSI_IFACE_PARAM_STRICT_LOGIN_COMP_EN:
5498c2ecf20Sopenharmony_ci		case ISCSI_IFACE_PARAM_INITIATOR_NAME:
5508c2ecf20Sopenharmony_ci			return S_IRUGO;
5518c2ecf20Sopenharmony_ci		default:
5528c2ecf20Sopenharmony_ci			return 0;
5538c2ecf20Sopenharmony_ci		}
5548c2ecf20Sopenharmony_ci	case ISCSI_FLASHNODE_PARAM:
5558c2ecf20Sopenharmony_ci		switch (param) {
5568c2ecf20Sopenharmony_ci		case ISCSI_FLASHNODE_IS_FW_ASSIGNED_IPV6:
5578c2ecf20Sopenharmony_ci		case ISCSI_FLASHNODE_PORTAL_TYPE:
5588c2ecf20Sopenharmony_ci		case ISCSI_FLASHNODE_AUTO_SND_TGT_DISABLE:
5598c2ecf20Sopenharmony_ci		case ISCSI_FLASHNODE_DISCOVERY_SESS:
5608c2ecf20Sopenharmony_ci		case ISCSI_FLASHNODE_ENTRY_EN:
5618c2ecf20Sopenharmony_ci		case ISCSI_FLASHNODE_HDR_DGST_EN:
5628c2ecf20Sopenharmony_ci		case ISCSI_FLASHNODE_DATA_DGST_EN:
5638c2ecf20Sopenharmony_ci		case ISCSI_FLASHNODE_IMM_DATA_EN:
5648c2ecf20Sopenharmony_ci		case ISCSI_FLASHNODE_INITIAL_R2T_EN:
5658c2ecf20Sopenharmony_ci		case ISCSI_FLASHNODE_DATASEQ_INORDER:
5668c2ecf20Sopenharmony_ci		case ISCSI_FLASHNODE_PDU_INORDER:
5678c2ecf20Sopenharmony_ci		case ISCSI_FLASHNODE_CHAP_AUTH_EN:
5688c2ecf20Sopenharmony_ci		case ISCSI_FLASHNODE_SNACK_REQ_EN:
5698c2ecf20Sopenharmony_ci		case ISCSI_FLASHNODE_DISCOVERY_LOGOUT_EN:
5708c2ecf20Sopenharmony_ci		case ISCSI_FLASHNODE_BIDI_CHAP_EN:
5718c2ecf20Sopenharmony_ci		case ISCSI_FLASHNODE_DISCOVERY_AUTH_OPTIONAL:
5728c2ecf20Sopenharmony_ci		case ISCSI_FLASHNODE_ERL:
5738c2ecf20Sopenharmony_ci		case ISCSI_FLASHNODE_TCP_TIMESTAMP_STAT:
5748c2ecf20Sopenharmony_ci		case ISCSI_FLASHNODE_TCP_NAGLE_DISABLE:
5758c2ecf20Sopenharmony_ci		case ISCSI_FLASHNODE_TCP_WSF_DISABLE:
5768c2ecf20Sopenharmony_ci		case ISCSI_FLASHNODE_TCP_TIMER_SCALE:
5778c2ecf20Sopenharmony_ci		case ISCSI_FLASHNODE_TCP_TIMESTAMP_EN:
5788c2ecf20Sopenharmony_ci		case ISCSI_FLASHNODE_IP_FRAG_DISABLE:
5798c2ecf20Sopenharmony_ci		case ISCSI_FLASHNODE_MAX_RECV_DLENGTH:
5808c2ecf20Sopenharmony_ci		case ISCSI_FLASHNODE_MAX_XMIT_DLENGTH:
5818c2ecf20Sopenharmony_ci		case ISCSI_FLASHNODE_FIRST_BURST:
5828c2ecf20Sopenharmony_ci		case ISCSI_FLASHNODE_DEF_TIME2WAIT:
5838c2ecf20Sopenharmony_ci		case ISCSI_FLASHNODE_DEF_TIME2RETAIN:
5848c2ecf20Sopenharmony_ci		case ISCSI_FLASHNODE_MAX_R2T:
5858c2ecf20Sopenharmony_ci		case ISCSI_FLASHNODE_KEEPALIVE_TMO:
5868c2ecf20Sopenharmony_ci		case ISCSI_FLASHNODE_ISID:
5878c2ecf20Sopenharmony_ci		case ISCSI_FLASHNODE_TSID:
5888c2ecf20Sopenharmony_ci		case ISCSI_FLASHNODE_PORT:
5898c2ecf20Sopenharmony_ci		case ISCSI_FLASHNODE_MAX_BURST:
5908c2ecf20Sopenharmony_ci		case ISCSI_FLASHNODE_DEF_TASKMGMT_TMO:
5918c2ecf20Sopenharmony_ci		case ISCSI_FLASHNODE_IPADDR:
5928c2ecf20Sopenharmony_ci		case ISCSI_FLASHNODE_ALIAS:
5938c2ecf20Sopenharmony_ci		case ISCSI_FLASHNODE_REDIRECT_IPADDR:
5948c2ecf20Sopenharmony_ci		case ISCSI_FLASHNODE_MAX_SEGMENT_SIZE:
5958c2ecf20Sopenharmony_ci		case ISCSI_FLASHNODE_LOCAL_PORT:
5968c2ecf20Sopenharmony_ci		case ISCSI_FLASHNODE_IPV4_TOS:
5978c2ecf20Sopenharmony_ci		case ISCSI_FLASHNODE_IPV6_TC:
5988c2ecf20Sopenharmony_ci		case ISCSI_FLASHNODE_IPV6_FLOW_LABEL:
5998c2ecf20Sopenharmony_ci		case ISCSI_FLASHNODE_NAME:
6008c2ecf20Sopenharmony_ci		case ISCSI_FLASHNODE_TPGT:
6018c2ecf20Sopenharmony_ci		case ISCSI_FLASHNODE_LINK_LOCAL_IPV6:
6028c2ecf20Sopenharmony_ci		case ISCSI_FLASHNODE_DISCOVERY_PARENT_IDX:
6038c2ecf20Sopenharmony_ci		case ISCSI_FLASHNODE_DISCOVERY_PARENT_TYPE:
6048c2ecf20Sopenharmony_ci		case ISCSI_FLASHNODE_TCP_XMIT_WSF:
6058c2ecf20Sopenharmony_ci		case ISCSI_FLASHNODE_TCP_RECV_WSF:
6068c2ecf20Sopenharmony_ci		case ISCSI_FLASHNODE_CHAP_OUT_IDX:
6078c2ecf20Sopenharmony_ci		case ISCSI_FLASHNODE_USERNAME:
6088c2ecf20Sopenharmony_ci		case ISCSI_FLASHNODE_PASSWORD:
6098c2ecf20Sopenharmony_ci		case ISCSI_FLASHNODE_STATSN:
6108c2ecf20Sopenharmony_ci		case ISCSI_FLASHNODE_EXP_STATSN:
6118c2ecf20Sopenharmony_ci		case ISCSI_FLASHNODE_IS_BOOT_TGT:
6128c2ecf20Sopenharmony_ci			return S_IRUGO;
6138c2ecf20Sopenharmony_ci		default:
6148c2ecf20Sopenharmony_ci			return 0;
6158c2ecf20Sopenharmony_ci		}
6168c2ecf20Sopenharmony_ci	}
6178c2ecf20Sopenharmony_ci
6188c2ecf20Sopenharmony_ci	return 0;
6198c2ecf20Sopenharmony_ci}
6208c2ecf20Sopenharmony_ci
6218c2ecf20Sopenharmony_ci/**
6228c2ecf20Sopenharmony_ci * qla4xxx_create chap_list - Create CHAP list from FLASH
6238c2ecf20Sopenharmony_ci * @ha: pointer to adapter structure
6248c2ecf20Sopenharmony_ci *
6258c2ecf20Sopenharmony_ci * Read flash and make a list of CHAP entries, during login when a CHAP entry
6268c2ecf20Sopenharmony_ci * is received, it will be checked in this list. If entry exist then the CHAP
6278c2ecf20Sopenharmony_ci * entry index is set in the DDB. If CHAP entry does not exist in this list
6288c2ecf20Sopenharmony_ci * then a new entry is added in FLASH in CHAP table and the index obtained is
6298c2ecf20Sopenharmony_ci * used in the DDB.
6308c2ecf20Sopenharmony_ci **/
6318c2ecf20Sopenharmony_cistatic void qla4xxx_create_chap_list(struct scsi_qla_host *ha)
6328c2ecf20Sopenharmony_ci{
6338c2ecf20Sopenharmony_ci	int rval = 0;
6348c2ecf20Sopenharmony_ci	uint8_t *chap_flash_data = NULL;
6358c2ecf20Sopenharmony_ci	uint32_t offset;
6368c2ecf20Sopenharmony_ci	dma_addr_t chap_dma;
6378c2ecf20Sopenharmony_ci	uint32_t chap_size = 0;
6388c2ecf20Sopenharmony_ci
6398c2ecf20Sopenharmony_ci	if (is_qla40XX(ha))
6408c2ecf20Sopenharmony_ci		chap_size = MAX_CHAP_ENTRIES_40XX *
6418c2ecf20Sopenharmony_ci			    sizeof(struct ql4_chap_table);
6428c2ecf20Sopenharmony_ci	else	/* Single region contains CHAP info for both
6438c2ecf20Sopenharmony_ci		 * ports which is divided into half for each port.
6448c2ecf20Sopenharmony_ci		 */
6458c2ecf20Sopenharmony_ci		chap_size = ha->hw.flt_chap_size / 2;
6468c2ecf20Sopenharmony_ci
6478c2ecf20Sopenharmony_ci	chap_flash_data = dma_alloc_coherent(&ha->pdev->dev, chap_size,
6488c2ecf20Sopenharmony_ci					     &chap_dma, GFP_KERNEL);
6498c2ecf20Sopenharmony_ci	if (!chap_flash_data) {
6508c2ecf20Sopenharmony_ci		ql4_printk(KERN_ERR, ha, "No memory for chap_flash_data\n");
6518c2ecf20Sopenharmony_ci		return;
6528c2ecf20Sopenharmony_ci	}
6538c2ecf20Sopenharmony_ci
6548c2ecf20Sopenharmony_ci	if (is_qla40XX(ha)) {
6558c2ecf20Sopenharmony_ci		offset = FLASH_CHAP_OFFSET;
6568c2ecf20Sopenharmony_ci	} else {
6578c2ecf20Sopenharmony_ci		offset = FLASH_RAW_ACCESS_ADDR + (ha->hw.flt_region_chap << 2);
6588c2ecf20Sopenharmony_ci		if (ha->port_num == 1)
6598c2ecf20Sopenharmony_ci			offset += chap_size;
6608c2ecf20Sopenharmony_ci	}
6618c2ecf20Sopenharmony_ci
6628c2ecf20Sopenharmony_ci	rval = qla4xxx_get_flash(ha, chap_dma, offset, chap_size);
6638c2ecf20Sopenharmony_ci	if (rval != QLA_SUCCESS)
6648c2ecf20Sopenharmony_ci		goto exit_chap_list;
6658c2ecf20Sopenharmony_ci
6668c2ecf20Sopenharmony_ci	if (ha->chap_list == NULL)
6678c2ecf20Sopenharmony_ci		ha->chap_list = vmalloc(chap_size);
6688c2ecf20Sopenharmony_ci	if (ha->chap_list == NULL) {
6698c2ecf20Sopenharmony_ci		ql4_printk(KERN_ERR, ha, "No memory for ha->chap_list\n");
6708c2ecf20Sopenharmony_ci		goto exit_chap_list;
6718c2ecf20Sopenharmony_ci	}
6728c2ecf20Sopenharmony_ci
6738c2ecf20Sopenharmony_ci	memset(ha->chap_list, 0, chap_size);
6748c2ecf20Sopenharmony_ci	memcpy(ha->chap_list, chap_flash_data, chap_size);
6758c2ecf20Sopenharmony_ci
6768c2ecf20Sopenharmony_ciexit_chap_list:
6778c2ecf20Sopenharmony_ci	dma_free_coherent(&ha->pdev->dev, chap_size, chap_flash_data, chap_dma);
6788c2ecf20Sopenharmony_ci}
6798c2ecf20Sopenharmony_ci
6808c2ecf20Sopenharmony_cistatic int qla4xxx_get_chap_by_index(struct scsi_qla_host *ha,
6818c2ecf20Sopenharmony_ci				     int16_t chap_index,
6828c2ecf20Sopenharmony_ci				     struct ql4_chap_table **chap_entry)
6838c2ecf20Sopenharmony_ci{
6848c2ecf20Sopenharmony_ci	int rval = QLA_ERROR;
6858c2ecf20Sopenharmony_ci	int max_chap_entries;
6868c2ecf20Sopenharmony_ci
6878c2ecf20Sopenharmony_ci	if (!ha->chap_list) {
6888c2ecf20Sopenharmony_ci		ql4_printk(KERN_ERR, ha, "CHAP table cache is empty!\n");
6898c2ecf20Sopenharmony_ci		rval = QLA_ERROR;
6908c2ecf20Sopenharmony_ci		goto exit_get_chap;
6918c2ecf20Sopenharmony_ci	}
6928c2ecf20Sopenharmony_ci
6938c2ecf20Sopenharmony_ci	if (is_qla80XX(ha))
6948c2ecf20Sopenharmony_ci		max_chap_entries = (ha->hw.flt_chap_size / 2) /
6958c2ecf20Sopenharmony_ci				   sizeof(struct ql4_chap_table);
6968c2ecf20Sopenharmony_ci	else
6978c2ecf20Sopenharmony_ci		max_chap_entries = MAX_CHAP_ENTRIES_40XX;
6988c2ecf20Sopenharmony_ci
6998c2ecf20Sopenharmony_ci	if (chap_index > max_chap_entries) {
7008c2ecf20Sopenharmony_ci		ql4_printk(KERN_ERR, ha, "Invalid Chap index\n");
7018c2ecf20Sopenharmony_ci		rval = QLA_ERROR;
7028c2ecf20Sopenharmony_ci		goto exit_get_chap;
7038c2ecf20Sopenharmony_ci	}
7048c2ecf20Sopenharmony_ci
7058c2ecf20Sopenharmony_ci	*chap_entry = (struct ql4_chap_table *)ha->chap_list + chap_index;
7068c2ecf20Sopenharmony_ci	if ((*chap_entry)->cookie !=
7078c2ecf20Sopenharmony_ci	     __constant_cpu_to_le16(CHAP_VALID_COOKIE)) {
7088c2ecf20Sopenharmony_ci		rval = QLA_ERROR;
7098c2ecf20Sopenharmony_ci		*chap_entry = NULL;
7108c2ecf20Sopenharmony_ci	} else {
7118c2ecf20Sopenharmony_ci		rval = QLA_SUCCESS;
7128c2ecf20Sopenharmony_ci	}
7138c2ecf20Sopenharmony_ci
7148c2ecf20Sopenharmony_ciexit_get_chap:
7158c2ecf20Sopenharmony_ci	return rval;
7168c2ecf20Sopenharmony_ci}
7178c2ecf20Sopenharmony_ci
7188c2ecf20Sopenharmony_ci/**
7198c2ecf20Sopenharmony_ci * qla4xxx_find_free_chap_index - Find the first free chap index
7208c2ecf20Sopenharmony_ci * @ha: pointer to adapter structure
7218c2ecf20Sopenharmony_ci * @chap_index: CHAP index to be returned
7228c2ecf20Sopenharmony_ci *
7238c2ecf20Sopenharmony_ci * Find the first free chap index available in the chap table
7248c2ecf20Sopenharmony_ci *
7258c2ecf20Sopenharmony_ci * Note: Caller should acquire the chap lock before getting here.
7268c2ecf20Sopenharmony_ci **/
7278c2ecf20Sopenharmony_cistatic int qla4xxx_find_free_chap_index(struct scsi_qla_host *ha,
7288c2ecf20Sopenharmony_ci					uint16_t *chap_index)
7298c2ecf20Sopenharmony_ci{
7308c2ecf20Sopenharmony_ci	int i, rval;
7318c2ecf20Sopenharmony_ci	int free_index = -1;
7328c2ecf20Sopenharmony_ci	int max_chap_entries = 0;
7338c2ecf20Sopenharmony_ci	struct ql4_chap_table *chap_table;
7348c2ecf20Sopenharmony_ci
7358c2ecf20Sopenharmony_ci	if (is_qla80XX(ha))
7368c2ecf20Sopenharmony_ci		max_chap_entries = (ha->hw.flt_chap_size / 2) /
7378c2ecf20Sopenharmony_ci						sizeof(struct ql4_chap_table);
7388c2ecf20Sopenharmony_ci	else
7398c2ecf20Sopenharmony_ci		max_chap_entries = MAX_CHAP_ENTRIES_40XX;
7408c2ecf20Sopenharmony_ci
7418c2ecf20Sopenharmony_ci	if (!ha->chap_list) {
7428c2ecf20Sopenharmony_ci		ql4_printk(KERN_ERR, ha, "CHAP table cache is empty!\n");
7438c2ecf20Sopenharmony_ci		rval = QLA_ERROR;
7448c2ecf20Sopenharmony_ci		goto exit_find_chap;
7458c2ecf20Sopenharmony_ci	}
7468c2ecf20Sopenharmony_ci
7478c2ecf20Sopenharmony_ci	for (i = 0; i < max_chap_entries; i++) {
7488c2ecf20Sopenharmony_ci		chap_table = (struct ql4_chap_table *)ha->chap_list + i;
7498c2ecf20Sopenharmony_ci
7508c2ecf20Sopenharmony_ci		if ((chap_table->cookie !=
7518c2ecf20Sopenharmony_ci		    __constant_cpu_to_le16(CHAP_VALID_COOKIE)) &&
7528c2ecf20Sopenharmony_ci		   (i > MAX_RESRV_CHAP_IDX)) {
7538c2ecf20Sopenharmony_ci				free_index = i;
7548c2ecf20Sopenharmony_ci				break;
7558c2ecf20Sopenharmony_ci		}
7568c2ecf20Sopenharmony_ci	}
7578c2ecf20Sopenharmony_ci
7588c2ecf20Sopenharmony_ci	if (free_index != -1) {
7598c2ecf20Sopenharmony_ci		*chap_index = free_index;
7608c2ecf20Sopenharmony_ci		rval = QLA_SUCCESS;
7618c2ecf20Sopenharmony_ci	} else {
7628c2ecf20Sopenharmony_ci		rval = QLA_ERROR;
7638c2ecf20Sopenharmony_ci	}
7648c2ecf20Sopenharmony_ci
7658c2ecf20Sopenharmony_ciexit_find_chap:
7668c2ecf20Sopenharmony_ci	return rval;
7678c2ecf20Sopenharmony_ci}
7688c2ecf20Sopenharmony_ci
7698c2ecf20Sopenharmony_cistatic int qla4xxx_get_chap_list(struct Scsi_Host *shost, uint16_t chap_tbl_idx,
7708c2ecf20Sopenharmony_ci				  uint32_t *num_entries, char *buf)
7718c2ecf20Sopenharmony_ci{
7728c2ecf20Sopenharmony_ci	struct scsi_qla_host *ha = to_qla_host(shost);
7738c2ecf20Sopenharmony_ci	struct ql4_chap_table *chap_table;
7748c2ecf20Sopenharmony_ci	struct iscsi_chap_rec *chap_rec;
7758c2ecf20Sopenharmony_ci	int max_chap_entries = 0;
7768c2ecf20Sopenharmony_ci	int valid_chap_entries = 0;
7778c2ecf20Sopenharmony_ci	int ret = 0, i;
7788c2ecf20Sopenharmony_ci
7798c2ecf20Sopenharmony_ci	if (is_qla80XX(ha))
7808c2ecf20Sopenharmony_ci		max_chap_entries = (ha->hw.flt_chap_size / 2) /
7818c2ecf20Sopenharmony_ci					sizeof(struct ql4_chap_table);
7828c2ecf20Sopenharmony_ci	else
7838c2ecf20Sopenharmony_ci		max_chap_entries = MAX_CHAP_ENTRIES_40XX;
7848c2ecf20Sopenharmony_ci
7858c2ecf20Sopenharmony_ci	ql4_printk(KERN_INFO, ha, "%s: num_entries = %d, CHAP idx = %d\n",
7868c2ecf20Sopenharmony_ci			__func__, *num_entries, chap_tbl_idx);
7878c2ecf20Sopenharmony_ci
7888c2ecf20Sopenharmony_ci	if (!buf) {
7898c2ecf20Sopenharmony_ci		ret = -ENOMEM;
7908c2ecf20Sopenharmony_ci		goto exit_get_chap_list;
7918c2ecf20Sopenharmony_ci	}
7928c2ecf20Sopenharmony_ci
7938c2ecf20Sopenharmony_ci	qla4xxx_create_chap_list(ha);
7948c2ecf20Sopenharmony_ci
7958c2ecf20Sopenharmony_ci	chap_rec = (struct iscsi_chap_rec *) buf;
7968c2ecf20Sopenharmony_ci	mutex_lock(&ha->chap_sem);
7978c2ecf20Sopenharmony_ci	for (i = chap_tbl_idx; i < max_chap_entries; i++) {
7988c2ecf20Sopenharmony_ci		chap_table = (struct ql4_chap_table *)ha->chap_list + i;
7998c2ecf20Sopenharmony_ci		if (chap_table->cookie !=
8008c2ecf20Sopenharmony_ci		    __constant_cpu_to_le16(CHAP_VALID_COOKIE))
8018c2ecf20Sopenharmony_ci			continue;
8028c2ecf20Sopenharmony_ci
8038c2ecf20Sopenharmony_ci		chap_rec->chap_tbl_idx = i;
8048c2ecf20Sopenharmony_ci		strlcpy(chap_rec->username, chap_table->name,
8058c2ecf20Sopenharmony_ci			ISCSI_CHAP_AUTH_NAME_MAX_LEN);
8068c2ecf20Sopenharmony_ci		strlcpy(chap_rec->password, chap_table->secret,
8078c2ecf20Sopenharmony_ci			QL4_CHAP_MAX_SECRET_LEN);
8088c2ecf20Sopenharmony_ci		chap_rec->password_length = chap_table->secret_len;
8098c2ecf20Sopenharmony_ci
8108c2ecf20Sopenharmony_ci		if (chap_table->flags & BIT_7) /* local */
8118c2ecf20Sopenharmony_ci			chap_rec->chap_type = CHAP_TYPE_OUT;
8128c2ecf20Sopenharmony_ci
8138c2ecf20Sopenharmony_ci		if (chap_table->flags & BIT_6) /* peer */
8148c2ecf20Sopenharmony_ci			chap_rec->chap_type = CHAP_TYPE_IN;
8158c2ecf20Sopenharmony_ci
8168c2ecf20Sopenharmony_ci		chap_rec++;
8178c2ecf20Sopenharmony_ci
8188c2ecf20Sopenharmony_ci		valid_chap_entries++;
8198c2ecf20Sopenharmony_ci		if (valid_chap_entries == *num_entries)
8208c2ecf20Sopenharmony_ci			break;
8218c2ecf20Sopenharmony_ci		else
8228c2ecf20Sopenharmony_ci			continue;
8238c2ecf20Sopenharmony_ci	}
8248c2ecf20Sopenharmony_ci	mutex_unlock(&ha->chap_sem);
8258c2ecf20Sopenharmony_ci
8268c2ecf20Sopenharmony_ciexit_get_chap_list:
8278c2ecf20Sopenharmony_ci	ql4_printk(KERN_INFO, ha, "%s: Valid CHAP Entries = %d\n",
8288c2ecf20Sopenharmony_ci			__func__,  valid_chap_entries);
8298c2ecf20Sopenharmony_ci	*num_entries = valid_chap_entries;
8308c2ecf20Sopenharmony_ci	return ret;
8318c2ecf20Sopenharmony_ci}
8328c2ecf20Sopenharmony_ci
8338c2ecf20Sopenharmony_cistatic int __qla4xxx_is_chap_active(struct device *dev, void *data)
8348c2ecf20Sopenharmony_ci{
8358c2ecf20Sopenharmony_ci	int ret = 0;
8368c2ecf20Sopenharmony_ci	uint16_t *chap_tbl_idx = (uint16_t *) data;
8378c2ecf20Sopenharmony_ci	struct iscsi_cls_session *cls_session;
8388c2ecf20Sopenharmony_ci	struct iscsi_session *sess;
8398c2ecf20Sopenharmony_ci	struct ddb_entry *ddb_entry;
8408c2ecf20Sopenharmony_ci
8418c2ecf20Sopenharmony_ci	if (!iscsi_is_session_dev(dev))
8428c2ecf20Sopenharmony_ci		goto exit_is_chap_active;
8438c2ecf20Sopenharmony_ci
8448c2ecf20Sopenharmony_ci	cls_session = iscsi_dev_to_session(dev);
8458c2ecf20Sopenharmony_ci	sess = cls_session->dd_data;
8468c2ecf20Sopenharmony_ci	ddb_entry = sess->dd_data;
8478c2ecf20Sopenharmony_ci
8488c2ecf20Sopenharmony_ci	if (iscsi_session_chkready(cls_session))
8498c2ecf20Sopenharmony_ci		goto exit_is_chap_active;
8508c2ecf20Sopenharmony_ci
8518c2ecf20Sopenharmony_ci	if (ddb_entry->chap_tbl_idx == *chap_tbl_idx)
8528c2ecf20Sopenharmony_ci		ret = 1;
8538c2ecf20Sopenharmony_ci
8548c2ecf20Sopenharmony_ciexit_is_chap_active:
8558c2ecf20Sopenharmony_ci	return ret;
8568c2ecf20Sopenharmony_ci}
8578c2ecf20Sopenharmony_ci
8588c2ecf20Sopenharmony_cistatic int qla4xxx_is_chap_active(struct Scsi_Host *shost,
8598c2ecf20Sopenharmony_ci				  uint16_t chap_tbl_idx)
8608c2ecf20Sopenharmony_ci{
8618c2ecf20Sopenharmony_ci	int ret = 0;
8628c2ecf20Sopenharmony_ci
8638c2ecf20Sopenharmony_ci	ret = device_for_each_child(&shost->shost_gendev, &chap_tbl_idx,
8648c2ecf20Sopenharmony_ci				    __qla4xxx_is_chap_active);
8658c2ecf20Sopenharmony_ci
8668c2ecf20Sopenharmony_ci	return ret;
8678c2ecf20Sopenharmony_ci}
8688c2ecf20Sopenharmony_ci
8698c2ecf20Sopenharmony_cistatic int qla4xxx_delete_chap(struct Scsi_Host *shost, uint16_t chap_tbl_idx)
8708c2ecf20Sopenharmony_ci{
8718c2ecf20Sopenharmony_ci	struct scsi_qla_host *ha = to_qla_host(shost);
8728c2ecf20Sopenharmony_ci	struct ql4_chap_table *chap_table;
8738c2ecf20Sopenharmony_ci	dma_addr_t chap_dma;
8748c2ecf20Sopenharmony_ci	int max_chap_entries = 0;
8758c2ecf20Sopenharmony_ci	uint32_t offset = 0;
8768c2ecf20Sopenharmony_ci	uint32_t chap_size;
8778c2ecf20Sopenharmony_ci	int ret = 0;
8788c2ecf20Sopenharmony_ci
8798c2ecf20Sopenharmony_ci	chap_table = dma_pool_zalloc(ha->chap_dma_pool, GFP_KERNEL, &chap_dma);
8808c2ecf20Sopenharmony_ci	if (chap_table == NULL)
8818c2ecf20Sopenharmony_ci		return -ENOMEM;
8828c2ecf20Sopenharmony_ci
8838c2ecf20Sopenharmony_ci	if (is_qla80XX(ha))
8848c2ecf20Sopenharmony_ci		max_chap_entries = (ha->hw.flt_chap_size / 2) /
8858c2ecf20Sopenharmony_ci				   sizeof(struct ql4_chap_table);
8868c2ecf20Sopenharmony_ci	else
8878c2ecf20Sopenharmony_ci		max_chap_entries = MAX_CHAP_ENTRIES_40XX;
8888c2ecf20Sopenharmony_ci
8898c2ecf20Sopenharmony_ci	if (chap_tbl_idx > max_chap_entries) {
8908c2ecf20Sopenharmony_ci		ret = -EINVAL;
8918c2ecf20Sopenharmony_ci		goto exit_delete_chap;
8928c2ecf20Sopenharmony_ci	}
8938c2ecf20Sopenharmony_ci
8948c2ecf20Sopenharmony_ci	/* Check if chap index is in use.
8958c2ecf20Sopenharmony_ci	 * If chap is in use don't delet chap entry */
8968c2ecf20Sopenharmony_ci	ret = qla4xxx_is_chap_active(shost, chap_tbl_idx);
8978c2ecf20Sopenharmony_ci	if (ret) {
8988c2ecf20Sopenharmony_ci		ql4_printk(KERN_INFO, ha, "CHAP entry %d is in use, cannot "
8998c2ecf20Sopenharmony_ci			   "delete from flash\n", chap_tbl_idx);
9008c2ecf20Sopenharmony_ci		ret = -EBUSY;
9018c2ecf20Sopenharmony_ci		goto exit_delete_chap;
9028c2ecf20Sopenharmony_ci	}
9038c2ecf20Sopenharmony_ci
9048c2ecf20Sopenharmony_ci	chap_size = sizeof(struct ql4_chap_table);
9058c2ecf20Sopenharmony_ci	if (is_qla40XX(ha))
9068c2ecf20Sopenharmony_ci		offset = FLASH_CHAP_OFFSET | (chap_tbl_idx * chap_size);
9078c2ecf20Sopenharmony_ci	else {
9088c2ecf20Sopenharmony_ci		offset = FLASH_RAW_ACCESS_ADDR + (ha->hw.flt_region_chap << 2);
9098c2ecf20Sopenharmony_ci		/* flt_chap_size is CHAP table size for both ports
9108c2ecf20Sopenharmony_ci		 * so divide it by 2 to calculate the offset for second port
9118c2ecf20Sopenharmony_ci		 */
9128c2ecf20Sopenharmony_ci		if (ha->port_num == 1)
9138c2ecf20Sopenharmony_ci			offset += (ha->hw.flt_chap_size / 2);
9148c2ecf20Sopenharmony_ci		offset += (chap_tbl_idx * chap_size);
9158c2ecf20Sopenharmony_ci	}
9168c2ecf20Sopenharmony_ci
9178c2ecf20Sopenharmony_ci	ret = qla4xxx_get_flash(ha, chap_dma, offset, chap_size);
9188c2ecf20Sopenharmony_ci	if (ret != QLA_SUCCESS) {
9198c2ecf20Sopenharmony_ci		ret = -EINVAL;
9208c2ecf20Sopenharmony_ci		goto exit_delete_chap;
9218c2ecf20Sopenharmony_ci	}
9228c2ecf20Sopenharmony_ci
9238c2ecf20Sopenharmony_ci	DEBUG2(ql4_printk(KERN_INFO, ha, "Chap Cookie: x%x\n",
9248c2ecf20Sopenharmony_ci			  __le16_to_cpu(chap_table->cookie)));
9258c2ecf20Sopenharmony_ci
9268c2ecf20Sopenharmony_ci	if (__le16_to_cpu(chap_table->cookie) != CHAP_VALID_COOKIE) {
9278c2ecf20Sopenharmony_ci		ql4_printk(KERN_ERR, ha, "No valid chap entry found\n");
9288c2ecf20Sopenharmony_ci		goto exit_delete_chap;
9298c2ecf20Sopenharmony_ci	}
9308c2ecf20Sopenharmony_ci
9318c2ecf20Sopenharmony_ci	chap_table->cookie = __constant_cpu_to_le16(0xFFFF);
9328c2ecf20Sopenharmony_ci
9338c2ecf20Sopenharmony_ci	offset = FLASH_CHAP_OFFSET |
9348c2ecf20Sopenharmony_ci			(chap_tbl_idx * sizeof(struct ql4_chap_table));
9358c2ecf20Sopenharmony_ci	ret = qla4xxx_set_flash(ha, chap_dma, offset, chap_size,
9368c2ecf20Sopenharmony_ci				FLASH_OPT_RMW_COMMIT);
9378c2ecf20Sopenharmony_ci	if (ret == QLA_SUCCESS && ha->chap_list) {
9388c2ecf20Sopenharmony_ci		mutex_lock(&ha->chap_sem);
9398c2ecf20Sopenharmony_ci		/* Update ha chap_list cache */
9408c2ecf20Sopenharmony_ci		memcpy((struct ql4_chap_table *)ha->chap_list + chap_tbl_idx,
9418c2ecf20Sopenharmony_ci			chap_table, sizeof(struct ql4_chap_table));
9428c2ecf20Sopenharmony_ci		mutex_unlock(&ha->chap_sem);
9438c2ecf20Sopenharmony_ci	}
9448c2ecf20Sopenharmony_ci	if (ret != QLA_SUCCESS)
9458c2ecf20Sopenharmony_ci		ret =  -EINVAL;
9468c2ecf20Sopenharmony_ci
9478c2ecf20Sopenharmony_ciexit_delete_chap:
9488c2ecf20Sopenharmony_ci	dma_pool_free(ha->chap_dma_pool, chap_table, chap_dma);
9498c2ecf20Sopenharmony_ci	return ret;
9508c2ecf20Sopenharmony_ci}
9518c2ecf20Sopenharmony_ci
9528c2ecf20Sopenharmony_ci/**
9538c2ecf20Sopenharmony_ci * qla4xxx_set_chap_entry - Make chap entry with given information
9548c2ecf20Sopenharmony_ci * @shost: pointer to host
9558c2ecf20Sopenharmony_ci * @data: chap info - credentials, index and type to make chap entry
9568c2ecf20Sopenharmony_ci * @len: length of data
9578c2ecf20Sopenharmony_ci *
9588c2ecf20Sopenharmony_ci * Add or update chap entry with the given information
9598c2ecf20Sopenharmony_ci **/
9608c2ecf20Sopenharmony_cistatic int qla4xxx_set_chap_entry(struct Scsi_Host *shost, void *data, int len)
9618c2ecf20Sopenharmony_ci{
9628c2ecf20Sopenharmony_ci	struct scsi_qla_host *ha = to_qla_host(shost);
9638c2ecf20Sopenharmony_ci	struct iscsi_chap_rec chap_rec;
9648c2ecf20Sopenharmony_ci	struct ql4_chap_table *chap_entry = NULL;
9658c2ecf20Sopenharmony_ci	struct iscsi_param_info *param_info;
9668c2ecf20Sopenharmony_ci	struct nlattr *attr;
9678c2ecf20Sopenharmony_ci	int max_chap_entries = 0;
9688c2ecf20Sopenharmony_ci	int type;
9698c2ecf20Sopenharmony_ci	int rem = len;
9708c2ecf20Sopenharmony_ci	int rc = 0;
9718c2ecf20Sopenharmony_ci	int size;
9728c2ecf20Sopenharmony_ci
9738c2ecf20Sopenharmony_ci	memset(&chap_rec, 0, sizeof(chap_rec));
9748c2ecf20Sopenharmony_ci
9758c2ecf20Sopenharmony_ci	nla_for_each_attr(attr, data, len, rem) {
9768c2ecf20Sopenharmony_ci		if (nla_len(attr) < sizeof(*param_info)) {
9778c2ecf20Sopenharmony_ci			rc = -EINVAL;
9788c2ecf20Sopenharmony_ci			goto exit_set_chap;
9798c2ecf20Sopenharmony_ci		}
9808c2ecf20Sopenharmony_ci
9818c2ecf20Sopenharmony_ci		param_info = nla_data(attr);
9828c2ecf20Sopenharmony_ci
9838c2ecf20Sopenharmony_ci		switch (param_info->param) {
9848c2ecf20Sopenharmony_ci		case ISCSI_CHAP_PARAM_INDEX:
9858c2ecf20Sopenharmony_ci			chap_rec.chap_tbl_idx = *(uint16_t *)param_info->value;
9868c2ecf20Sopenharmony_ci			break;
9878c2ecf20Sopenharmony_ci		case ISCSI_CHAP_PARAM_CHAP_TYPE:
9888c2ecf20Sopenharmony_ci			chap_rec.chap_type = param_info->value[0];
9898c2ecf20Sopenharmony_ci			break;
9908c2ecf20Sopenharmony_ci		case ISCSI_CHAP_PARAM_USERNAME:
9918c2ecf20Sopenharmony_ci			size = min_t(size_t, sizeof(chap_rec.username),
9928c2ecf20Sopenharmony_ci				     param_info->len);
9938c2ecf20Sopenharmony_ci			memcpy(chap_rec.username, param_info->value, size);
9948c2ecf20Sopenharmony_ci			break;
9958c2ecf20Sopenharmony_ci		case ISCSI_CHAP_PARAM_PASSWORD:
9968c2ecf20Sopenharmony_ci			size = min_t(size_t, sizeof(chap_rec.password),
9978c2ecf20Sopenharmony_ci				     param_info->len);
9988c2ecf20Sopenharmony_ci			memcpy(chap_rec.password, param_info->value, size);
9998c2ecf20Sopenharmony_ci			break;
10008c2ecf20Sopenharmony_ci		case ISCSI_CHAP_PARAM_PASSWORD_LEN:
10018c2ecf20Sopenharmony_ci			chap_rec.password_length = param_info->value[0];
10028c2ecf20Sopenharmony_ci			break;
10038c2ecf20Sopenharmony_ci		default:
10048c2ecf20Sopenharmony_ci			ql4_printk(KERN_ERR, ha,
10058c2ecf20Sopenharmony_ci				   "%s: No such sysfs attribute\n", __func__);
10068c2ecf20Sopenharmony_ci			rc = -ENOSYS;
10078c2ecf20Sopenharmony_ci			goto exit_set_chap;
10088c2ecf20Sopenharmony_ci		}
10098c2ecf20Sopenharmony_ci	}
10108c2ecf20Sopenharmony_ci
10118c2ecf20Sopenharmony_ci	if (chap_rec.chap_type == CHAP_TYPE_IN)
10128c2ecf20Sopenharmony_ci		type = BIDI_CHAP;
10138c2ecf20Sopenharmony_ci	else
10148c2ecf20Sopenharmony_ci		type = LOCAL_CHAP;
10158c2ecf20Sopenharmony_ci
10168c2ecf20Sopenharmony_ci	if (is_qla80XX(ha))
10178c2ecf20Sopenharmony_ci		max_chap_entries = (ha->hw.flt_chap_size / 2) /
10188c2ecf20Sopenharmony_ci				   sizeof(struct ql4_chap_table);
10198c2ecf20Sopenharmony_ci	else
10208c2ecf20Sopenharmony_ci		max_chap_entries = MAX_CHAP_ENTRIES_40XX;
10218c2ecf20Sopenharmony_ci
10228c2ecf20Sopenharmony_ci	mutex_lock(&ha->chap_sem);
10238c2ecf20Sopenharmony_ci	if (chap_rec.chap_tbl_idx < max_chap_entries) {
10248c2ecf20Sopenharmony_ci		rc = qla4xxx_get_chap_by_index(ha, chap_rec.chap_tbl_idx,
10258c2ecf20Sopenharmony_ci					       &chap_entry);
10268c2ecf20Sopenharmony_ci		if (!rc) {
10278c2ecf20Sopenharmony_ci			if (!(type == qla4xxx_get_chap_type(chap_entry))) {
10288c2ecf20Sopenharmony_ci				ql4_printk(KERN_INFO, ha,
10298c2ecf20Sopenharmony_ci					   "Type mismatch for CHAP entry %d\n",
10308c2ecf20Sopenharmony_ci					   chap_rec.chap_tbl_idx);
10318c2ecf20Sopenharmony_ci				rc = -EINVAL;
10328c2ecf20Sopenharmony_ci				goto exit_unlock_chap;
10338c2ecf20Sopenharmony_ci			}
10348c2ecf20Sopenharmony_ci
10358c2ecf20Sopenharmony_ci			/* If chap index is in use then don't modify it */
10368c2ecf20Sopenharmony_ci			rc = qla4xxx_is_chap_active(shost,
10378c2ecf20Sopenharmony_ci						    chap_rec.chap_tbl_idx);
10388c2ecf20Sopenharmony_ci			if (rc) {
10398c2ecf20Sopenharmony_ci				ql4_printk(KERN_INFO, ha,
10408c2ecf20Sopenharmony_ci					   "CHAP entry %d is in use\n",
10418c2ecf20Sopenharmony_ci					   chap_rec.chap_tbl_idx);
10428c2ecf20Sopenharmony_ci				rc = -EBUSY;
10438c2ecf20Sopenharmony_ci				goto exit_unlock_chap;
10448c2ecf20Sopenharmony_ci			}
10458c2ecf20Sopenharmony_ci		}
10468c2ecf20Sopenharmony_ci	} else {
10478c2ecf20Sopenharmony_ci		rc = qla4xxx_find_free_chap_index(ha, &chap_rec.chap_tbl_idx);
10488c2ecf20Sopenharmony_ci		if (rc) {
10498c2ecf20Sopenharmony_ci			ql4_printk(KERN_INFO, ha, "CHAP entry not available\n");
10508c2ecf20Sopenharmony_ci			rc = -EBUSY;
10518c2ecf20Sopenharmony_ci			goto exit_unlock_chap;
10528c2ecf20Sopenharmony_ci		}
10538c2ecf20Sopenharmony_ci	}
10548c2ecf20Sopenharmony_ci
10558c2ecf20Sopenharmony_ci	rc = qla4xxx_set_chap(ha, chap_rec.username, chap_rec.password,
10568c2ecf20Sopenharmony_ci			      chap_rec.chap_tbl_idx, type);
10578c2ecf20Sopenharmony_ci
10588c2ecf20Sopenharmony_ciexit_unlock_chap:
10598c2ecf20Sopenharmony_ci	mutex_unlock(&ha->chap_sem);
10608c2ecf20Sopenharmony_ci
10618c2ecf20Sopenharmony_ciexit_set_chap:
10628c2ecf20Sopenharmony_ci	return rc;
10638c2ecf20Sopenharmony_ci}
10648c2ecf20Sopenharmony_ci
10658c2ecf20Sopenharmony_ci
10668c2ecf20Sopenharmony_cistatic int qla4xxx_get_host_stats(struct Scsi_Host *shost, char *buf, int len)
10678c2ecf20Sopenharmony_ci{
10688c2ecf20Sopenharmony_ci	struct scsi_qla_host *ha = to_qla_host(shost);
10698c2ecf20Sopenharmony_ci	struct iscsi_offload_host_stats *host_stats = NULL;
10708c2ecf20Sopenharmony_ci	int host_stats_size;
10718c2ecf20Sopenharmony_ci	int ret = 0;
10728c2ecf20Sopenharmony_ci	int ddb_idx = 0;
10738c2ecf20Sopenharmony_ci	struct ql_iscsi_stats *ql_iscsi_stats = NULL;
10748c2ecf20Sopenharmony_ci	int stats_size;
10758c2ecf20Sopenharmony_ci	dma_addr_t iscsi_stats_dma;
10768c2ecf20Sopenharmony_ci
10778c2ecf20Sopenharmony_ci	DEBUG2(ql4_printk(KERN_INFO, ha, "Func: %s\n", __func__));
10788c2ecf20Sopenharmony_ci
10798c2ecf20Sopenharmony_ci	host_stats_size = sizeof(struct iscsi_offload_host_stats);
10808c2ecf20Sopenharmony_ci
10818c2ecf20Sopenharmony_ci	if (host_stats_size != len) {
10828c2ecf20Sopenharmony_ci		ql4_printk(KERN_INFO, ha, "%s: host_stats size mismatch expected = %d, is = %d\n",
10838c2ecf20Sopenharmony_ci			   __func__, len, host_stats_size);
10848c2ecf20Sopenharmony_ci		ret = -EINVAL;
10858c2ecf20Sopenharmony_ci		goto exit_host_stats;
10868c2ecf20Sopenharmony_ci	}
10878c2ecf20Sopenharmony_ci	host_stats = (struct iscsi_offload_host_stats *)buf;
10888c2ecf20Sopenharmony_ci
10898c2ecf20Sopenharmony_ci	if (!buf) {
10908c2ecf20Sopenharmony_ci		ret = -ENOMEM;
10918c2ecf20Sopenharmony_ci		goto exit_host_stats;
10928c2ecf20Sopenharmony_ci	}
10938c2ecf20Sopenharmony_ci
10948c2ecf20Sopenharmony_ci	stats_size = PAGE_ALIGN(sizeof(struct ql_iscsi_stats));
10958c2ecf20Sopenharmony_ci
10968c2ecf20Sopenharmony_ci	ql_iscsi_stats = dma_alloc_coherent(&ha->pdev->dev, stats_size,
10978c2ecf20Sopenharmony_ci					    &iscsi_stats_dma, GFP_KERNEL);
10988c2ecf20Sopenharmony_ci	if (!ql_iscsi_stats) {
10998c2ecf20Sopenharmony_ci		ql4_printk(KERN_ERR, ha,
11008c2ecf20Sopenharmony_ci			   "Unable to allocate memory for iscsi stats\n");
11018c2ecf20Sopenharmony_ci		ret = -ENOMEM;
11028c2ecf20Sopenharmony_ci		goto exit_host_stats;
11038c2ecf20Sopenharmony_ci	}
11048c2ecf20Sopenharmony_ci
11058c2ecf20Sopenharmony_ci	ret =  qla4xxx_get_mgmt_data(ha, ddb_idx, stats_size,
11068c2ecf20Sopenharmony_ci				     iscsi_stats_dma);
11078c2ecf20Sopenharmony_ci	if (ret != QLA_SUCCESS) {
11088c2ecf20Sopenharmony_ci		ql4_printk(KERN_ERR, ha,
11098c2ecf20Sopenharmony_ci			   "Unable to retrieve iscsi stats\n");
11108c2ecf20Sopenharmony_ci		ret = -EIO;
11118c2ecf20Sopenharmony_ci		goto exit_host_stats;
11128c2ecf20Sopenharmony_ci	}
11138c2ecf20Sopenharmony_ci	host_stats->mactx_frames = le64_to_cpu(ql_iscsi_stats->mac_tx_frames);
11148c2ecf20Sopenharmony_ci	host_stats->mactx_bytes = le64_to_cpu(ql_iscsi_stats->mac_tx_bytes);
11158c2ecf20Sopenharmony_ci	host_stats->mactx_multicast_frames =
11168c2ecf20Sopenharmony_ci			le64_to_cpu(ql_iscsi_stats->mac_tx_multicast_frames);
11178c2ecf20Sopenharmony_ci	host_stats->mactx_broadcast_frames =
11188c2ecf20Sopenharmony_ci			le64_to_cpu(ql_iscsi_stats->mac_tx_broadcast_frames);
11198c2ecf20Sopenharmony_ci	host_stats->mactx_pause_frames =
11208c2ecf20Sopenharmony_ci			le64_to_cpu(ql_iscsi_stats->mac_tx_pause_frames);
11218c2ecf20Sopenharmony_ci	host_stats->mactx_control_frames =
11228c2ecf20Sopenharmony_ci			le64_to_cpu(ql_iscsi_stats->mac_tx_control_frames);
11238c2ecf20Sopenharmony_ci	host_stats->mactx_deferral =
11248c2ecf20Sopenharmony_ci			le64_to_cpu(ql_iscsi_stats->mac_tx_deferral);
11258c2ecf20Sopenharmony_ci	host_stats->mactx_excess_deferral =
11268c2ecf20Sopenharmony_ci			le64_to_cpu(ql_iscsi_stats->mac_tx_excess_deferral);
11278c2ecf20Sopenharmony_ci	host_stats->mactx_late_collision =
11288c2ecf20Sopenharmony_ci			le64_to_cpu(ql_iscsi_stats->mac_tx_late_collision);
11298c2ecf20Sopenharmony_ci	host_stats->mactx_abort	= le64_to_cpu(ql_iscsi_stats->mac_tx_abort);
11308c2ecf20Sopenharmony_ci	host_stats->mactx_single_collision =
11318c2ecf20Sopenharmony_ci			le64_to_cpu(ql_iscsi_stats->mac_tx_single_collision);
11328c2ecf20Sopenharmony_ci	host_stats->mactx_multiple_collision =
11338c2ecf20Sopenharmony_ci			le64_to_cpu(ql_iscsi_stats->mac_tx_multiple_collision);
11348c2ecf20Sopenharmony_ci	host_stats->mactx_collision =
11358c2ecf20Sopenharmony_ci			le64_to_cpu(ql_iscsi_stats->mac_tx_collision);
11368c2ecf20Sopenharmony_ci	host_stats->mactx_frames_dropped =
11378c2ecf20Sopenharmony_ci			le64_to_cpu(ql_iscsi_stats->mac_tx_frames_dropped);
11388c2ecf20Sopenharmony_ci	host_stats->mactx_jumbo_frames =
11398c2ecf20Sopenharmony_ci			le64_to_cpu(ql_iscsi_stats->mac_tx_jumbo_frames);
11408c2ecf20Sopenharmony_ci	host_stats->macrx_frames = le64_to_cpu(ql_iscsi_stats->mac_rx_frames);
11418c2ecf20Sopenharmony_ci	host_stats->macrx_bytes = le64_to_cpu(ql_iscsi_stats->mac_rx_bytes);
11428c2ecf20Sopenharmony_ci	host_stats->macrx_unknown_control_frames =
11438c2ecf20Sopenharmony_ci		le64_to_cpu(ql_iscsi_stats->mac_rx_unknown_control_frames);
11448c2ecf20Sopenharmony_ci	host_stats->macrx_pause_frames =
11458c2ecf20Sopenharmony_ci			le64_to_cpu(ql_iscsi_stats->mac_rx_pause_frames);
11468c2ecf20Sopenharmony_ci	host_stats->macrx_control_frames =
11478c2ecf20Sopenharmony_ci			le64_to_cpu(ql_iscsi_stats->mac_rx_control_frames);
11488c2ecf20Sopenharmony_ci	host_stats->macrx_dribble =
11498c2ecf20Sopenharmony_ci			le64_to_cpu(ql_iscsi_stats->mac_rx_dribble);
11508c2ecf20Sopenharmony_ci	host_stats->macrx_frame_length_error =
11518c2ecf20Sopenharmony_ci			le64_to_cpu(ql_iscsi_stats->mac_rx_frame_length_error);
11528c2ecf20Sopenharmony_ci	host_stats->macrx_jabber = le64_to_cpu(ql_iscsi_stats->mac_rx_jabber);
11538c2ecf20Sopenharmony_ci	host_stats->macrx_carrier_sense_error =
11548c2ecf20Sopenharmony_ci		le64_to_cpu(ql_iscsi_stats->mac_rx_carrier_sense_error);
11558c2ecf20Sopenharmony_ci	host_stats->macrx_frame_discarded =
11568c2ecf20Sopenharmony_ci			le64_to_cpu(ql_iscsi_stats->mac_rx_frame_discarded);
11578c2ecf20Sopenharmony_ci	host_stats->macrx_frames_dropped =
11588c2ecf20Sopenharmony_ci			le64_to_cpu(ql_iscsi_stats->mac_rx_frames_dropped);
11598c2ecf20Sopenharmony_ci	host_stats->mac_crc_error = le64_to_cpu(ql_iscsi_stats->mac_crc_error);
11608c2ecf20Sopenharmony_ci	host_stats->mac_encoding_error =
11618c2ecf20Sopenharmony_ci			le64_to_cpu(ql_iscsi_stats->mac_encoding_error);
11628c2ecf20Sopenharmony_ci	host_stats->macrx_length_error_large =
11638c2ecf20Sopenharmony_ci			le64_to_cpu(ql_iscsi_stats->mac_rx_length_error_large);
11648c2ecf20Sopenharmony_ci	host_stats->macrx_length_error_small =
11658c2ecf20Sopenharmony_ci			le64_to_cpu(ql_iscsi_stats->mac_rx_length_error_small);
11668c2ecf20Sopenharmony_ci	host_stats->macrx_multicast_frames =
11678c2ecf20Sopenharmony_ci			le64_to_cpu(ql_iscsi_stats->mac_rx_multicast_frames);
11688c2ecf20Sopenharmony_ci	host_stats->macrx_broadcast_frames =
11698c2ecf20Sopenharmony_ci			le64_to_cpu(ql_iscsi_stats->mac_rx_broadcast_frames);
11708c2ecf20Sopenharmony_ci	host_stats->iptx_packets = le64_to_cpu(ql_iscsi_stats->ip_tx_packets);
11718c2ecf20Sopenharmony_ci	host_stats->iptx_bytes = le64_to_cpu(ql_iscsi_stats->ip_tx_bytes);
11728c2ecf20Sopenharmony_ci	host_stats->iptx_fragments =
11738c2ecf20Sopenharmony_ci			le64_to_cpu(ql_iscsi_stats->ip_tx_fragments);
11748c2ecf20Sopenharmony_ci	host_stats->iprx_packets = le64_to_cpu(ql_iscsi_stats->ip_rx_packets);
11758c2ecf20Sopenharmony_ci	host_stats->iprx_bytes = le64_to_cpu(ql_iscsi_stats->ip_rx_bytes);
11768c2ecf20Sopenharmony_ci	host_stats->iprx_fragments =
11778c2ecf20Sopenharmony_ci			le64_to_cpu(ql_iscsi_stats->ip_rx_fragments);
11788c2ecf20Sopenharmony_ci	host_stats->ip_datagram_reassembly =
11798c2ecf20Sopenharmony_ci			le64_to_cpu(ql_iscsi_stats->ip_datagram_reassembly);
11808c2ecf20Sopenharmony_ci	host_stats->ip_invalid_address_error =
11818c2ecf20Sopenharmony_ci			le64_to_cpu(ql_iscsi_stats->ip_invalid_address_error);
11828c2ecf20Sopenharmony_ci	host_stats->ip_error_packets =
11838c2ecf20Sopenharmony_ci			le64_to_cpu(ql_iscsi_stats->ip_error_packets);
11848c2ecf20Sopenharmony_ci	host_stats->ip_fragrx_overlap =
11858c2ecf20Sopenharmony_ci			le64_to_cpu(ql_iscsi_stats->ip_fragrx_overlap);
11868c2ecf20Sopenharmony_ci	host_stats->ip_fragrx_outoforder =
11878c2ecf20Sopenharmony_ci			le64_to_cpu(ql_iscsi_stats->ip_fragrx_outoforder);
11888c2ecf20Sopenharmony_ci	host_stats->ip_datagram_reassembly_timeout =
11898c2ecf20Sopenharmony_ci		le64_to_cpu(ql_iscsi_stats->ip_datagram_reassembly_timeout);
11908c2ecf20Sopenharmony_ci	host_stats->ipv6tx_packets =
11918c2ecf20Sopenharmony_ci			le64_to_cpu(ql_iscsi_stats->ipv6_tx_packets);
11928c2ecf20Sopenharmony_ci	host_stats->ipv6tx_bytes = le64_to_cpu(ql_iscsi_stats->ipv6_tx_bytes);
11938c2ecf20Sopenharmony_ci	host_stats->ipv6tx_fragments =
11948c2ecf20Sopenharmony_ci			le64_to_cpu(ql_iscsi_stats->ipv6_tx_fragments);
11958c2ecf20Sopenharmony_ci	host_stats->ipv6rx_packets =
11968c2ecf20Sopenharmony_ci			le64_to_cpu(ql_iscsi_stats->ipv6_rx_packets);
11978c2ecf20Sopenharmony_ci	host_stats->ipv6rx_bytes = le64_to_cpu(ql_iscsi_stats->ipv6_rx_bytes);
11988c2ecf20Sopenharmony_ci	host_stats->ipv6rx_fragments =
11998c2ecf20Sopenharmony_ci			le64_to_cpu(ql_iscsi_stats->ipv6_rx_fragments);
12008c2ecf20Sopenharmony_ci	host_stats->ipv6_datagram_reassembly =
12018c2ecf20Sopenharmony_ci			le64_to_cpu(ql_iscsi_stats->ipv6_datagram_reassembly);
12028c2ecf20Sopenharmony_ci	host_stats->ipv6_invalid_address_error =
12038c2ecf20Sopenharmony_ci		le64_to_cpu(ql_iscsi_stats->ipv6_invalid_address_error);
12048c2ecf20Sopenharmony_ci	host_stats->ipv6_error_packets =
12058c2ecf20Sopenharmony_ci			le64_to_cpu(ql_iscsi_stats->ipv6_error_packets);
12068c2ecf20Sopenharmony_ci	host_stats->ipv6_fragrx_overlap =
12078c2ecf20Sopenharmony_ci			le64_to_cpu(ql_iscsi_stats->ipv6_fragrx_overlap);
12088c2ecf20Sopenharmony_ci	host_stats->ipv6_fragrx_outoforder =
12098c2ecf20Sopenharmony_ci			le64_to_cpu(ql_iscsi_stats->ipv6_fragrx_outoforder);
12108c2ecf20Sopenharmony_ci	host_stats->ipv6_datagram_reassembly_timeout =
12118c2ecf20Sopenharmony_ci		le64_to_cpu(ql_iscsi_stats->ipv6_datagram_reassembly_timeout);
12128c2ecf20Sopenharmony_ci	host_stats->tcptx_segments =
12138c2ecf20Sopenharmony_ci			le64_to_cpu(ql_iscsi_stats->tcp_tx_segments);
12148c2ecf20Sopenharmony_ci	host_stats->tcptx_bytes	= le64_to_cpu(ql_iscsi_stats->tcp_tx_bytes);
12158c2ecf20Sopenharmony_ci	host_stats->tcprx_segments =
12168c2ecf20Sopenharmony_ci			le64_to_cpu(ql_iscsi_stats->tcp_rx_segments);
12178c2ecf20Sopenharmony_ci	host_stats->tcprx_byte = le64_to_cpu(ql_iscsi_stats->tcp_rx_byte);
12188c2ecf20Sopenharmony_ci	host_stats->tcp_duplicate_ack_retx =
12198c2ecf20Sopenharmony_ci			le64_to_cpu(ql_iscsi_stats->tcp_duplicate_ack_retx);
12208c2ecf20Sopenharmony_ci	host_stats->tcp_retx_timer_expired =
12218c2ecf20Sopenharmony_ci			le64_to_cpu(ql_iscsi_stats->tcp_retx_timer_expired);
12228c2ecf20Sopenharmony_ci	host_stats->tcprx_duplicate_ack	=
12238c2ecf20Sopenharmony_ci			le64_to_cpu(ql_iscsi_stats->tcp_rx_duplicate_ack);
12248c2ecf20Sopenharmony_ci	host_stats->tcprx_pure_ackr =
12258c2ecf20Sopenharmony_ci			le64_to_cpu(ql_iscsi_stats->tcp_rx_pure_ackr);
12268c2ecf20Sopenharmony_ci	host_stats->tcptx_delayed_ack =
12278c2ecf20Sopenharmony_ci			le64_to_cpu(ql_iscsi_stats->tcp_tx_delayed_ack);
12288c2ecf20Sopenharmony_ci	host_stats->tcptx_pure_ack =
12298c2ecf20Sopenharmony_ci			le64_to_cpu(ql_iscsi_stats->tcp_tx_pure_ack);
12308c2ecf20Sopenharmony_ci	host_stats->tcprx_segment_error =
12318c2ecf20Sopenharmony_ci			le64_to_cpu(ql_iscsi_stats->tcp_rx_segment_error);
12328c2ecf20Sopenharmony_ci	host_stats->tcprx_segment_outoforder =
12338c2ecf20Sopenharmony_ci			le64_to_cpu(ql_iscsi_stats->tcp_rx_segment_outoforder);
12348c2ecf20Sopenharmony_ci	host_stats->tcprx_window_probe =
12358c2ecf20Sopenharmony_ci			le64_to_cpu(ql_iscsi_stats->tcp_rx_window_probe);
12368c2ecf20Sopenharmony_ci	host_stats->tcprx_window_update =
12378c2ecf20Sopenharmony_ci			le64_to_cpu(ql_iscsi_stats->tcp_rx_window_update);
12388c2ecf20Sopenharmony_ci	host_stats->tcptx_window_probe_persist =
12398c2ecf20Sopenharmony_ci		le64_to_cpu(ql_iscsi_stats->tcp_tx_window_probe_persist);
12408c2ecf20Sopenharmony_ci	host_stats->ecc_error_correction =
12418c2ecf20Sopenharmony_ci			le64_to_cpu(ql_iscsi_stats->ecc_error_correction);
12428c2ecf20Sopenharmony_ci	host_stats->iscsi_pdu_tx = le64_to_cpu(ql_iscsi_stats->iscsi_pdu_tx);
12438c2ecf20Sopenharmony_ci	host_stats->iscsi_data_bytes_tx =
12448c2ecf20Sopenharmony_ci			le64_to_cpu(ql_iscsi_stats->iscsi_data_bytes_tx);
12458c2ecf20Sopenharmony_ci	host_stats->iscsi_pdu_rx = le64_to_cpu(ql_iscsi_stats->iscsi_pdu_rx);
12468c2ecf20Sopenharmony_ci	host_stats->iscsi_data_bytes_rx	=
12478c2ecf20Sopenharmony_ci			le64_to_cpu(ql_iscsi_stats->iscsi_data_bytes_rx);
12488c2ecf20Sopenharmony_ci	host_stats->iscsi_io_completed =
12498c2ecf20Sopenharmony_ci			le64_to_cpu(ql_iscsi_stats->iscsi_io_completed);
12508c2ecf20Sopenharmony_ci	host_stats->iscsi_unexpected_io_rx =
12518c2ecf20Sopenharmony_ci			le64_to_cpu(ql_iscsi_stats->iscsi_unexpected_io_rx);
12528c2ecf20Sopenharmony_ci	host_stats->iscsi_format_error =
12538c2ecf20Sopenharmony_ci			le64_to_cpu(ql_iscsi_stats->iscsi_format_error);
12548c2ecf20Sopenharmony_ci	host_stats->iscsi_hdr_digest_error =
12558c2ecf20Sopenharmony_ci			le64_to_cpu(ql_iscsi_stats->iscsi_hdr_digest_error);
12568c2ecf20Sopenharmony_ci	host_stats->iscsi_data_digest_error =
12578c2ecf20Sopenharmony_ci			le64_to_cpu(ql_iscsi_stats->iscsi_data_digest_error);
12588c2ecf20Sopenharmony_ci	host_stats->iscsi_sequence_error =
12598c2ecf20Sopenharmony_ci			le64_to_cpu(ql_iscsi_stats->iscsi_sequence_error);
12608c2ecf20Sopenharmony_ciexit_host_stats:
12618c2ecf20Sopenharmony_ci	if (ql_iscsi_stats)
12628c2ecf20Sopenharmony_ci		dma_free_coherent(&ha->pdev->dev, stats_size,
12638c2ecf20Sopenharmony_ci				  ql_iscsi_stats, iscsi_stats_dma);
12648c2ecf20Sopenharmony_ci
12658c2ecf20Sopenharmony_ci	ql4_printk(KERN_INFO, ha, "%s: Get host stats done\n",
12668c2ecf20Sopenharmony_ci		   __func__);
12678c2ecf20Sopenharmony_ci	return ret;
12688c2ecf20Sopenharmony_ci}
12698c2ecf20Sopenharmony_ci
12708c2ecf20Sopenharmony_cistatic int qla4xxx_get_iface_param(struct iscsi_iface *iface,
12718c2ecf20Sopenharmony_ci				   enum iscsi_param_type param_type,
12728c2ecf20Sopenharmony_ci				   int param, char *buf)
12738c2ecf20Sopenharmony_ci{
12748c2ecf20Sopenharmony_ci	struct Scsi_Host *shost = iscsi_iface_to_shost(iface);
12758c2ecf20Sopenharmony_ci	struct scsi_qla_host *ha = to_qla_host(shost);
12768c2ecf20Sopenharmony_ci	int ival;
12778c2ecf20Sopenharmony_ci	char *pval = NULL;
12788c2ecf20Sopenharmony_ci	int len = -ENOSYS;
12798c2ecf20Sopenharmony_ci
12808c2ecf20Sopenharmony_ci	if (param_type == ISCSI_NET_PARAM) {
12818c2ecf20Sopenharmony_ci		switch (param) {
12828c2ecf20Sopenharmony_ci		case ISCSI_NET_PARAM_IPV4_ADDR:
12838c2ecf20Sopenharmony_ci			len = sprintf(buf, "%pI4\n", &ha->ip_config.ip_address);
12848c2ecf20Sopenharmony_ci			break;
12858c2ecf20Sopenharmony_ci		case ISCSI_NET_PARAM_IPV4_SUBNET:
12868c2ecf20Sopenharmony_ci			len = sprintf(buf, "%pI4\n",
12878c2ecf20Sopenharmony_ci				      &ha->ip_config.subnet_mask);
12888c2ecf20Sopenharmony_ci			break;
12898c2ecf20Sopenharmony_ci		case ISCSI_NET_PARAM_IPV4_GW:
12908c2ecf20Sopenharmony_ci			len = sprintf(buf, "%pI4\n", &ha->ip_config.gateway);
12918c2ecf20Sopenharmony_ci			break;
12928c2ecf20Sopenharmony_ci		case ISCSI_NET_PARAM_IFACE_ENABLE:
12938c2ecf20Sopenharmony_ci			if (iface->iface_type == ISCSI_IFACE_TYPE_IPV4) {
12948c2ecf20Sopenharmony_ci				OP_STATE(ha->ip_config.ipv4_options,
12958c2ecf20Sopenharmony_ci					 IPOPT_IPV4_PROTOCOL_ENABLE, pval);
12968c2ecf20Sopenharmony_ci			} else {
12978c2ecf20Sopenharmony_ci				OP_STATE(ha->ip_config.ipv6_options,
12988c2ecf20Sopenharmony_ci					 IPV6_OPT_IPV6_PROTOCOL_ENABLE, pval);
12998c2ecf20Sopenharmony_ci			}
13008c2ecf20Sopenharmony_ci
13018c2ecf20Sopenharmony_ci			len = sprintf(buf, "%s\n", pval);
13028c2ecf20Sopenharmony_ci			break;
13038c2ecf20Sopenharmony_ci		case ISCSI_NET_PARAM_IPV4_BOOTPROTO:
13048c2ecf20Sopenharmony_ci			len = sprintf(buf, "%s\n",
13058c2ecf20Sopenharmony_ci				      (ha->ip_config.tcp_options &
13068c2ecf20Sopenharmony_ci				       TCPOPT_DHCP_ENABLE) ?
13078c2ecf20Sopenharmony_ci				      "dhcp" : "static");
13088c2ecf20Sopenharmony_ci			break;
13098c2ecf20Sopenharmony_ci		case ISCSI_NET_PARAM_IPV6_ADDR:
13108c2ecf20Sopenharmony_ci			if (iface->iface_num == 0)
13118c2ecf20Sopenharmony_ci				len = sprintf(buf, "%pI6\n",
13128c2ecf20Sopenharmony_ci					      &ha->ip_config.ipv6_addr0);
13138c2ecf20Sopenharmony_ci			if (iface->iface_num == 1)
13148c2ecf20Sopenharmony_ci				len = sprintf(buf, "%pI6\n",
13158c2ecf20Sopenharmony_ci					      &ha->ip_config.ipv6_addr1);
13168c2ecf20Sopenharmony_ci			break;
13178c2ecf20Sopenharmony_ci		case ISCSI_NET_PARAM_IPV6_LINKLOCAL:
13188c2ecf20Sopenharmony_ci			len = sprintf(buf, "%pI6\n",
13198c2ecf20Sopenharmony_ci				      &ha->ip_config.ipv6_link_local_addr);
13208c2ecf20Sopenharmony_ci			break;
13218c2ecf20Sopenharmony_ci		case ISCSI_NET_PARAM_IPV6_ROUTER:
13228c2ecf20Sopenharmony_ci			len = sprintf(buf, "%pI6\n",
13238c2ecf20Sopenharmony_ci				      &ha->ip_config.ipv6_default_router_addr);
13248c2ecf20Sopenharmony_ci			break;
13258c2ecf20Sopenharmony_ci		case ISCSI_NET_PARAM_IPV6_ADDR_AUTOCFG:
13268c2ecf20Sopenharmony_ci			pval = (ha->ip_config.ipv6_addl_options &
13278c2ecf20Sopenharmony_ci				IPV6_ADDOPT_NEIGHBOR_DISCOVERY_ADDR_ENABLE) ?
13288c2ecf20Sopenharmony_ci				"nd" : "static";
13298c2ecf20Sopenharmony_ci
13308c2ecf20Sopenharmony_ci			len = sprintf(buf, "%s\n", pval);
13318c2ecf20Sopenharmony_ci			break;
13328c2ecf20Sopenharmony_ci		case ISCSI_NET_PARAM_IPV6_LINKLOCAL_AUTOCFG:
13338c2ecf20Sopenharmony_ci			pval = (ha->ip_config.ipv6_addl_options &
13348c2ecf20Sopenharmony_ci				IPV6_ADDOPT_AUTOCONFIG_LINK_LOCAL_ADDR) ?
13358c2ecf20Sopenharmony_ci				"auto" : "static";
13368c2ecf20Sopenharmony_ci
13378c2ecf20Sopenharmony_ci			len = sprintf(buf, "%s\n", pval);
13388c2ecf20Sopenharmony_ci			break;
13398c2ecf20Sopenharmony_ci		case ISCSI_NET_PARAM_VLAN_ID:
13408c2ecf20Sopenharmony_ci			if (iface->iface_type == ISCSI_IFACE_TYPE_IPV4)
13418c2ecf20Sopenharmony_ci				ival = ha->ip_config.ipv4_vlan_tag &
13428c2ecf20Sopenharmony_ci				       ISCSI_MAX_VLAN_ID;
13438c2ecf20Sopenharmony_ci			else
13448c2ecf20Sopenharmony_ci				ival = ha->ip_config.ipv6_vlan_tag &
13458c2ecf20Sopenharmony_ci				       ISCSI_MAX_VLAN_ID;
13468c2ecf20Sopenharmony_ci
13478c2ecf20Sopenharmony_ci			len = sprintf(buf, "%d\n", ival);
13488c2ecf20Sopenharmony_ci			break;
13498c2ecf20Sopenharmony_ci		case ISCSI_NET_PARAM_VLAN_PRIORITY:
13508c2ecf20Sopenharmony_ci			if (iface->iface_type == ISCSI_IFACE_TYPE_IPV4)
13518c2ecf20Sopenharmony_ci				ival = (ha->ip_config.ipv4_vlan_tag >> 13) &
13528c2ecf20Sopenharmony_ci				       ISCSI_MAX_VLAN_PRIORITY;
13538c2ecf20Sopenharmony_ci			else
13548c2ecf20Sopenharmony_ci				ival = (ha->ip_config.ipv6_vlan_tag >> 13) &
13558c2ecf20Sopenharmony_ci				       ISCSI_MAX_VLAN_PRIORITY;
13568c2ecf20Sopenharmony_ci
13578c2ecf20Sopenharmony_ci			len = sprintf(buf, "%d\n", ival);
13588c2ecf20Sopenharmony_ci			break;
13598c2ecf20Sopenharmony_ci		case ISCSI_NET_PARAM_VLAN_ENABLED:
13608c2ecf20Sopenharmony_ci			if (iface->iface_type == ISCSI_IFACE_TYPE_IPV4) {
13618c2ecf20Sopenharmony_ci				OP_STATE(ha->ip_config.ipv4_options,
13628c2ecf20Sopenharmony_ci					 IPOPT_VLAN_TAGGING_ENABLE, pval);
13638c2ecf20Sopenharmony_ci			} else {
13648c2ecf20Sopenharmony_ci				OP_STATE(ha->ip_config.ipv6_options,
13658c2ecf20Sopenharmony_ci					 IPV6_OPT_VLAN_TAGGING_ENABLE, pval);
13668c2ecf20Sopenharmony_ci			}
13678c2ecf20Sopenharmony_ci			len = sprintf(buf, "%s\n", pval);
13688c2ecf20Sopenharmony_ci			break;
13698c2ecf20Sopenharmony_ci		case ISCSI_NET_PARAM_MTU:
13708c2ecf20Sopenharmony_ci			len = sprintf(buf, "%d\n", ha->ip_config.eth_mtu_size);
13718c2ecf20Sopenharmony_ci			break;
13728c2ecf20Sopenharmony_ci		case ISCSI_NET_PARAM_PORT:
13738c2ecf20Sopenharmony_ci			if (iface->iface_type == ISCSI_IFACE_TYPE_IPV4)
13748c2ecf20Sopenharmony_ci				len = sprintf(buf, "%d\n",
13758c2ecf20Sopenharmony_ci					      ha->ip_config.ipv4_port);
13768c2ecf20Sopenharmony_ci			else
13778c2ecf20Sopenharmony_ci				len = sprintf(buf, "%d\n",
13788c2ecf20Sopenharmony_ci					      ha->ip_config.ipv6_port);
13798c2ecf20Sopenharmony_ci			break;
13808c2ecf20Sopenharmony_ci		case ISCSI_NET_PARAM_IPADDR_STATE:
13818c2ecf20Sopenharmony_ci			if (iface->iface_type == ISCSI_IFACE_TYPE_IPV4) {
13828c2ecf20Sopenharmony_ci				pval = iscsi_get_ipaddress_state_name(
13838c2ecf20Sopenharmony_ci						ha->ip_config.ipv4_addr_state);
13848c2ecf20Sopenharmony_ci			} else {
13858c2ecf20Sopenharmony_ci				if (iface->iface_num == 0)
13868c2ecf20Sopenharmony_ci					pval = iscsi_get_ipaddress_state_name(
13878c2ecf20Sopenharmony_ci						ha->ip_config.ipv6_addr0_state);
13888c2ecf20Sopenharmony_ci				else if (iface->iface_num == 1)
13898c2ecf20Sopenharmony_ci					pval = iscsi_get_ipaddress_state_name(
13908c2ecf20Sopenharmony_ci						ha->ip_config.ipv6_addr1_state);
13918c2ecf20Sopenharmony_ci			}
13928c2ecf20Sopenharmony_ci
13938c2ecf20Sopenharmony_ci			len = sprintf(buf, "%s\n", pval);
13948c2ecf20Sopenharmony_ci			break;
13958c2ecf20Sopenharmony_ci		case ISCSI_NET_PARAM_IPV6_LINKLOCAL_STATE:
13968c2ecf20Sopenharmony_ci			pval = iscsi_get_ipaddress_state_name(
13978c2ecf20Sopenharmony_ci					ha->ip_config.ipv6_link_local_state);
13988c2ecf20Sopenharmony_ci			len = sprintf(buf, "%s\n", pval);
13998c2ecf20Sopenharmony_ci			break;
14008c2ecf20Sopenharmony_ci		case ISCSI_NET_PARAM_IPV6_ROUTER_STATE:
14018c2ecf20Sopenharmony_ci			pval = iscsi_get_router_state_name(
14028c2ecf20Sopenharmony_ci				      ha->ip_config.ipv6_default_router_state);
14038c2ecf20Sopenharmony_ci			len = sprintf(buf, "%s\n", pval);
14048c2ecf20Sopenharmony_ci			break;
14058c2ecf20Sopenharmony_ci		case ISCSI_NET_PARAM_DELAYED_ACK_EN:
14068c2ecf20Sopenharmony_ci			if (iface->iface_type == ISCSI_IFACE_TYPE_IPV4) {
14078c2ecf20Sopenharmony_ci				OP_STATE(~ha->ip_config.tcp_options,
14088c2ecf20Sopenharmony_ci					 TCPOPT_DELAYED_ACK_DISABLE, pval);
14098c2ecf20Sopenharmony_ci			} else {
14108c2ecf20Sopenharmony_ci				OP_STATE(~ha->ip_config.ipv6_tcp_options,
14118c2ecf20Sopenharmony_ci					 IPV6_TCPOPT_DELAYED_ACK_DISABLE, pval);
14128c2ecf20Sopenharmony_ci			}
14138c2ecf20Sopenharmony_ci			len = sprintf(buf, "%s\n", pval);
14148c2ecf20Sopenharmony_ci			break;
14158c2ecf20Sopenharmony_ci		case ISCSI_NET_PARAM_TCP_NAGLE_DISABLE:
14168c2ecf20Sopenharmony_ci			if (iface->iface_type == ISCSI_IFACE_TYPE_IPV4) {
14178c2ecf20Sopenharmony_ci				OP_STATE(~ha->ip_config.tcp_options,
14188c2ecf20Sopenharmony_ci					 TCPOPT_NAGLE_ALGO_DISABLE, pval);
14198c2ecf20Sopenharmony_ci			} else {
14208c2ecf20Sopenharmony_ci				OP_STATE(~ha->ip_config.ipv6_tcp_options,
14218c2ecf20Sopenharmony_ci					 IPV6_TCPOPT_NAGLE_ALGO_DISABLE, pval);
14228c2ecf20Sopenharmony_ci			}
14238c2ecf20Sopenharmony_ci			len = sprintf(buf, "%s\n", pval);
14248c2ecf20Sopenharmony_ci			break;
14258c2ecf20Sopenharmony_ci		case ISCSI_NET_PARAM_TCP_WSF_DISABLE:
14268c2ecf20Sopenharmony_ci			if (iface->iface_type == ISCSI_IFACE_TYPE_IPV4) {
14278c2ecf20Sopenharmony_ci				OP_STATE(~ha->ip_config.tcp_options,
14288c2ecf20Sopenharmony_ci					 TCPOPT_WINDOW_SCALE_DISABLE, pval);
14298c2ecf20Sopenharmony_ci			} else {
14308c2ecf20Sopenharmony_ci				OP_STATE(~ha->ip_config.ipv6_tcp_options,
14318c2ecf20Sopenharmony_ci					 IPV6_TCPOPT_WINDOW_SCALE_DISABLE,
14328c2ecf20Sopenharmony_ci					 pval);
14338c2ecf20Sopenharmony_ci			}
14348c2ecf20Sopenharmony_ci			len = sprintf(buf, "%s\n", pval);
14358c2ecf20Sopenharmony_ci			break;
14368c2ecf20Sopenharmony_ci		case ISCSI_NET_PARAM_TCP_WSF:
14378c2ecf20Sopenharmony_ci			if (iface->iface_type == ISCSI_IFACE_TYPE_IPV4)
14388c2ecf20Sopenharmony_ci				len = sprintf(buf, "%d\n",
14398c2ecf20Sopenharmony_ci					      ha->ip_config.tcp_wsf);
14408c2ecf20Sopenharmony_ci			else
14418c2ecf20Sopenharmony_ci				len = sprintf(buf, "%d\n",
14428c2ecf20Sopenharmony_ci					      ha->ip_config.ipv6_tcp_wsf);
14438c2ecf20Sopenharmony_ci			break;
14448c2ecf20Sopenharmony_ci		case ISCSI_NET_PARAM_TCP_TIMER_SCALE:
14458c2ecf20Sopenharmony_ci			if (iface->iface_type == ISCSI_IFACE_TYPE_IPV4)
14468c2ecf20Sopenharmony_ci				ival = (ha->ip_config.tcp_options &
14478c2ecf20Sopenharmony_ci					TCPOPT_TIMER_SCALE) >> 1;
14488c2ecf20Sopenharmony_ci			else
14498c2ecf20Sopenharmony_ci				ival = (ha->ip_config.ipv6_tcp_options &
14508c2ecf20Sopenharmony_ci					IPV6_TCPOPT_TIMER_SCALE) >> 1;
14518c2ecf20Sopenharmony_ci
14528c2ecf20Sopenharmony_ci			len = sprintf(buf, "%d\n", ival);
14538c2ecf20Sopenharmony_ci			break;
14548c2ecf20Sopenharmony_ci		case ISCSI_NET_PARAM_TCP_TIMESTAMP_EN:
14558c2ecf20Sopenharmony_ci			if (iface->iface_type == ISCSI_IFACE_TYPE_IPV4) {
14568c2ecf20Sopenharmony_ci				OP_STATE(ha->ip_config.tcp_options,
14578c2ecf20Sopenharmony_ci					 TCPOPT_TIMESTAMP_ENABLE, pval);
14588c2ecf20Sopenharmony_ci			} else {
14598c2ecf20Sopenharmony_ci				OP_STATE(ha->ip_config.ipv6_tcp_options,
14608c2ecf20Sopenharmony_ci					 IPV6_TCPOPT_TIMESTAMP_EN, pval);
14618c2ecf20Sopenharmony_ci			}
14628c2ecf20Sopenharmony_ci			len = sprintf(buf, "%s\n", pval);
14638c2ecf20Sopenharmony_ci			break;
14648c2ecf20Sopenharmony_ci		case ISCSI_NET_PARAM_CACHE_ID:
14658c2ecf20Sopenharmony_ci			if (iface->iface_type == ISCSI_IFACE_TYPE_IPV4)
14668c2ecf20Sopenharmony_ci				len = sprintf(buf, "%d\n",
14678c2ecf20Sopenharmony_ci					      ha->ip_config.ipv4_cache_id);
14688c2ecf20Sopenharmony_ci			else
14698c2ecf20Sopenharmony_ci				len = sprintf(buf, "%d\n",
14708c2ecf20Sopenharmony_ci					      ha->ip_config.ipv6_cache_id);
14718c2ecf20Sopenharmony_ci			break;
14728c2ecf20Sopenharmony_ci		case ISCSI_NET_PARAM_IPV4_DHCP_DNS_ADDR_EN:
14738c2ecf20Sopenharmony_ci			OP_STATE(ha->ip_config.tcp_options,
14748c2ecf20Sopenharmony_ci				 TCPOPT_DNS_SERVER_IP_EN, pval);
14758c2ecf20Sopenharmony_ci
14768c2ecf20Sopenharmony_ci			len = sprintf(buf, "%s\n", pval);
14778c2ecf20Sopenharmony_ci			break;
14788c2ecf20Sopenharmony_ci		case ISCSI_NET_PARAM_IPV4_DHCP_SLP_DA_EN:
14798c2ecf20Sopenharmony_ci			OP_STATE(ha->ip_config.tcp_options,
14808c2ecf20Sopenharmony_ci				 TCPOPT_SLP_DA_INFO_EN, pval);
14818c2ecf20Sopenharmony_ci
14828c2ecf20Sopenharmony_ci			len = sprintf(buf, "%s\n", pval);
14838c2ecf20Sopenharmony_ci			break;
14848c2ecf20Sopenharmony_ci		case ISCSI_NET_PARAM_IPV4_TOS_EN:
14858c2ecf20Sopenharmony_ci			OP_STATE(ha->ip_config.ipv4_options,
14868c2ecf20Sopenharmony_ci				 IPOPT_IPV4_TOS_EN, pval);
14878c2ecf20Sopenharmony_ci
14888c2ecf20Sopenharmony_ci			len = sprintf(buf, "%s\n", pval);
14898c2ecf20Sopenharmony_ci			break;
14908c2ecf20Sopenharmony_ci		case ISCSI_NET_PARAM_IPV4_TOS:
14918c2ecf20Sopenharmony_ci			len = sprintf(buf, "%d\n", ha->ip_config.ipv4_tos);
14928c2ecf20Sopenharmony_ci			break;
14938c2ecf20Sopenharmony_ci		case ISCSI_NET_PARAM_IPV4_GRAT_ARP_EN:
14948c2ecf20Sopenharmony_ci			OP_STATE(ha->ip_config.ipv4_options,
14958c2ecf20Sopenharmony_ci				 IPOPT_GRAT_ARP_EN, pval);
14968c2ecf20Sopenharmony_ci
14978c2ecf20Sopenharmony_ci			len = sprintf(buf, "%s\n", pval);
14988c2ecf20Sopenharmony_ci			break;
14998c2ecf20Sopenharmony_ci		case ISCSI_NET_PARAM_IPV4_DHCP_ALT_CLIENT_ID_EN:
15008c2ecf20Sopenharmony_ci			OP_STATE(ha->ip_config.ipv4_options, IPOPT_ALT_CID_EN,
15018c2ecf20Sopenharmony_ci				 pval);
15028c2ecf20Sopenharmony_ci
15038c2ecf20Sopenharmony_ci			len = sprintf(buf, "%s\n", pval);
15048c2ecf20Sopenharmony_ci			break;
15058c2ecf20Sopenharmony_ci		case ISCSI_NET_PARAM_IPV4_DHCP_ALT_CLIENT_ID:
15068c2ecf20Sopenharmony_ci			pval = (ha->ip_config.ipv4_alt_cid_len) ?
15078c2ecf20Sopenharmony_ci			       (char *)ha->ip_config.ipv4_alt_cid : "";
15088c2ecf20Sopenharmony_ci
15098c2ecf20Sopenharmony_ci			len = sprintf(buf, "%s\n", pval);
15108c2ecf20Sopenharmony_ci			break;
15118c2ecf20Sopenharmony_ci		case ISCSI_NET_PARAM_IPV4_DHCP_REQ_VENDOR_ID_EN:
15128c2ecf20Sopenharmony_ci			OP_STATE(ha->ip_config.ipv4_options,
15138c2ecf20Sopenharmony_ci				 IPOPT_REQ_VID_EN, pval);
15148c2ecf20Sopenharmony_ci
15158c2ecf20Sopenharmony_ci			len = sprintf(buf, "%s\n", pval);
15168c2ecf20Sopenharmony_ci			break;
15178c2ecf20Sopenharmony_ci		case ISCSI_NET_PARAM_IPV4_DHCP_USE_VENDOR_ID_EN:
15188c2ecf20Sopenharmony_ci			OP_STATE(ha->ip_config.ipv4_options,
15198c2ecf20Sopenharmony_ci				 IPOPT_USE_VID_EN, pval);
15208c2ecf20Sopenharmony_ci
15218c2ecf20Sopenharmony_ci			len = sprintf(buf, "%s\n", pval);
15228c2ecf20Sopenharmony_ci			break;
15238c2ecf20Sopenharmony_ci		case ISCSI_NET_PARAM_IPV4_DHCP_VENDOR_ID:
15248c2ecf20Sopenharmony_ci			pval = (ha->ip_config.ipv4_vid_len) ?
15258c2ecf20Sopenharmony_ci			       (char *)ha->ip_config.ipv4_vid : "";
15268c2ecf20Sopenharmony_ci
15278c2ecf20Sopenharmony_ci			len = sprintf(buf, "%s\n", pval);
15288c2ecf20Sopenharmony_ci			break;
15298c2ecf20Sopenharmony_ci		case ISCSI_NET_PARAM_IPV4_DHCP_LEARN_IQN_EN:
15308c2ecf20Sopenharmony_ci			OP_STATE(ha->ip_config.ipv4_options,
15318c2ecf20Sopenharmony_ci				 IPOPT_LEARN_IQN_EN, pval);
15328c2ecf20Sopenharmony_ci
15338c2ecf20Sopenharmony_ci			len = sprintf(buf, "%s\n", pval);
15348c2ecf20Sopenharmony_ci			break;
15358c2ecf20Sopenharmony_ci		case ISCSI_NET_PARAM_IPV4_FRAGMENT_DISABLE:
15368c2ecf20Sopenharmony_ci			OP_STATE(~ha->ip_config.ipv4_options,
15378c2ecf20Sopenharmony_ci				 IPOPT_FRAGMENTATION_DISABLE, pval);
15388c2ecf20Sopenharmony_ci
15398c2ecf20Sopenharmony_ci			len = sprintf(buf, "%s\n", pval);
15408c2ecf20Sopenharmony_ci			break;
15418c2ecf20Sopenharmony_ci		case ISCSI_NET_PARAM_IPV4_IN_FORWARD_EN:
15428c2ecf20Sopenharmony_ci			OP_STATE(ha->ip_config.ipv4_options,
15438c2ecf20Sopenharmony_ci				 IPOPT_IN_FORWARD_EN, pval);
15448c2ecf20Sopenharmony_ci
15458c2ecf20Sopenharmony_ci			len = sprintf(buf, "%s\n", pval);
15468c2ecf20Sopenharmony_ci			break;
15478c2ecf20Sopenharmony_ci		case ISCSI_NET_PARAM_REDIRECT_EN:
15488c2ecf20Sopenharmony_ci			if (iface->iface_type == ISCSI_IFACE_TYPE_IPV4) {
15498c2ecf20Sopenharmony_ci				OP_STATE(ha->ip_config.ipv4_options,
15508c2ecf20Sopenharmony_ci					 IPOPT_ARP_REDIRECT_EN, pval);
15518c2ecf20Sopenharmony_ci			} else {
15528c2ecf20Sopenharmony_ci				OP_STATE(ha->ip_config.ipv6_options,
15538c2ecf20Sopenharmony_ci					 IPV6_OPT_REDIRECT_EN, pval);
15548c2ecf20Sopenharmony_ci			}
15558c2ecf20Sopenharmony_ci			len = sprintf(buf, "%s\n", pval);
15568c2ecf20Sopenharmony_ci			break;
15578c2ecf20Sopenharmony_ci		case ISCSI_NET_PARAM_IPV4_TTL:
15588c2ecf20Sopenharmony_ci			len = sprintf(buf, "%d\n", ha->ip_config.ipv4_ttl);
15598c2ecf20Sopenharmony_ci			break;
15608c2ecf20Sopenharmony_ci		case ISCSI_NET_PARAM_IPV6_GRAT_NEIGHBOR_ADV_EN:
15618c2ecf20Sopenharmony_ci			OP_STATE(ha->ip_config.ipv6_options,
15628c2ecf20Sopenharmony_ci				 IPV6_OPT_GRAT_NEIGHBOR_ADV_EN, pval);
15638c2ecf20Sopenharmony_ci
15648c2ecf20Sopenharmony_ci			len = sprintf(buf, "%s\n", pval);
15658c2ecf20Sopenharmony_ci			break;
15668c2ecf20Sopenharmony_ci		case ISCSI_NET_PARAM_IPV6_MLD_EN:
15678c2ecf20Sopenharmony_ci			OP_STATE(ha->ip_config.ipv6_addl_options,
15688c2ecf20Sopenharmony_ci				 IPV6_ADDOPT_MLD_EN, pval);
15698c2ecf20Sopenharmony_ci
15708c2ecf20Sopenharmony_ci			len = sprintf(buf, "%s\n", pval);
15718c2ecf20Sopenharmony_ci			break;
15728c2ecf20Sopenharmony_ci		case ISCSI_NET_PARAM_IPV6_FLOW_LABEL:
15738c2ecf20Sopenharmony_ci			len = sprintf(buf, "%u\n", ha->ip_config.ipv6_flow_lbl);
15748c2ecf20Sopenharmony_ci			break;
15758c2ecf20Sopenharmony_ci		case ISCSI_NET_PARAM_IPV6_TRAFFIC_CLASS:
15768c2ecf20Sopenharmony_ci			len = sprintf(buf, "%d\n",
15778c2ecf20Sopenharmony_ci				      ha->ip_config.ipv6_traffic_class);
15788c2ecf20Sopenharmony_ci			break;
15798c2ecf20Sopenharmony_ci		case ISCSI_NET_PARAM_IPV6_HOP_LIMIT:
15808c2ecf20Sopenharmony_ci			len = sprintf(buf, "%d\n",
15818c2ecf20Sopenharmony_ci				      ha->ip_config.ipv6_hop_limit);
15828c2ecf20Sopenharmony_ci			break;
15838c2ecf20Sopenharmony_ci		case ISCSI_NET_PARAM_IPV6_ND_REACHABLE_TMO:
15848c2ecf20Sopenharmony_ci			len = sprintf(buf, "%d\n",
15858c2ecf20Sopenharmony_ci				      ha->ip_config.ipv6_nd_reach_time);
15868c2ecf20Sopenharmony_ci			break;
15878c2ecf20Sopenharmony_ci		case ISCSI_NET_PARAM_IPV6_ND_REXMIT_TIME:
15888c2ecf20Sopenharmony_ci			len = sprintf(buf, "%d\n",
15898c2ecf20Sopenharmony_ci				      ha->ip_config.ipv6_nd_rexmit_timer);
15908c2ecf20Sopenharmony_ci			break;
15918c2ecf20Sopenharmony_ci		case ISCSI_NET_PARAM_IPV6_ND_STALE_TMO:
15928c2ecf20Sopenharmony_ci			len = sprintf(buf, "%d\n",
15938c2ecf20Sopenharmony_ci				      ha->ip_config.ipv6_nd_stale_timeout);
15948c2ecf20Sopenharmony_ci			break;
15958c2ecf20Sopenharmony_ci		case ISCSI_NET_PARAM_IPV6_DUP_ADDR_DETECT_CNT:
15968c2ecf20Sopenharmony_ci			len = sprintf(buf, "%d\n",
15978c2ecf20Sopenharmony_ci				      ha->ip_config.ipv6_dup_addr_detect_count);
15988c2ecf20Sopenharmony_ci			break;
15998c2ecf20Sopenharmony_ci		case ISCSI_NET_PARAM_IPV6_RTR_ADV_LINK_MTU:
16008c2ecf20Sopenharmony_ci			len = sprintf(buf, "%d\n",
16018c2ecf20Sopenharmony_ci				      ha->ip_config.ipv6_gw_advrt_mtu);
16028c2ecf20Sopenharmony_ci			break;
16038c2ecf20Sopenharmony_ci		default:
16048c2ecf20Sopenharmony_ci			len = -ENOSYS;
16058c2ecf20Sopenharmony_ci		}
16068c2ecf20Sopenharmony_ci	} else if (param_type == ISCSI_IFACE_PARAM) {
16078c2ecf20Sopenharmony_ci		switch (param) {
16088c2ecf20Sopenharmony_ci		case ISCSI_IFACE_PARAM_DEF_TASKMGMT_TMO:
16098c2ecf20Sopenharmony_ci			len = sprintf(buf, "%d\n", ha->ip_config.def_timeout);
16108c2ecf20Sopenharmony_ci			break;
16118c2ecf20Sopenharmony_ci		case ISCSI_IFACE_PARAM_HDRDGST_EN:
16128c2ecf20Sopenharmony_ci			OP_STATE(ha->ip_config.iscsi_options,
16138c2ecf20Sopenharmony_ci				 ISCSIOPTS_HEADER_DIGEST_EN, pval);
16148c2ecf20Sopenharmony_ci
16158c2ecf20Sopenharmony_ci			len = sprintf(buf, "%s\n", pval);
16168c2ecf20Sopenharmony_ci			break;
16178c2ecf20Sopenharmony_ci		case ISCSI_IFACE_PARAM_DATADGST_EN:
16188c2ecf20Sopenharmony_ci			OP_STATE(ha->ip_config.iscsi_options,
16198c2ecf20Sopenharmony_ci				 ISCSIOPTS_DATA_DIGEST_EN, pval);
16208c2ecf20Sopenharmony_ci
16218c2ecf20Sopenharmony_ci			len = sprintf(buf, "%s\n", pval);
16228c2ecf20Sopenharmony_ci			break;
16238c2ecf20Sopenharmony_ci		case ISCSI_IFACE_PARAM_IMM_DATA_EN:
16248c2ecf20Sopenharmony_ci			OP_STATE(ha->ip_config.iscsi_options,
16258c2ecf20Sopenharmony_ci				 ISCSIOPTS_IMMEDIATE_DATA_EN, pval);
16268c2ecf20Sopenharmony_ci
16278c2ecf20Sopenharmony_ci			len = sprintf(buf, "%s\n", pval);
16288c2ecf20Sopenharmony_ci			break;
16298c2ecf20Sopenharmony_ci		case ISCSI_IFACE_PARAM_INITIAL_R2T_EN:
16308c2ecf20Sopenharmony_ci			OP_STATE(ha->ip_config.iscsi_options,
16318c2ecf20Sopenharmony_ci				 ISCSIOPTS_INITIAL_R2T_EN, pval);
16328c2ecf20Sopenharmony_ci
16338c2ecf20Sopenharmony_ci			len = sprintf(buf, "%s\n", pval);
16348c2ecf20Sopenharmony_ci			break;
16358c2ecf20Sopenharmony_ci		case ISCSI_IFACE_PARAM_DATASEQ_INORDER_EN:
16368c2ecf20Sopenharmony_ci			OP_STATE(ha->ip_config.iscsi_options,
16378c2ecf20Sopenharmony_ci				 ISCSIOPTS_DATA_SEQ_INORDER_EN, pval);
16388c2ecf20Sopenharmony_ci
16398c2ecf20Sopenharmony_ci			len = sprintf(buf, "%s\n", pval);
16408c2ecf20Sopenharmony_ci			break;
16418c2ecf20Sopenharmony_ci		case ISCSI_IFACE_PARAM_PDU_INORDER_EN:
16428c2ecf20Sopenharmony_ci			OP_STATE(ha->ip_config.iscsi_options,
16438c2ecf20Sopenharmony_ci				 ISCSIOPTS_DATA_PDU_INORDER_EN, pval);
16448c2ecf20Sopenharmony_ci
16458c2ecf20Sopenharmony_ci			len = sprintf(buf, "%s\n", pval);
16468c2ecf20Sopenharmony_ci			break;
16478c2ecf20Sopenharmony_ci		case ISCSI_IFACE_PARAM_ERL:
16488c2ecf20Sopenharmony_ci			len = sprintf(buf, "%d\n",
16498c2ecf20Sopenharmony_ci				      (ha->ip_config.iscsi_options &
16508c2ecf20Sopenharmony_ci				       ISCSIOPTS_ERL));
16518c2ecf20Sopenharmony_ci			break;
16528c2ecf20Sopenharmony_ci		case ISCSI_IFACE_PARAM_MAX_RECV_DLENGTH:
16538c2ecf20Sopenharmony_ci			len = sprintf(buf, "%u\n",
16548c2ecf20Sopenharmony_ci				      ha->ip_config.iscsi_max_pdu_size *
16558c2ecf20Sopenharmony_ci				      BYTE_UNITS);
16568c2ecf20Sopenharmony_ci			break;
16578c2ecf20Sopenharmony_ci		case ISCSI_IFACE_PARAM_FIRST_BURST:
16588c2ecf20Sopenharmony_ci			len = sprintf(buf, "%u\n",
16598c2ecf20Sopenharmony_ci				      ha->ip_config.iscsi_first_burst_len *
16608c2ecf20Sopenharmony_ci				      BYTE_UNITS);
16618c2ecf20Sopenharmony_ci			break;
16628c2ecf20Sopenharmony_ci		case ISCSI_IFACE_PARAM_MAX_R2T:
16638c2ecf20Sopenharmony_ci			len = sprintf(buf, "%d\n",
16648c2ecf20Sopenharmony_ci				      ha->ip_config.iscsi_max_outstnd_r2t);
16658c2ecf20Sopenharmony_ci			break;
16668c2ecf20Sopenharmony_ci		case ISCSI_IFACE_PARAM_MAX_BURST:
16678c2ecf20Sopenharmony_ci			len = sprintf(buf, "%u\n",
16688c2ecf20Sopenharmony_ci				      ha->ip_config.iscsi_max_burst_len *
16698c2ecf20Sopenharmony_ci				      BYTE_UNITS);
16708c2ecf20Sopenharmony_ci			break;
16718c2ecf20Sopenharmony_ci		case ISCSI_IFACE_PARAM_CHAP_AUTH_EN:
16728c2ecf20Sopenharmony_ci			OP_STATE(ha->ip_config.iscsi_options,
16738c2ecf20Sopenharmony_ci				 ISCSIOPTS_CHAP_AUTH_EN, pval);
16748c2ecf20Sopenharmony_ci
16758c2ecf20Sopenharmony_ci			len = sprintf(buf, "%s\n", pval);
16768c2ecf20Sopenharmony_ci			break;
16778c2ecf20Sopenharmony_ci		case ISCSI_IFACE_PARAM_BIDI_CHAP_EN:
16788c2ecf20Sopenharmony_ci			OP_STATE(ha->ip_config.iscsi_options,
16798c2ecf20Sopenharmony_ci				 ISCSIOPTS_BIDI_CHAP_EN, pval);
16808c2ecf20Sopenharmony_ci
16818c2ecf20Sopenharmony_ci			len = sprintf(buf, "%s\n", pval);
16828c2ecf20Sopenharmony_ci			break;
16838c2ecf20Sopenharmony_ci		case ISCSI_IFACE_PARAM_DISCOVERY_AUTH_OPTIONAL:
16848c2ecf20Sopenharmony_ci			OP_STATE(ha->ip_config.iscsi_options,
16858c2ecf20Sopenharmony_ci				 ISCSIOPTS_DISCOVERY_AUTH_EN, pval);
16868c2ecf20Sopenharmony_ci
16878c2ecf20Sopenharmony_ci			len = sprintf(buf, "%s\n", pval);
16888c2ecf20Sopenharmony_ci			break;
16898c2ecf20Sopenharmony_ci		case ISCSI_IFACE_PARAM_DISCOVERY_LOGOUT_EN:
16908c2ecf20Sopenharmony_ci			OP_STATE(ha->ip_config.iscsi_options,
16918c2ecf20Sopenharmony_ci				 ISCSIOPTS_DISCOVERY_LOGOUT_EN, pval);
16928c2ecf20Sopenharmony_ci
16938c2ecf20Sopenharmony_ci			len = sprintf(buf, "%s\n", pval);
16948c2ecf20Sopenharmony_ci			break;
16958c2ecf20Sopenharmony_ci		case ISCSI_IFACE_PARAM_STRICT_LOGIN_COMP_EN:
16968c2ecf20Sopenharmony_ci			OP_STATE(ha->ip_config.iscsi_options,
16978c2ecf20Sopenharmony_ci				 ISCSIOPTS_STRICT_LOGIN_COMP_EN, pval);
16988c2ecf20Sopenharmony_ci
16998c2ecf20Sopenharmony_ci			len = sprintf(buf, "%s\n", pval);
17008c2ecf20Sopenharmony_ci			break;
17018c2ecf20Sopenharmony_ci		case ISCSI_IFACE_PARAM_INITIATOR_NAME:
17028c2ecf20Sopenharmony_ci			len = sprintf(buf, "%s\n", ha->ip_config.iscsi_name);
17038c2ecf20Sopenharmony_ci			break;
17048c2ecf20Sopenharmony_ci		default:
17058c2ecf20Sopenharmony_ci			len = -ENOSYS;
17068c2ecf20Sopenharmony_ci		}
17078c2ecf20Sopenharmony_ci	}
17088c2ecf20Sopenharmony_ci
17098c2ecf20Sopenharmony_ci	return len;
17108c2ecf20Sopenharmony_ci}
17118c2ecf20Sopenharmony_ci
17128c2ecf20Sopenharmony_cistatic struct iscsi_endpoint *
17138c2ecf20Sopenharmony_ciqla4xxx_ep_connect(struct Scsi_Host *shost, struct sockaddr *dst_addr,
17148c2ecf20Sopenharmony_ci		   int non_blocking)
17158c2ecf20Sopenharmony_ci{
17168c2ecf20Sopenharmony_ci	int ret;
17178c2ecf20Sopenharmony_ci	struct iscsi_endpoint *ep;
17188c2ecf20Sopenharmony_ci	struct qla_endpoint *qla_ep;
17198c2ecf20Sopenharmony_ci	struct scsi_qla_host *ha;
17208c2ecf20Sopenharmony_ci	struct sockaddr_in *addr;
17218c2ecf20Sopenharmony_ci	struct sockaddr_in6 *addr6;
17228c2ecf20Sopenharmony_ci
17238c2ecf20Sopenharmony_ci	if (!shost) {
17248c2ecf20Sopenharmony_ci		ret = -ENXIO;
17258c2ecf20Sopenharmony_ci		pr_err("%s: shost is NULL\n", __func__);
17268c2ecf20Sopenharmony_ci		return ERR_PTR(ret);
17278c2ecf20Sopenharmony_ci	}
17288c2ecf20Sopenharmony_ci
17298c2ecf20Sopenharmony_ci	ha = iscsi_host_priv(shost);
17308c2ecf20Sopenharmony_ci	ep = iscsi_create_endpoint(sizeof(struct qla_endpoint));
17318c2ecf20Sopenharmony_ci	if (!ep) {
17328c2ecf20Sopenharmony_ci		ret = -ENOMEM;
17338c2ecf20Sopenharmony_ci		return ERR_PTR(ret);
17348c2ecf20Sopenharmony_ci	}
17358c2ecf20Sopenharmony_ci
17368c2ecf20Sopenharmony_ci	qla_ep = ep->dd_data;
17378c2ecf20Sopenharmony_ci	memset(qla_ep, 0, sizeof(struct qla_endpoint));
17388c2ecf20Sopenharmony_ci	if (dst_addr->sa_family == AF_INET) {
17398c2ecf20Sopenharmony_ci		memcpy(&qla_ep->dst_addr, dst_addr, sizeof(struct sockaddr_in));
17408c2ecf20Sopenharmony_ci		addr = (struct sockaddr_in *)&qla_ep->dst_addr;
17418c2ecf20Sopenharmony_ci		DEBUG2(ql4_printk(KERN_INFO, ha, "%s: %pI4\n", __func__,
17428c2ecf20Sopenharmony_ci				  (char *)&addr->sin_addr));
17438c2ecf20Sopenharmony_ci	} else if (dst_addr->sa_family == AF_INET6) {
17448c2ecf20Sopenharmony_ci		memcpy(&qla_ep->dst_addr, dst_addr,
17458c2ecf20Sopenharmony_ci		       sizeof(struct sockaddr_in6));
17468c2ecf20Sopenharmony_ci		addr6 = (struct sockaddr_in6 *)&qla_ep->dst_addr;
17478c2ecf20Sopenharmony_ci		DEBUG2(ql4_printk(KERN_INFO, ha, "%s: %pI6\n", __func__,
17488c2ecf20Sopenharmony_ci				  (char *)&addr6->sin6_addr));
17498c2ecf20Sopenharmony_ci	} else {
17508c2ecf20Sopenharmony_ci		ql4_printk(KERN_WARNING, ha, "%s: Invalid endpoint\n",
17518c2ecf20Sopenharmony_ci			   __func__);
17528c2ecf20Sopenharmony_ci	}
17538c2ecf20Sopenharmony_ci
17548c2ecf20Sopenharmony_ci	qla_ep->host = shost;
17558c2ecf20Sopenharmony_ci
17568c2ecf20Sopenharmony_ci	return ep;
17578c2ecf20Sopenharmony_ci}
17588c2ecf20Sopenharmony_ci
17598c2ecf20Sopenharmony_cistatic int qla4xxx_ep_poll(struct iscsi_endpoint *ep, int timeout_ms)
17608c2ecf20Sopenharmony_ci{
17618c2ecf20Sopenharmony_ci	struct qla_endpoint *qla_ep;
17628c2ecf20Sopenharmony_ci	struct scsi_qla_host *ha;
17638c2ecf20Sopenharmony_ci	int ret = 0;
17648c2ecf20Sopenharmony_ci
17658c2ecf20Sopenharmony_ci	qla_ep = ep->dd_data;
17668c2ecf20Sopenharmony_ci	ha = to_qla_host(qla_ep->host);
17678c2ecf20Sopenharmony_ci	DEBUG2(pr_info_ratelimited("%s: host: %ld\n", __func__, ha->host_no));
17688c2ecf20Sopenharmony_ci
17698c2ecf20Sopenharmony_ci	if (adapter_up(ha) && !test_bit(AF_BUILD_DDB_LIST, &ha->flags))
17708c2ecf20Sopenharmony_ci		ret = 1;
17718c2ecf20Sopenharmony_ci
17728c2ecf20Sopenharmony_ci	return ret;
17738c2ecf20Sopenharmony_ci}
17748c2ecf20Sopenharmony_ci
17758c2ecf20Sopenharmony_cistatic void qla4xxx_ep_disconnect(struct iscsi_endpoint *ep)
17768c2ecf20Sopenharmony_ci{
17778c2ecf20Sopenharmony_ci	struct qla_endpoint *qla_ep;
17788c2ecf20Sopenharmony_ci	struct scsi_qla_host *ha;
17798c2ecf20Sopenharmony_ci
17808c2ecf20Sopenharmony_ci	qla_ep = ep->dd_data;
17818c2ecf20Sopenharmony_ci	ha = to_qla_host(qla_ep->host);
17828c2ecf20Sopenharmony_ci	DEBUG2(ql4_printk(KERN_INFO, ha, "%s: host: %ld\n", __func__,
17838c2ecf20Sopenharmony_ci			  ha->host_no));
17848c2ecf20Sopenharmony_ci	iscsi_destroy_endpoint(ep);
17858c2ecf20Sopenharmony_ci}
17868c2ecf20Sopenharmony_ci
17878c2ecf20Sopenharmony_cistatic int qla4xxx_get_ep_param(struct iscsi_endpoint *ep,
17888c2ecf20Sopenharmony_ci				enum iscsi_param param,
17898c2ecf20Sopenharmony_ci				char *buf)
17908c2ecf20Sopenharmony_ci{
17918c2ecf20Sopenharmony_ci	struct qla_endpoint *qla_ep = ep->dd_data;
17928c2ecf20Sopenharmony_ci	struct sockaddr *dst_addr;
17938c2ecf20Sopenharmony_ci	struct scsi_qla_host *ha;
17948c2ecf20Sopenharmony_ci
17958c2ecf20Sopenharmony_ci	if (!qla_ep)
17968c2ecf20Sopenharmony_ci		return -ENOTCONN;
17978c2ecf20Sopenharmony_ci
17988c2ecf20Sopenharmony_ci	ha = to_qla_host(qla_ep->host);
17998c2ecf20Sopenharmony_ci	DEBUG2(ql4_printk(KERN_INFO, ha, "%s: host: %ld\n", __func__,
18008c2ecf20Sopenharmony_ci			  ha->host_no));
18018c2ecf20Sopenharmony_ci
18028c2ecf20Sopenharmony_ci	switch (param) {
18038c2ecf20Sopenharmony_ci	case ISCSI_PARAM_CONN_PORT:
18048c2ecf20Sopenharmony_ci	case ISCSI_PARAM_CONN_ADDRESS:
18058c2ecf20Sopenharmony_ci		dst_addr = (struct sockaddr *)&qla_ep->dst_addr;
18068c2ecf20Sopenharmony_ci		if (!dst_addr)
18078c2ecf20Sopenharmony_ci			return -ENOTCONN;
18088c2ecf20Sopenharmony_ci
18098c2ecf20Sopenharmony_ci		return iscsi_conn_get_addr_param((struct sockaddr_storage *)
18108c2ecf20Sopenharmony_ci						 &qla_ep->dst_addr, param, buf);
18118c2ecf20Sopenharmony_ci	default:
18128c2ecf20Sopenharmony_ci		return -ENOSYS;
18138c2ecf20Sopenharmony_ci	}
18148c2ecf20Sopenharmony_ci}
18158c2ecf20Sopenharmony_ci
18168c2ecf20Sopenharmony_cistatic void qla4xxx_conn_get_stats(struct iscsi_cls_conn *cls_conn,
18178c2ecf20Sopenharmony_ci				   struct iscsi_stats *stats)
18188c2ecf20Sopenharmony_ci{
18198c2ecf20Sopenharmony_ci	struct iscsi_session *sess;
18208c2ecf20Sopenharmony_ci	struct iscsi_cls_session *cls_sess;
18218c2ecf20Sopenharmony_ci	struct ddb_entry *ddb_entry;
18228c2ecf20Sopenharmony_ci	struct scsi_qla_host *ha;
18238c2ecf20Sopenharmony_ci	struct ql_iscsi_stats *ql_iscsi_stats;
18248c2ecf20Sopenharmony_ci	int stats_size;
18258c2ecf20Sopenharmony_ci	int ret;
18268c2ecf20Sopenharmony_ci	dma_addr_t iscsi_stats_dma;
18278c2ecf20Sopenharmony_ci
18288c2ecf20Sopenharmony_ci	cls_sess = iscsi_conn_to_session(cls_conn);
18298c2ecf20Sopenharmony_ci	sess = cls_sess->dd_data;
18308c2ecf20Sopenharmony_ci	ddb_entry = sess->dd_data;
18318c2ecf20Sopenharmony_ci	ha = ddb_entry->ha;
18328c2ecf20Sopenharmony_ci
18338c2ecf20Sopenharmony_ci	DEBUG2(ql4_printk(KERN_INFO, ha, "%s: host: %ld\n", __func__,
18348c2ecf20Sopenharmony_ci			  ha->host_no));
18358c2ecf20Sopenharmony_ci	stats_size = PAGE_ALIGN(sizeof(struct ql_iscsi_stats));
18368c2ecf20Sopenharmony_ci	/* Allocate memory */
18378c2ecf20Sopenharmony_ci	ql_iscsi_stats = dma_alloc_coherent(&ha->pdev->dev, stats_size,
18388c2ecf20Sopenharmony_ci					    &iscsi_stats_dma, GFP_KERNEL);
18398c2ecf20Sopenharmony_ci	if (!ql_iscsi_stats) {
18408c2ecf20Sopenharmony_ci		ql4_printk(KERN_ERR, ha,
18418c2ecf20Sopenharmony_ci			   "Unable to allocate memory for iscsi stats\n");
18428c2ecf20Sopenharmony_ci		goto exit_get_stats;
18438c2ecf20Sopenharmony_ci	}
18448c2ecf20Sopenharmony_ci
18458c2ecf20Sopenharmony_ci	ret =  qla4xxx_get_mgmt_data(ha, ddb_entry->fw_ddb_index, stats_size,
18468c2ecf20Sopenharmony_ci				     iscsi_stats_dma);
18478c2ecf20Sopenharmony_ci	if (ret != QLA_SUCCESS) {
18488c2ecf20Sopenharmony_ci		ql4_printk(KERN_ERR, ha,
18498c2ecf20Sopenharmony_ci			   "Unable to retrieve iscsi stats\n");
18508c2ecf20Sopenharmony_ci		goto free_stats;
18518c2ecf20Sopenharmony_ci	}
18528c2ecf20Sopenharmony_ci
18538c2ecf20Sopenharmony_ci	/* octets */
18548c2ecf20Sopenharmony_ci	stats->txdata_octets = le64_to_cpu(ql_iscsi_stats->tx_data_octets);
18558c2ecf20Sopenharmony_ci	stats->rxdata_octets = le64_to_cpu(ql_iscsi_stats->rx_data_octets);
18568c2ecf20Sopenharmony_ci	/* xmit pdus */
18578c2ecf20Sopenharmony_ci	stats->noptx_pdus = le32_to_cpu(ql_iscsi_stats->tx_nopout_pdus);
18588c2ecf20Sopenharmony_ci	stats->scsicmd_pdus = le32_to_cpu(ql_iscsi_stats->tx_scsi_cmd_pdus);
18598c2ecf20Sopenharmony_ci	stats->tmfcmd_pdus = le32_to_cpu(ql_iscsi_stats->tx_tmf_cmd_pdus);
18608c2ecf20Sopenharmony_ci	stats->login_pdus = le32_to_cpu(ql_iscsi_stats->tx_login_cmd_pdus);
18618c2ecf20Sopenharmony_ci	stats->text_pdus = le32_to_cpu(ql_iscsi_stats->tx_text_cmd_pdus);
18628c2ecf20Sopenharmony_ci	stats->dataout_pdus = le32_to_cpu(ql_iscsi_stats->tx_scsi_write_pdus);
18638c2ecf20Sopenharmony_ci	stats->logout_pdus = le32_to_cpu(ql_iscsi_stats->tx_logout_cmd_pdus);
18648c2ecf20Sopenharmony_ci	stats->snack_pdus = le32_to_cpu(ql_iscsi_stats->tx_snack_req_pdus);
18658c2ecf20Sopenharmony_ci	/* recv pdus */
18668c2ecf20Sopenharmony_ci	stats->noprx_pdus = le32_to_cpu(ql_iscsi_stats->rx_nopin_pdus);
18678c2ecf20Sopenharmony_ci	stats->scsirsp_pdus = le32_to_cpu(ql_iscsi_stats->rx_scsi_resp_pdus);
18688c2ecf20Sopenharmony_ci	stats->tmfrsp_pdus = le32_to_cpu(ql_iscsi_stats->rx_tmf_resp_pdus);
18698c2ecf20Sopenharmony_ci	stats->textrsp_pdus = le32_to_cpu(ql_iscsi_stats->rx_text_resp_pdus);
18708c2ecf20Sopenharmony_ci	stats->datain_pdus = le32_to_cpu(ql_iscsi_stats->rx_scsi_read_pdus);
18718c2ecf20Sopenharmony_ci	stats->logoutrsp_pdus =
18728c2ecf20Sopenharmony_ci			le32_to_cpu(ql_iscsi_stats->rx_logout_resp_pdus);
18738c2ecf20Sopenharmony_ci	stats->r2t_pdus = le32_to_cpu(ql_iscsi_stats->rx_r2t_pdus);
18748c2ecf20Sopenharmony_ci	stats->async_pdus = le32_to_cpu(ql_iscsi_stats->rx_async_pdus);
18758c2ecf20Sopenharmony_ci	stats->rjt_pdus = le32_to_cpu(ql_iscsi_stats->rx_reject_pdus);
18768c2ecf20Sopenharmony_ci
18778c2ecf20Sopenharmony_cifree_stats:
18788c2ecf20Sopenharmony_ci	dma_free_coherent(&ha->pdev->dev, stats_size, ql_iscsi_stats,
18798c2ecf20Sopenharmony_ci			  iscsi_stats_dma);
18808c2ecf20Sopenharmony_ciexit_get_stats:
18818c2ecf20Sopenharmony_ci	return;
18828c2ecf20Sopenharmony_ci}
18838c2ecf20Sopenharmony_ci
18848c2ecf20Sopenharmony_cistatic enum blk_eh_timer_return qla4xxx_eh_cmd_timed_out(struct scsi_cmnd *sc)
18858c2ecf20Sopenharmony_ci{
18868c2ecf20Sopenharmony_ci	struct iscsi_cls_session *session;
18878c2ecf20Sopenharmony_ci	unsigned long flags;
18888c2ecf20Sopenharmony_ci	enum blk_eh_timer_return ret = BLK_EH_DONE;
18898c2ecf20Sopenharmony_ci
18908c2ecf20Sopenharmony_ci	session = starget_to_session(scsi_target(sc->device));
18918c2ecf20Sopenharmony_ci
18928c2ecf20Sopenharmony_ci	spin_lock_irqsave(&session->lock, flags);
18938c2ecf20Sopenharmony_ci	if (session->state == ISCSI_SESSION_FAILED)
18948c2ecf20Sopenharmony_ci		ret = BLK_EH_RESET_TIMER;
18958c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&session->lock, flags);
18968c2ecf20Sopenharmony_ci
18978c2ecf20Sopenharmony_ci	return ret;
18988c2ecf20Sopenharmony_ci}
18998c2ecf20Sopenharmony_ci
19008c2ecf20Sopenharmony_cistatic void qla4xxx_set_port_speed(struct Scsi_Host *shost)
19018c2ecf20Sopenharmony_ci{
19028c2ecf20Sopenharmony_ci	struct scsi_qla_host *ha = to_qla_host(shost);
19038c2ecf20Sopenharmony_ci	struct iscsi_cls_host *ihost = shost->shost_data;
19048c2ecf20Sopenharmony_ci	uint32_t speed = ISCSI_PORT_SPEED_UNKNOWN;
19058c2ecf20Sopenharmony_ci
19068c2ecf20Sopenharmony_ci	qla4xxx_get_firmware_state(ha);
19078c2ecf20Sopenharmony_ci
19088c2ecf20Sopenharmony_ci	switch (ha->addl_fw_state & 0x0F00) {
19098c2ecf20Sopenharmony_ci	case FW_ADDSTATE_LINK_SPEED_10MBPS:
19108c2ecf20Sopenharmony_ci		speed = ISCSI_PORT_SPEED_10MBPS;
19118c2ecf20Sopenharmony_ci		break;
19128c2ecf20Sopenharmony_ci	case FW_ADDSTATE_LINK_SPEED_100MBPS:
19138c2ecf20Sopenharmony_ci		speed = ISCSI_PORT_SPEED_100MBPS;
19148c2ecf20Sopenharmony_ci		break;
19158c2ecf20Sopenharmony_ci	case FW_ADDSTATE_LINK_SPEED_1GBPS:
19168c2ecf20Sopenharmony_ci		speed = ISCSI_PORT_SPEED_1GBPS;
19178c2ecf20Sopenharmony_ci		break;
19188c2ecf20Sopenharmony_ci	case FW_ADDSTATE_LINK_SPEED_10GBPS:
19198c2ecf20Sopenharmony_ci		speed = ISCSI_PORT_SPEED_10GBPS;
19208c2ecf20Sopenharmony_ci		break;
19218c2ecf20Sopenharmony_ci	}
19228c2ecf20Sopenharmony_ci	ihost->port_speed = speed;
19238c2ecf20Sopenharmony_ci}
19248c2ecf20Sopenharmony_ci
19258c2ecf20Sopenharmony_cistatic void qla4xxx_set_port_state(struct Scsi_Host *shost)
19268c2ecf20Sopenharmony_ci{
19278c2ecf20Sopenharmony_ci	struct scsi_qla_host *ha = to_qla_host(shost);
19288c2ecf20Sopenharmony_ci	struct iscsi_cls_host *ihost = shost->shost_data;
19298c2ecf20Sopenharmony_ci	uint32_t state = ISCSI_PORT_STATE_DOWN;
19308c2ecf20Sopenharmony_ci
19318c2ecf20Sopenharmony_ci	if (test_bit(AF_LINK_UP, &ha->flags))
19328c2ecf20Sopenharmony_ci		state = ISCSI_PORT_STATE_UP;
19338c2ecf20Sopenharmony_ci
19348c2ecf20Sopenharmony_ci	ihost->port_state = state;
19358c2ecf20Sopenharmony_ci}
19368c2ecf20Sopenharmony_ci
19378c2ecf20Sopenharmony_cistatic int qla4xxx_host_get_param(struct Scsi_Host *shost,
19388c2ecf20Sopenharmony_ci				  enum iscsi_host_param param, char *buf)
19398c2ecf20Sopenharmony_ci{
19408c2ecf20Sopenharmony_ci	struct scsi_qla_host *ha = to_qla_host(shost);
19418c2ecf20Sopenharmony_ci	int len;
19428c2ecf20Sopenharmony_ci
19438c2ecf20Sopenharmony_ci	switch (param) {
19448c2ecf20Sopenharmony_ci	case ISCSI_HOST_PARAM_HWADDRESS:
19458c2ecf20Sopenharmony_ci		len = sysfs_format_mac(buf, ha->my_mac, MAC_ADDR_LEN);
19468c2ecf20Sopenharmony_ci		break;
19478c2ecf20Sopenharmony_ci	case ISCSI_HOST_PARAM_IPADDRESS:
19488c2ecf20Sopenharmony_ci		len = sprintf(buf, "%pI4\n", &ha->ip_config.ip_address);
19498c2ecf20Sopenharmony_ci		break;
19508c2ecf20Sopenharmony_ci	case ISCSI_HOST_PARAM_INITIATOR_NAME:
19518c2ecf20Sopenharmony_ci		len = sprintf(buf, "%s\n", ha->name_string);
19528c2ecf20Sopenharmony_ci		break;
19538c2ecf20Sopenharmony_ci	case ISCSI_HOST_PARAM_PORT_STATE:
19548c2ecf20Sopenharmony_ci		qla4xxx_set_port_state(shost);
19558c2ecf20Sopenharmony_ci		len = sprintf(buf, "%s\n", iscsi_get_port_state_name(shost));
19568c2ecf20Sopenharmony_ci		break;
19578c2ecf20Sopenharmony_ci	case ISCSI_HOST_PARAM_PORT_SPEED:
19588c2ecf20Sopenharmony_ci		qla4xxx_set_port_speed(shost);
19598c2ecf20Sopenharmony_ci		len = sprintf(buf, "%s\n", iscsi_get_port_speed_name(shost));
19608c2ecf20Sopenharmony_ci		break;
19618c2ecf20Sopenharmony_ci	default:
19628c2ecf20Sopenharmony_ci		return -ENOSYS;
19638c2ecf20Sopenharmony_ci	}
19648c2ecf20Sopenharmony_ci
19658c2ecf20Sopenharmony_ci	return len;
19668c2ecf20Sopenharmony_ci}
19678c2ecf20Sopenharmony_ci
19688c2ecf20Sopenharmony_cistatic void qla4xxx_create_ipv4_iface(struct scsi_qla_host *ha)
19698c2ecf20Sopenharmony_ci{
19708c2ecf20Sopenharmony_ci	if (ha->iface_ipv4)
19718c2ecf20Sopenharmony_ci		return;
19728c2ecf20Sopenharmony_ci
19738c2ecf20Sopenharmony_ci	/* IPv4 */
19748c2ecf20Sopenharmony_ci	ha->iface_ipv4 = iscsi_create_iface(ha->host,
19758c2ecf20Sopenharmony_ci					    &qla4xxx_iscsi_transport,
19768c2ecf20Sopenharmony_ci					    ISCSI_IFACE_TYPE_IPV4, 0, 0);
19778c2ecf20Sopenharmony_ci	if (!ha->iface_ipv4)
19788c2ecf20Sopenharmony_ci		ql4_printk(KERN_ERR, ha, "Could not create IPv4 iSCSI "
19798c2ecf20Sopenharmony_ci			   "iface0.\n");
19808c2ecf20Sopenharmony_ci}
19818c2ecf20Sopenharmony_ci
19828c2ecf20Sopenharmony_cistatic void qla4xxx_create_ipv6_iface(struct scsi_qla_host *ha)
19838c2ecf20Sopenharmony_ci{
19848c2ecf20Sopenharmony_ci	if (!ha->iface_ipv6_0)
19858c2ecf20Sopenharmony_ci		/* IPv6 iface-0 */
19868c2ecf20Sopenharmony_ci		ha->iface_ipv6_0 = iscsi_create_iface(ha->host,
19878c2ecf20Sopenharmony_ci						      &qla4xxx_iscsi_transport,
19888c2ecf20Sopenharmony_ci						      ISCSI_IFACE_TYPE_IPV6, 0,
19898c2ecf20Sopenharmony_ci						      0);
19908c2ecf20Sopenharmony_ci	if (!ha->iface_ipv6_0)
19918c2ecf20Sopenharmony_ci		ql4_printk(KERN_ERR, ha, "Could not create IPv6 iSCSI "
19928c2ecf20Sopenharmony_ci			   "iface0.\n");
19938c2ecf20Sopenharmony_ci
19948c2ecf20Sopenharmony_ci	if (!ha->iface_ipv6_1)
19958c2ecf20Sopenharmony_ci		/* IPv6 iface-1 */
19968c2ecf20Sopenharmony_ci		ha->iface_ipv6_1 = iscsi_create_iface(ha->host,
19978c2ecf20Sopenharmony_ci						      &qla4xxx_iscsi_transport,
19988c2ecf20Sopenharmony_ci						      ISCSI_IFACE_TYPE_IPV6, 1,
19998c2ecf20Sopenharmony_ci						      0);
20008c2ecf20Sopenharmony_ci	if (!ha->iface_ipv6_1)
20018c2ecf20Sopenharmony_ci		ql4_printk(KERN_ERR, ha, "Could not create IPv6 iSCSI "
20028c2ecf20Sopenharmony_ci			   "iface1.\n");
20038c2ecf20Sopenharmony_ci}
20048c2ecf20Sopenharmony_ci
20058c2ecf20Sopenharmony_cistatic void qla4xxx_create_ifaces(struct scsi_qla_host *ha)
20068c2ecf20Sopenharmony_ci{
20078c2ecf20Sopenharmony_ci	if (ha->ip_config.ipv4_options & IPOPT_IPV4_PROTOCOL_ENABLE)
20088c2ecf20Sopenharmony_ci		qla4xxx_create_ipv4_iface(ha);
20098c2ecf20Sopenharmony_ci
20108c2ecf20Sopenharmony_ci	if (ha->ip_config.ipv6_options & IPV6_OPT_IPV6_PROTOCOL_ENABLE)
20118c2ecf20Sopenharmony_ci		qla4xxx_create_ipv6_iface(ha);
20128c2ecf20Sopenharmony_ci}
20138c2ecf20Sopenharmony_ci
20148c2ecf20Sopenharmony_cistatic void qla4xxx_destroy_ipv4_iface(struct scsi_qla_host *ha)
20158c2ecf20Sopenharmony_ci{
20168c2ecf20Sopenharmony_ci	if (ha->iface_ipv4) {
20178c2ecf20Sopenharmony_ci		iscsi_destroy_iface(ha->iface_ipv4);
20188c2ecf20Sopenharmony_ci		ha->iface_ipv4 = NULL;
20198c2ecf20Sopenharmony_ci	}
20208c2ecf20Sopenharmony_ci}
20218c2ecf20Sopenharmony_ci
20228c2ecf20Sopenharmony_cistatic void qla4xxx_destroy_ipv6_iface(struct scsi_qla_host *ha)
20238c2ecf20Sopenharmony_ci{
20248c2ecf20Sopenharmony_ci	if (ha->iface_ipv6_0) {
20258c2ecf20Sopenharmony_ci		iscsi_destroy_iface(ha->iface_ipv6_0);
20268c2ecf20Sopenharmony_ci		ha->iface_ipv6_0 = NULL;
20278c2ecf20Sopenharmony_ci	}
20288c2ecf20Sopenharmony_ci	if (ha->iface_ipv6_1) {
20298c2ecf20Sopenharmony_ci		iscsi_destroy_iface(ha->iface_ipv6_1);
20308c2ecf20Sopenharmony_ci		ha->iface_ipv6_1 = NULL;
20318c2ecf20Sopenharmony_ci	}
20328c2ecf20Sopenharmony_ci}
20338c2ecf20Sopenharmony_ci
20348c2ecf20Sopenharmony_cistatic void qla4xxx_destroy_ifaces(struct scsi_qla_host *ha)
20358c2ecf20Sopenharmony_ci{
20368c2ecf20Sopenharmony_ci	qla4xxx_destroy_ipv4_iface(ha);
20378c2ecf20Sopenharmony_ci	qla4xxx_destroy_ipv6_iface(ha);
20388c2ecf20Sopenharmony_ci}
20398c2ecf20Sopenharmony_ci
20408c2ecf20Sopenharmony_cistatic void qla4xxx_set_ipv6(struct scsi_qla_host *ha,
20418c2ecf20Sopenharmony_ci			     struct iscsi_iface_param_info *iface_param,
20428c2ecf20Sopenharmony_ci			     struct addr_ctrl_blk *init_fw_cb)
20438c2ecf20Sopenharmony_ci{
20448c2ecf20Sopenharmony_ci	/*
20458c2ecf20Sopenharmony_ci	 * iface_num 0 is valid for IPv6 Addr, linklocal, router, autocfg.
20468c2ecf20Sopenharmony_ci	 * iface_num 1 is valid only for IPv6 Addr.
20478c2ecf20Sopenharmony_ci	 */
20488c2ecf20Sopenharmony_ci	switch (iface_param->param) {
20498c2ecf20Sopenharmony_ci	case ISCSI_NET_PARAM_IPV6_ADDR:
20508c2ecf20Sopenharmony_ci		if (iface_param->iface_num & 0x1)
20518c2ecf20Sopenharmony_ci			/* IPv6 Addr 1 */
20528c2ecf20Sopenharmony_ci			memcpy(init_fw_cb->ipv6_addr1, iface_param->value,
20538c2ecf20Sopenharmony_ci			       sizeof(init_fw_cb->ipv6_addr1));
20548c2ecf20Sopenharmony_ci		else
20558c2ecf20Sopenharmony_ci			/* IPv6 Addr 0 */
20568c2ecf20Sopenharmony_ci			memcpy(init_fw_cb->ipv6_addr0, iface_param->value,
20578c2ecf20Sopenharmony_ci			       sizeof(init_fw_cb->ipv6_addr0));
20588c2ecf20Sopenharmony_ci		break;
20598c2ecf20Sopenharmony_ci	case ISCSI_NET_PARAM_IPV6_LINKLOCAL:
20608c2ecf20Sopenharmony_ci		if (iface_param->iface_num & 0x1)
20618c2ecf20Sopenharmony_ci			break;
20628c2ecf20Sopenharmony_ci		memcpy(init_fw_cb->ipv6_if_id, &iface_param->value[8],
20638c2ecf20Sopenharmony_ci		       sizeof(init_fw_cb->ipv6_if_id));
20648c2ecf20Sopenharmony_ci		break;
20658c2ecf20Sopenharmony_ci	case ISCSI_NET_PARAM_IPV6_ROUTER:
20668c2ecf20Sopenharmony_ci		if (iface_param->iface_num & 0x1)
20678c2ecf20Sopenharmony_ci			break;
20688c2ecf20Sopenharmony_ci		memcpy(init_fw_cb->ipv6_dflt_rtr_addr, iface_param->value,
20698c2ecf20Sopenharmony_ci		       sizeof(init_fw_cb->ipv6_dflt_rtr_addr));
20708c2ecf20Sopenharmony_ci		break;
20718c2ecf20Sopenharmony_ci	case ISCSI_NET_PARAM_IPV6_ADDR_AUTOCFG:
20728c2ecf20Sopenharmony_ci		/* Autocfg applies to even interface */
20738c2ecf20Sopenharmony_ci		if (iface_param->iface_num & 0x1)
20748c2ecf20Sopenharmony_ci			break;
20758c2ecf20Sopenharmony_ci
20768c2ecf20Sopenharmony_ci		if (iface_param->value[0] == ISCSI_IPV6_AUTOCFG_DISABLE)
20778c2ecf20Sopenharmony_ci			init_fw_cb->ipv6_addtl_opts &=
20788c2ecf20Sopenharmony_ci				cpu_to_le16(
20798c2ecf20Sopenharmony_ci				  ~IPV6_ADDOPT_NEIGHBOR_DISCOVERY_ADDR_ENABLE);
20808c2ecf20Sopenharmony_ci		else if (iface_param->value[0] == ISCSI_IPV6_AUTOCFG_ND_ENABLE)
20818c2ecf20Sopenharmony_ci			init_fw_cb->ipv6_addtl_opts |=
20828c2ecf20Sopenharmony_ci				cpu_to_le16(
20838c2ecf20Sopenharmony_ci				  IPV6_ADDOPT_NEIGHBOR_DISCOVERY_ADDR_ENABLE);
20848c2ecf20Sopenharmony_ci		else
20858c2ecf20Sopenharmony_ci			ql4_printk(KERN_ERR, ha,
20868c2ecf20Sopenharmony_ci				   "Invalid autocfg setting for IPv6 addr\n");
20878c2ecf20Sopenharmony_ci		break;
20888c2ecf20Sopenharmony_ci	case ISCSI_NET_PARAM_IPV6_LINKLOCAL_AUTOCFG:
20898c2ecf20Sopenharmony_ci		/* Autocfg applies to even interface */
20908c2ecf20Sopenharmony_ci		if (iface_param->iface_num & 0x1)
20918c2ecf20Sopenharmony_ci			break;
20928c2ecf20Sopenharmony_ci
20938c2ecf20Sopenharmony_ci		if (iface_param->value[0] ==
20948c2ecf20Sopenharmony_ci		    ISCSI_IPV6_LINKLOCAL_AUTOCFG_ENABLE)
20958c2ecf20Sopenharmony_ci			init_fw_cb->ipv6_addtl_opts |= cpu_to_le16(
20968c2ecf20Sopenharmony_ci					IPV6_ADDOPT_AUTOCONFIG_LINK_LOCAL_ADDR);
20978c2ecf20Sopenharmony_ci		else if (iface_param->value[0] ==
20988c2ecf20Sopenharmony_ci			 ISCSI_IPV6_LINKLOCAL_AUTOCFG_DISABLE)
20998c2ecf20Sopenharmony_ci			init_fw_cb->ipv6_addtl_opts &= cpu_to_le16(
21008c2ecf20Sopenharmony_ci				       ~IPV6_ADDOPT_AUTOCONFIG_LINK_LOCAL_ADDR);
21018c2ecf20Sopenharmony_ci		else
21028c2ecf20Sopenharmony_ci			ql4_printk(KERN_ERR, ha,
21038c2ecf20Sopenharmony_ci				   "Invalid autocfg setting for IPv6 linklocal addr\n");
21048c2ecf20Sopenharmony_ci		break;
21058c2ecf20Sopenharmony_ci	case ISCSI_NET_PARAM_IPV6_ROUTER_AUTOCFG:
21068c2ecf20Sopenharmony_ci		/* Autocfg applies to even interface */
21078c2ecf20Sopenharmony_ci		if (iface_param->iface_num & 0x1)
21088c2ecf20Sopenharmony_ci			break;
21098c2ecf20Sopenharmony_ci
21108c2ecf20Sopenharmony_ci		if (iface_param->value[0] == ISCSI_IPV6_ROUTER_AUTOCFG_ENABLE)
21118c2ecf20Sopenharmony_ci			memset(init_fw_cb->ipv6_dflt_rtr_addr, 0,
21128c2ecf20Sopenharmony_ci			       sizeof(init_fw_cb->ipv6_dflt_rtr_addr));
21138c2ecf20Sopenharmony_ci		break;
21148c2ecf20Sopenharmony_ci	case ISCSI_NET_PARAM_IFACE_ENABLE:
21158c2ecf20Sopenharmony_ci		if (iface_param->value[0] == ISCSI_IFACE_ENABLE) {
21168c2ecf20Sopenharmony_ci			init_fw_cb->ipv6_opts |=
21178c2ecf20Sopenharmony_ci				cpu_to_le16(IPV6_OPT_IPV6_PROTOCOL_ENABLE);
21188c2ecf20Sopenharmony_ci			qla4xxx_create_ipv6_iface(ha);
21198c2ecf20Sopenharmony_ci		} else {
21208c2ecf20Sopenharmony_ci			init_fw_cb->ipv6_opts &=
21218c2ecf20Sopenharmony_ci				cpu_to_le16(~IPV6_OPT_IPV6_PROTOCOL_ENABLE &
21228c2ecf20Sopenharmony_ci					    0xFFFF);
21238c2ecf20Sopenharmony_ci			qla4xxx_destroy_ipv6_iface(ha);
21248c2ecf20Sopenharmony_ci		}
21258c2ecf20Sopenharmony_ci		break;
21268c2ecf20Sopenharmony_ci	case ISCSI_NET_PARAM_VLAN_TAG:
21278c2ecf20Sopenharmony_ci		if (iface_param->len != sizeof(init_fw_cb->ipv6_vlan_tag))
21288c2ecf20Sopenharmony_ci			break;
21298c2ecf20Sopenharmony_ci		init_fw_cb->ipv6_vlan_tag =
21308c2ecf20Sopenharmony_ci				cpu_to_be16(*(uint16_t *)iface_param->value);
21318c2ecf20Sopenharmony_ci		break;
21328c2ecf20Sopenharmony_ci	case ISCSI_NET_PARAM_VLAN_ENABLED:
21338c2ecf20Sopenharmony_ci		if (iface_param->value[0] == ISCSI_VLAN_ENABLE)
21348c2ecf20Sopenharmony_ci			init_fw_cb->ipv6_opts |=
21358c2ecf20Sopenharmony_ci				cpu_to_le16(IPV6_OPT_VLAN_TAGGING_ENABLE);
21368c2ecf20Sopenharmony_ci		else
21378c2ecf20Sopenharmony_ci			init_fw_cb->ipv6_opts &=
21388c2ecf20Sopenharmony_ci				cpu_to_le16(~IPV6_OPT_VLAN_TAGGING_ENABLE);
21398c2ecf20Sopenharmony_ci		break;
21408c2ecf20Sopenharmony_ci	case ISCSI_NET_PARAM_MTU:
21418c2ecf20Sopenharmony_ci		init_fw_cb->eth_mtu_size =
21428c2ecf20Sopenharmony_ci				cpu_to_le16(*(uint16_t *)iface_param->value);
21438c2ecf20Sopenharmony_ci		break;
21448c2ecf20Sopenharmony_ci	case ISCSI_NET_PARAM_PORT:
21458c2ecf20Sopenharmony_ci		/* Autocfg applies to even interface */
21468c2ecf20Sopenharmony_ci		if (iface_param->iface_num & 0x1)
21478c2ecf20Sopenharmony_ci			break;
21488c2ecf20Sopenharmony_ci
21498c2ecf20Sopenharmony_ci		init_fw_cb->ipv6_port =
21508c2ecf20Sopenharmony_ci				cpu_to_le16(*(uint16_t *)iface_param->value);
21518c2ecf20Sopenharmony_ci		break;
21528c2ecf20Sopenharmony_ci	case ISCSI_NET_PARAM_DELAYED_ACK_EN:
21538c2ecf20Sopenharmony_ci		if (iface_param->iface_num & 0x1)
21548c2ecf20Sopenharmony_ci			break;
21558c2ecf20Sopenharmony_ci		if (iface_param->value[0] == ISCSI_NET_PARAM_DISABLE)
21568c2ecf20Sopenharmony_ci			init_fw_cb->ipv6_tcp_opts |=
21578c2ecf20Sopenharmony_ci				cpu_to_le16(IPV6_TCPOPT_DELAYED_ACK_DISABLE);
21588c2ecf20Sopenharmony_ci		else
21598c2ecf20Sopenharmony_ci			init_fw_cb->ipv6_tcp_opts &=
21608c2ecf20Sopenharmony_ci				cpu_to_le16(~IPV6_TCPOPT_DELAYED_ACK_DISABLE &
21618c2ecf20Sopenharmony_ci					    0xFFFF);
21628c2ecf20Sopenharmony_ci		break;
21638c2ecf20Sopenharmony_ci	case ISCSI_NET_PARAM_TCP_NAGLE_DISABLE:
21648c2ecf20Sopenharmony_ci		if (iface_param->iface_num & 0x1)
21658c2ecf20Sopenharmony_ci			break;
21668c2ecf20Sopenharmony_ci		if (iface_param->value[0] == ISCSI_NET_PARAM_DISABLE)
21678c2ecf20Sopenharmony_ci			init_fw_cb->ipv6_tcp_opts |=
21688c2ecf20Sopenharmony_ci				cpu_to_le16(IPV6_TCPOPT_NAGLE_ALGO_DISABLE);
21698c2ecf20Sopenharmony_ci		else
21708c2ecf20Sopenharmony_ci			init_fw_cb->ipv6_tcp_opts &=
21718c2ecf20Sopenharmony_ci				cpu_to_le16(~IPV6_TCPOPT_NAGLE_ALGO_DISABLE);
21728c2ecf20Sopenharmony_ci		break;
21738c2ecf20Sopenharmony_ci	case ISCSI_NET_PARAM_TCP_WSF_DISABLE:
21748c2ecf20Sopenharmony_ci		if (iface_param->iface_num & 0x1)
21758c2ecf20Sopenharmony_ci			break;
21768c2ecf20Sopenharmony_ci		if (iface_param->value[0] == ISCSI_NET_PARAM_DISABLE)
21778c2ecf20Sopenharmony_ci			init_fw_cb->ipv6_tcp_opts |=
21788c2ecf20Sopenharmony_ci				cpu_to_le16(IPV6_TCPOPT_WINDOW_SCALE_DISABLE);
21798c2ecf20Sopenharmony_ci		else
21808c2ecf20Sopenharmony_ci			init_fw_cb->ipv6_tcp_opts &=
21818c2ecf20Sopenharmony_ci				cpu_to_le16(~IPV6_TCPOPT_WINDOW_SCALE_DISABLE);
21828c2ecf20Sopenharmony_ci		break;
21838c2ecf20Sopenharmony_ci	case ISCSI_NET_PARAM_TCP_WSF:
21848c2ecf20Sopenharmony_ci		if (iface_param->iface_num & 0x1)
21858c2ecf20Sopenharmony_ci			break;
21868c2ecf20Sopenharmony_ci		init_fw_cb->ipv6_tcp_wsf = iface_param->value[0];
21878c2ecf20Sopenharmony_ci		break;
21888c2ecf20Sopenharmony_ci	case ISCSI_NET_PARAM_TCP_TIMER_SCALE:
21898c2ecf20Sopenharmony_ci		if (iface_param->iface_num & 0x1)
21908c2ecf20Sopenharmony_ci			break;
21918c2ecf20Sopenharmony_ci		init_fw_cb->ipv6_tcp_opts &=
21928c2ecf20Sopenharmony_ci					cpu_to_le16(~IPV6_TCPOPT_TIMER_SCALE);
21938c2ecf20Sopenharmony_ci		init_fw_cb->ipv6_tcp_opts |=
21948c2ecf20Sopenharmony_ci				cpu_to_le16((iface_param->value[0] << 1) &
21958c2ecf20Sopenharmony_ci					    IPV6_TCPOPT_TIMER_SCALE);
21968c2ecf20Sopenharmony_ci		break;
21978c2ecf20Sopenharmony_ci	case ISCSI_NET_PARAM_TCP_TIMESTAMP_EN:
21988c2ecf20Sopenharmony_ci		if (iface_param->iface_num & 0x1)
21998c2ecf20Sopenharmony_ci			break;
22008c2ecf20Sopenharmony_ci		if (iface_param->value[0] == ISCSI_NET_PARAM_ENABLE)
22018c2ecf20Sopenharmony_ci			init_fw_cb->ipv6_tcp_opts |=
22028c2ecf20Sopenharmony_ci				cpu_to_le16(IPV6_TCPOPT_TIMESTAMP_EN);
22038c2ecf20Sopenharmony_ci		else
22048c2ecf20Sopenharmony_ci			init_fw_cb->ipv6_tcp_opts &=
22058c2ecf20Sopenharmony_ci				cpu_to_le16(~IPV6_TCPOPT_TIMESTAMP_EN);
22068c2ecf20Sopenharmony_ci		break;
22078c2ecf20Sopenharmony_ci	case ISCSI_NET_PARAM_IPV6_GRAT_NEIGHBOR_ADV_EN:
22088c2ecf20Sopenharmony_ci		if (iface_param->iface_num & 0x1)
22098c2ecf20Sopenharmony_ci			break;
22108c2ecf20Sopenharmony_ci		if (iface_param->value[0] == ISCSI_NET_PARAM_ENABLE)
22118c2ecf20Sopenharmony_ci			init_fw_cb->ipv6_opts |=
22128c2ecf20Sopenharmony_ci				cpu_to_le16(IPV6_OPT_GRAT_NEIGHBOR_ADV_EN);
22138c2ecf20Sopenharmony_ci		else
22148c2ecf20Sopenharmony_ci			init_fw_cb->ipv6_opts &=
22158c2ecf20Sopenharmony_ci				cpu_to_le16(~IPV6_OPT_GRAT_NEIGHBOR_ADV_EN);
22168c2ecf20Sopenharmony_ci		break;
22178c2ecf20Sopenharmony_ci	case ISCSI_NET_PARAM_REDIRECT_EN:
22188c2ecf20Sopenharmony_ci		if (iface_param->iface_num & 0x1)
22198c2ecf20Sopenharmony_ci			break;
22208c2ecf20Sopenharmony_ci		if (iface_param->value[0] == ISCSI_NET_PARAM_ENABLE)
22218c2ecf20Sopenharmony_ci			init_fw_cb->ipv6_opts |=
22228c2ecf20Sopenharmony_ci				cpu_to_le16(IPV6_OPT_REDIRECT_EN);
22238c2ecf20Sopenharmony_ci		else
22248c2ecf20Sopenharmony_ci			init_fw_cb->ipv6_opts &=
22258c2ecf20Sopenharmony_ci				cpu_to_le16(~IPV6_OPT_REDIRECT_EN);
22268c2ecf20Sopenharmony_ci		break;
22278c2ecf20Sopenharmony_ci	case ISCSI_NET_PARAM_IPV6_MLD_EN:
22288c2ecf20Sopenharmony_ci		if (iface_param->iface_num & 0x1)
22298c2ecf20Sopenharmony_ci			break;
22308c2ecf20Sopenharmony_ci		if (iface_param->value[0] == ISCSI_NET_PARAM_ENABLE)
22318c2ecf20Sopenharmony_ci			init_fw_cb->ipv6_addtl_opts |=
22328c2ecf20Sopenharmony_ci				cpu_to_le16(IPV6_ADDOPT_MLD_EN);
22338c2ecf20Sopenharmony_ci		else
22348c2ecf20Sopenharmony_ci			init_fw_cb->ipv6_addtl_opts &=
22358c2ecf20Sopenharmony_ci				cpu_to_le16(~IPV6_ADDOPT_MLD_EN);
22368c2ecf20Sopenharmony_ci		break;
22378c2ecf20Sopenharmony_ci	case ISCSI_NET_PARAM_IPV6_FLOW_LABEL:
22388c2ecf20Sopenharmony_ci		if (iface_param->iface_num & 0x1)
22398c2ecf20Sopenharmony_ci			break;
22408c2ecf20Sopenharmony_ci		init_fw_cb->ipv6_flow_lbl =
22418c2ecf20Sopenharmony_ci				cpu_to_le16(*(uint16_t *)iface_param->value);
22428c2ecf20Sopenharmony_ci		break;
22438c2ecf20Sopenharmony_ci	case ISCSI_NET_PARAM_IPV6_TRAFFIC_CLASS:
22448c2ecf20Sopenharmony_ci		if (iface_param->iface_num & 0x1)
22458c2ecf20Sopenharmony_ci			break;
22468c2ecf20Sopenharmony_ci		init_fw_cb->ipv6_traffic_class = iface_param->value[0];
22478c2ecf20Sopenharmony_ci		break;
22488c2ecf20Sopenharmony_ci	case ISCSI_NET_PARAM_IPV6_HOP_LIMIT:
22498c2ecf20Sopenharmony_ci		if (iface_param->iface_num & 0x1)
22508c2ecf20Sopenharmony_ci			break;
22518c2ecf20Sopenharmony_ci		init_fw_cb->ipv6_hop_limit = iface_param->value[0];
22528c2ecf20Sopenharmony_ci		break;
22538c2ecf20Sopenharmony_ci	case ISCSI_NET_PARAM_IPV6_ND_REACHABLE_TMO:
22548c2ecf20Sopenharmony_ci		if (iface_param->iface_num & 0x1)
22558c2ecf20Sopenharmony_ci			break;
22568c2ecf20Sopenharmony_ci		init_fw_cb->ipv6_nd_reach_time =
22578c2ecf20Sopenharmony_ci				cpu_to_le32(*(uint32_t *)iface_param->value);
22588c2ecf20Sopenharmony_ci		break;
22598c2ecf20Sopenharmony_ci	case ISCSI_NET_PARAM_IPV6_ND_REXMIT_TIME:
22608c2ecf20Sopenharmony_ci		if (iface_param->iface_num & 0x1)
22618c2ecf20Sopenharmony_ci			break;
22628c2ecf20Sopenharmony_ci		init_fw_cb->ipv6_nd_rexmit_timer =
22638c2ecf20Sopenharmony_ci				cpu_to_le32(*(uint32_t *)iface_param->value);
22648c2ecf20Sopenharmony_ci		break;
22658c2ecf20Sopenharmony_ci	case ISCSI_NET_PARAM_IPV6_ND_STALE_TMO:
22668c2ecf20Sopenharmony_ci		if (iface_param->iface_num & 0x1)
22678c2ecf20Sopenharmony_ci			break;
22688c2ecf20Sopenharmony_ci		init_fw_cb->ipv6_nd_stale_timeout =
22698c2ecf20Sopenharmony_ci				cpu_to_le32(*(uint32_t *)iface_param->value);
22708c2ecf20Sopenharmony_ci		break;
22718c2ecf20Sopenharmony_ci	case ISCSI_NET_PARAM_IPV6_DUP_ADDR_DETECT_CNT:
22728c2ecf20Sopenharmony_ci		if (iface_param->iface_num & 0x1)
22738c2ecf20Sopenharmony_ci			break;
22748c2ecf20Sopenharmony_ci		init_fw_cb->ipv6_dup_addr_detect_count = iface_param->value[0];
22758c2ecf20Sopenharmony_ci		break;
22768c2ecf20Sopenharmony_ci	case ISCSI_NET_PARAM_IPV6_RTR_ADV_LINK_MTU:
22778c2ecf20Sopenharmony_ci		if (iface_param->iface_num & 0x1)
22788c2ecf20Sopenharmony_ci			break;
22798c2ecf20Sopenharmony_ci		init_fw_cb->ipv6_gw_advrt_mtu =
22808c2ecf20Sopenharmony_ci				cpu_to_le32(*(uint32_t *)iface_param->value);
22818c2ecf20Sopenharmony_ci		break;
22828c2ecf20Sopenharmony_ci	default:
22838c2ecf20Sopenharmony_ci		ql4_printk(KERN_ERR, ha, "Unknown IPv6 param = %d\n",
22848c2ecf20Sopenharmony_ci			   iface_param->param);
22858c2ecf20Sopenharmony_ci		break;
22868c2ecf20Sopenharmony_ci	}
22878c2ecf20Sopenharmony_ci}
22888c2ecf20Sopenharmony_ci
22898c2ecf20Sopenharmony_cistatic void qla4xxx_set_ipv4(struct scsi_qla_host *ha,
22908c2ecf20Sopenharmony_ci			     struct iscsi_iface_param_info *iface_param,
22918c2ecf20Sopenharmony_ci			     struct addr_ctrl_blk *init_fw_cb)
22928c2ecf20Sopenharmony_ci{
22938c2ecf20Sopenharmony_ci	switch (iface_param->param) {
22948c2ecf20Sopenharmony_ci	case ISCSI_NET_PARAM_IPV4_ADDR:
22958c2ecf20Sopenharmony_ci		memcpy(init_fw_cb->ipv4_addr, iface_param->value,
22968c2ecf20Sopenharmony_ci		       sizeof(init_fw_cb->ipv4_addr));
22978c2ecf20Sopenharmony_ci		break;
22988c2ecf20Sopenharmony_ci	case ISCSI_NET_PARAM_IPV4_SUBNET:
22998c2ecf20Sopenharmony_ci		memcpy(init_fw_cb->ipv4_subnet,	iface_param->value,
23008c2ecf20Sopenharmony_ci		       sizeof(init_fw_cb->ipv4_subnet));
23018c2ecf20Sopenharmony_ci		break;
23028c2ecf20Sopenharmony_ci	case ISCSI_NET_PARAM_IPV4_GW:
23038c2ecf20Sopenharmony_ci		memcpy(init_fw_cb->ipv4_gw_addr, iface_param->value,
23048c2ecf20Sopenharmony_ci		       sizeof(init_fw_cb->ipv4_gw_addr));
23058c2ecf20Sopenharmony_ci		break;
23068c2ecf20Sopenharmony_ci	case ISCSI_NET_PARAM_IPV4_BOOTPROTO:
23078c2ecf20Sopenharmony_ci		if (iface_param->value[0] == ISCSI_BOOTPROTO_DHCP)
23088c2ecf20Sopenharmony_ci			init_fw_cb->ipv4_tcp_opts |=
23098c2ecf20Sopenharmony_ci					cpu_to_le16(TCPOPT_DHCP_ENABLE);
23108c2ecf20Sopenharmony_ci		else if (iface_param->value[0] == ISCSI_BOOTPROTO_STATIC)
23118c2ecf20Sopenharmony_ci			init_fw_cb->ipv4_tcp_opts &=
23128c2ecf20Sopenharmony_ci					cpu_to_le16(~TCPOPT_DHCP_ENABLE);
23138c2ecf20Sopenharmony_ci		else
23148c2ecf20Sopenharmony_ci			ql4_printk(KERN_ERR, ha, "Invalid IPv4 bootproto\n");
23158c2ecf20Sopenharmony_ci		break;
23168c2ecf20Sopenharmony_ci	case ISCSI_NET_PARAM_IFACE_ENABLE:
23178c2ecf20Sopenharmony_ci		if (iface_param->value[0] == ISCSI_IFACE_ENABLE) {
23188c2ecf20Sopenharmony_ci			init_fw_cb->ipv4_ip_opts |=
23198c2ecf20Sopenharmony_ci				cpu_to_le16(IPOPT_IPV4_PROTOCOL_ENABLE);
23208c2ecf20Sopenharmony_ci			qla4xxx_create_ipv4_iface(ha);
23218c2ecf20Sopenharmony_ci		} else {
23228c2ecf20Sopenharmony_ci			init_fw_cb->ipv4_ip_opts &=
23238c2ecf20Sopenharmony_ci				cpu_to_le16(~IPOPT_IPV4_PROTOCOL_ENABLE &
23248c2ecf20Sopenharmony_ci					    0xFFFF);
23258c2ecf20Sopenharmony_ci			qla4xxx_destroy_ipv4_iface(ha);
23268c2ecf20Sopenharmony_ci		}
23278c2ecf20Sopenharmony_ci		break;
23288c2ecf20Sopenharmony_ci	case ISCSI_NET_PARAM_VLAN_TAG:
23298c2ecf20Sopenharmony_ci		if (iface_param->len != sizeof(init_fw_cb->ipv4_vlan_tag))
23308c2ecf20Sopenharmony_ci			break;
23318c2ecf20Sopenharmony_ci		init_fw_cb->ipv4_vlan_tag =
23328c2ecf20Sopenharmony_ci				cpu_to_be16(*(uint16_t *)iface_param->value);
23338c2ecf20Sopenharmony_ci		break;
23348c2ecf20Sopenharmony_ci	case ISCSI_NET_PARAM_VLAN_ENABLED:
23358c2ecf20Sopenharmony_ci		if (iface_param->value[0] == ISCSI_VLAN_ENABLE)
23368c2ecf20Sopenharmony_ci			init_fw_cb->ipv4_ip_opts |=
23378c2ecf20Sopenharmony_ci					cpu_to_le16(IPOPT_VLAN_TAGGING_ENABLE);
23388c2ecf20Sopenharmony_ci		else
23398c2ecf20Sopenharmony_ci			init_fw_cb->ipv4_ip_opts &=
23408c2ecf20Sopenharmony_ci					cpu_to_le16(~IPOPT_VLAN_TAGGING_ENABLE);
23418c2ecf20Sopenharmony_ci		break;
23428c2ecf20Sopenharmony_ci	case ISCSI_NET_PARAM_MTU:
23438c2ecf20Sopenharmony_ci		init_fw_cb->eth_mtu_size =
23448c2ecf20Sopenharmony_ci				cpu_to_le16(*(uint16_t *)iface_param->value);
23458c2ecf20Sopenharmony_ci		break;
23468c2ecf20Sopenharmony_ci	case ISCSI_NET_PARAM_PORT:
23478c2ecf20Sopenharmony_ci		init_fw_cb->ipv4_port =
23488c2ecf20Sopenharmony_ci				cpu_to_le16(*(uint16_t *)iface_param->value);
23498c2ecf20Sopenharmony_ci		break;
23508c2ecf20Sopenharmony_ci	case ISCSI_NET_PARAM_DELAYED_ACK_EN:
23518c2ecf20Sopenharmony_ci		if (iface_param->iface_num & 0x1)
23528c2ecf20Sopenharmony_ci			break;
23538c2ecf20Sopenharmony_ci		if (iface_param->value[0] == ISCSI_NET_PARAM_DISABLE)
23548c2ecf20Sopenharmony_ci			init_fw_cb->ipv4_tcp_opts |=
23558c2ecf20Sopenharmony_ci				cpu_to_le16(TCPOPT_DELAYED_ACK_DISABLE);
23568c2ecf20Sopenharmony_ci		else
23578c2ecf20Sopenharmony_ci			init_fw_cb->ipv4_tcp_opts &=
23588c2ecf20Sopenharmony_ci				cpu_to_le16(~TCPOPT_DELAYED_ACK_DISABLE &
23598c2ecf20Sopenharmony_ci					    0xFFFF);
23608c2ecf20Sopenharmony_ci		break;
23618c2ecf20Sopenharmony_ci	case ISCSI_NET_PARAM_TCP_NAGLE_DISABLE:
23628c2ecf20Sopenharmony_ci		if (iface_param->iface_num & 0x1)
23638c2ecf20Sopenharmony_ci			break;
23648c2ecf20Sopenharmony_ci		if (iface_param->value[0] == ISCSI_NET_PARAM_DISABLE)
23658c2ecf20Sopenharmony_ci			init_fw_cb->ipv4_tcp_opts |=
23668c2ecf20Sopenharmony_ci				cpu_to_le16(TCPOPT_NAGLE_ALGO_DISABLE);
23678c2ecf20Sopenharmony_ci		else
23688c2ecf20Sopenharmony_ci			init_fw_cb->ipv4_tcp_opts &=
23698c2ecf20Sopenharmony_ci				cpu_to_le16(~TCPOPT_NAGLE_ALGO_DISABLE);
23708c2ecf20Sopenharmony_ci		break;
23718c2ecf20Sopenharmony_ci	case ISCSI_NET_PARAM_TCP_WSF_DISABLE:
23728c2ecf20Sopenharmony_ci		if (iface_param->iface_num & 0x1)
23738c2ecf20Sopenharmony_ci			break;
23748c2ecf20Sopenharmony_ci		if (iface_param->value[0] == ISCSI_NET_PARAM_DISABLE)
23758c2ecf20Sopenharmony_ci			init_fw_cb->ipv4_tcp_opts |=
23768c2ecf20Sopenharmony_ci				cpu_to_le16(TCPOPT_WINDOW_SCALE_DISABLE);
23778c2ecf20Sopenharmony_ci		else
23788c2ecf20Sopenharmony_ci			init_fw_cb->ipv4_tcp_opts &=
23798c2ecf20Sopenharmony_ci				cpu_to_le16(~TCPOPT_WINDOW_SCALE_DISABLE);
23808c2ecf20Sopenharmony_ci		break;
23818c2ecf20Sopenharmony_ci	case ISCSI_NET_PARAM_TCP_WSF:
23828c2ecf20Sopenharmony_ci		if (iface_param->iface_num & 0x1)
23838c2ecf20Sopenharmony_ci			break;
23848c2ecf20Sopenharmony_ci		init_fw_cb->ipv4_tcp_wsf = iface_param->value[0];
23858c2ecf20Sopenharmony_ci		break;
23868c2ecf20Sopenharmony_ci	case ISCSI_NET_PARAM_TCP_TIMER_SCALE:
23878c2ecf20Sopenharmony_ci		if (iface_param->iface_num & 0x1)
23888c2ecf20Sopenharmony_ci			break;
23898c2ecf20Sopenharmony_ci		init_fw_cb->ipv4_tcp_opts &= cpu_to_le16(~TCPOPT_TIMER_SCALE);
23908c2ecf20Sopenharmony_ci		init_fw_cb->ipv4_tcp_opts |=
23918c2ecf20Sopenharmony_ci				cpu_to_le16((iface_param->value[0] << 1) &
23928c2ecf20Sopenharmony_ci					    TCPOPT_TIMER_SCALE);
23938c2ecf20Sopenharmony_ci		break;
23948c2ecf20Sopenharmony_ci	case ISCSI_NET_PARAM_TCP_TIMESTAMP_EN:
23958c2ecf20Sopenharmony_ci		if (iface_param->iface_num & 0x1)
23968c2ecf20Sopenharmony_ci			break;
23978c2ecf20Sopenharmony_ci		if (iface_param->value[0] == ISCSI_NET_PARAM_ENABLE)
23988c2ecf20Sopenharmony_ci			init_fw_cb->ipv4_tcp_opts |=
23998c2ecf20Sopenharmony_ci				cpu_to_le16(TCPOPT_TIMESTAMP_ENABLE);
24008c2ecf20Sopenharmony_ci		else
24018c2ecf20Sopenharmony_ci			init_fw_cb->ipv4_tcp_opts &=
24028c2ecf20Sopenharmony_ci				cpu_to_le16(~TCPOPT_TIMESTAMP_ENABLE);
24038c2ecf20Sopenharmony_ci		break;
24048c2ecf20Sopenharmony_ci	case ISCSI_NET_PARAM_IPV4_DHCP_DNS_ADDR_EN:
24058c2ecf20Sopenharmony_ci		if (iface_param->iface_num & 0x1)
24068c2ecf20Sopenharmony_ci			break;
24078c2ecf20Sopenharmony_ci		if (iface_param->value[0] == ISCSI_NET_PARAM_ENABLE)
24088c2ecf20Sopenharmony_ci			init_fw_cb->ipv4_tcp_opts |=
24098c2ecf20Sopenharmony_ci				cpu_to_le16(TCPOPT_DNS_SERVER_IP_EN);
24108c2ecf20Sopenharmony_ci		else
24118c2ecf20Sopenharmony_ci			init_fw_cb->ipv4_tcp_opts &=
24128c2ecf20Sopenharmony_ci				cpu_to_le16(~TCPOPT_DNS_SERVER_IP_EN);
24138c2ecf20Sopenharmony_ci		break;
24148c2ecf20Sopenharmony_ci	case ISCSI_NET_PARAM_IPV4_DHCP_SLP_DA_EN:
24158c2ecf20Sopenharmony_ci		if (iface_param->iface_num & 0x1)
24168c2ecf20Sopenharmony_ci			break;
24178c2ecf20Sopenharmony_ci		if (iface_param->value[0] == ISCSI_NET_PARAM_ENABLE)
24188c2ecf20Sopenharmony_ci			init_fw_cb->ipv4_tcp_opts |=
24198c2ecf20Sopenharmony_ci				cpu_to_le16(TCPOPT_SLP_DA_INFO_EN);
24208c2ecf20Sopenharmony_ci		else
24218c2ecf20Sopenharmony_ci			init_fw_cb->ipv4_tcp_opts &=
24228c2ecf20Sopenharmony_ci				cpu_to_le16(~TCPOPT_SLP_DA_INFO_EN);
24238c2ecf20Sopenharmony_ci		break;
24248c2ecf20Sopenharmony_ci	case ISCSI_NET_PARAM_IPV4_TOS_EN:
24258c2ecf20Sopenharmony_ci		if (iface_param->iface_num & 0x1)
24268c2ecf20Sopenharmony_ci			break;
24278c2ecf20Sopenharmony_ci		if (iface_param->value[0] == ISCSI_NET_PARAM_ENABLE)
24288c2ecf20Sopenharmony_ci			init_fw_cb->ipv4_ip_opts |=
24298c2ecf20Sopenharmony_ci				cpu_to_le16(IPOPT_IPV4_TOS_EN);
24308c2ecf20Sopenharmony_ci		else
24318c2ecf20Sopenharmony_ci			init_fw_cb->ipv4_ip_opts &=
24328c2ecf20Sopenharmony_ci				cpu_to_le16(~IPOPT_IPV4_TOS_EN);
24338c2ecf20Sopenharmony_ci		break;
24348c2ecf20Sopenharmony_ci	case ISCSI_NET_PARAM_IPV4_TOS:
24358c2ecf20Sopenharmony_ci		if (iface_param->iface_num & 0x1)
24368c2ecf20Sopenharmony_ci			break;
24378c2ecf20Sopenharmony_ci		init_fw_cb->ipv4_tos = iface_param->value[0];
24388c2ecf20Sopenharmony_ci		break;
24398c2ecf20Sopenharmony_ci	case ISCSI_NET_PARAM_IPV4_GRAT_ARP_EN:
24408c2ecf20Sopenharmony_ci		if (iface_param->iface_num & 0x1)
24418c2ecf20Sopenharmony_ci			break;
24428c2ecf20Sopenharmony_ci		if (iface_param->value[0] == ISCSI_NET_PARAM_ENABLE)
24438c2ecf20Sopenharmony_ci			init_fw_cb->ipv4_ip_opts |=
24448c2ecf20Sopenharmony_ci					cpu_to_le16(IPOPT_GRAT_ARP_EN);
24458c2ecf20Sopenharmony_ci		else
24468c2ecf20Sopenharmony_ci			init_fw_cb->ipv4_ip_opts &=
24478c2ecf20Sopenharmony_ci					cpu_to_le16(~IPOPT_GRAT_ARP_EN);
24488c2ecf20Sopenharmony_ci		break;
24498c2ecf20Sopenharmony_ci	case ISCSI_NET_PARAM_IPV4_DHCP_ALT_CLIENT_ID_EN:
24508c2ecf20Sopenharmony_ci		if (iface_param->iface_num & 0x1)
24518c2ecf20Sopenharmony_ci			break;
24528c2ecf20Sopenharmony_ci		if (iface_param->value[0] == ISCSI_NET_PARAM_ENABLE)
24538c2ecf20Sopenharmony_ci			init_fw_cb->ipv4_ip_opts |=
24548c2ecf20Sopenharmony_ci				cpu_to_le16(IPOPT_ALT_CID_EN);
24558c2ecf20Sopenharmony_ci		else
24568c2ecf20Sopenharmony_ci			init_fw_cb->ipv4_ip_opts &=
24578c2ecf20Sopenharmony_ci				cpu_to_le16(~IPOPT_ALT_CID_EN);
24588c2ecf20Sopenharmony_ci		break;
24598c2ecf20Sopenharmony_ci	case ISCSI_NET_PARAM_IPV4_DHCP_ALT_CLIENT_ID:
24608c2ecf20Sopenharmony_ci		if (iface_param->iface_num & 0x1)
24618c2ecf20Sopenharmony_ci			break;
24628c2ecf20Sopenharmony_ci		memcpy(init_fw_cb->ipv4_dhcp_alt_cid, iface_param->value,
24638c2ecf20Sopenharmony_ci		       (sizeof(init_fw_cb->ipv4_dhcp_alt_cid) - 1));
24648c2ecf20Sopenharmony_ci		init_fw_cb->ipv4_dhcp_alt_cid_len =
24658c2ecf20Sopenharmony_ci					strlen(init_fw_cb->ipv4_dhcp_alt_cid);
24668c2ecf20Sopenharmony_ci		break;
24678c2ecf20Sopenharmony_ci	case ISCSI_NET_PARAM_IPV4_DHCP_REQ_VENDOR_ID_EN:
24688c2ecf20Sopenharmony_ci		if (iface_param->iface_num & 0x1)
24698c2ecf20Sopenharmony_ci			break;
24708c2ecf20Sopenharmony_ci		if (iface_param->value[0] == ISCSI_NET_PARAM_ENABLE)
24718c2ecf20Sopenharmony_ci			init_fw_cb->ipv4_ip_opts |=
24728c2ecf20Sopenharmony_ci					cpu_to_le16(IPOPT_REQ_VID_EN);
24738c2ecf20Sopenharmony_ci		else
24748c2ecf20Sopenharmony_ci			init_fw_cb->ipv4_ip_opts &=
24758c2ecf20Sopenharmony_ci					cpu_to_le16(~IPOPT_REQ_VID_EN);
24768c2ecf20Sopenharmony_ci		break;
24778c2ecf20Sopenharmony_ci	case ISCSI_NET_PARAM_IPV4_DHCP_USE_VENDOR_ID_EN:
24788c2ecf20Sopenharmony_ci		if (iface_param->iface_num & 0x1)
24798c2ecf20Sopenharmony_ci			break;
24808c2ecf20Sopenharmony_ci		if (iface_param->value[0] == ISCSI_NET_PARAM_ENABLE)
24818c2ecf20Sopenharmony_ci			init_fw_cb->ipv4_ip_opts |=
24828c2ecf20Sopenharmony_ci					cpu_to_le16(IPOPT_USE_VID_EN);
24838c2ecf20Sopenharmony_ci		else
24848c2ecf20Sopenharmony_ci			init_fw_cb->ipv4_ip_opts &=
24858c2ecf20Sopenharmony_ci					cpu_to_le16(~IPOPT_USE_VID_EN);
24868c2ecf20Sopenharmony_ci		break;
24878c2ecf20Sopenharmony_ci	case ISCSI_NET_PARAM_IPV4_DHCP_VENDOR_ID:
24888c2ecf20Sopenharmony_ci		if (iface_param->iface_num & 0x1)
24898c2ecf20Sopenharmony_ci			break;
24908c2ecf20Sopenharmony_ci		memcpy(init_fw_cb->ipv4_dhcp_vid, iface_param->value,
24918c2ecf20Sopenharmony_ci		       (sizeof(init_fw_cb->ipv4_dhcp_vid) - 1));
24928c2ecf20Sopenharmony_ci		init_fw_cb->ipv4_dhcp_vid_len =
24938c2ecf20Sopenharmony_ci					strlen(init_fw_cb->ipv4_dhcp_vid);
24948c2ecf20Sopenharmony_ci		break;
24958c2ecf20Sopenharmony_ci	case ISCSI_NET_PARAM_IPV4_DHCP_LEARN_IQN_EN:
24968c2ecf20Sopenharmony_ci		if (iface_param->iface_num & 0x1)
24978c2ecf20Sopenharmony_ci			break;
24988c2ecf20Sopenharmony_ci		if (iface_param->value[0] == ISCSI_NET_PARAM_ENABLE)
24998c2ecf20Sopenharmony_ci			init_fw_cb->ipv4_ip_opts |=
25008c2ecf20Sopenharmony_ci					cpu_to_le16(IPOPT_LEARN_IQN_EN);
25018c2ecf20Sopenharmony_ci		else
25028c2ecf20Sopenharmony_ci			init_fw_cb->ipv4_ip_opts &=
25038c2ecf20Sopenharmony_ci					cpu_to_le16(~IPOPT_LEARN_IQN_EN);
25048c2ecf20Sopenharmony_ci		break;
25058c2ecf20Sopenharmony_ci	case ISCSI_NET_PARAM_IPV4_FRAGMENT_DISABLE:
25068c2ecf20Sopenharmony_ci		if (iface_param->iface_num & 0x1)
25078c2ecf20Sopenharmony_ci			break;
25088c2ecf20Sopenharmony_ci		if (iface_param->value[0] == ISCSI_NET_PARAM_DISABLE)
25098c2ecf20Sopenharmony_ci			init_fw_cb->ipv4_ip_opts |=
25108c2ecf20Sopenharmony_ci				cpu_to_le16(IPOPT_FRAGMENTATION_DISABLE);
25118c2ecf20Sopenharmony_ci		else
25128c2ecf20Sopenharmony_ci			init_fw_cb->ipv4_ip_opts &=
25138c2ecf20Sopenharmony_ci				cpu_to_le16(~IPOPT_FRAGMENTATION_DISABLE);
25148c2ecf20Sopenharmony_ci		break;
25158c2ecf20Sopenharmony_ci	case ISCSI_NET_PARAM_IPV4_IN_FORWARD_EN:
25168c2ecf20Sopenharmony_ci		if (iface_param->iface_num & 0x1)
25178c2ecf20Sopenharmony_ci			break;
25188c2ecf20Sopenharmony_ci		if (iface_param->value[0] == ISCSI_NET_PARAM_ENABLE)
25198c2ecf20Sopenharmony_ci			init_fw_cb->ipv4_ip_opts |=
25208c2ecf20Sopenharmony_ci				cpu_to_le16(IPOPT_IN_FORWARD_EN);
25218c2ecf20Sopenharmony_ci		else
25228c2ecf20Sopenharmony_ci			init_fw_cb->ipv4_ip_opts &=
25238c2ecf20Sopenharmony_ci				cpu_to_le16(~IPOPT_IN_FORWARD_EN);
25248c2ecf20Sopenharmony_ci		break;
25258c2ecf20Sopenharmony_ci	case ISCSI_NET_PARAM_REDIRECT_EN:
25268c2ecf20Sopenharmony_ci		if (iface_param->iface_num & 0x1)
25278c2ecf20Sopenharmony_ci			break;
25288c2ecf20Sopenharmony_ci		if (iface_param->value[0] == ISCSI_NET_PARAM_ENABLE)
25298c2ecf20Sopenharmony_ci			init_fw_cb->ipv4_ip_opts |=
25308c2ecf20Sopenharmony_ci				cpu_to_le16(IPOPT_ARP_REDIRECT_EN);
25318c2ecf20Sopenharmony_ci		else
25328c2ecf20Sopenharmony_ci			init_fw_cb->ipv4_ip_opts &=
25338c2ecf20Sopenharmony_ci				cpu_to_le16(~IPOPT_ARP_REDIRECT_EN);
25348c2ecf20Sopenharmony_ci		break;
25358c2ecf20Sopenharmony_ci	case ISCSI_NET_PARAM_IPV4_TTL:
25368c2ecf20Sopenharmony_ci		if (iface_param->iface_num & 0x1)
25378c2ecf20Sopenharmony_ci			break;
25388c2ecf20Sopenharmony_ci		init_fw_cb->ipv4_ttl = iface_param->value[0];
25398c2ecf20Sopenharmony_ci		break;
25408c2ecf20Sopenharmony_ci	default:
25418c2ecf20Sopenharmony_ci		ql4_printk(KERN_ERR, ha, "Unknown IPv4 param = %d\n",
25428c2ecf20Sopenharmony_ci			   iface_param->param);
25438c2ecf20Sopenharmony_ci		break;
25448c2ecf20Sopenharmony_ci	}
25458c2ecf20Sopenharmony_ci}
25468c2ecf20Sopenharmony_ci
25478c2ecf20Sopenharmony_cistatic void qla4xxx_set_iscsi_param(struct scsi_qla_host *ha,
25488c2ecf20Sopenharmony_ci				    struct iscsi_iface_param_info *iface_param,
25498c2ecf20Sopenharmony_ci				    struct addr_ctrl_blk *init_fw_cb)
25508c2ecf20Sopenharmony_ci{
25518c2ecf20Sopenharmony_ci	switch (iface_param->param) {
25528c2ecf20Sopenharmony_ci	case ISCSI_IFACE_PARAM_DEF_TASKMGMT_TMO:
25538c2ecf20Sopenharmony_ci		if (iface_param->iface_num & 0x1)
25548c2ecf20Sopenharmony_ci			break;
25558c2ecf20Sopenharmony_ci		init_fw_cb->def_timeout =
25568c2ecf20Sopenharmony_ci				cpu_to_le16(*(uint16_t *)iface_param->value);
25578c2ecf20Sopenharmony_ci		break;
25588c2ecf20Sopenharmony_ci	case ISCSI_IFACE_PARAM_HDRDGST_EN:
25598c2ecf20Sopenharmony_ci		if (iface_param->iface_num & 0x1)
25608c2ecf20Sopenharmony_ci			break;
25618c2ecf20Sopenharmony_ci		if (iface_param->value[0] == ISCSI_NET_PARAM_ENABLE)
25628c2ecf20Sopenharmony_ci			init_fw_cb->iscsi_opts |=
25638c2ecf20Sopenharmony_ci				cpu_to_le16(ISCSIOPTS_HEADER_DIGEST_EN);
25648c2ecf20Sopenharmony_ci		else
25658c2ecf20Sopenharmony_ci			init_fw_cb->iscsi_opts &=
25668c2ecf20Sopenharmony_ci				cpu_to_le16(~ISCSIOPTS_HEADER_DIGEST_EN);
25678c2ecf20Sopenharmony_ci		break;
25688c2ecf20Sopenharmony_ci	case ISCSI_IFACE_PARAM_DATADGST_EN:
25698c2ecf20Sopenharmony_ci		if (iface_param->iface_num & 0x1)
25708c2ecf20Sopenharmony_ci			break;
25718c2ecf20Sopenharmony_ci		if (iface_param->value[0] == ISCSI_NET_PARAM_ENABLE)
25728c2ecf20Sopenharmony_ci			init_fw_cb->iscsi_opts |=
25738c2ecf20Sopenharmony_ci				cpu_to_le16(ISCSIOPTS_DATA_DIGEST_EN);
25748c2ecf20Sopenharmony_ci		else
25758c2ecf20Sopenharmony_ci			init_fw_cb->iscsi_opts &=
25768c2ecf20Sopenharmony_ci				cpu_to_le16(~ISCSIOPTS_DATA_DIGEST_EN);
25778c2ecf20Sopenharmony_ci		break;
25788c2ecf20Sopenharmony_ci	case ISCSI_IFACE_PARAM_IMM_DATA_EN:
25798c2ecf20Sopenharmony_ci		if (iface_param->iface_num & 0x1)
25808c2ecf20Sopenharmony_ci			break;
25818c2ecf20Sopenharmony_ci		if (iface_param->value[0] == ISCSI_NET_PARAM_ENABLE)
25828c2ecf20Sopenharmony_ci			init_fw_cb->iscsi_opts |=
25838c2ecf20Sopenharmony_ci				cpu_to_le16(ISCSIOPTS_IMMEDIATE_DATA_EN);
25848c2ecf20Sopenharmony_ci		else
25858c2ecf20Sopenharmony_ci			init_fw_cb->iscsi_opts &=
25868c2ecf20Sopenharmony_ci				cpu_to_le16(~ISCSIOPTS_IMMEDIATE_DATA_EN);
25878c2ecf20Sopenharmony_ci		break;
25888c2ecf20Sopenharmony_ci	case ISCSI_IFACE_PARAM_INITIAL_R2T_EN:
25898c2ecf20Sopenharmony_ci		if (iface_param->iface_num & 0x1)
25908c2ecf20Sopenharmony_ci			break;
25918c2ecf20Sopenharmony_ci		if (iface_param->value[0] == ISCSI_NET_PARAM_ENABLE)
25928c2ecf20Sopenharmony_ci			init_fw_cb->iscsi_opts |=
25938c2ecf20Sopenharmony_ci				cpu_to_le16(ISCSIOPTS_INITIAL_R2T_EN);
25948c2ecf20Sopenharmony_ci		else
25958c2ecf20Sopenharmony_ci			init_fw_cb->iscsi_opts &=
25968c2ecf20Sopenharmony_ci				cpu_to_le16(~ISCSIOPTS_INITIAL_R2T_EN);
25978c2ecf20Sopenharmony_ci		break;
25988c2ecf20Sopenharmony_ci	case ISCSI_IFACE_PARAM_DATASEQ_INORDER_EN:
25998c2ecf20Sopenharmony_ci		if (iface_param->iface_num & 0x1)
26008c2ecf20Sopenharmony_ci			break;
26018c2ecf20Sopenharmony_ci		if (iface_param->value[0] == ISCSI_NET_PARAM_ENABLE)
26028c2ecf20Sopenharmony_ci			init_fw_cb->iscsi_opts |=
26038c2ecf20Sopenharmony_ci				cpu_to_le16(ISCSIOPTS_DATA_SEQ_INORDER_EN);
26048c2ecf20Sopenharmony_ci		else
26058c2ecf20Sopenharmony_ci			init_fw_cb->iscsi_opts &=
26068c2ecf20Sopenharmony_ci				cpu_to_le16(~ISCSIOPTS_DATA_SEQ_INORDER_EN);
26078c2ecf20Sopenharmony_ci		break;
26088c2ecf20Sopenharmony_ci	case ISCSI_IFACE_PARAM_PDU_INORDER_EN:
26098c2ecf20Sopenharmony_ci		if (iface_param->iface_num & 0x1)
26108c2ecf20Sopenharmony_ci			break;
26118c2ecf20Sopenharmony_ci		if (iface_param->value[0] == ISCSI_NET_PARAM_ENABLE)
26128c2ecf20Sopenharmony_ci			init_fw_cb->iscsi_opts |=
26138c2ecf20Sopenharmony_ci				cpu_to_le16(ISCSIOPTS_DATA_PDU_INORDER_EN);
26148c2ecf20Sopenharmony_ci		else
26158c2ecf20Sopenharmony_ci			init_fw_cb->iscsi_opts &=
26168c2ecf20Sopenharmony_ci				cpu_to_le16(~ISCSIOPTS_DATA_PDU_INORDER_EN);
26178c2ecf20Sopenharmony_ci		break;
26188c2ecf20Sopenharmony_ci	case ISCSI_IFACE_PARAM_ERL:
26198c2ecf20Sopenharmony_ci		if (iface_param->iface_num & 0x1)
26208c2ecf20Sopenharmony_ci			break;
26218c2ecf20Sopenharmony_ci		init_fw_cb->iscsi_opts &= cpu_to_le16(~ISCSIOPTS_ERL);
26228c2ecf20Sopenharmony_ci		init_fw_cb->iscsi_opts |= cpu_to_le16(iface_param->value[0] &
26238c2ecf20Sopenharmony_ci						      ISCSIOPTS_ERL);
26248c2ecf20Sopenharmony_ci		break;
26258c2ecf20Sopenharmony_ci	case ISCSI_IFACE_PARAM_MAX_RECV_DLENGTH:
26268c2ecf20Sopenharmony_ci		if (iface_param->iface_num & 0x1)
26278c2ecf20Sopenharmony_ci			break;
26288c2ecf20Sopenharmony_ci		init_fw_cb->iscsi_max_pdu_size =
26298c2ecf20Sopenharmony_ci				cpu_to_le32(*(uint32_t *)iface_param->value) /
26308c2ecf20Sopenharmony_ci				BYTE_UNITS;
26318c2ecf20Sopenharmony_ci		break;
26328c2ecf20Sopenharmony_ci	case ISCSI_IFACE_PARAM_FIRST_BURST:
26338c2ecf20Sopenharmony_ci		if (iface_param->iface_num & 0x1)
26348c2ecf20Sopenharmony_ci			break;
26358c2ecf20Sopenharmony_ci		init_fw_cb->iscsi_fburst_len =
26368c2ecf20Sopenharmony_ci				cpu_to_le32(*(uint32_t *)iface_param->value) /
26378c2ecf20Sopenharmony_ci				BYTE_UNITS;
26388c2ecf20Sopenharmony_ci		break;
26398c2ecf20Sopenharmony_ci	case ISCSI_IFACE_PARAM_MAX_R2T:
26408c2ecf20Sopenharmony_ci		if (iface_param->iface_num & 0x1)
26418c2ecf20Sopenharmony_ci			break;
26428c2ecf20Sopenharmony_ci		init_fw_cb->iscsi_max_outstnd_r2t =
26438c2ecf20Sopenharmony_ci				cpu_to_le16(*(uint16_t *)iface_param->value);
26448c2ecf20Sopenharmony_ci		break;
26458c2ecf20Sopenharmony_ci	case ISCSI_IFACE_PARAM_MAX_BURST:
26468c2ecf20Sopenharmony_ci		if (iface_param->iface_num & 0x1)
26478c2ecf20Sopenharmony_ci			break;
26488c2ecf20Sopenharmony_ci		init_fw_cb->iscsi_max_burst_len =
26498c2ecf20Sopenharmony_ci				cpu_to_le32(*(uint32_t *)iface_param->value) /
26508c2ecf20Sopenharmony_ci				BYTE_UNITS;
26518c2ecf20Sopenharmony_ci		break;
26528c2ecf20Sopenharmony_ci	case ISCSI_IFACE_PARAM_CHAP_AUTH_EN:
26538c2ecf20Sopenharmony_ci		if (iface_param->iface_num & 0x1)
26548c2ecf20Sopenharmony_ci			break;
26558c2ecf20Sopenharmony_ci		if (iface_param->value[0] == ISCSI_NET_PARAM_ENABLE)
26568c2ecf20Sopenharmony_ci			init_fw_cb->iscsi_opts |=
26578c2ecf20Sopenharmony_ci				cpu_to_le16(ISCSIOPTS_CHAP_AUTH_EN);
26588c2ecf20Sopenharmony_ci		else
26598c2ecf20Sopenharmony_ci			init_fw_cb->iscsi_opts &=
26608c2ecf20Sopenharmony_ci				cpu_to_le16(~ISCSIOPTS_CHAP_AUTH_EN);
26618c2ecf20Sopenharmony_ci		break;
26628c2ecf20Sopenharmony_ci	case ISCSI_IFACE_PARAM_BIDI_CHAP_EN:
26638c2ecf20Sopenharmony_ci		if (iface_param->iface_num & 0x1)
26648c2ecf20Sopenharmony_ci			break;
26658c2ecf20Sopenharmony_ci		if (iface_param->value[0] == ISCSI_NET_PARAM_ENABLE)
26668c2ecf20Sopenharmony_ci			init_fw_cb->iscsi_opts |=
26678c2ecf20Sopenharmony_ci				cpu_to_le16(ISCSIOPTS_BIDI_CHAP_EN);
26688c2ecf20Sopenharmony_ci		else
26698c2ecf20Sopenharmony_ci			init_fw_cb->iscsi_opts &=
26708c2ecf20Sopenharmony_ci				cpu_to_le16(~ISCSIOPTS_BIDI_CHAP_EN);
26718c2ecf20Sopenharmony_ci		break;
26728c2ecf20Sopenharmony_ci	case ISCSI_IFACE_PARAM_DISCOVERY_AUTH_OPTIONAL:
26738c2ecf20Sopenharmony_ci		if (iface_param->iface_num & 0x1)
26748c2ecf20Sopenharmony_ci			break;
26758c2ecf20Sopenharmony_ci		if (iface_param->value[0] == ISCSI_NET_PARAM_ENABLE)
26768c2ecf20Sopenharmony_ci			init_fw_cb->iscsi_opts |=
26778c2ecf20Sopenharmony_ci				cpu_to_le16(ISCSIOPTS_DISCOVERY_AUTH_EN);
26788c2ecf20Sopenharmony_ci		else
26798c2ecf20Sopenharmony_ci			init_fw_cb->iscsi_opts &=
26808c2ecf20Sopenharmony_ci				cpu_to_le16(~ISCSIOPTS_DISCOVERY_AUTH_EN);
26818c2ecf20Sopenharmony_ci		break;
26828c2ecf20Sopenharmony_ci	case ISCSI_IFACE_PARAM_DISCOVERY_LOGOUT_EN:
26838c2ecf20Sopenharmony_ci		if (iface_param->iface_num & 0x1)
26848c2ecf20Sopenharmony_ci			break;
26858c2ecf20Sopenharmony_ci		if (iface_param->value[0] == ISCSI_NET_PARAM_ENABLE)
26868c2ecf20Sopenharmony_ci			init_fw_cb->iscsi_opts |=
26878c2ecf20Sopenharmony_ci				cpu_to_le16(ISCSIOPTS_DISCOVERY_LOGOUT_EN);
26888c2ecf20Sopenharmony_ci		else
26898c2ecf20Sopenharmony_ci			init_fw_cb->iscsi_opts &=
26908c2ecf20Sopenharmony_ci				cpu_to_le16(~ISCSIOPTS_DISCOVERY_LOGOUT_EN);
26918c2ecf20Sopenharmony_ci		break;
26928c2ecf20Sopenharmony_ci	case ISCSI_IFACE_PARAM_STRICT_LOGIN_COMP_EN:
26938c2ecf20Sopenharmony_ci		if (iface_param->iface_num & 0x1)
26948c2ecf20Sopenharmony_ci			break;
26958c2ecf20Sopenharmony_ci		if (iface_param->value[0] == ISCSI_NET_PARAM_ENABLE)
26968c2ecf20Sopenharmony_ci			init_fw_cb->iscsi_opts |=
26978c2ecf20Sopenharmony_ci				cpu_to_le16(ISCSIOPTS_STRICT_LOGIN_COMP_EN);
26988c2ecf20Sopenharmony_ci		else
26998c2ecf20Sopenharmony_ci			init_fw_cb->iscsi_opts &=
27008c2ecf20Sopenharmony_ci				cpu_to_le16(~ISCSIOPTS_STRICT_LOGIN_COMP_EN);
27018c2ecf20Sopenharmony_ci		break;
27028c2ecf20Sopenharmony_ci	default:
27038c2ecf20Sopenharmony_ci		ql4_printk(KERN_ERR, ha, "Unknown iscsi param = %d\n",
27048c2ecf20Sopenharmony_ci			   iface_param->param);
27058c2ecf20Sopenharmony_ci		break;
27068c2ecf20Sopenharmony_ci	}
27078c2ecf20Sopenharmony_ci}
27088c2ecf20Sopenharmony_ci
27098c2ecf20Sopenharmony_cistatic void
27108c2ecf20Sopenharmony_ciqla4xxx_initcb_to_acb(struct addr_ctrl_blk *init_fw_cb)
27118c2ecf20Sopenharmony_ci{
27128c2ecf20Sopenharmony_ci	struct addr_ctrl_blk_def *acb;
27138c2ecf20Sopenharmony_ci	acb = (struct addr_ctrl_blk_def *)init_fw_cb;
27148c2ecf20Sopenharmony_ci	memset(acb->reserved1, 0, sizeof(acb->reserved1));
27158c2ecf20Sopenharmony_ci	memset(acb->reserved2, 0, sizeof(acb->reserved2));
27168c2ecf20Sopenharmony_ci	memset(acb->reserved3, 0, sizeof(acb->reserved3));
27178c2ecf20Sopenharmony_ci	memset(acb->reserved4, 0, sizeof(acb->reserved4));
27188c2ecf20Sopenharmony_ci	memset(acb->reserved5, 0, sizeof(acb->reserved5));
27198c2ecf20Sopenharmony_ci	memset(acb->reserved6, 0, sizeof(acb->reserved6));
27208c2ecf20Sopenharmony_ci	memset(acb->reserved7, 0, sizeof(acb->reserved7));
27218c2ecf20Sopenharmony_ci	memset(acb->reserved8, 0, sizeof(acb->reserved8));
27228c2ecf20Sopenharmony_ci	memset(acb->reserved9, 0, sizeof(acb->reserved9));
27238c2ecf20Sopenharmony_ci	memset(acb->reserved10, 0, sizeof(acb->reserved10));
27248c2ecf20Sopenharmony_ci	memset(acb->reserved11, 0, sizeof(acb->reserved11));
27258c2ecf20Sopenharmony_ci	memset(acb->reserved12, 0, sizeof(acb->reserved12));
27268c2ecf20Sopenharmony_ci	memset(acb->reserved13, 0, sizeof(acb->reserved13));
27278c2ecf20Sopenharmony_ci	memset(acb->reserved14, 0, sizeof(acb->reserved14));
27288c2ecf20Sopenharmony_ci	memset(acb->reserved15, 0, sizeof(acb->reserved15));
27298c2ecf20Sopenharmony_ci}
27308c2ecf20Sopenharmony_ci
27318c2ecf20Sopenharmony_cistatic int
27328c2ecf20Sopenharmony_ciqla4xxx_iface_set_param(struct Scsi_Host *shost, void *data, uint32_t len)
27338c2ecf20Sopenharmony_ci{
27348c2ecf20Sopenharmony_ci	struct scsi_qla_host *ha = to_qla_host(shost);
27358c2ecf20Sopenharmony_ci	int rval = 0;
27368c2ecf20Sopenharmony_ci	struct iscsi_iface_param_info *iface_param = NULL;
27378c2ecf20Sopenharmony_ci	struct addr_ctrl_blk *init_fw_cb = NULL;
27388c2ecf20Sopenharmony_ci	dma_addr_t init_fw_cb_dma;
27398c2ecf20Sopenharmony_ci	uint32_t mbox_cmd[MBOX_REG_COUNT];
27408c2ecf20Sopenharmony_ci	uint32_t mbox_sts[MBOX_REG_COUNT];
27418c2ecf20Sopenharmony_ci	uint32_t rem = len;
27428c2ecf20Sopenharmony_ci	struct nlattr *attr;
27438c2ecf20Sopenharmony_ci
27448c2ecf20Sopenharmony_ci	init_fw_cb = dma_alloc_coherent(&ha->pdev->dev,
27458c2ecf20Sopenharmony_ci					sizeof(struct addr_ctrl_blk),
27468c2ecf20Sopenharmony_ci					&init_fw_cb_dma, GFP_KERNEL);
27478c2ecf20Sopenharmony_ci	if (!init_fw_cb) {
27488c2ecf20Sopenharmony_ci		ql4_printk(KERN_ERR, ha, "%s: Unable to alloc init_cb\n",
27498c2ecf20Sopenharmony_ci			   __func__);
27508c2ecf20Sopenharmony_ci		return -ENOMEM;
27518c2ecf20Sopenharmony_ci	}
27528c2ecf20Sopenharmony_ci
27538c2ecf20Sopenharmony_ci	memset(&mbox_cmd, 0, sizeof(mbox_cmd));
27548c2ecf20Sopenharmony_ci	memset(&mbox_sts, 0, sizeof(mbox_sts));
27558c2ecf20Sopenharmony_ci
27568c2ecf20Sopenharmony_ci	if (qla4xxx_get_ifcb(ha, &mbox_cmd[0], &mbox_sts[0], init_fw_cb_dma)) {
27578c2ecf20Sopenharmony_ci		ql4_printk(KERN_ERR, ha, "%s: get ifcb failed\n", __func__);
27588c2ecf20Sopenharmony_ci		rval = -EIO;
27598c2ecf20Sopenharmony_ci		goto exit_init_fw_cb;
27608c2ecf20Sopenharmony_ci	}
27618c2ecf20Sopenharmony_ci
27628c2ecf20Sopenharmony_ci	nla_for_each_attr(attr, data, len, rem) {
27638c2ecf20Sopenharmony_ci		if (nla_len(attr) < sizeof(*iface_param)) {
27648c2ecf20Sopenharmony_ci			rval = -EINVAL;
27658c2ecf20Sopenharmony_ci			goto exit_init_fw_cb;
27668c2ecf20Sopenharmony_ci		}
27678c2ecf20Sopenharmony_ci
27688c2ecf20Sopenharmony_ci		iface_param = nla_data(attr);
27698c2ecf20Sopenharmony_ci
27708c2ecf20Sopenharmony_ci		if (iface_param->param_type == ISCSI_NET_PARAM) {
27718c2ecf20Sopenharmony_ci			switch (iface_param->iface_type) {
27728c2ecf20Sopenharmony_ci			case ISCSI_IFACE_TYPE_IPV4:
27738c2ecf20Sopenharmony_ci				switch (iface_param->iface_num) {
27748c2ecf20Sopenharmony_ci				case 0:
27758c2ecf20Sopenharmony_ci					qla4xxx_set_ipv4(ha, iface_param,
27768c2ecf20Sopenharmony_ci							 init_fw_cb);
27778c2ecf20Sopenharmony_ci					break;
27788c2ecf20Sopenharmony_ci				default:
27798c2ecf20Sopenharmony_ci				/* Cannot have more than one IPv4 interface */
27808c2ecf20Sopenharmony_ci					ql4_printk(KERN_ERR, ha,
27818c2ecf20Sopenharmony_ci						   "Invalid IPv4 iface number = %d\n",
27828c2ecf20Sopenharmony_ci						   iface_param->iface_num);
27838c2ecf20Sopenharmony_ci					break;
27848c2ecf20Sopenharmony_ci				}
27858c2ecf20Sopenharmony_ci				break;
27868c2ecf20Sopenharmony_ci			case ISCSI_IFACE_TYPE_IPV6:
27878c2ecf20Sopenharmony_ci				switch (iface_param->iface_num) {
27888c2ecf20Sopenharmony_ci				case 0:
27898c2ecf20Sopenharmony_ci				case 1:
27908c2ecf20Sopenharmony_ci					qla4xxx_set_ipv6(ha, iface_param,
27918c2ecf20Sopenharmony_ci							 init_fw_cb);
27928c2ecf20Sopenharmony_ci					break;
27938c2ecf20Sopenharmony_ci				default:
27948c2ecf20Sopenharmony_ci				/* Cannot have more than two IPv6 interface */
27958c2ecf20Sopenharmony_ci					ql4_printk(KERN_ERR, ha,
27968c2ecf20Sopenharmony_ci						   "Invalid IPv6 iface number = %d\n",
27978c2ecf20Sopenharmony_ci						   iface_param->iface_num);
27988c2ecf20Sopenharmony_ci					break;
27998c2ecf20Sopenharmony_ci				}
28008c2ecf20Sopenharmony_ci				break;
28018c2ecf20Sopenharmony_ci			default:
28028c2ecf20Sopenharmony_ci				ql4_printk(KERN_ERR, ha,
28038c2ecf20Sopenharmony_ci					   "Invalid iface type\n");
28048c2ecf20Sopenharmony_ci				break;
28058c2ecf20Sopenharmony_ci			}
28068c2ecf20Sopenharmony_ci		} else if (iface_param->param_type == ISCSI_IFACE_PARAM) {
28078c2ecf20Sopenharmony_ci				qla4xxx_set_iscsi_param(ha, iface_param,
28088c2ecf20Sopenharmony_ci							init_fw_cb);
28098c2ecf20Sopenharmony_ci		} else {
28108c2ecf20Sopenharmony_ci			continue;
28118c2ecf20Sopenharmony_ci		}
28128c2ecf20Sopenharmony_ci	}
28138c2ecf20Sopenharmony_ci
28148c2ecf20Sopenharmony_ci	init_fw_cb->cookie = cpu_to_le32(0x11BEAD5A);
28158c2ecf20Sopenharmony_ci
28168c2ecf20Sopenharmony_ci	rval = qla4xxx_set_flash(ha, init_fw_cb_dma, FLASH_SEGMENT_IFCB,
28178c2ecf20Sopenharmony_ci				 sizeof(struct addr_ctrl_blk),
28188c2ecf20Sopenharmony_ci				 FLASH_OPT_RMW_COMMIT);
28198c2ecf20Sopenharmony_ci	if (rval != QLA_SUCCESS) {
28208c2ecf20Sopenharmony_ci		ql4_printk(KERN_ERR, ha, "%s: set flash mbx failed\n",
28218c2ecf20Sopenharmony_ci			   __func__);
28228c2ecf20Sopenharmony_ci		rval = -EIO;
28238c2ecf20Sopenharmony_ci		goto exit_init_fw_cb;
28248c2ecf20Sopenharmony_ci	}
28258c2ecf20Sopenharmony_ci
28268c2ecf20Sopenharmony_ci	rval = qla4xxx_disable_acb(ha);
28278c2ecf20Sopenharmony_ci	if (rval != QLA_SUCCESS) {
28288c2ecf20Sopenharmony_ci		ql4_printk(KERN_ERR, ha, "%s: disable acb mbx failed\n",
28298c2ecf20Sopenharmony_ci			   __func__);
28308c2ecf20Sopenharmony_ci		rval = -EIO;
28318c2ecf20Sopenharmony_ci		goto exit_init_fw_cb;
28328c2ecf20Sopenharmony_ci	}
28338c2ecf20Sopenharmony_ci
28348c2ecf20Sopenharmony_ci	wait_for_completion_timeout(&ha->disable_acb_comp,
28358c2ecf20Sopenharmony_ci				    DISABLE_ACB_TOV * HZ);
28368c2ecf20Sopenharmony_ci
28378c2ecf20Sopenharmony_ci	qla4xxx_initcb_to_acb(init_fw_cb);
28388c2ecf20Sopenharmony_ci
28398c2ecf20Sopenharmony_ci	rval = qla4xxx_set_acb(ha, &mbox_cmd[0], &mbox_sts[0], init_fw_cb_dma);
28408c2ecf20Sopenharmony_ci	if (rval != QLA_SUCCESS) {
28418c2ecf20Sopenharmony_ci		ql4_printk(KERN_ERR, ha, "%s: set acb mbx failed\n",
28428c2ecf20Sopenharmony_ci			   __func__);
28438c2ecf20Sopenharmony_ci		rval = -EIO;
28448c2ecf20Sopenharmony_ci		goto exit_init_fw_cb;
28458c2ecf20Sopenharmony_ci	}
28468c2ecf20Sopenharmony_ci
28478c2ecf20Sopenharmony_ci	memset(init_fw_cb, 0, sizeof(struct addr_ctrl_blk));
28488c2ecf20Sopenharmony_ci	qla4xxx_update_local_ifcb(ha, &mbox_cmd[0], &mbox_sts[0], init_fw_cb,
28498c2ecf20Sopenharmony_ci				  init_fw_cb_dma);
28508c2ecf20Sopenharmony_ci
28518c2ecf20Sopenharmony_ciexit_init_fw_cb:
28528c2ecf20Sopenharmony_ci	dma_free_coherent(&ha->pdev->dev, sizeof(struct addr_ctrl_blk),
28538c2ecf20Sopenharmony_ci			  init_fw_cb, init_fw_cb_dma);
28548c2ecf20Sopenharmony_ci
28558c2ecf20Sopenharmony_ci	return rval;
28568c2ecf20Sopenharmony_ci}
28578c2ecf20Sopenharmony_ci
28588c2ecf20Sopenharmony_cistatic int qla4xxx_session_get_param(struct iscsi_cls_session *cls_sess,
28598c2ecf20Sopenharmony_ci				     enum iscsi_param param, char *buf)
28608c2ecf20Sopenharmony_ci{
28618c2ecf20Sopenharmony_ci	struct iscsi_session *sess = cls_sess->dd_data;
28628c2ecf20Sopenharmony_ci	struct ddb_entry *ddb_entry = sess->dd_data;
28638c2ecf20Sopenharmony_ci	struct scsi_qla_host *ha = ddb_entry->ha;
28648c2ecf20Sopenharmony_ci	struct iscsi_cls_conn *cls_conn = ddb_entry->conn;
28658c2ecf20Sopenharmony_ci	struct ql4_chap_table chap_tbl;
28668c2ecf20Sopenharmony_ci	int rval, len;
28678c2ecf20Sopenharmony_ci	uint16_t idx;
28688c2ecf20Sopenharmony_ci
28698c2ecf20Sopenharmony_ci	memset(&chap_tbl, 0, sizeof(chap_tbl));
28708c2ecf20Sopenharmony_ci	switch (param) {
28718c2ecf20Sopenharmony_ci	case ISCSI_PARAM_CHAP_IN_IDX:
28728c2ecf20Sopenharmony_ci		rval = qla4xxx_get_chap_index(ha, sess->username_in,
28738c2ecf20Sopenharmony_ci					      sess->password_in, BIDI_CHAP,
28748c2ecf20Sopenharmony_ci					      &idx);
28758c2ecf20Sopenharmony_ci		if (rval)
28768c2ecf20Sopenharmony_ci			len = sprintf(buf, "\n");
28778c2ecf20Sopenharmony_ci		else
28788c2ecf20Sopenharmony_ci			len = sprintf(buf, "%hu\n", idx);
28798c2ecf20Sopenharmony_ci		break;
28808c2ecf20Sopenharmony_ci	case ISCSI_PARAM_CHAP_OUT_IDX:
28818c2ecf20Sopenharmony_ci		if (ddb_entry->ddb_type == FLASH_DDB) {
28828c2ecf20Sopenharmony_ci			if (ddb_entry->chap_tbl_idx != INVALID_ENTRY) {
28838c2ecf20Sopenharmony_ci				idx = ddb_entry->chap_tbl_idx;
28848c2ecf20Sopenharmony_ci				rval = QLA_SUCCESS;
28858c2ecf20Sopenharmony_ci			} else {
28868c2ecf20Sopenharmony_ci				rval = QLA_ERROR;
28878c2ecf20Sopenharmony_ci			}
28888c2ecf20Sopenharmony_ci		} else {
28898c2ecf20Sopenharmony_ci			rval = qla4xxx_get_chap_index(ha, sess->username,
28908c2ecf20Sopenharmony_ci						      sess->password,
28918c2ecf20Sopenharmony_ci						      LOCAL_CHAP, &idx);
28928c2ecf20Sopenharmony_ci		}
28938c2ecf20Sopenharmony_ci		if (rval)
28948c2ecf20Sopenharmony_ci			len = sprintf(buf, "\n");
28958c2ecf20Sopenharmony_ci		else
28968c2ecf20Sopenharmony_ci			len = sprintf(buf, "%hu\n", idx);
28978c2ecf20Sopenharmony_ci		break;
28988c2ecf20Sopenharmony_ci	case ISCSI_PARAM_USERNAME:
28998c2ecf20Sopenharmony_ci	case ISCSI_PARAM_PASSWORD:
29008c2ecf20Sopenharmony_ci		/* First, populate session username and password for FLASH DDB,
29018c2ecf20Sopenharmony_ci		 * if not already done. This happens when session login fails
29028c2ecf20Sopenharmony_ci		 * for a FLASH DDB.
29038c2ecf20Sopenharmony_ci		 */
29048c2ecf20Sopenharmony_ci		if (ddb_entry->ddb_type == FLASH_DDB &&
29058c2ecf20Sopenharmony_ci		    ddb_entry->chap_tbl_idx != INVALID_ENTRY &&
29068c2ecf20Sopenharmony_ci		    !sess->username && !sess->password) {
29078c2ecf20Sopenharmony_ci			idx = ddb_entry->chap_tbl_idx;
29088c2ecf20Sopenharmony_ci			rval = qla4xxx_get_uni_chap_at_index(ha, chap_tbl.name,
29098c2ecf20Sopenharmony_ci							    chap_tbl.secret,
29108c2ecf20Sopenharmony_ci							    idx);
29118c2ecf20Sopenharmony_ci			if (!rval) {
29128c2ecf20Sopenharmony_ci				iscsi_set_param(cls_conn, ISCSI_PARAM_USERNAME,
29138c2ecf20Sopenharmony_ci						(char *)chap_tbl.name,
29148c2ecf20Sopenharmony_ci						strlen((char *)chap_tbl.name));
29158c2ecf20Sopenharmony_ci				iscsi_set_param(cls_conn, ISCSI_PARAM_PASSWORD,
29168c2ecf20Sopenharmony_ci						(char *)chap_tbl.secret,
29178c2ecf20Sopenharmony_ci						chap_tbl.secret_len);
29188c2ecf20Sopenharmony_ci			}
29198c2ecf20Sopenharmony_ci		}
29208c2ecf20Sopenharmony_ci		fallthrough;
29218c2ecf20Sopenharmony_ci	default:
29228c2ecf20Sopenharmony_ci		return iscsi_session_get_param(cls_sess, param, buf);
29238c2ecf20Sopenharmony_ci	}
29248c2ecf20Sopenharmony_ci
29258c2ecf20Sopenharmony_ci	return len;
29268c2ecf20Sopenharmony_ci}
29278c2ecf20Sopenharmony_ci
29288c2ecf20Sopenharmony_cistatic int qla4xxx_conn_get_param(struct iscsi_cls_conn *cls_conn,
29298c2ecf20Sopenharmony_ci				  enum iscsi_param param, char *buf)
29308c2ecf20Sopenharmony_ci{
29318c2ecf20Sopenharmony_ci	struct iscsi_conn *conn;
29328c2ecf20Sopenharmony_ci	struct qla_conn *qla_conn;
29338c2ecf20Sopenharmony_ci	struct sockaddr *dst_addr;
29348c2ecf20Sopenharmony_ci
29358c2ecf20Sopenharmony_ci	conn = cls_conn->dd_data;
29368c2ecf20Sopenharmony_ci	qla_conn = conn->dd_data;
29378c2ecf20Sopenharmony_ci	dst_addr = (struct sockaddr *)&qla_conn->qla_ep->dst_addr;
29388c2ecf20Sopenharmony_ci
29398c2ecf20Sopenharmony_ci	switch (param) {
29408c2ecf20Sopenharmony_ci	case ISCSI_PARAM_CONN_PORT:
29418c2ecf20Sopenharmony_ci	case ISCSI_PARAM_CONN_ADDRESS:
29428c2ecf20Sopenharmony_ci		return iscsi_conn_get_addr_param((struct sockaddr_storage *)
29438c2ecf20Sopenharmony_ci						 dst_addr, param, buf);
29448c2ecf20Sopenharmony_ci	default:
29458c2ecf20Sopenharmony_ci		return iscsi_conn_get_param(cls_conn, param, buf);
29468c2ecf20Sopenharmony_ci	}
29478c2ecf20Sopenharmony_ci}
29488c2ecf20Sopenharmony_ci
29498c2ecf20Sopenharmony_ciint qla4xxx_get_ddb_index(struct scsi_qla_host *ha, uint16_t *ddb_index)
29508c2ecf20Sopenharmony_ci{
29518c2ecf20Sopenharmony_ci	uint32_t mbx_sts = 0;
29528c2ecf20Sopenharmony_ci	uint16_t tmp_ddb_index;
29538c2ecf20Sopenharmony_ci	int ret;
29548c2ecf20Sopenharmony_ci
29558c2ecf20Sopenharmony_ciget_ddb_index:
29568c2ecf20Sopenharmony_ci	tmp_ddb_index = find_first_zero_bit(ha->ddb_idx_map, MAX_DDB_ENTRIES);
29578c2ecf20Sopenharmony_ci
29588c2ecf20Sopenharmony_ci	if (tmp_ddb_index >= MAX_DDB_ENTRIES) {
29598c2ecf20Sopenharmony_ci		DEBUG2(ql4_printk(KERN_INFO, ha,
29608c2ecf20Sopenharmony_ci				  "Free DDB index not available\n"));
29618c2ecf20Sopenharmony_ci		ret = QLA_ERROR;
29628c2ecf20Sopenharmony_ci		goto exit_get_ddb_index;
29638c2ecf20Sopenharmony_ci	}
29648c2ecf20Sopenharmony_ci
29658c2ecf20Sopenharmony_ci	if (test_and_set_bit(tmp_ddb_index, ha->ddb_idx_map))
29668c2ecf20Sopenharmony_ci		goto get_ddb_index;
29678c2ecf20Sopenharmony_ci
29688c2ecf20Sopenharmony_ci	DEBUG2(ql4_printk(KERN_INFO, ha,
29698c2ecf20Sopenharmony_ci			  "Found a free DDB index at %d\n", tmp_ddb_index));
29708c2ecf20Sopenharmony_ci	ret = qla4xxx_req_ddb_entry(ha, tmp_ddb_index, &mbx_sts);
29718c2ecf20Sopenharmony_ci	if (ret == QLA_ERROR) {
29728c2ecf20Sopenharmony_ci		if (mbx_sts == MBOX_STS_COMMAND_ERROR) {
29738c2ecf20Sopenharmony_ci			ql4_printk(KERN_INFO, ha,
29748c2ecf20Sopenharmony_ci				   "DDB index = %d not available trying next\n",
29758c2ecf20Sopenharmony_ci				   tmp_ddb_index);
29768c2ecf20Sopenharmony_ci			goto get_ddb_index;
29778c2ecf20Sopenharmony_ci		}
29788c2ecf20Sopenharmony_ci		DEBUG2(ql4_printk(KERN_INFO, ha,
29798c2ecf20Sopenharmony_ci				  "Free FW DDB not available\n"));
29808c2ecf20Sopenharmony_ci	}
29818c2ecf20Sopenharmony_ci
29828c2ecf20Sopenharmony_ci	*ddb_index = tmp_ddb_index;
29838c2ecf20Sopenharmony_ci
29848c2ecf20Sopenharmony_ciexit_get_ddb_index:
29858c2ecf20Sopenharmony_ci	return ret;
29868c2ecf20Sopenharmony_ci}
29878c2ecf20Sopenharmony_ci
29888c2ecf20Sopenharmony_cistatic int qla4xxx_match_ipaddress(struct scsi_qla_host *ha,
29898c2ecf20Sopenharmony_ci				   struct ddb_entry *ddb_entry,
29908c2ecf20Sopenharmony_ci				   char *existing_ipaddr,
29918c2ecf20Sopenharmony_ci				   char *user_ipaddr)
29928c2ecf20Sopenharmony_ci{
29938c2ecf20Sopenharmony_ci	uint8_t dst_ipaddr[IPv6_ADDR_LEN];
29948c2ecf20Sopenharmony_ci	char formatted_ipaddr[DDB_IPADDR_LEN];
29958c2ecf20Sopenharmony_ci	int status = QLA_SUCCESS, ret = 0;
29968c2ecf20Sopenharmony_ci
29978c2ecf20Sopenharmony_ci	if (ddb_entry->fw_ddb_entry.options & DDB_OPT_IPV6_DEVICE) {
29988c2ecf20Sopenharmony_ci		ret = in6_pton(user_ipaddr, strlen(user_ipaddr), dst_ipaddr,
29998c2ecf20Sopenharmony_ci			       '\0', NULL);
30008c2ecf20Sopenharmony_ci		if (ret == 0) {
30018c2ecf20Sopenharmony_ci			status = QLA_ERROR;
30028c2ecf20Sopenharmony_ci			goto out_match;
30038c2ecf20Sopenharmony_ci		}
30048c2ecf20Sopenharmony_ci		ret = sprintf(formatted_ipaddr, "%pI6", dst_ipaddr);
30058c2ecf20Sopenharmony_ci	} else {
30068c2ecf20Sopenharmony_ci		ret = in4_pton(user_ipaddr, strlen(user_ipaddr), dst_ipaddr,
30078c2ecf20Sopenharmony_ci			       '\0', NULL);
30088c2ecf20Sopenharmony_ci		if (ret == 0) {
30098c2ecf20Sopenharmony_ci			status = QLA_ERROR;
30108c2ecf20Sopenharmony_ci			goto out_match;
30118c2ecf20Sopenharmony_ci		}
30128c2ecf20Sopenharmony_ci		ret = sprintf(formatted_ipaddr, "%pI4", dst_ipaddr);
30138c2ecf20Sopenharmony_ci	}
30148c2ecf20Sopenharmony_ci
30158c2ecf20Sopenharmony_ci	if (strcmp(existing_ipaddr, formatted_ipaddr))
30168c2ecf20Sopenharmony_ci		status = QLA_ERROR;
30178c2ecf20Sopenharmony_ci
30188c2ecf20Sopenharmony_ciout_match:
30198c2ecf20Sopenharmony_ci	return status;
30208c2ecf20Sopenharmony_ci}
30218c2ecf20Sopenharmony_ci
30228c2ecf20Sopenharmony_cistatic int qla4xxx_match_fwdb_session(struct scsi_qla_host *ha,
30238c2ecf20Sopenharmony_ci				      struct iscsi_cls_conn *cls_conn)
30248c2ecf20Sopenharmony_ci{
30258c2ecf20Sopenharmony_ci	int idx = 0, max_ddbs, rval;
30268c2ecf20Sopenharmony_ci	struct iscsi_cls_session *cls_sess = iscsi_conn_to_session(cls_conn);
30278c2ecf20Sopenharmony_ci	struct iscsi_session *sess, *existing_sess;
30288c2ecf20Sopenharmony_ci	struct iscsi_conn *conn, *existing_conn;
30298c2ecf20Sopenharmony_ci	struct ddb_entry *ddb_entry;
30308c2ecf20Sopenharmony_ci
30318c2ecf20Sopenharmony_ci	sess = cls_sess->dd_data;
30328c2ecf20Sopenharmony_ci	conn = cls_conn->dd_data;
30338c2ecf20Sopenharmony_ci
30348c2ecf20Sopenharmony_ci	if (sess->targetname == NULL ||
30358c2ecf20Sopenharmony_ci	    conn->persistent_address == NULL ||
30368c2ecf20Sopenharmony_ci	    conn->persistent_port == 0)
30378c2ecf20Sopenharmony_ci		return QLA_ERROR;
30388c2ecf20Sopenharmony_ci
30398c2ecf20Sopenharmony_ci	max_ddbs =  is_qla40XX(ha) ? MAX_DEV_DB_ENTRIES_40XX :
30408c2ecf20Sopenharmony_ci				     MAX_DEV_DB_ENTRIES;
30418c2ecf20Sopenharmony_ci
30428c2ecf20Sopenharmony_ci	for (idx = 0; idx < max_ddbs; idx++) {
30438c2ecf20Sopenharmony_ci		ddb_entry = qla4xxx_lookup_ddb_by_fw_index(ha, idx);
30448c2ecf20Sopenharmony_ci		if (ddb_entry == NULL)
30458c2ecf20Sopenharmony_ci			continue;
30468c2ecf20Sopenharmony_ci
30478c2ecf20Sopenharmony_ci		if (ddb_entry->ddb_type != FLASH_DDB)
30488c2ecf20Sopenharmony_ci			continue;
30498c2ecf20Sopenharmony_ci
30508c2ecf20Sopenharmony_ci		existing_sess = ddb_entry->sess->dd_data;
30518c2ecf20Sopenharmony_ci		existing_conn = ddb_entry->conn->dd_data;
30528c2ecf20Sopenharmony_ci
30538c2ecf20Sopenharmony_ci		if (existing_sess->targetname == NULL ||
30548c2ecf20Sopenharmony_ci		    existing_conn->persistent_address == NULL ||
30558c2ecf20Sopenharmony_ci		    existing_conn->persistent_port == 0)
30568c2ecf20Sopenharmony_ci			continue;
30578c2ecf20Sopenharmony_ci
30588c2ecf20Sopenharmony_ci		DEBUG2(ql4_printk(KERN_INFO, ha,
30598c2ecf20Sopenharmony_ci				  "IQN = %s User IQN = %s\n",
30608c2ecf20Sopenharmony_ci				  existing_sess->targetname,
30618c2ecf20Sopenharmony_ci				  sess->targetname));
30628c2ecf20Sopenharmony_ci
30638c2ecf20Sopenharmony_ci		DEBUG2(ql4_printk(KERN_INFO, ha,
30648c2ecf20Sopenharmony_ci				  "IP = %s User IP = %s\n",
30658c2ecf20Sopenharmony_ci				  existing_conn->persistent_address,
30668c2ecf20Sopenharmony_ci				  conn->persistent_address));
30678c2ecf20Sopenharmony_ci
30688c2ecf20Sopenharmony_ci		DEBUG2(ql4_printk(KERN_INFO, ha,
30698c2ecf20Sopenharmony_ci				  "Port = %d User Port = %d\n",
30708c2ecf20Sopenharmony_ci				  existing_conn->persistent_port,
30718c2ecf20Sopenharmony_ci				  conn->persistent_port));
30728c2ecf20Sopenharmony_ci
30738c2ecf20Sopenharmony_ci		if (strcmp(existing_sess->targetname, sess->targetname))
30748c2ecf20Sopenharmony_ci			continue;
30758c2ecf20Sopenharmony_ci		rval = qla4xxx_match_ipaddress(ha, ddb_entry,
30768c2ecf20Sopenharmony_ci					existing_conn->persistent_address,
30778c2ecf20Sopenharmony_ci					conn->persistent_address);
30788c2ecf20Sopenharmony_ci		if (rval == QLA_ERROR)
30798c2ecf20Sopenharmony_ci			continue;
30808c2ecf20Sopenharmony_ci		if (existing_conn->persistent_port != conn->persistent_port)
30818c2ecf20Sopenharmony_ci			continue;
30828c2ecf20Sopenharmony_ci		break;
30838c2ecf20Sopenharmony_ci	}
30848c2ecf20Sopenharmony_ci
30858c2ecf20Sopenharmony_ci	if (idx == max_ddbs)
30868c2ecf20Sopenharmony_ci		return QLA_ERROR;
30878c2ecf20Sopenharmony_ci
30888c2ecf20Sopenharmony_ci	DEBUG2(ql4_printk(KERN_INFO, ha,
30898c2ecf20Sopenharmony_ci			  "Match found in fwdb sessions\n"));
30908c2ecf20Sopenharmony_ci	return QLA_SUCCESS;
30918c2ecf20Sopenharmony_ci}
30928c2ecf20Sopenharmony_ci
30938c2ecf20Sopenharmony_cistatic struct iscsi_cls_session *
30948c2ecf20Sopenharmony_ciqla4xxx_session_create(struct iscsi_endpoint *ep,
30958c2ecf20Sopenharmony_ci			uint16_t cmds_max, uint16_t qdepth,
30968c2ecf20Sopenharmony_ci			uint32_t initial_cmdsn)
30978c2ecf20Sopenharmony_ci{
30988c2ecf20Sopenharmony_ci	struct iscsi_cls_session *cls_sess;
30998c2ecf20Sopenharmony_ci	struct scsi_qla_host *ha;
31008c2ecf20Sopenharmony_ci	struct qla_endpoint *qla_ep;
31018c2ecf20Sopenharmony_ci	struct ddb_entry *ddb_entry;
31028c2ecf20Sopenharmony_ci	uint16_t ddb_index;
31038c2ecf20Sopenharmony_ci	struct iscsi_session *sess;
31048c2ecf20Sopenharmony_ci	int ret;
31058c2ecf20Sopenharmony_ci
31068c2ecf20Sopenharmony_ci	if (!ep) {
31078c2ecf20Sopenharmony_ci		printk(KERN_ERR "qla4xxx: missing ep.\n");
31088c2ecf20Sopenharmony_ci		return NULL;
31098c2ecf20Sopenharmony_ci	}
31108c2ecf20Sopenharmony_ci
31118c2ecf20Sopenharmony_ci	qla_ep = ep->dd_data;
31128c2ecf20Sopenharmony_ci	ha = to_qla_host(qla_ep->host);
31138c2ecf20Sopenharmony_ci	DEBUG2(ql4_printk(KERN_INFO, ha, "%s: host: %ld\n", __func__,
31148c2ecf20Sopenharmony_ci			  ha->host_no));
31158c2ecf20Sopenharmony_ci
31168c2ecf20Sopenharmony_ci	ret = qla4xxx_get_ddb_index(ha, &ddb_index);
31178c2ecf20Sopenharmony_ci	if (ret == QLA_ERROR)
31188c2ecf20Sopenharmony_ci		return NULL;
31198c2ecf20Sopenharmony_ci
31208c2ecf20Sopenharmony_ci	cls_sess = iscsi_session_setup(&qla4xxx_iscsi_transport, qla_ep->host,
31218c2ecf20Sopenharmony_ci				       cmds_max, sizeof(struct ddb_entry),
31228c2ecf20Sopenharmony_ci				       sizeof(struct ql4_task_data),
31238c2ecf20Sopenharmony_ci				       initial_cmdsn, ddb_index);
31248c2ecf20Sopenharmony_ci	if (!cls_sess)
31258c2ecf20Sopenharmony_ci		return NULL;
31268c2ecf20Sopenharmony_ci
31278c2ecf20Sopenharmony_ci	sess = cls_sess->dd_data;
31288c2ecf20Sopenharmony_ci	ddb_entry = sess->dd_data;
31298c2ecf20Sopenharmony_ci	ddb_entry->fw_ddb_index = ddb_index;
31308c2ecf20Sopenharmony_ci	ddb_entry->fw_ddb_device_state = DDB_DS_NO_CONNECTION_ACTIVE;
31318c2ecf20Sopenharmony_ci	ddb_entry->ha = ha;
31328c2ecf20Sopenharmony_ci	ddb_entry->sess = cls_sess;
31338c2ecf20Sopenharmony_ci	ddb_entry->unblock_sess = qla4xxx_unblock_ddb;
31348c2ecf20Sopenharmony_ci	ddb_entry->ddb_change = qla4xxx_ddb_change;
31358c2ecf20Sopenharmony_ci	clear_bit(DDB_CONN_CLOSE_FAILURE, &ddb_entry->flags);
31368c2ecf20Sopenharmony_ci	cls_sess->recovery_tmo = ql4xsess_recovery_tmo;
31378c2ecf20Sopenharmony_ci	ha->fw_ddb_index_map[ddb_entry->fw_ddb_index] = ddb_entry;
31388c2ecf20Sopenharmony_ci	ha->tot_ddbs++;
31398c2ecf20Sopenharmony_ci
31408c2ecf20Sopenharmony_ci	return cls_sess;
31418c2ecf20Sopenharmony_ci}
31428c2ecf20Sopenharmony_ci
31438c2ecf20Sopenharmony_cistatic void qla4xxx_session_destroy(struct iscsi_cls_session *cls_sess)
31448c2ecf20Sopenharmony_ci{
31458c2ecf20Sopenharmony_ci	struct iscsi_session *sess;
31468c2ecf20Sopenharmony_ci	struct ddb_entry *ddb_entry;
31478c2ecf20Sopenharmony_ci	struct scsi_qla_host *ha;
31488c2ecf20Sopenharmony_ci	unsigned long flags, wtime;
31498c2ecf20Sopenharmony_ci	struct dev_db_entry *fw_ddb_entry = NULL;
31508c2ecf20Sopenharmony_ci	dma_addr_t fw_ddb_entry_dma;
31518c2ecf20Sopenharmony_ci	uint32_t ddb_state;
31528c2ecf20Sopenharmony_ci	int ret;
31538c2ecf20Sopenharmony_ci
31548c2ecf20Sopenharmony_ci	sess = cls_sess->dd_data;
31558c2ecf20Sopenharmony_ci	ddb_entry = sess->dd_data;
31568c2ecf20Sopenharmony_ci	ha = ddb_entry->ha;
31578c2ecf20Sopenharmony_ci	DEBUG2(ql4_printk(KERN_INFO, ha, "%s: host: %ld\n", __func__,
31588c2ecf20Sopenharmony_ci			  ha->host_no));
31598c2ecf20Sopenharmony_ci
31608c2ecf20Sopenharmony_ci	fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
31618c2ecf20Sopenharmony_ci					  &fw_ddb_entry_dma, GFP_KERNEL);
31628c2ecf20Sopenharmony_ci	if (!fw_ddb_entry) {
31638c2ecf20Sopenharmony_ci		ql4_printk(KERN_ERR, ha,
31648c2ecf20Sopenharmony_ci			   "%s: Unable to allocate dma buffer\n", __func__);
31658c2ecf20Sopenharmony_ci		goto destroy_session;
31668c2ecf20Sopenharmony_ci	}
31678c2ecf20Sopenharmony_ci
31688c2ecf20Sopenharmony_ci	wtime = jiffies + (HZ * LOGOUT_TOV);
31698c2ecf20Sopenharmony_ci	do {
31708c2ecf20Sopenharmony_ci		ret = qla4xxx_get_fwddb_entry(ha, ddb_entry->fw_ddb_index,
31718c2ecf20Sopenharmony_ci					      fw_ddb_entry, fw_ddb_entry_dma,
31728c2ecf20Sopenharmony_ci					      NULL, NULL, &ddb_state, NULL,
31738c2ecf20Sopenharmony_ci					      NULL, NULL);
31748c2ecf20Sopenharmony_ci		if (ret == QLA_ERROR)
31758c2ecf20Sopenharmony_ci			goto destroy_session;
31768c2ecf20Sopenharmony_ci
31778c2ecf20Sopenharmony_ci		if ((ddb_state == DDB_DS_NO_CONNECTION_ACTIVE) ||
31788c2ecf20Sopenharmony_ci		    (ddb_state == DDB_DS_SESSION_FAILED))
31798c2ecf20Sopenharmony_ci			goto destroy_session;
31808c2ecf20Sopenharmony_ci
31818c2ecf20Sopenharmony_ci		schedule_timeout_uninterruptible(HZ);
31828c2ecf20Sopenharmony_ci	} while ((time_after(wtime, jiffies)));
31838c2ecf20Sopenharmony_ci
31848c2ecf20Sopenharmony_cidestroy_session:
31858c2ecf20Sopenharmony_ci	qla4xxx_clear_ddb_entry(ha, ddb_entry->fw_ddb_index);
31868c2ecf20Sopenharmony_ci	if (test_and_clear_bit(DDB_CONN_CLOSE_FAILURE, &ddb_entry->flags))
31878c2ecf20Sopenharmony_ci		clear_bit(ddb_entry->fw_ddb_index, ha->ddb_idx_map);
31888c2ecf20Sopenharmony_ci	spin_lock_irqsave(&ha->hardware_lock, flags);
31898c2ecf20Sopenharmony_ci	qla4xxx_free_ddb(ha, ddb_entry);
31908c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&ha->hardware_lock, flags);
31918c2ecf20Sopenharmony_ci
31928c2ecf20Sopenharmony_ci	iscsi_session_teardown(cls_sess);
31938c2ecf20Sopenharmony_ci
31948c2ecf20Sopenharmony_ci	if (fw_ddb_entry)
31958c2ecf20Sopenharmony_ci		dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
31968c2ecf20Sopenharmony_ci				  fw_ddb_entry, fw_ddb_entry_dma);
31978c2ecf20Sopenharmony_ci}
31988c2ecf20Sopenharmony_ci
31998c2ecf20Sopenharmony_cistatic struct iscsi_cls_conn *
32008c2ecf20Sopenharmony_ciqla4xxx_conn_create(struct iscsi_cls_session *cls_sess, uint32_t conn_idx)
32018c2ecf20Sopenharmony_ci{
32028c2ecf20Sopenharmony_ci	struct iscsi_cls_conn *cls_conn;
32038c2ecf20Sopenharmony_ci	struct iscsi_session *sess;
32048c2ecf20Sopenharmony_ci	struct ddb_entry *ddb_entry;
32058c2ecf20Sopenharmony_ci	struct scsi_qla_host *ha;
32068c2ecf20Sopenharmony_ci
32078c2ecf20Sopenharmony_ci	cls_conn = iscsi_conn_setup(cls_sess, sizeof(struct qla_conn),
32088c2ecf20Sopenharmony_ci				    conn_idx);
32098c2ecf20Sopenharmony_ci	if (!cls_conn) {
32108c2ecf20Sopenharmony_ci		pr_info("%s: Can not create connection for conn_idx = %u\n",
32118c2ecf20Sopenharmony_ci			__func__, conn_idx);
32128c2ecf20Sopenharmony_ci		return NULL;
32138c2ecf20Sopenharmony_ci	}
32148c2ecf20Sopenharmony_ci
32158c2ecf20Sopenharmony_ci	sess = cls_sess->dd_data;
32168c2ecf20Sopenharmony_ci	ddb_entry = sess->dd_data;
32178c2ecf20Sopenharmony_ci	ddb_entry->conn = cls_conn;
32188c2ecf20Sopenharmony_ci
32198c2ecf20Sopenharmony_ci	ha = ddb_entry->ha;
32208c2ecf20Sopenharmony_ci	DEBUG2(ql4_printk(KERN_INFO, ha, "%s: conn_idx = %u\n", __func__,
32218c2ecf20Sopenharmony_ci			  conn_idx));
32228c2ecf20Sopenharmony_ci	return cls_conn;
32238c2ecf20Sopenharmony_ci}
32248c2ecf20Sopenharmony_ci
32258c2ecf20Sopenharmony_cistatic int qla4xxx_conn_bind(struct iscsi_cls_session *cls_session,
32268c2ecf20Sopenharmony_ci			     struct iscsi_cls_conn *cls_conn,
32278c2ecf20Sopenharmony_ci			     uint64_t transport_fd, int is_leading)
32288c2ecf20Sopenharmony_ci{
32298c2ecf20Sopenharmony_ci	struct iscsi_conn *conn;
32308c2ecf20Sopenharmony_ci	struct qla_conn *qla_conn;
32318c2ecf20Sopenharmony_ci	struct iscsi_endpoint *ep;
32328c2ecf20Sopenharmony_ci	struct ddb_entry *ddb_entry;
32338c2ecf20Sopenharmony_ci	struct scsi_qla_host *ha;
32348c2ecf20Sopenharmony_ci	struct iscsi_session *sess;
32358c2ecf20Sopenharmony_ci
32368c2ecf20Sopenharmony_ci	sess = cls_session->dd_data;
32378c2ecf20Sopenharmony_ci	ddb_entry = sess->dd_data;
32388c2ecf20Sopenharmony_ci	ha = ddb_entry->ha;
32398c2ecf20Sopenharmony_ci
32408c2ecf20Sopenharmony_ci	DEBUG2(ql4_printk(KERN_INFO, ha, "%s: sid = %d, cid = %d\n", __func__,
32418c2ecf20Sopenharmony_ci			  cls_session->sid, cls_conn->cid));
32428c2ecf20Sopenharmony_ci
32438c2ecf20Sopenharmony_ci	if (iscsi_conn_bind(cls_session, cls_conn, is_leading))
32448c2ecf20Sopenharmony_ci		return -EINVAL;
32458c2ecf20Sopenharmony_ci	ep = iscsi_lookup_endpoint(transport_fd);
32468c2ecf20Sopenharmony_ci	if (!ep)
32478c2ecf20Sopenharmony_ci		return -EINVAL;
32488c2ecf20Sopenharmony_ci	conn = cls_conn->dd_data;
32498c2ecf20Sopenharmony_ci	qla_conn = conn->dd_data;
32508c2ecf20Sopenharmony_ci	qla_conn->qla_ep = ep->dd_data;
32518c2ecf20Sopenharmony_ci	iscsi_put_endpoint(ep);
32528c2ecf20Sopenharmony_ci	return 0;
32538c2ecf20Sopenharmony_ci}
32548c2ecf20Sopenharmony_ci
32558c2ecf20Sopenharmony_cistatic int qla4xxx_conn_start(struct iscsi_cls_conn *cls_conn)
32568c2ecf20Sopenharmony_ci{
32578c2ecf20Sopenharmony_ci	struct iscsi_cls_session *cls_sess = iscsi_conn_to_session(cls_conn);
32588c2ecf20Sopenharmony_ci	struct iscsi_session *sess;
32598c2ecf20Sopenharmony_ci	struct ddb_entry *ddb_entry;
32608c2ecf20Sopenharmony_ci	struct scsi_qla_host *ha;
32618c2ecf20Sopenharmony_ci	struct dev_db_entry *fw_ddb_entry = NULL;
32628c2ecf20Sopenharmony_ci	dma_addr_t fw_ddb_entry_dma;
32638c2ecf20Sopenharmony_ci	uint32_t mbx_sts = 0;
32648c2ecf20Sopenharmony_ci	int ret = 0;
32658c2ecf20Sopenharmony_ci	int status = QLA_SUCCESS;
32668c2ecf20Sopenharmony_ci
32678c2ecf20Sopenharmony_ci	sess = cls_sess->dd_data;
32688c2ecf20Sopenharmony_ci	ddb_entry = sess->dd_data;
32698c2ecf20Sopenharmony_ci	ha = ddb_entry->ha;
32708c2ecf20Sopenharmony_ci	DEBUG2(ql4_printk(KERN_INFO, ha, "%s: sid = %d, cid = %d\n", __func__,
32718c2ecf20Sopenharmony_ci			  cls_sess->sid, cls_conn->cid));
32728c2ecf20Sopenharmony_ci
32738c2ecf20Sopenharmony_ci	/* Check if we have  matching FW DDB, if yes then do not
32748c2ecf20Sopenharmony_ci	 * login to this target. This could cause target to logout previous
32758c2ecf20Sopenharmony_ci	 * connection
32768c2ecf20Sopenharmony_ci	 */
32778c2ecf20Sopenharmony_ci	ret = qla4xxx_match_fwdb_session(ha, cls_conn);
32788c2ecf20Sopenharmony_ci	if (ret == QLA_SUCCESS) {
32798c2ecf20Sopenharmony_ci		ql4_printk(KERN_INFO, ha,
32808c2ecf20Sopenharmony_ci			   "Session already exist in FW.\n");
32818c2ecf20Sopenharmony_ci		ret = -EEXIST;
32828c2ecf20Sopenharmony_ci		goto exit_conn_start;
32838c2ecf20Sopenharmony_ci	}
32848c2ecf20Sopenharmony_ci
32858c2ecf20Sopenharmony_ci	fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
32868c2ecf20Sopenharmony_ci					  &fw_ddb_entry_dma, GFP_KERNEL);
32878c2ecf20Sopenharmony_ci	if (!fw_ddb_entry) {
32888c2ecf20Sopenharmony_ci		ql4_printk(KERN_ERR, ha,
32898c2ecf20Sopenharmony_ci			   "%s: Unable to allocate dma buffer\n", __func__);
32908c2ecf20Sopenharmony_ci		ret = -ENOMEM;
32918c2ecf20Sopenharmony_ci		goto exit_conn_start;
32928c2ecf20Sopenharmony_ci	}
32938c2ecf20Sopenharmony_ci
32948c2ecf20Sopenharmony_ci	ret = qla4xxx_set_param_ddbentry(ha, ddb_entry, cls_conn, &mbx_sts);
32958c2ecf20Sopenharmony_ci	if (ret) {
32968c2ecf20Sopenharmony_ci		/* If iscsid is stopped and started then no need to do
32978c2ecf20Sopenharmony_ci		* set param again since ddb state will be already
32988c2ecf20Sopenharmony_ci		* active and FW does not allow set ddb to an
32998c2ecf20Sopenharmony_ci		* active session.
33008c2ecf20Sopenharmony_ci		*/
33018c2ecf20Sopenharmony_ci		if (mbx_sts)
33028c2ecf20Sopenharmony_ci			if (ddb_entry->fw_ddb_device_state ==
33038c2ecf20Sopenharmony_ci						DDB_DS_SESSION_ACTIVE) {
33048c2ecf20Sopenharmony_ci				ddb_entry->unblock_sess(ddb_entry->sess);
33058c2ecf20Sopenharmony_ci				goto exit_set_param;
33068c2ecf20Sopenharmony_ci			}
33078c2ecf20Sopenharmony_ci
33088c2ecf20Sopenharmony_ci		ql4_printk(KERN_ERR, ha, "%s: Failed set param for index[%d]\n",
33098c2ecf20Sopenharmony_ci			   __func__, ddb_entry->fw_ddb_index);
33108c2ecf20Sopenharmony_ci		goto exit_conn_start;
33118c2ecf20Sopenharmony_ci	}
33128c2ecf20Sopenharmony_ci
33138c2ecf20Sopenharmony_ci	status = qla4xxx_conn_open(ha, ddb_entry->fw_ddb_index);
33148c2ecf20Sopenharmony_ci	if (status == QLA_ERROR) {
33158c2ecf20Sopenharmony_ci		ql4_printk(KERN_ERR, ha, "%s: Login failed: %s\n", __func__,
33168c2ecf20Sopenharmony_ci			   sess->targetname);
33178c2ecf20Sopenharmony_ci		ret = -EINVAL;
33188c2ecf20Sopenharmony_ci		goto exit_conn_start;
33198c2ecf20Sopenharmony_ci	}
33208c2ecf20Sopenharmony_ci
33218c2ecf20Sopenharmony_ci	if (ddb_entry->fw_ddb_device_state == DDB_DS_NO_CONNECTION_ACTIVE)
33228c2ecf20Sopenharmony_ci		ddb_entry->fw_ddb_device_state = DDB_DS_LOGIN_IN_PROCESS;
33238c2ecf20Sopenharmony_ci
33248c2ecf20Sopenharmony_ci	DEBUG2(printk(KERN_INFO "%s: DDB state [%d]\n", __func__,
33258c2ecf20Sopenharmony_ci		      ddb_entry->fw_ddb_device_state));
33268c2ecf20Sopenharmony_ci
33278c2ecf20Sopenharmony_ciexit_set_param:
33288c2ecf20Sopenharmony_ci	ret = 0;
33298c2ecf20Sopenharmony_ci
33308c2ecf20Sopenharmony_ciexit_conn_start:
33318c2ecf20Sopenharmony_ci	if (fw_ddb_entry)
33328c2ecf20Sopenharmony_ci		dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
33338c2ecf20Sopenharmony_ci				  fw_ddb_entry, fw_ddb_entry_dma);
33348c2ecf20Sopenharmony_ci	return ret;
33358c2ecf20Sopenharmony_ci}
33368c2ecf20Sopenharmony_ci
33378c2ecf20Sopenharmony_cistatic void qla4xxx_conn_destroy(struct iscsi_cls_conn *cls_conn)
33388c2ecf20Sopenharmony_ci{
33398c2ecf20Sopenharmony_ci	struct iscsi_cls_session *cls_sess = iscsi_conn_to_session(cls_conn);
33408c2ecf20Sopenharmony_ci	struct iscsi_session *sess;
33418c2ecf20Sopenharmony_ci	struct scsi_qla_host *ha;
33428c2ecf20Sopenharmony_ci	struct ddb_entry *ddb_entry;
33438c2ecf20Sopenharmony_ci	int options;
33448c2ecf20Sopenharmony_ci
33458c2ecf20Sopenharmony_ci	sess = cls_sess->dd_data;
33468c2ecf20Sopenharmony_ci	ddb_entry = sess->dd_data;
33478c2ecf20Sopenharmony_ci	ha = ddb_entry->ha;
33488c2ecf20Sopenharmony_ci	DEBUG2(ql4_printk(KERN_INFO, ha, "%s: cid = %d\n", __func__,
33498c2ecf20Sopenharmony_ci			  cls_conn->cid));
33508c2ecf20Sopenharmony_ci
33518c2ecf20Sopenharmony_ci	options = LOGOUT_OPTION_CLOSE_SESSION;
33528c2ecf20Sopenharmony_ci	if (qla4xxx_session_logout_ddb(ha, ddb_entry, options) == QLA_ERROR)
33538c2ecf20Sopenharmony_ci		ql4_printk(KERN_ERR, ha, "%s: Logout failed\n", __func__);
33548c2ecf20Sopenharmony_ci}
33558c2ecf20Sopenharmony_ci
33568c2ecf20Sopenharmony_cistatic void qla4xxx_task_work(struct work_struct *wdata)
33578c2ecf20Sopenharmony_ci{
33588c2ecf20Sopenharmony_ci	struct ql4_task_data *task_data;
33598c2ecf20Sopenharmony_ci	struct scsi_qla_host *ha;
33608c2ecf20Sopenharmony_ci	struct passthru_status *sts;
33618c2ecf20Sopenharmony_ci	struct iscsi_task *task;
33628c2ecf20Sopenharmony_ci	struct iscsi_hdr *hdr;
33638c2ecf20Sopenharmony_ci	uint8_t *data;
33648c2ecf20Sopenharmony_ci	uint32_t data_len;
33658c2ecf20Sopenharmony_ci	struct iscsi_conn *conn;
33668c2ecf20Sopenharmony_ci	int hdr_len;
33678c2ecf20Sopenharmony_ci	itt_t itt;
33688c2ecf20Sopenharmony_ci
33698c2ecf20Sopenharmony_ci	task_data = container_of(wdata, struct ql4_task_data, task_work);
33708c2ecf20Sopenharmony_ci	ha = task_data->ha;
33718c2ecf20Sopenharmony_ci	task = task_data->task;
33728c2ecf20Sopenharmony_ci	sts = &task_data->sts;
33738c2ecf20Sopenharmony_ci	hdr_len = sizeof(struct iscsi_hdr);
33748c2ecf20Sopenharmony_ci
33758c2ecf20Sopenharmony_ci	DEBUG3(printk(KERN_INFO "Status returned\n"));
33768c2ecf20Sopenharmony_ci	DEBUG3(qla4xxx_dump_buffer(sts, 64));
33778c2ecf20Sopenharmony_ci	DEBUG3(printk(KERN_INFO "Response buffer"));
33788c2ecf20Sopenharmony_ci	DEBUG3(qla4xxx_dump_buffer(task_data->resp_buffer, 64));
33798c2ecf20Sopenharmony_ci
33808c2ecf20Sopenharmony_ci	conn = task->conn;
33818c2ecf20Sopenharmony_ci
33828c2ecf20Sopenharmony_ci	switch (sts->completionStatus) {
33838c2ecf20Sopenharmony_ci	case PASSTHRU_STATUS_COMPLETE:
33848c2ecf20Sopenharmony_ci		hdr = (struct iscsi_hdr *)task_data->resp_buffer;
33858c2ecf20Sopenharmony_ci		/* Assign back the itt in hdr, until we use the PREASSIGN_TAG */
33868c2ecf20Sopenharmony_ci		itt = sts->handle;
33878c2ecf20Sopenharmony_ci		hdr->itt = itt;
33888c2ecf20Sopenharmony_ci		data = task_data->resp_buffer + hdr_len;
33898c2ecf20Sopenharmony_ci		data_len = task_data->resp_len - hdr_len;
33908c2ecf20Sopenharmony_ci		iscsi_complete_pdu(conn, hdr, data, data_len);
33918c2ecf20Sopenharmony_ci		break;
33928c2ecf20Sopenharmony_ci	default:
33938c2ecf20Sopenharmony_ci		ql4_printk(KERN_ERR, ha, "Passthru failed status = 0x%x\n",
33948c2ecf20Sopenharmony_ci			   sts->completionStatus);
33958c2ecf20Sopenharmony_ci		break;
33968c2ecf20Sopenharmony_ci	}
33978c2ecf20Sopenharmony_ci	return;
33988c2ecf20Sopenharmony_ci}
33998c2ecf20Sopenharmony_ci
34008c2ecf20Sopenharmony_cistatic int qla4xxx_alloc_pdu(struct iscsi_task *task, uint8_t opcode)
34018c2ecf20Sopenharmony_ci{
34028c2ecf20Sopenharmony_ci	struct ql4_task_data *task_data;
34038c2ecf20Sopenharmony_ci	struct iscsi_session *sess;
34048c2ecf20Sopenharmony_ci	struct ddb_entry *ddb_entry;
34058c2ecf20Sopenharmony_ci	struct scsi_qla_host *ha;
34068c2ecf20Sopenharmony_ci	int hdr_len;
34078c2ecf20Sopenharmony_ci
34088c2ecf20Sopenharmony_ci	sess = task->conn->session;
34098c2ecf20Sopenharmony_ci	ddb_entry = sess->dd_data;
34108c2ecf20Sopenharmony_ci	ha = ddb_entry->ha;
34118c2ecf20Sopenharmony_ci	task_data = task->dd_data;
34128c2ecf20Sopenharmony_ci	memset(task_data, 0, sizeof(struct ql4_task_data));
34138c2ecf20Sopenharmony_ci
34148c2ecf20Sopenharmony_ci	if (task->sc) {
34158c2ecf20Sopenharmony_ci		ql4_printk(KERN_INFO, ha,
34168c2ecf20Sopenharmony_ci			   "%s: SCSI Commands not implemented\n", __func__);
34178c2ecf20Sopenharmony_ci		return -EINVAL;
34188c2ecf20Sopenharmony_ci	}
34198c2ecf20Sopenharmony_ci
34208c2ecf20Sopenharmony_ci	hdr_len = sizeof(struct iscsi_hdr);
34218c2ecf20Sopenharmony_ci	task_data->ha = ha;
34228c2ecf20Sopenharmony_ci	task_data->task = task;
34238c2ecf20Sopenharmony_ci
34248c2ecf20Sopenharmony_ci	if (task->data_count) {
34258c2ecf20Sopenharmony_ci		task_data->data_dma = dma_map_single(&ha->pdev->dev, task->data,
34268c2ecf20Sopenharmony_ci						     task->data_count,
34278c2ecf20Sopenharmony_ci						     DMA_TO_DEVICE);
34288c2ecf20Sopenharmony_ci	}
34298c2ecf20Sopenharmony_ci
34308c2ecf20Sopenharmony_ci	DEBUG2(ql4_printk(KERN_INFO, ha, "%s: MaxRecvLen %u, iscsi hrd %d\n",
34318c2ecf20Sopenharmony_ci		      __func__, task->conn->max_recv_dlength, hdr_len));
34328c2ecf20Sopenharmony_ci
34338c2ecf20Sopenharmony_ci	task_data->resp_len = task->conn->max_recv_dlength + hdr_len;
34348c2ecf20Sopenharmony_ci	task_data->resp_buffer = dma_alloc_coherent(&ha->pdev->dev,
34358c2ecf20Sopenharmony_ci						    task_data->resp_len,
34368c2ecf20Sopenharmony_ci						    &task_data->resp_dma,
34378c2ecf20Sopenharmony_ci						    GFP_ATOMIC);
34388c2ecf20Sopenharmony_ci	if (!task_data->resp_buffer)
34398c2ecf20Sopenharmony_ci		goto exit_alloc_pdu;
34408c2ecf20Sopenharmony_ci
34418c2ecf20Sopenharmony_ci	task_data->req_len = task->data_count + hdr_len;
34428c2ecf20Sopenharmony_ci	task_data->req_buffer = dma_alloc_coherent(&ha->pdev->dev,
34438c2ecf20Sopenharmony_ci						   task_data->req_len,
34448c2ecf20Sopenharmony_ci						   &task_data->req_dma,
34458c2ecf20Sopenharmony_ci						   GFP_ATOMIC);
34468c2ecf20Sopenharmony_ci	if (!task_data->req_buffer)
34478c2ecf20Sopenharmony_ci		goto exit_alloc_pdu;
34488c2ecf20Sopenharmony_ci
34498c2ecf20Sopenharmony_ci	task->hdr = task_data->req_buffer;
34508c2ecf20Sopenharmony_ci
34518c2ecf20Sopenharmony_ci	INIT_WORK(&task_data->task_work, qla4xxx_task_work);
34528c2ecf20Sopenharmony_ci
34538c2ecf20Sopenharmony_ci	return 0;
34548c2ecf20Sopenharmony_ci
34558c2ecf20Sopenharmony_ciexit_alloc_pdu:
34568c2ecf20Sopenharmony_ci	if (task_data->resp_buffer)
34578c2ecf20Sopenharmony_ci		dma_free_coherent(&ha->pdev->dev, task_data->resp_len,
34588c2ecf20Sopenharmony_ci				  task_data->resp_buffer, task_data->resp_dma);
34598c2ecf20Sopenharmony_ci
34608c2ecf20Sopenharmony_ci	if (task_data->req_buffer)
34618c2ecf20Sopenharmony_ci		dma_free_coherent(&ha->pdev->dev, task_data->req_len,
34628c2ecf20Sopenharmony_ci				  task_data->req_buffer, task_data->req_dma);
34638c2ecf20Sopenharmony_ci	return -ENOMEM;
34648c2ecf20Sopenharmony_ci}
34658c2ecf20Sopenharmony_ci
34668c2ecf20Sopenharmony_cistatic void qla4xxx_task_cleanup(struct iscsi_task *task)
34678c2ecf20Sopenharmony_ci{
34688c2ecf20Sopenharmony_ci	struct ql4_task_data *task_data;
34698c2ecf20Sopenharmony_ci	struct iscsi_session *sess;
34708c2ecf20Sopenharmony_ci	struct ddb_entry *ddb_entry;
34718c2ecf20Sopenharmony_ci	struct scsi_qla_host *ha;
34728c2ecf20Sopenharmony_ci	int hdr_len;
34738c2ecf20Sopenharmony_ci
34748c2ecf20Sopenharmony_ci	hdr_len = sizeof(struct iscsi_hdr);
34758c2ecf20Sopenharmony_ci	sess = task->conn->session;
34768c2ecf20Sopenharmony_ci	ddb_entry = sess->dd_data;
34778c2ecf20Sopenharmony_ci	ha = ddb_entry->ha;
34788c2ecf20Sopenharmony_ci	task_data = task->dd_data;
34798c2ecf20Sopenharmony_ci
34808c2ecf20Sopenharmony_ci	if (task->data_count) {
34818c2ecf20Sopenharmony_ci		dma_unmap_single(&ha->pdev->dev, task_data->data_dma,
34828c2ecf20Sopenharmony_ci				 task->data_count, DMA_TO_DEVICE);
34838c2ecf20Sopenharmony_ci	}
34848c2ecf20Sopenharmony_ci
34858c2ecf20Sopenharmony_ci	DEBUG2(ql4_printk(KERN_INFO, ha, "%s: MaxRecvLen %u, iscsi hrd %d\n",
34868c2ecf20Sopenharmony_ci		      __func__, task->conn->max_recv_dlength, hdr_len));
34878c2ecf20Sopenharmony_ci
34888c2ecf20Sopenharmony_ci	dma_free_coherent(&ha->pdev->dev, task_data->resp_len,
34898c2ecf20Sopenharmony_ci			  task_data->resp_buffer, task_data->resp_dma);
34908c2ecf20Sopenharmony_ci	dma_free_coherent(&ha->pdev->dev, task_data->req_len,
34918c2ecf20Sopenharmony_ci			  task_data->req_buffer, task_data->req_dma);
34928c2ecf20Sopenharmony_ci	return;
34938c2ecf20Sopenharmony_ci}
34948c2ecf20Sopenharmony_ci
34958c2ecf20Sopenharmony_cistatic int qla4xxx_task_xmit(struct iscsi_task *task)
34968c2ecf20Sopenharmony_ci{
34978c2ecf20Sopenharmony_ci	struct scsi_cmnd *sc = task->sc;
34988c2ecf20Sopenharmony_ci	struct iscsi_session *sess = task->conn->session;
34998c2ecf20Sopenharmony_ci	struct ddb_entry *ddb_entry = sess->dd_data;
35008c2ecf20Sopenharmony_ci	struct scsi_qla_host *ha = ddb_entry->ha;
35018c2ecf20Sopenharmony_ci
35028c2ecf20Sopenharmony_ci	if (!sc)
35038c2ecf20Sopenharmony_ci		return qla4xxx_send_passthru0(task);
35048c2ecf20Sopenharmony_ci
35058c2ecf20Sopenharmony_ci	ql4_printk(KERN_INFO, ha, "%s: scsi cmd xmit not implemented\n",
35068c2ecf20Sopenharmony_ci		   __func__);
35078c2ecf20Sopenharmony_ci	return -ENOSYS;
35088c2ecf20Sopenharmony_ci}
35098c2ecf20Sopenharmony_ci
35108c2ecf20Sopenharmony_cistatic int qla4xxx_copy_from_fwddb_param(struct iscsi_bus_flash_session *sess,
35118c2ecf20Sopenharmony_ci					 struct iscsi_bus_flash_conn *conn,
35128c2ecf20Sopenharmony_ci					 struct dev_db_entry *fw_ddb_entry)
35138c2ecf20Sopenharmony_ci{
35148c2ecf20Sopenharmony_ci	unsigned long options = 0;
35158c2ecf20Sopenharmony_ci	int rc = 0;
35168c2ecf20Sopenharmony_ci
35178c2ecf20Sopenharmony_ci	options = le16_to_cpu(fw_ddb_entry->options);
35188c2ecf20Sopenharmony_ci	conn->is_fw_assigned_ipv6 = test_bit(OPT_IS_FW_ASSIGNED_IPV6, &options);
35198c2ecf20Sopenharmony_ci	if (test_bit(OPT_IPV6_DEVICE, &options)) {
35208c2ecf20Sopenharmony_ci		rc = iscsi_switch_str_param(&sess->portal_type,
35218c2ecf20Sopenharmony_ci					    PORTAL_TYPE_IPV6);
35228c2ecf20Sopenharmony_ci		if (rc)
35238c2ecf20Sopenharmony_ci			goto exit_copy;
35248c2ecf20Sopenharmony_ci	} else {
35258c2ecf20Sopenharmony_ci		rc = iscsi_switch_str_param(&sess->portal_type,
35268c2ecf20Sopenharmony_ci					    PORTAL_TYPE_IPV4);
35278c2ecf20Sopenharmony_ci		if (rc)
35288c2ecf20Sopenharmony_ci			goto exit_copy;
35298c2ecf20Sopenharmony_ci	}
35308c2ecf20Sopenharmony_ci
35318c2ecf20Sopenharmony_ci	sess->auto_snd_tgt_disable = test_bit(OPT_AUTO_SENDTGTS_DISABLE,
35328c2ecf20Sopenharmony_ci					      &options);
35338c2ecf20Sopenharmony_ci	sess->discovery_sess = test_bit(OPT_DISC_SESSION, &options);
35348c2ecf20Sopenharmony_ci	sess->entry_state = test_bit(OPT_ENTRY_STATE, &options);
35358c2ecf20Sopenharmony_ci
35368c2ecf20Sopenharmony_ci	options = le16_to_cpu(fw_ddb_entry->iscsi_options);
35378c2ecf20Sopenharmony_ci	conn->hdrdgst_en = test_bit(ISCSIOPT_HEADER_DIGEST_EN, &options);
35388c2ecf20Sopenharmony_ci	conn->datadgst_en = test_bit(ISCSIOPT_DATA_DIGEST_EN, &options);
35398c2ecf20Sopenharmony_ci	sess->imm_data_en = test_bit(ISCSIOPT_IMMEDIATE_DATA_EN, &options);
35408c2ecf20Sopenharmony_ci	sess->initial_r2t_en = test_bit(ISCSIOPT_INITIAL_R2T_EN, &options);
35418c2ecf20Sopenharmony_ci	sess->dataseq_inorder_en = test_bit(ISCSIOPT_DATA_SEQ_IN_ORDER,
35428c2ecf20Sopenharmony_ci					    &options);
35438c2ecf20Sopenharmony_ci	sess->pdu_inorder_en = test_bit(ISCSIOPT_DATA_PDU_IN_ORDER, &options);
35448c2ecf20Sopenharmony_ci	sess->chap_auth_en = test_bit(ISCSIOPT_CHAP_AUTH_EN, &options);
35458c2ecf20Sopenharmony_ci	conn->snack_req_en = test_bit(ISCSIOPT_SNACK_REQ_EN, &options);
35468c2ecf20Sopenharmony_ci	sess->discovery_logout_en = test_bit(ISCSIOPT_DISCOVERY_LOGOUT_EN,
35478c2ecf20Sopenharmony_ci					     &options);
35488c2ecf20Sopenharmony_ci	sess->bidi_chap_en = test_bit(ISCSIOPT_BIDI_CHAP_EN, &options);
35498c2ecf20Sopenharmony_ci	sess->discovery_auth_optional =
35508c2ecf20Sopenharmony_ci			test_bit(ISCSIOPT_DISCOVERY_AUTH_OPTIONAL, &options);
35518c2ecf20Sopenharmony_ci	if (test_bit(ISCSIOPT_ERL1, &options))
35528c2ecf20Sopenharmony_ci		sess->erl |= BIT_1;
35538c2ecf20Sopenharmony_ci	if (test_bit(ISCSIOPT_ERL0, &options))
35548c2ecf20Sopenharmony_ci		sess->erl |= BIT_0;
35558c2ecf20Sopenharmony_ci
35568c2ecf20Sopenharmony_ci	options = le16_to_cpu(fw_ddb_entry->tcp_options);
35578c2ecf20Sopenharmony_ci	conn->tcp_timestamp_stat = test_bit(TCPOPT_TIMESTAMP_STAT, &options);
35588c2ecf20Sopenharmony_ci	conn->tcp_nagle_disable = test_bit(TCPOPT_NAGLE_DISABLE, &options);
35598c2ecf20Sopenharmony_ci	conn->tcp_wsf_disable = test_bit(TCPOPT_WSF_DISABLE, &options);
35608c2ecf20Sopenharmony_ci	if (test_bit(TCPOPT_TIMER_SCALE3, &options))
35618c2ecf20Sopenharmony_ci		conn->tcp_timer_scale |= BIT_3;
35628c2ecf20Sopenharmony_ci	if (test_bit(TCPOPT_TIMER_SCALE2, &options))
35638c2ecf20Sopenharmony_ci		conn->tcp_timer_scale |= BIT_2;
35648c2ecf20Sopenharmony_ci	if (test_bit(TCPOPT_TIMER_SCALE1, &options))
35658c2ecf20Sopenharmony_ci		conn->tcp_timer_scale |= BIT_1;
35668c2ecf20Sopenharmony_ci
35678c2ecf20Sopenharmony_ci	conn->tcp_timer_scale >>= 1;
35688c2ecf20Sopenharmony_ci	conn->tcp_timestamp_en = test_bit(TCPOPT_TIMESTAMP_EN, &options);
35698c2ecf20Sopenharmony_ci
35708c2ecf20Sopenharmony_ci	options = le16_to_cpu(fw_ddb_entry->ip_options);
35718c2ecf20Sopenharmony_ci	conn->fragment_disable = test_bit(IPOPT_FRAGMENT_DISABLE, &options);
35728c2ecf20Sopenharmony_ci
35738c2ecf20Sopenharmony_ci	conn->max_recv_dlength = BYTE_UNITS *
35748c2ecf20Sopenharmony_ci			  le16_to_cpu(fw_ddb_entry->iscsi_max_rcv_data_seg_len);
35758c2ecf20Sopenharmony_ci	conn->max_xmit_dlength = BYTE_UNITS *
35768c2ecf20Sopenharmony_ci			  le16_to_cpu(fw_ddb_entry->iscsi_max_snd_data_seg_len);
35778c2ecf20Sopenharmony_ci	sess->first_burst = BYTE_UNITS *
35788c2ecf20Sopenharmony_ci			       le16_to_cpu(fw_ddb_entry->iscsi_first_burst_len);
35798c2ecf20Sopenharmony_ci	sess->max_burst = BYTE_UNITS *
35808c2ecf20Sopenharmony_ci				 le16_to_cpu(fw_ddb_entry->iscsi_max_burst_len);
35818c2ecf20Sopenharmony_ci	sess->max_r2t = le16_to_cpu(fw_ddb_entry->iscsi_max_outsnd_r2t);
35828c2ecf20Sopenharmony_ci	sess->time2wait = le16_to_cpu(fw_ddb_entry->iscsi_def_time2wait);
35838c2ecf20Sopenharmony_ci	sess->time2retain = le16_to_cpu(fw_ddb_entry->iscsi_def_time2retain);
35848c2ecf20Sopenharmony_ci	sess->tpgt = le32_to_cpu(fw_ddb_entry->tgt_portal_grp);
35858c2ecf20Sopenharmony_ci	conn->max_segment_size = le16_to_cpu(fw_ddb_entry->mss);
35868c2ecf20Sopenharmony_ci	conn->tcp_xmit_wsf = fw_ddb_entry->tcp_xmt_wsf;
35878c2ecf20Sopenharmony_ci	conn->tcp_recv_wsf = fw_ddb_entry->tcp_rcv_wsf;
35888c2ecf20Sopenharmony_ci	conn->ipv6_flow_label = le16_to_cpu(fw_ddb_entry->ipv6_flow_lbl);
35898c2ecf20Sopenharmony_ci	conn->keepalive_timeout = le16_to_cpu(fw_ddb_entry->ka_timeout);
35908c2ecf20Sopenharmony_ci	conn->local_port = le16_to_cpu(fw_ddb_entry->lcl_port);
35918c2ecf20Sopenharmony_ci	conn->statsn = le32_to_cpu(fw_ddb_entry->stat_sn);
35928c2ecf20Sopenharmony_ci	conn->exp_statsn = le32_to_cpu(fw_ddb_entry->exp_stat_sn);
35938c2ecf20Sopenharmony_ci	sess->discovery_parent_idx = le16_to_cpu(fw_ddb_entry->ddb_link);
35948c2ecf20Sopenharmony_ci	sess->discovery_parent_type = le16_to_cpu(fw_ddb_entry->ddb_link);
35958c2ecf20Sopenharmony_ci	sess->chap_out_idx = le16_to_cpu(fw_ddb_entry->chap_tbl_idx);
35968c2ecf20Sopenharmony_ci	sess->tsid = le16_to_cpu(fw_ddb_entry->tsid);
35978c2ecf20Sopenharmony_ci
35988c2ecf20Sopenharmony_ci	sess->default_taskmgmt_timeout =
35998c2ecf20Sopenharmony_ci				le16_to_cpu(fw_ddb_entry->def_timeout);
36008c2ecf20Sopenharmony_ci	conn->port = le16_to_cpu(fw_ddb_entry->port);
36018c2ecf20Sopenharmony_ci
36028c2ecf20Sopenharmony_ci	options = le16_to_cpu(fw_ddb_entry->options);
36038c2ecf20Sopenharmony_ci	conn->ipaddress = kzalloc(IPv6_ADDR_LEN, GFP_KERNEL);
36048c2ecf20Sopenharmony_ci	if (!conn->ipaddress) {
36058c2ecf20Sopenharmony_ci		rc = -ENOMEM;
36068c2ecf20Sopenharmony_ci		goto exit_copy;
36078c2ecf20Sopenharmony_ci	}
36088c2ecf20Sopenharmony_ci
36098c2ecf20Sopenharmony_ci	conn->redirect_ipaddr = kzalloc(IPv6_ADDR_LEN, GFP_KERNEL);
36108c2ecf20Sopenharmony_ci	if (!conn->redirect_ipaddr) {
36118c2ecf20Sopenharmony_ci		rc = -ENOMEM;
36128c2ecf20Sopenharmony_ci		goto exit_copy;
36138c2ecf20Sopenharmony_ci	}
36148c2ecf20Sopenharmony_ci
36158c2ecf20Sopenharmony_ci	memcpy(conn->ipaddress, fw_ddb_entry->ip_addr, IPv6_ADDR_LEN);
36168c2ecf20Sopenharmony_ci	memcpy(conn->redirect_ipaddr, fw_ddb_entry->tgt_addr, IPv6_ADDR_LEN);
36178c2ecf20Sopenharmony_ci
36188c2ecf20Sopenharmony_ci	if (test_bit(OPT_IPV6_DEVICE, &options)) {
36198c2ecf20Sopenharmony_ci		conn->ipv6_traffic_class = fw_ddb_entry->ipv4_tos;
36208c2ecf20Sopenharmony_ci
36218c2ecf20Sopenharmony_ci		conn->link_local_ipv6_addr = kmemdup(
36228c2ecf20Sopenharmony_ci					fw_ddb_entry->link_local_ipv6_addr,
36238c2ecf20Sopenharmony_ci					IPv6_ADDR_LEN, GFP_KERNEL);
36248c2ecf20Sopenharmony_ci		if (!conn->link_local_ipv6_addr) {
36258c2ecf20Sopenharmony_ci			rc = -ENOMEM;
36268c2ecf20Sopenharmony_ci			goto exit_copy;
36278c2ecf20Sopenharmony_ci		}
36288c2ecf20Sopenharmony_ci	} else {
36298c2ecf20Sopenharmony_ci		conn->ipv4_tos = fw_ddb_entry->ipv4_tos;
36308c2ecf20Sopenharmony_ci	}
36318c2ecf20Sopenharmony_ci
36328c2ecf20Sopenharmony_ci	if (fw_ddb_entry->iscsi_name[0]) {
36338c2ecf20Sopenharmony_ci		rc = iscsi_switch_str_param(&sess->targetname,
36348c2ecf20Sopenharmony_ci					    (char *)fw_ddb_entry->iscsi_name);
36358c2ecf20Sopenharmony_ci		if (rc)
36368c2ecf20Sopenharmony_ci			goto exit_copy;
36378c2ecf20Sopenharmony_ci	}
36388c2ecf20Sopenharmony_ci
36398c2ecf20Sopenharmony_ci	if (fw_ddb_entry->iscsi_alias[0]) {
36408c2ecf20Sopenharmony_ci		rc = iscsi_switch_str_param(&sess->targetalias,
36418c2ecf20Sopenharmony_ci					    (char *)fw_ddb_entry->iscsi_alias);
36428c2ecf20Sopenharmony_ci		if (rc)
36438c2ecf20Sopenharmony_ci			goto exit_copy;
36448c2ecf20Sopenharmony_ci	}
36458c2ecf20Sopenharmony_ci
36468c2ecf20Sopenharmony_ci	COPY_ISID(sess->isid, fw_ddb_entry->isid);
36478c2ecf20Sopenharmony_ci
36488c2ecf20Sopenharmony_ciexit_copy:
36498c2ecf20Sopenharmony_ci	return rc;
36508c2ecf20Sopenharmony_ci}
36518c2ecf20Sopenharmony_ci
36528c2ecf20Sopenharmony_cistatic int qla4xxx_copy_to_fwddb_param(struct iscsi_bus_flash_session *sess,
36538c2ecf20Sopenharmony_ci				       struct iscsi_bus_flash_conn *conn,
36548c2ecf20Sopenharmony_ci				       struct dev_db_entry *fw_ddb_entry)
36558c2ecf20Sopenharmony_ci{
36568c2ecf20Sopenharmony_ci	uint16_t options;
36578c2ecf20Sopenharmony_ci	int rc = 0;
36588c2ecf20Sopenharmony_ci
36598c2ecf20Sopenharmony_ci	options = le16_to_cpu(fw_ddb_entry->options);
36608c2ecf20Sopenharmony_ci	SET_BITVAL(conn->is_fw_assigned_ipv6,  options, BIT_11);
36618c2ecf20Sopenharmony_ci	if (!strncmp(sess->portal_type, PORTAL_TYPE_IPV6, 4))
36628c2ecf20Sopenharmony_ci		options |= BIT_8;
36638c2ecf20Sopenharmony_ci	else
36648c2ecf20Sopenharmony_ci		options &= ~BIT_8;
36658c2ecf20Sopenharmony_ci
36668c2ecf20Sopenharmony_ci	SET_BITVAL(sess->auto_snd_tgt_disable, options, BIT_6);
36678c2ecf20Sopenharmony_ci	SET_BITVAL(sess->discovery_sess, options, BIT_4);
36688c2ecf20Sopenharmony_ci	SET_BITVAL(sess->entry_state, options, BIT_3);
36698c2ecf20Sopenharmony_ci	fw_ddb_entry->options = cpu_to_le16(options);
36708c2ecf20Sopenharmony_ci
36718c2ecf20Sopenharmony_ci	options = le16_to_cpu(fw_ddb_entry->iscsi_options);
36728c2ecf20Sopenharmony_ci	SET_BITVAL(conn->hdrdgst_en, options, BIT_13);
36738c2ecf20Sopenharmony_ci	SET_BITVAL(conn->datadgst_en, options, BIT_12);
36748c2ecf20Sopenharmony_ci	SET_BITVAL(sess->imm_data_en, options, BIT_11);
36758c2ecf20Sopenharmony_ci	SET_BITVAL(sess->initial_r2t_en, options, BIT_10);
36768c2ecf20Sopenharmony_ci	SET_BITVAL(sess->dataseq_inorder_en, options, BIT_9);
36778c2ecf20Sopenharmony_ci	SET_BITVAL(sess->pdu_inorder_en, options, BIT_8);
36788c2ecf20Sopenharmony_ci	SET_BITVAL(sess->chap_auth_en, options, BIT_7);
36798c2ecf20Sopenharmony_ci	SET_BITVAL(conn->snack_req_en, options, BIT_6);
36808c2ecf20Sopenharmony_ci	SET_BITVAL(sess->discovery_logout_en, options, BIT_5);
36818c2ecf20Sopenharmony_ci	SET_BITVAL(sess->bidi_chap_en, options, BIT_4);
36828c2ecf20Sopenharmony_ci	SET_BITVAL(sess->discovery_auth_optional, options, BIT_3);
36838c2ecf20Sopenharmony_ci	SET_BITVAL(sess->erl & BIT_1, options, BIT_1);
36848c2ecf20Sopenharmony_ci	SET_BITVAL(sess->erl & BIT_0, options, BIT_0);
36858c2ecf20Sopenharmony_ci	fw_ddb_entry->iscsi_options = cpu_to_le16(options);
36868c2ecf20Sopenharmony_ci
36878c2ecf20Sopenharmony_ci	options = le16_to_cpu(fw_ddb_entry->tcp_options);
36888c2ecf20Sopenharmony_ci	SET_BITVAL(conn->tcp_timestamp_stat, options, BIT_6);
36898c2ecf20Sopenharmony_ci	SET_BITVAL(conn->tcp_nagle_disable, options, BIT_5);
36908c2ecf20Sopenharmony_ci	SET_BITVAL(conn->tcp_wsf_disable, options, BIT_4);
36918c2ecf20Sopenharmony_ci	SET_BITVAL(conn->tcp_timer_scale & BIT_2, options, BIT_3);
36928c2ecf20Sopenharmony_ci	SET_BITVAL(conn->tcp_timer_scale & BIT_1, options, BIT_2);
36938c2ecf20Sopenharmony_ci	SET_BITVAL(conn->tcp_timer_scale & BIT_0, options, BIT_1);
36948c2ecf20Sopenharmony_ci	SET_BITVAL(conn->tcp_timestamp_en, options, BIT_0);
36958c2ecf20Sopenharmony_ci	fw_ddb_entry->tcp_options = cpu_to_le16(options);
36968c2ecf20Sopenharmony_ci
36978c2ecf20Sopenharmony_ci	options = le16_to_cpu(fw_ddb_entry->ip_options);
36988c2ecf20Sopenharmony_ci	SET_BITVAL(conn->fragment_disable, options, BIT_4);
36998c2ecf20Sopenharmony_ci	fw_ddb_entry->ip_options = cpu_to_le16(options);
37008c2ecf20Sopenharmony_ci
37018c2ecf20Sopenharmony_ci	fw_ddb_entry->iscsi_max_outsnd_r2t = cpu_to_le16(sess->max_r2t);
37028c2ecf20Sopenharmony_ci	fw_ddb_entry->iscsi_max_rcv_data_seg_len =
37038c2ecf20Sopenharmony_ci			       cpu_to_le16(conn->max_recv_dlength / BYTE_UNITS);
37048c2ecf20Sopenharmony_ci	fw_ddb_entry->iscsi_max_snd_data_seg_len =
37058c2ecf20Sopenharmony_ci			       cpu_to_le16(conn->max_xmit_dlength / BYTE_UNITS);
37068c2ecf20Sopenharmony_ci	fw_ddb_entry->iscsi_first_burst_len =
37078c2ecf20Sopenharmony_ci				cpu_to_le16(sess->first_burst / BYTE_UNITS);
37088c2ecf20Sopenharmony_ci	fw_ddb_entry->iscsi_max_burst_len = cpu_to_le16(sess->max_burst /
37098c2ecf20Sopenharmony_ci					    BYTE_UNITS);
37108c2ecf20Sopenharmony_ci	fw_ddb_entry->iscsi_def_time2wait = cpu_to_le16(sess->time2wait);
37118c2ecf20Sopenharmony_ci	fw_ddb_entry->iscsi_def_time2retain = cpu_to_le16(sess->time2retain);
37128c2ecf20Sopenharmony_ci	fw_ddb_entry->tgt_portal_grp = cpu_to_le16(sess->tpgt);
37138c2ecf20Sopenharmony_ci	fw_ddb_entry->mss = cpu_to_le16(conn->max_segment_size);
37148c2ecf20Sopenharmony_ci	fw_ddb_entry->tcp_xmt_wsf = (uint8_t) cpu_to_le32(conn->tcp_xmit_wsf);
37158c2ecf20Sopenharmony_ci	fw_ddb_entry->tcp_rcv_wsf = (uint8_t) cpu_to_le32(conn->tcp_recv_wsf);
37168c2ecf20Sopenharmony_ci	fw_ddb_entry->ipv6_flow_lbl = cpu_to_le16(conn->ipv6_flow_label);
37178c2ecf20Sopenharmony_ci	fw_ddb_entry->ka_timeout = cpu_to_le16(conn->keepalive_timeout);
37188c2ecf20Sopenharmony_ci	fw_ddb_entry->lcl_port = cpu_to_le16(conn->local_port);
37198c2ecf20Sopenharmony_ci	fw_ddb_entry->stat_sn = cpu_to_le32(conn->statsn);
37208c2ecf20Sopenharmony_ci	fw_ddb_entry->exp_stat_sn = cpu_to_le32(conn->exp_statsn);
37218c2ecf20Sopenharmony_ci	fw_ddb_entry->ddb_link = cpu_to_le16(sess->discovery_parent_idx);
37228c2ecf20Sopenharmony_ci	fw_ddb_entry->chap_tbl_idx = cpu_to_le16(sess->chap_out_idx);
37238c2ecf20Sopenharmony_ci	fw_ddb_entry->tsid = cpu_to_le16(sess->tsid);
37248c2ecf20Sopenharmony_ci	fw_ddb_entry->port = cpu_to_le16(conn->port);
37258c2ecf20Sopenharmony_ci	fw_ddb_entry->def_timeout =
37268c2ecf20Sopenharmony_ci				cpu_to_le16(sess->default_taskmgmt_timeout);
37278c2ecf20Sopenharmony_ci
37288c2ecf20Sopenharmony_ci	if (!strncmp(sess->portal_type, PORTAL_TYPE_IPV6, 4))
37298c2ecf20Sopenharmony_ci		fw_ddb_entry->ipv4_tos = conn->ipv6_traffic_class;
37308c2ecf20Sopenharmony_ci	else
37318c2ecf20Sopenharmony_ci		fw_ddb_entry->ipv4_tos = conn->ipv4_tos;
37328c2ecf20Sopenharmony_ci
37338c2ecf20Sopenharmony_ci	if (conn->ipaddress)
37348c2ecf20Sopenharmony_ci		memcpy(fw_ddb_entry->ip_addr, conn->ipaddress,
37358c2ecf20Sopenharmony_ci		       sizeof(fw_ddb_entry->ip_addr));
37368c2ecf20Sopenharmony_ci
37378c2ecf20Sopenharmony_ci	if (conn->redirect_ipaddr)
37388c2ecf20Sopenharmony_ci		memcpy(fw_ddb_entry->tgt_addr, conn->redirect_ipaddr,
37398c2ecf20Sopenharmony_ci		       sizeof(fw_ddb_entry->tgt_addr));
37408c2ecf20Sopenharmony_ci
37418c2ecf20Sopenharmony_ci	if (conn->link_local_ipv6_addr)
37428c2ecf20Sopenharmony_ci		memcpy(fw_ddb_entry->link_local_ipv6_addr,
37438c2ecf20Sopenharmony_ci		       conn->link_local_ipv6_addr,
37448c2ecf20Sopenharmony_ci		       sizeof(fw_ddb_entry->link_local_ipv6_addr));
37458c2ecf20Sopenharmony_ci
37468c2ecf20Sopenharmony_ci	if (sess->targetname)
37478c2ecf20Sopenharmony_ci		memcpy(fw_ddb_entry->iscsi_name, sess->targetname,
37488c2ecf20Sopenharmony_ci		       sizeof(fw_ddb_entry->iscsi_name));
37498c2ecf20Sopenharmony_ci
37508c2ecf20Sopenharmony_ci	if (sess->targetalias)
37518c2ecf20Sopenharmony_ci		memcpy(fw_ddb_entry->iscsi_alias, sess->targetalias,
37528c2ecf20Sopenharmony_ci		       sizeof(fw_ddb_entry->iscsi_alias));
37538c2ecf20Sopenharmony_ci
37548c2ecf20Sopenharmony_ci	COPY_ISID(fw_ddb_entry->isid, sess->isid);
37558c2ecf20Sopenharmony_ci
37568c2ecf20Sopenharmony_ci	return rc;
37578c2ecf20Sopenharmony_ci}
37588c2ecf20Sopenharmony_ci
37598c2ecf20Sopenharmony_cistatic void qla4xxx_copy_to_sess_conn_params(struct iscsi_conn *conn,
37608c2ecf20Sopenharmony_ci					     struct iscsi_session *sess,
37618c2ecf20Sopenharmony_ci					     struct dev_db_entry *fw_ddb_entry)
37628c2ecf20Sopenharmony_ci{
37638c2ecf20Sopenharmony_ci	unsigned long options = 0;
37648c2ecf20Sopenharmony_ci	uint16_t ddb_link;
37658c2ecf20Sopenharmony_ci	uint16_t disc_parent;
37668c2ecf20Sopenharmony_ci	char ip_addr[DDB_IPADDR_LEN];
37678c2ecf20Sopenharmony_ci
37688c2ecf20Sopenharmony_ci	options = le16_to_cpu(fw_ddb_entry->options);
37698c2ecf20Sopenharmony_ci	conn->is_fw_assigned_ipv6 = test_bit(OPT_IS_FW_ASSIGNED_IPV6, &options);
37708c2ecf20Sopenharmony_ci	sess->auto_snd_tgt_disable = test_bit(OPT_AUTO_SENDTGTS_DISABLE,
37718c2ecf20Sopenharmony_ci					      &options);
37728c2ecf20Sopenharmony_ci	sess->discovery_sess = test_bit(OPT_DISC_SESSION, &options);
37738c2ecf20Sopenharmony_ci
37748c2ecf20Sopenharmony_ci	options = le16_to_cpu(fw_ddb_entry->iscsi_options);
37758c2ecf20Sopenharmony_ci	conn->hdrdgst_en = test_bit(ISCSIOPT_HEADER_DIGEST_EN, &options);
37768c2ecf20Sopenharmony_ci	conn->datadgst_en = test_bit(ISCSIOPT_DATA_DIGEST_EN, &options);
37778c2ecf20Sopenharmony_ci	sess->imm_data_en = test_bit(ISCSIOPT_IMMEDIATE_DATA_EN, &options);
37788c2ecf20Sopenharmony_ci	sess->initial_r2t_en = test_bit(ISCSIOPT_INITIAL_R2T_EN, &options);
37798c2ecf20Sopenharmony_ci	sess->dataseq_inorder_en = test_bit(ISCSIOPT_DATA_SEQ_IN_ORDER,
37808c2ecf20Sopenharmony_ci					    &options);
37818c2ecf20Sopenharmony_ci	sess->pdu_inorder_en = test_bit(ISCSIOPT_DATA_PDU_IN_ORDER, &options);
37828c2ecf20Sopenharmony_ci	sess->chap_auth_en = test_bit(ISCSIOPT_CHAP_AUTH_EN, &options);
37838c2ecf20Sopenharmony_ci	sess->discovery_logout_en = test_bit(ISCSIOPT_DISCOVERY_LOGOUT_EN,
37848c2ecf20Sopenharmony_ci					     &options);
37858c2ecf20Sopenharmony_ci	sess->bidi_chap_en = test_bit(ISCSIOPT_BIDI_CHAP_EN, &options);
37868c2ecf20Sopenharmony_ci	sess->discovery_auth_optional =
37878c2ecf20Sopenharmony_ci			test_bit(ISCSIOPT_DISCOVERY_AUTH_OPTIONAL, &options);
37888c2ecf20Sopenharmony_ci	if (test_bit(ISCSIOPT_ERL1, &options))
37898c2ecf20Sopenharmony_ci		sess->erl |= BIT_1;
37908c2ecf20Sopenharmony_ci	if (test_bit(ISCSIOPT_ERL0, &options))
37918c2ecf20Sopenharmony_ci		sess->erl |= BIT_0;
37928c2ecf20Sopenharmony_ci
37938c2ecf20Sopenharmony_ci	options = le16_to_cpu(fw_ddb_entry->tcp_options);
37948c2ecf20Sopenharmony_ci	conn->tcp_timestamp_stat = test_bit(TCPOPT_TIMESTAMP_STAT, &options);
37958c2ecf20Sopenharmony_ci	conn->tcp_nagle_disable = test_bit(TCPOPT_NAGLE_DISABLE, &options);
37968c2ecf20Sopenharmony_ci	conn->tcp_wsf_disable = test_bit(TCPOPT_WSF_DISABLE, &options);
37978c2ecf20Sopenharmony_ci	if (test_bit(TCPOPT_TIMER_SCALE3, &options))
37988c2ecf20Sopenharmony_ci		conn->tcp_timer_scale |= BIT_3;
37998c2ecf20Sopenharmony_ci	if (test_bit(TCPOPT_TIMER_SCALE2, &options))
38008c2ecf20Sopenharmony_ci		conn->tcp_timer_scale |= BIT_2;
38018c2ecf20Sopenharmony_ci	if (test_bit(TCPOPT_TIMER_SCALE1, &options))
38028c2ecf20Sopenharmony_ci		conn->tcp_timer_scale |= BIT_1;
38038c2ecf20Sopenharmony_ci
38048c2ecf20Sopenharmony_ci	conn->tcp_timer_scale >>= 1;
38058c2ecf20Sopenharmony_ci	conn->tcp_timestamp_en = test_bit(TCPOPT_TIMESTAMP_EN, &options);
38068c2ecf20Sopenharmony_ci
38078c2ecf20Sopenharmony_ci	options = le16_to_cpu(fw_ddb_entry->ip_options);
38088c2ecf20Sopenharmony_ci	conn->fragment_disable = test_bit(IPOPT_FRAGMENT_DISABLE, &options);
38098c2ecf20Sopenharmony_ci
38108c2ecf20Sopenharmony_ci	conn->max_recv_dlength = BYTE_UNITS *
38118c2ecf20Sopenharmony_ci			  le16_to_cpu(fw_ddb_entry->iscsi_max_rcv_data_seg_len);
38128c2ecf20Sopenharmony_ci	conn->max_xmit_dlength = BYTE_UNITS *
38138c2ecf20Sopenharmony_ci			  le16_to_cpu(fw_ddb_entry->iscsi_max_snd_data_seg_len);
38148c2ecf20Sopenharmony_ci	sess->max_r2t = le16_to_cpu(fw_ddb_entry->iscsi_max_outsnd_r2t);
38158c2ecf20Sopenharmony_ci	sess->first_burst = BYTE_UNITS *
38168c2ecf20Sopenharmony_ci			       le16_to_cpu(fw_ddb_entry->iscsi_first_burst_len);
38178c2ecf20Sopenharmony_ci	sess->max_burst = BYTE_UNITS *
38188c2ecf20Sopenharmony_ci				 le16_to_cpu(fw_ddb_entry->iscsi_max_burst_len);
38198c2ecf20Sopenharmony_ci	sess->time2wait = le16_to_cpu(fw_ddb_entry->iscsi_def_time2wait);
38208c2ecf20Sopenharmony_ci	sess->time2retain = le16_to_cpu(fw_ddb_entry->iscsi_def_time2retain);
38218c2ecf20Sopenharmony_ci	sess->tpgt = le32_to_cpu(fw_ddb_entry->tgt_portal_grp);
38228c2ecf20Sopenharmony_ci	conn->max_segment_size = le16_to_cpu(fw_ddb_entry->mss);
38238c2ecf20Sopenharmony_ci	conn->tcp_xmit_wsf = fw_ddb_entry->tcp_xmt_wsf;
38248c2ecf20Sopenharmony_ci	conn->tcp_recv_wsf = fw_ddb_entry->tcp_rcv_wsf;
38258c2ecf20Sopenharmony_ci	conn->ipv4_tos = fw_ddb_entry->ipv4_tos;
38268c2ecf20Sopenharmony_ci	conn->keepalive_tmo = le16_to_cpu(fw_ddb_entry->ka_timeout);
38278c2ecf20Sopenharmony_ci	conn->local_port = le16_to_cpu(fw_ddb_entry->lcl_port);
38288c2ecf20Sopenharmony_ci	conn->statsn = le32_to_cpu(fw_ddb_entry->stat_sn);
38298c2ecf20Sopenharmony_ci	conn->exp_statsn = le32_to_cpu(fw_ddb_entry->exp_stat_sn);
38308c2ecf20Sopenharmony_ci	sess->tsid = le16_to_cpu(fw_ddb_entry->tsid);
38318c2ecf20Sopenharmony_ci	COPY_ISID(sess->isid, fw_ddb_entry->isid);
38328c2ecf20Sopenharmony_ci
38338c2ecf20Sopenharmony_ci	ddb_link = le16_to_cpu(fw_ddb_entry->ddb_link);
38348c2ecf20Sopenharmony_ci	if (ddb_link == DDB_ISNS)
38358c2ecf20Sopenharmony_ci		disc_parent = ISCSI_DISC_PARENT_ISNS;
38368c2ecf20Sopenharmony_ci	else if (ddb_link == DDB_NO_LINK)
38378c2ecf20Sopenharmony_ci		disc_parent = ISCSI_DISC_PARENT_UNKNOWN;
38388c2ecf20Sopenharmony_ci	else if (ddb_link < MAX_DDB_ENTRIES)
38398c2ecf20Sopenharmony_ci		disc_parent = ISCSI_DISC_PARENT_SENDTGT;
38408c2ecf20Sopenharmony_ci	else
38418c2ecf20Sopenharmony_ci		disc_parent = ISCSI_DISC_PARENT_UNKNOWN;
38428c2ecf20Sopenharmony_ci
38438c2ecf20Sopenharmony_ci	iscsi_set_param(conn->cls_conn, ISCSI_PARAM_DISCOVERY_PARENT_TYPE,
38448c2ecf20Sopenharmony_ci			iscsi_get_discovery_parent_name(disc_parent), 0);
38458c2ecf20Sopenharmony_ci
38468c2ecf20Sopenharmony_ci	iscsi_set_param(conn->cls_conn, ISCSI_PARAM_TARGET_ALIAS,
38478c2ecf20Sopenharmony_ci			(char *)fw_ddb_entry->iscsi_alias, 0);
38488c2ecf20Sopenharmony_ci
38498c2ecf20Sopenharmony_ci	options = le16_to_cpu(fw_ddb_entry->options);
38508c2ecf20Sopenharmony_ci	if (options & DDB_OPT_IPV6_DEVICE) {
38518c2ecf20Sopenharmony_ci		memset(ip_addr, 0, sizeof(ip_addr));
38528c2ecf20Sopenharmony_ci		sprintf(ip_addr, "%pI6", fw_ddb_entry->link_local_ipv6_addr);
38538c2ecf20Sopenharmony_ci		iscsi_set_param(conn->cls_conn, ISCSI_PARAM_LOCAL_IPADDR,
38548c2ecf20Sopenharmony_ci				(char *)ip_addr, 0);
38558c2ecf20Sopenharmony_ci	}
38568c2ecf20Sopenharmony_ci}
38578c2ecf20Sopenharmony_ci
38588c2ecf20Sopenharmony_cistatic void qla4xxx_copy_fwddb_param(struct scsi_qla_host *ha,
38598c2ecf20Sopenharmony_ci				     struct dev_db_entry *fw_ddb_entry,
38608c2ecf20Sopenharmony_ci				     struct iscsi_cls_session *cls_sess,
38618c2ecf20Sopenharmony_ci				     struct iscsi_cls_conn *cls_conn)
38628c2ecf20Sopenharmony_ci{
38638c2ecf20Sopenharmony_ci	int buflen = 0;
38648c2ecf20Sopenharmony_ci	struct iscsi_session *sess;
38658c2ecf20Sopenharmony_ci	struct ddb_entry *ddb_entry;
38668c2ecf20Sopenharmony_ci	struct ql4_chap_table chap_tbl;
38678c2ecf20Sopenharmony_ci	struct iscsi_conn *conn;
38688c2ecf20Sopenharmony_ci	char ip_addr[DDB_IPADDR_LEN];
38698c2ecf20Sopenharmony_ci	uint16_t options = 0;
38708c2ecf20Sopenharmony_ci
38718c2ecf20Sopenharmony_ci	sess = cls_sess->dd_data;
38728c2ecf20Sopenharmony_ci	ddb_entry = sess->dd_data;
38738c2ecf20Sopenharmony_ci	conn = cls_conn->dd_data;
38748c2ecf20Sopenharmony_ci	memset(&chap_tbl, 0, sizeof(chap_tbl));
38758c2ecf20Sopenharmony_ci
38768c2ecf20Sopenharmony_ci	ddb_entry->chap_tbl_idx = le16_to_cpu(fw_ddb_entry->chap_tbl_idx);
38778c2ecf20Sopenharmony_ci
38788c2ecf20Sopenharmony_ci	qla4xxx_copy_to_sess_conn_params(conn, sess, fw_ddb_entry);
38798c2ecf20Sopenharmony_ci
38808c2ecf20Sopenharmony_ci	sess->def_taskmgmt_tmo = le16_to_cpu(fw_ddb_entry->def_timeout);
38818c2ecf20Sopenharmony_ci	conn->persistent_port = le16_to_cpu(fw_ddb_entry->port);
38828c2ecf20Sopenharmony_ci
38838c2ecf20Sopenharmony_ci	memset(ip_addr, 0, sizeof(ip_addr));
38848c2ecf20Sopenharmony_ci	options = le16_to_cpu(fw_ddb_entry->options);
38858c2ecf20Sopenharmony_ci	if (options & DDB_OPT_IPV6_DEVICE) {
38868c2ecf20Sopenharmony_ci		iscsi_set_param(cls_conn, ISCSI_PARAM_PORTAL_TYPE, "ipv6", 4);
38878c2ecf20Sopenharmony_ci
38888c2ecf20Sopenharmony_ci		memset(ip_addr, 0, sizeof(ip_addr));
38898c2ecf20Sopenharmony_ci		sprintf(ip_addr, "%pI6", fw_ddb_entry->ip_addr);
38908c2ecf20Sopenharmony_ci	} else {
38918c2ecf20Sopenharmony_ci		iscsi_set_param(cls_conn, ISCSI_PARAM_PORTAL_TYPE, "ipv4", 4);
38928c2ecf20Sopenharmony_ci		sprintf(ip_addr, "%pI4", fw_ddb_entry->ip_addr);
38938c2ecf20Sopenharmony_ci	}
38948c2ecf20Sopenharmony_ci
38958c2ecf20Sopenharmony_ci	iscsi_set_param(cls_conn, ISCSI_PARAM_PERSISTENT_ADDRESS,
38968c2ecf20Sopenharmony_ci			(char *)ip_addr, buflen);
38978c2ecf20Sopenharmony_ci	iscsi_set_param(cls_conn, ISCSI_PARAM_TARGET_NAME,
38988c2ecf20Sopenharmony_ci			(char *)fw_ddb_entry->iscsi_name, buflen);
38998c2ecf20Sopenharmony_ci	iscsi_set_param(cls_conn, ISCSI_PARAM_INITIATOR_NAME,
39008c2ecf20Sopenharmony_ci			(char *)ha->name_string, buflen);
39018c2ecf20Sopenharmony_ci
39028c2ecf20Sopenharmony_ci	if (ddb_entry->chap_tbl_idx != INVALID_ENTRY) {
39038c2ecf20Sopenharmony_ci		if (!qla4xxx_get_uni_chap_at_index(ha, chap_tbl.name,
39048c2ecf20Sopenharmony_ci						   chap_tbl.secret,
39058c2ecf20Sopenharmony_ci						   ddb_entry->chap_tbl_idx)) {
39068c2ecf20Sopenharmony_ci			iscsi_set_param(cls_conn, ISCSI_PARAM_USERNAME,
39078c2ecf20Sopenharmony_ci					(char *)chap_tbl.name,
39088c2ecf20Sopenharmony_ci					strlen((char *)chap_tbl.name));
39098c2ecf20Sopenharmony_ci			iscsi_set_param(cls_conn, ISCSI_PARAM_PASSWORD,
39108c2ecf20Sopenharmony_ci					(char *)chap_tbl.secret,
39118c2ecf20Sopenharmony_ci					chap_tbl.secret_len);
39128c2ecf20Sopenharmony_ci		}
39138c2ecf20Sopenharmony_ci	}
39148c2ecf20Sopenharmony_ci}
39158c2ecf20Sopenharmony_ci
39168c2ecf20Sopenharmony_civoid qla4xxx_update_session_conn_fwddb_param(struct scsi_qla_host *ha,
39178c2ecf20Sopenharmony_ci					     struct ddb_entry *ddb_entry)
39188c2ecf20Sopenharmony_ci{
39198c2ecf20Sopenharmony_ci	struct iscsi_cls_session *cls_sess;
39208c2ecf20Sopenharmony_ci	struct iscsi_cls_conn *cls_conn;
39218c2ecf20Sopenharmony_ci	uint32_t ddb_state;
39228c2ecf20Sopenharmony_ci	dma_addr_t fw_ddb_entry_dma;
39238c2ecf20Sopenharmony_ci	struct dev_db_entry *fw_ddb_entry;
39248c2ecf20Sopenharmony_ci
39258c2ecf20Sopenharmony_ci	fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
39268c2ecf20Sopenharmony_ci					  &fw_ddb_entry_dma, GFP_KERNEL);
39278c2ecf20Sopenharmony_ci	if (!fw_ddb_entry) {
39288c2ecf20Sopenharmony_ci		ql4_printk(KERN_ERR, ha,
39298c2ecf20Sopenharmony_ci			   "%s: Unable to allocate dma buffer\n", __func__);
39308c2ecf20Sopenharmony_ci		goto exit_session_conn_fwddb_param;
39318c2ecf20Sopenharmony_ci	}
39328c2ecf20Sopenharmony_ci
39338c2ecf20Sopenharmony_ci	if (qla4xxx_get_fwddb_entry(ha, ddb_entry->fw_ddb_index, fw_ddb_entry,
39348c2ecf20Sopenharmony_ci				    fw_ddb_entry_dma, NULL, NULL, &ddb_state,
39358c2ecf20Sopenharmony_ci				    NULL, NULL, NULL) == QLA_ERROR) {
39368c2ecf20Sopenharmony_ci		DEBUG2(ql4_printk(KERN_ERR, ha, "scsi%ld: %s: failed "
39378c2ecf20Sopenharmony_ci				  "get_ddb_entry for fw_ddb_index %d\n",
39388c2ecf20Sopenharmony_ci				  ha->host_no, __func__,
39398c2ecf20Sopenharmony_ci				  ddb_entry->fw_ddb_index));
39408c2ecf20Sopenharmony_ci		goto exit_session_conn_fwddb_param;
39418c2ecf20Sopenharmony_ci	}
39428c2ecf20Sopenharmony_ci
39438c2ecf20Sopenharmony_ci	cls_sess = ddb_entry->sess;
39448c2ecf20Sopenharmony_ci
39458c2ecf20Sopenharmony_ci	cls_conn = ddb_entry->conn;
39468c2ecf20Sopenharmony_ci
39478c2ecf20Sopenharmony_ci	/* Update params */
39488c2ecf20Sopenharmony_ci	qla4xxx_copy_fwddb_param(ha, fw_ddb_entry, cls_sess, cls_conn);
39498c2ecf20Sopenharmony_ci
39508c2ecf20Sopenharmony_ciexit_session_conn_fwddb_param:
39518c2ecf20Sopenharmony_ci	if (fw_ddb_entry)
39528c2ecf20Sopenharmony_ci		dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
39538c2ecf20Sopenharmony_ci				  fw_ddb_entry, fw_ddb_entry_dma);
39548c2ecf20Sopenharmony_ci}
39558c2ecf20Sopenharmony_ci
39568c2ecf20Sopenharmony_civoid qla4xxx_update_session_conn_param(struct scsi_qla_host *ha,
39578c2ecf20Sopenharmony_ci				       struct ddb_entry *ddb_entry)
39588c2ecf20Sopenharmony_ci{
39598c2ecf20Sopenharmony_ci	struct iscsi_cls_session *cls_sess;
39608c2ecf20Sopenharmony_ci	struct iscsi_cls_conn *cls_conn;
39618c2ecf20Sopenharmony_ci	struct iscsi_session *sess;
39628c2ecf20Sopenharmony_ci	struct iscsi_conn *conn;
39638c2ecf20Sopenharmony_ci	uint32_t ddb_state;
39648c2ecf20Sopenharmony_ci	dma_addr_t fw_ddb_entry_dma;
39658c2ecf20Sopenharmony_ci	struct dev_db_entry *fw_ddb_entry;
39668c2ecf20Sopenharmony_ci
39678c2ecf20Sopenharmony_ci	fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
39688c2ecf20Sopenharmony_ci					  &fw_ddb_entry_dma, GFP_KERNEL);
39698c2ecf20Sopenharmony_ci	if (!fw_ddb_entry) {
39708c2ecf20Sopenharmony_ci		ql4_printk(KERN_ERR, ha,
39718c2ecf20Sopenharmony_ci			   "%s: Unable to allocate dma buffer\n", __func__);
39728c2ecf20Sopenharmony_ci		goto exit_session_conn_param;
39738c2ecf20Sopenharmony_ci	}
39748c2ecf20Sopenharmony_ci
39758c2ecf20Sopenharmony_ci	if (qla4xxx_get_fwddb_entry(ha, ddb_entry->fw_ddb_index, fw_ddb_entry,
39768c2ecf20Sopenharmony_ci				    fw_ddb_entry_dma, NULL, NULL, &ddb_state,
39778c2ecf20Sopenharmony_ci				    NULL, NULL, NULL) == QLA_ERROR) {
39788c2ecf20Sopenharmony_ci		DEBUG2(ql4_printk(KERN_ERR, ha, "scsi%ld: %s: failed "
39798c2ecf20Sopenharmony_ci				  "get_ddb_entry for fw_ddb_index %d\n",
39808c2ecf20Sopenharmony_ci				  ha->host_no, __func__,
39818c2ecf20Sopenharmony_ci				  ddb_entry->fw_ddb_index));
39828c2ecf20Sopenharmony_ci		goto exit_session_conn_param;
39838c2ecf20Sopenharmony_ci	}
39848c2ecf20Sopenharmony_ci
39858c2ecf20Sopenharmony_ci	cls_sess = ddb_entry->sess;
39868c2ecf20Sopenharmony_ci	sess = cls_sess->dd_data;
39878c2ecf20Sopenharmony_ci
39888c2ecf20Sopenharmony_ci	cls_conn = ddb_entry->conn;
39898c2ecf20Sopenharmony_ci	conn = cls_conn->dd_data;
39908c2ecf20Sopenharmony_ci
39918c2ecf20Sopenharmony_ci	/* Update timers after login */
39928c2ecf20Sopenharmony_ci	ddb_entry->default_relogin_timeout =
39938c2ecf20Sopenharmony_ci		(le16_to_cpu(fw_ddb_entry->def_timeout) > LOGIN_TOV) &&
39948c2ecf20Sopenharmony_ci		 (le16_to_cpu(fw_ddb_entry->def_timeout) < LOGIN_TOV * 10) ?
39958c2ecf20Sopenharmony_ci		 le16_to_cpu(fw_ddb_entry->def_timeout) : LOGIN_TOV;
39968c2ecf20Sopenharmony_ci	ddb_entry->default_time2wait =
39978c2ecf20Sopenharmony_ci				le16_to_cpu(fw_ddb_entry->iscsi_def_time2wait);
39988c2ecf20Sopenharmony_ci
39998c2ecf20Sopenharmony_ci	/* Update params */
40008c2ecf20Sopenharmony_ci	ddb_entry->chap_tbl_idx = le16_to_cpu(fw_ddb_entry->chap_tbl_idx);
40018c2ecf20Sopenharmony_ci	qla4xxx_copy_to_sess_conn_params(conn, sess, fw_ddb_entry);
40028c2ecf20Sopenharmony_ci
40038c2ecf20Sopenharmony_ci	memcpy(sess->initiatorname, ha->name_string,
40048c2ecf20Sopenharmony_ci	       min(sizeof(ha->name_string), sizeof(sess->initiatorname)));
40058c2ecf20Sopenharmony_ci
40068c2ecf20Sopenharmony_ciexit_session_conn_param:
40078c2ecf20Sopenharmony_ci	if (fw_ddb_entry)
40088c2ecf20Sopenharmony_ci		dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
40098c2ecf20Sopenharmony_ci				  fw_ddb_entry, fw_ddb_entry_dma);
40108c2ecf20Sopenharmony_ci}
40118c2ecf20Sopenharmony_ci
40128c2ecf20Sopenharmony_ci/*
40138c2ecf20Sopenharmony_ci * Timer routines
40148c2ecf20Sopenharmony_ci */
40158c2ecf20Sopenharmony_cistatic void qla4xxx_timer(struct timer_list *t);
40168c2ecf20Sopenharmony_ci
40178c2ecf20Sopenharmony_cistatic void qla4xxx_start_timer(struct scsi_qla_host *ha,
40188c2ecf20Sopenharmony_ci				unsigned long interval)
40198c2ecf20Sopenharmony_ci{
40208c2ecf20Sopenharmony_ci	DEBUG(printk("scsi: %s: Starting timer thread for adapter %d\n",
40218c2ecf20Sopenharmony_ci		     __func__, ha->host->host_no));
40228c2ecf20Sopenharmony_ci	timer_setup(&ha->timer, qla4xxx_timer, 0);
40238c2ecf20Sopenharmony_ci	ha->timer.expires = jiffies + interval * HZ;
40248c2ecf20Sopenharmony_ci	add_timer(&ha->timer);
40258c2ecf20Sopenharmony_ci	ha->timer_active = 1;
40268c2ecf20Sopenharmony_ci}
40278c2ecf20Sopenharmony_ci
40288c2ecf20Sopenharmony_cistatic void qla4xxx_stop_timer(struct scsi_qla_host *ha)
40298c2ecf20Sopenharmony_ci{
40308c2ecf20Sopenharmony_ci	del_timer_sync(&ha->timer);
40318c2ecf20Sopenharmony_ci	ha->timer_active = 0;
40328c2ecf20Sopenharmony_ci}
40338c2ecf20Sopenharmony_ci
40348c2ecf20Sopenharmony_ci/***
40358c2ecf20Sopenharmony_ci * qla4xxx_mark_device_missing - blocks the session
40368c2ecf20Sopenharmony_ci * @cls_session: Pointer to the session to be blocked
40378c2ecf20Sopenharmony_ci * @ddb_entry: Pointer to device database entry
40388c2ecf20Sopenharmony_ci *
40398c2ecf20Sopenharmony_ci * This routine marks a device missing and close connection.
40408c2ecf20Sopenharmony_ci **/
40418c2ecf20Sopenharmony_civoid qla4xxx_mark_device_missing(struct iscsi_cls_session *cls_session)
40428c2ecf20Sopenharmony_ci{
40438c2ecf20Sopenharmony_ci	iscsi_block_session(cls_session);
40448c2ecf20Sopenharmony_ci}
40458c2ecf20Sopenharmony_ci
40468c2ecf20Sopenharmony_ci/**
40478c2ecf20Sopenharmony_ci * qla4xxx_mark_all_devices_missing - mark all devices as missing.
40488c2ecf20Sopenharmony_ci * @ha: Pointer to host adapter structure.
40498c2ecf20Sopenharmony_ci *
40508c2ecf20Sopenharmony_ci * This routine marks a device missing and resets the relogin retry count.
40518c2ecf20Sopenharmony_ci **/
40528c2ecf20Sopenharmony_civoid qla4xxx_mark_all_devices_missing(struct scsi_qla_host *ha)
40538c2ecf20Sopenharmony_ci{
40548c2ecf20Sopenharmony_ci	iscsi_host_for_each_session(ha->host, qla4xxx_mark_device_missing);
40558c2ecf20Sopenharmony_ci}
40568c2ecf20Sopenharmony_ci
40578c2ecf20Sopenharmony_cistatic struct srb* qla4xxx_get_new_srb(struct scsi_qla_host *ha,
40588c2ecf20Sopenharmony_ci				       struct ddb_entry *ddb_entry,
40598c2ecf20Sopenharmony_ci				       struct scsi_cmnd *cmd)
40608c2ecf20Sopenharmony_ci{
40618c2ecf20Sopenharmony_ci	struct srb *srb;
40628c2ecf20Sopenharmony_ci
40638c2ecf20Sopenharmony_ci	srb = mempool_alloc(ha->srb_mempool, GFP_ATOMIC);
40648c2ecf20Sopenharmony_ci	if (!srb)
40658c2ecf20Sopenharmony_ci		return srb;
40668c2ecf20Sopenharmony_ci
40678c2ecf20Sopenharmony_ci	kref_init(&srb->srb_ref);
40688c2ecf20Sopenharmony_ci	srb->ha = ha;
40698c2ecf20Sopenharmony_ci	srb->ddb = ddb_entry;
40708c2ecf20Sopenharmony_ci	srb->cmd = cmd;
40718c2ecf20Sopenharmony_ci	srb->flags = 0;
40728c2ecf20Sopenharmony_ci	CMD_SP(cmd) = (void *)srb;
40738c2ecf20Sopenharmony_ci
40748c2ecf20Sopenharmony_ci	return srb;
40758c2ecf20Sopenharmony_ci}
40768c2ecf20Sopenharmony_ci
40778c2ecf20Sopenharmony_cistatic void qla4xxx_srb_free_dma(struct scsi_qla_host *ha, struct srb *srb)
40788c2ecf20Sopenharmony_ci{
40798c2ecf20Sopenharmony_ci	struct scsi_cmnd *cmd = srb->cmd;
40808c2ecf20Sopenharmony_ci
40818c2ecf20Sopenharmony_ci	if (srb->flags & SRB_DMA_VALID) {
40828c2ecf20Sopenharmony_ci		scsi_dma_unmap(cmd);
40838c2ecf20Sopenharmony_ci		srb->flags &= ~SRB_DMA_VALID;
40848c2ecf20Sopenharmony_ci	}
40858c2ecf20Sopenharmony_ci	CMD_SP(cmd) = NULL;
40868c2ecf20Sopenharmony_ci}
40878c2ecf20Sopenharmony_ci
40888c2ecf20Sopenharmony_civoid qla4xxx_srb_compl(struct kref *ref)
40898c2ecf20Sopenharmony_ci{
40908c2ecf20Sopenharmony_ci	struct srb *srb = container_of(ref, struct srb, srb_ref);
40918c2ecf20Sopenharmony_ci	struct scsi_cmnd *cmd = srb->cmd;
40928c2ecf20Sopenharmony_ci	struct scsi_qla_host *ha = srb->ha;
40938c2ecf20Sopenharmony_ci
40948c2ecf20Sopenharmony_ci	qla4xxx_srb_free_dma(ha, srb);
40958c2ecf20Sopenharmony_ci
40968c2ecf20Sopenharmony_ci	mempool_free(srb, ha->srb_mempool);
40978c2ecf20Sopenharmony_ci
40988c2ecf20Sopenharmony_ci	cmd->scsi_done(cmd);
40998c2ecf20Sopenharmony_ci}
41008c2ecf20Sopenharmony_ci
41018c2ecf20Sopenharmony_ci/**
41028c2ecf20Sopenharmony_ci * qla4xxx_queuecommand - scsi layer issues scsi command to driver.
41038c2ecf20Sopenharmony_ci * @host: scsi host
41048c2ecf20Sopenharmony_ci * @cmd: Pointer to Linux's SCSI command structure
41058c2ecf20Sopenharmony_ci *
41068c2ecf20Sopenharmony_ci * Remarks:
41078c2ecf20Sopenharmony_ci * This routine is invoked by Linux to send a SCSI command to the driver.
41088c2ecf20Sopenharmony_ci * The mid-level driver tries to ensure that queuecommand never gets
41098c2ecf20Sopenharmony_ci * invoked concurrently with itself or the interrupt handler (although
41108c2ecf20Sopenharmony_ci * the interrupt handler may call this routine as part of request-
41118c2ecf20Sopenharmony_ci * completion handling).   Unfortunely, it sometimes calls the scheduler
41128c2ecf20Sopenharmony_ci * in interrupt context which is a big NO! NO!.
41138c2ecf20Sopenharmony_ci **/
41148c2ecf20Sopenharmony_cistatic int qla4xxx_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd)
41158c2ecf20Sopenharmony_ci{
41168c2ecf20Sopenharmony_ci	struct scsi_qla_host *ha = to_qla_host(host);
41178c2ecf20Sopenharmony_ci	struct ddb_entry *ddb_entry = cmd->device->hostdata;
41188c2ecf20Sopenharmony_ci	struct iscsi_cls_session *sess = ddb_entry->sess;
41198c2ecf20Sopenharmony_ci	struct srb *srb;
41208c2ecf20Sopenharmony_ci	int rval;
41218c2ecf20Sopenharmony_ci
41228c2ecf20Sopenharmony_ci	if (test_bit(AF_EEH_BUSY, &ha->flags)) {
41238c2ecf20Sopenharmony_ci		if (test_bit(AF_PCI_CHANNEL_IO_PERM_FAILURE, &ha->flags))
41248c2ecf20Sopenharmony_ci			cmd->result = DID_NO_CONNECT << 16;
41258c2ecf20Sopenharmony_ci		else
41268c2ecf20Sopenharmony_ci			cmd->result = DID_REQUEUE << 16;
41278c2ecf20Sopenharmony_ci		goto qc_fail_command;
41288c2ecf20Sopenharmony_ci	}
41298c2ecf20Sopenharmony_ci
41308c2ecf20Sopenharmony_ci	if (!sess) {
41318c2ecf20Sopenharmony_ci		cmd->result = DID_IMM_RETRY << 16;
41328c2ecf20Sopenharmony_ci		goto qc_fail_command;
41338c2ecf20Sopenharmony_ci	}
41348c2ecf20Sopenharmony_ci
41358c2ecf20Sopenharmony_ci	rval = iscsi_session_chkready(sess);
41368c2ecf20Sopenharmony_ci	if (rval) {
41378c2ecf20Sopenharmony_ci		cmd->result = rval;
41388c2ecf20Sopenharmony_ci		goto qc_fail_command;
41398c2ecf20Sopenharmony_ci	}
41408c2ecf20Sopenharmony_ci
41418c2ecf20Sopenharmony_ci	if (test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags) ||
41428c2ecf20Sopenharmony_ci	    test_bit(DPC_RESET_ACTIVE, &ha->dpc_flags) ||
41438c2ecf20Sopenharmony_ci	    test_bit(DPC_RESET_HA, &ha->dpc_flags) ||
41448c2ecf20Sopenharmony_ci	    test_bit(DPC_HA_UNRECOVERABLE, &ha->dpc_flags) ||
41458c2ecf20Sopenharmony_ci	    test_bit(DPC_HA_NEED_QUIESCENT, &ha->dpc_flags) ||
41468c2ecf20Sopenharmony_ci	    !test_bit(AF_ONLINE, &ha->flags) ||
41478c2ecf20Sopenharmony_ci	    !test_bit(AF_LINK_UP, &ha->flags) ||
41488c2ecf20Sopenharmony_ci	    test_bit(AF_LOOPBACK, &ha->flags) ||
41498c2ecf20Sopenharmony_ci	    test_bit(DPC_POST_IDC_ACK, &ha->dpc_flags) ||
41508c2ecf20Sopenharmony_ci	    test_bit(DPC_RESTORE_ACB, &ha->dpc_flags) ||
41518c2ecf20Sopenharmony_ci	    test_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags))
41528c2ecf20Sopenharmony_ci		goto qc_host_busy;
41538c2ecf20Sopenharmony_ci
41548c2ecf20Sopenharmony_ci	srb = qla4xxx_get_new_srb(ha, ddb_entry, cmd);
41558c2ecf20Sopenharmony_ci	if (!srb)
41568c2ecf20Sopenharmony_ci		goto qc_host_busy;
41578c2ecf20Sopenharmony_ci
41588c2ecf20Sopenharmony_ci	rval = qla4xxx_send_command_to_isp(ha, srb);
41598c2ecf20Sopenharmony_ci	if (rval != QLA_SUCCESS)
41608c2ecf20Sopenharmony_ci		goto qc_host_busy_free_sp;
41618c2ecf20Sopenharmony_ci
41628c2ecf20Sopenharmony_ci	return 0;
41638c2ecf20Sopenharmony_ci
41648c2ecf20Sopenharmony_ciqc_host_busy_free_sp:
41658c2ecf20Sopenharmony_ci	qla4xxx_srb_free_dma(ha, srb);
41668c2ecf20Sopenharmony_ci	mempool_free(srb, ha->srb_mempool);
41678c2ecf20Sopenharmony_ci
41688c2ecf20Sopenharmony_ciqc_host_busy:
41698c2ecf20Sopenharmony_ci	return SCSI_MLQUEUE_HOST_BUSY;
41708c2ecf20Sopenharmony_ci
41718c2ecf20Sopenharmony_ciqc_fail_command:
41728c2ecf20Sopenharmony_ci	cmd->scsi_done(cmd);
41738c2ecf20Sopenharmony_ci
41748c2ecf20Sopenharmony_ci	return 0;
41758c2ecf20Sopenharmony_ci}
41768c2ecf20Sopenharmony_ci
41778c2ecf20Sopenharmony_ci/**
41788c2ecf20Sopenharmony_ci * qla4xxx_mem_free - frees memory allocated to adapter
41798c2ecf20Sopenharmony_ci * @ha: Pointer to host adapter structure.
41808c2ecf20Sopenharmony_ci *
41818c2ecf20Sopenharmony_ci * Frees memory previously allocated by qla4xxx_mem_alloc
41828c2ecf20Sopenharmony_ci **/
41838c2ecf20Sopenharmony_cistatic void qla4xxx_mem_free(struct scsi_qla_host *ha)
41848c2ecf20Sopenharmony_ci{
41858c2ecf20Sopenharmony_ci	if (ha->queues)
41868c2ecf20Sopenharmony_ci		dma_free_coherent(&ha->pdev->dev, ha->queues_len, ha->queues,
41878c2ecf20Sopenharmony_ci				  ha->queues_dma);
41888c2ecf20Sopenharmony_ci
41898c2ecf20Sopenharmony_ci	if (ha->fw_dump)
41908c2ecf20Sopenharmony_ci		vfree(ha->fw_dump);
41918c2ecf20Sopenharmony_ci
41928c2ecf20Sopenharmony_ci	ha->queues_len = 0;
41938c2ecf20Sopenharmony_ci	ha->queues = NULL;
41948c2ecf20Sopenharmony_ci	ha->queues_dma = 0;
41958c2ecf20Sopenharmony_ci	ha->request_ring = NULL;
41968c2ecf20Sopenharmony_ci	ha->request_dma = 0;
41978c2ecf20Sopenharmony_ci	ha->response_ring = NULL;
41988c2ecf20Sopenharmony_ci	ha->response_dma = 0;
41998c2ecf20Sopenharmony_ci	ha->shadow_regs = NULL;
42008c2ecf20Sopenharmony_ci	ha->shadow_regs_dma = 0;
42018c2ecf20Sopenharmony_ci	ha->fw_dump = NULL;
42028c2ecf20Sopenharmony_ci	ha->fw_dump_size = 0;
42038c2ecf20Sopenharmony_ci
42048c2ecf20Sopenharmony_ci	/* Free srb pool. */
42058c2ecf20Sopenharmony_ci	mempool_destroy(ha->srb_mempool);
42068c2ecf20Sopenharmony_ci	ha->srb_mempool = NULL;
42078c2ecf20Sopenharmony_ci
42088c2ecf20Sopenharmony_ci	dma_pool_destroy(ha->chap_dma_pool);
42098c2ecf20Sopenharmony_ci
42108c2ecf20Sopenharmony_ci	if (ha->chap_list)
42118c2ecf20Sopenharmony_ci		vfree(ha->chap_list);
42128c2ecf20Sopenharmony_ci	ha->chap_list = NULL;
42138c2ecf20Sopenharmony_ci
42148c2ecf20Sopenharmony_ci	dma_pool_destroy(ha->fw_ddb_dma_pool);
42158c2ecf20Sopenharmony_ci
42168c2ecf20Sopenharmony_ci	/* release io space registers  */
42178c2ecf20Sopenharmony_ci	if (is_qla8022(ha)) {
42188c2ecf20Sopenharmony_ci		if (ha->nx_pcibase)
42198c2ecf20Sopenharmony_ci			iounmap(
42208c2ecf20Sopenharmony_ci			    (struct device_reg_82xx __iomem *)ha->nx_pcibase);
42218c2ecf20Sopenharmony_ci	} else if (is_qla8032(ha) || is_qla8042(ha)) {
42228c2ecf20Sopenharmony_ci		if (ha->nx_pcibase)
42238c2ecf20Sopenharmony_ci			iounmap(
42248c2ecf20Sopenharmony_ci			    (struct device_reg_83xx __iomem *)ha->nx_pcibase);
42258c2ecf20Sopenharmony_ci	} else if (ha->reg) {
42268c2ecf20Sopenharmony_ci		iounmap(ha->reg);
42278c2ecf20Sopenharmony_ci	}
42288c2ecf20Sopenharmony_ci
42298c2ecf20Sopenharmony_ci	if (ha->reset_tmplt.buff)
42308c2ecf20Sopenharmony_ci		vfree(ha->reset_tmplt.buff);
42318c2ecf20Sopenharmony_ci
42328c2ecf20Sopenharmony_ci	pci_release_regions(ha->pdev);
42338c2ecf20Sopenharmony_ci}
42348c2ecf20Sopenharmony_ci
42358c2ecf20Sopenharmony_ci/**
42368c2ecf20Sopenharmony_ci * qla4xxx_mem_alloc - allocates memory for use by adapter.
42378c2ecf20Sopenharmony_ci * @ha: Pointer to host adapter structure
42388c2ecf20Sopenharmony_ci *
42398c2ecf20Sopenharmony_ci * Allocates DMA memory for request and response queues. Also allocates memory
42408c2ecf20Sopenharmony_ci * for srbs.
42418c2ecf20Sopenharmony_ci **/
42428c2ecf20Sopenharmony_cistatic int qla4xxx_mem_alloc(struct scsi_qla_host *ha)
42438c2ecf20Sopenharmony_ci{
42448c2ecf20Sopenharmony_ci	unsigned long align;
42458c2ecf20Sopenharmony_ci
42468c2ecf20Sopenharmony_ci	/* Allocate contiguous block of DMA memory for queues. */
42478c2ecf20Sopenharmony_ci	ha->queues_len = ((REQUEST_QUEUE_DEPTH * QUEUE_SIZE) +
42488c2ecf20Sopenharmony_ci			  (RESPONSE_QUEUE_DEPTH * QUEUE_SIZE) +
42498c2ecf20Sopenharmony_ci			  sizeof(struct shadow_regs) +
42508c2ecf20Sopenharmony_ci			  MEM_ALIGN_VALUE +
42518c2ecf20Sopenharmony_ci			  (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1);
42528c2ecf20Sopenharmony_ci	ha->queues = dma_alloc_coherent(&ha->pdev->dev, ha->queues_len,
42538c2ecf20Sopenharmony_ci					&ha->queues_dma, GFP_KERNEL);
42548c2ecf20Sopenharmony_ci	if (ha->queues == NULL) {
42558c2ecf20Sopenharmony_ci		ql4_printk(KERN_WARNING, ha,
42568c2ecf20Sopenharmony_ci		    "Memory Allocation failed - queues.\n");
42578c2ecf20Sopenharmony_ci
42588c2ecf20Sopenharmony_ci		goto mem_alloc_error_exit;
42598c2ecf20Sopenharmony_ci	}
42608c2ecf20Sopenharmony_ci
42618c2ecf20Sopenharmony_ci	/*
42628c2ecf20Sopenharmony_ci	 * As per RISC alignment requirements -- the bus-address must be a
42638c2ecf20Sopenharmony_ci	 * multiple of the request-ring size (in bytes).
42648c2ecf20Sopenharmony_ci	 */
42658c2ecf20Sopenharmony_ci	align = 0;
42668c2ecf20Sopenharmony_ci	if ((unsigned long)ha->queues_dma & (MEM_ALIGN_VALUE - 1))
42678c2ecf20Sopenharmony_ci		align = MEM_ALIGN_VALUE - ((unsigned long)ha->queues_dma &
42688c2ecf20Sopenharmony_ci					   (MEM_ALIGN_VALUE - 1));
42698c2ecf20Sopenharmony_ci
42708c2ecf20Sopenharmony_ci	/* Update request and response queue pointers. */
42718c2ecf20Sopenharmony_ci	ha->request_dma = ha->queues_dma + align;
42728c2ecf20Sopenharmony_ci	ha->request_ring = (struct queue_entry *) (ha->queues + align);
42738c2ecf20Sopenharmony_ci	ha->response_dma = ha->queues_dma + align +
42748c2ecf20Sopenharmony_ci		(REQUEST_QUEUE_DEPTH * QUEUE_SIZE);
42758c2ecf20Sopenharmony_ci	ha->response_ring = (struct queue_entry *) (ha->queues + align +
42768c2ecf20Sopenharmony_ci						    (REQUEST_QUEUE_DEPTH *
42778c2ecf20Sopenharmony_ci						     QUEUE_SIZE));
42788c2ecf20Sopenharmony_ci	ha->shadow_regs_dma = ha->queues_dma + align +
42798c2ecf20Sopenharmony_ci		(REQUEST_QUEUE_DEPTH * QUEUE_SIZE) +
42808c2ecf20Sopenharmony_ci		(RESPONSE_QUEUE_DEPTH * QUEUE_SIZE);
42818c2ecf20Sopenharmony_ci	ha->shadow_regs = (struct shadow_regs *) (ha->queues + align +
42828c2ecf20Sopenharmony_ci						  (REQUEST_QUEUE_DEPTH *
42838c2ecf20Sopenharmony_ci						   QUEUE_SIZE) +
42848c2ecf20Sopenharmony_ci						  (RESPONSE_QUEUE_DEPTH *
42858c2ecf20Sopenharmony_ci						   QUEUE_SIZE));
42868c2ecf20Sopenharmony_ci
42878c2ecf20Sopenharmony_ci	/* Allocate memory for srb pool. */
42888c2ecf20Sopenharmony_ci	ha->srb_mempool = mempool_create(SRB_MIN_REQ, mempool_alloc_slab,
42898c2ecf20Sopenharmony_ci					 mempool_free_slab, srb_cachep);
42908c2ecf20Sopenharmony_ci	if (ha->srb_mempool == NULL) {
42918c2ecf20Sopenharmony_ci		ql4_printk(KERN_WARNING, ha,
42928c2ecf20Sopenharmony_ci		    "Memory Allocation failed - SRB Pool.\n");
42938c2ecf20Sopenharmony_ci
42948c2ecf20Sopenharmony_ci		goto mem_alloc_error_exit;
42958c2ecf20Sopenharmony_ci	}
42968c2ecf20Sopenharmony_ci
42978c2ecf20Sopenharmony_ci	ha->chap_dma_pool = dma_pool_create("ql4_chap", &ha->pdev->dev,
42988c2ecf20Sopenharmony_ci					    CHAP_DMA_BLOCK_SIZE, 8, 0);
42998c2ecf20Sopenharmony_ci
43008c2ecf20Sopenharmony_ci	if (ha->chap_dma_pool == NULL) {
43018c2ecf20Sopenharmony_ci		ql4_printk(KERN_WARNING, ha,
43028c2ecf20Sopenharmony_ci		    "%s: chap_dma_pool allocation failed..\n", __func__);
43038c2ecf20Sopenharmony_ci		goto mem_alloc_error_exit;
43048c2ecf20Sopenharmony_ci	}
43058c2ecf20Sopenharmony_ci
43068c2ecf20Sopenharmony_ci	ha->fw_ddb_dma_pool = dma_pool_create("ql4_fw_ddb", &ha->pdev->dev,
43078c2ecf20Sopenharmony_ci					      DDB_DMA_BLOCK_SIZE, 8, 0);
43088c2ecf20Sopenharmony_ci
43098c2ecf20Sopenharmony_ci	if (ha->fw_ddb_dma_pool == NULL) {
43108c2ecf20Sopenharmony_ci		ql4_printk(KERN_WARNING, ha,
43118c2ecf20Sopenharmony_ci			   "%s: fw_ddb_dma_pool allocation failed..\n",
43128c2ecf20Sopenharmony_ci			   __func__);
43138c2ecf20Sopenharmony_ci		goto mem_alloc_error_exit;
43148c2ecf20Sopenharmony_ci	}
43158c2ecf20Sopenharmony_ci
43168c2ecf20Sopenharmony_ci	return QLA_SUCCESS;
43178c2ecf20Sopenharmony_ci
43188c2ecf20Sopenharmony_cimem_alloc_error_exit:
43198c2ecf20Sopenharmony_ci	return QLA_ERROR;
43208c2ecf20Sopenharmony_ci}
43218c2ecf20Sopenharmony_ci
43228c2ecf20Sopenharmony_ci/**
43238c2ecf20Sopenharmony_ci * qla4_8xxx_check_temp - Check the ISP82XX temperature.
43248c2ecf20Sopenharmony_ci * @ha: adapter block pointer.
43258c2ecf20Sopenharmony_ci *
43268c2ecf20Sopenharmony_ci * Note: The caller should not hold the idc lock.
43278c2ecf20Sopenharmony_ci **/
43288c2ecf20Sopenharmony_cistatic int qla4_8xxx_check_temp(struct scsi_qla_host *ha)
43298c2ecf20Sopenharmony_ci{
43308c2ecf20Sopenharmony_ci	uint32_t temp, temp_state, temp_val;
43318c2ecf20Sopenharmony_ci	int status = QLA_SUCCESS;
43328c2ecf20Sopenharmony_ci
43338c2ecf20Sopenharmony_ci	temp = qla4_8xxx_rd_direct(ha, QLA8XXX_CRB_TEMP_STATE);
43348c2ecf20Sopenharmony_ci
43358c2ecf20Sopenharmony_ci	temp_state = qla82xx_get_temp_state(temp);
43368c2ecf20Sopenharmony_ci	temp_val = qla82xx_get_temp_val(temp);
43378c2ecf20Sopenharmony_ci
43388c2ecf20Sopenharmony_ci	if (temp_state == QLA82XX_TEMP_PANIC) {
43398c2ecf20Sopenharmony_ci		ql4_printk(KERN_WARNING, ha, "Device temperature %d degrees C"
43408c2ecf20Sopenharmony_ci			   " exceeds maximum allowed. Hardware has been shut"
43418c2ecf20Sopenharmony_ci			   " down.\n", temp_val);
43428c2ecf20Sopenharmony_ci		status = QLA_ERROR;
43438c2ecf20Sopenharmony_ci	} else if (temp_state == QLA82XX_TEMP_WARN) {
43448c2ecf20Sopenharmony_ci		if (ha->temperature == QLA82XX_TEMP_NORMAL)
43458c2ecf20Sopenharmony_ci			ql4_printk(KERN_WARNING, ha, "Device temperature %d"
43468c2ecf20Sopenharmony_ci				   " degrees C exceeds operating range."
43478c2ecf20Sopenharmony_ci				   " Immediate action needed.\n", temp_val);
43488c2ecf20Sopenharmony_ci	} else {
43498c2ecf20Sopenharmony_ci		if (ha->temperature == QLA82XX_TEMP_WARN)
43508c2ecf20Sopenharmony_ci			ql4_printk(KERN_INFO, ha, "Device temperature is"
43518c2ecf20Sopenharmony_ci				   " now %d degrees C in normal range.\n",
43528c2ecf20Sopenharmony_ci				   temp_val);
43538c2ecf20Sopenharmony_ci	}
43548c2ecf20Sopenharmony_ci	ha->temperature = temp_state;
43558c2ecf20Sopenharmony_ci	return status;
43568c2ecf20Sopenharmony_ci}
43578c2ecf20Sopenharmony_ci
43588c2ecf20Sopenharmony_ci/**
43598c2ecf20Sopenharmony_ci * qla4_8xxx_check_fw_alive  - Check firmware health
43608c2ecf20Sopenharmony_ci * @ha: Pointer to host adapter structure.
43618c2ecf20Sopenharmony_ci *
43628c2ecf20Sopenharmony_ci * Context: Interrupt
43638c2ecf20Sopenharmony_ci **/
43648c2ecf20Sopenharmony_cistatic int qla4_8xxx_check_fw_alive(struct scsi_qla_host *ha)
43658c2ecf20Sopenharmony_ci{
43668c2ecf20Sopenharmony_ci	uint32_t fw_heartbeat_counter;
43678c2ecf20Sopenharmony_ci	int status = QLA_SUCCESS;
43688c2ecf20Sopenharmony_ci
43698c2ecf20Sopenharmony_ci	fw_heartbeat_counter = qla4_8xxx_rd_direct(ha,
43708c2ecf20Sopenharmony_ci						   QLA8XXX_PEG_ALIVE_COUNTER);
43718c2ecf20Sopenharmony_ci	/* If PEG_ALIVE_COUNTER is 0xffffffff, AER/EEH is in progress, ignore */
43728c2ecf20Sopenharmony_ci	if (fw_heartbeat_counter == 0xffffffff) {
43738c2ecf20Sopenharmony_ci		DEBUG2(printk(KERN_WARNING "scsi%ld: %s: Device in frozen "
43748c2ecf20Sopenharmony_ci		    "state, QLA82XX_PEG_ALIVE_COUNTER is 0xffffffff\n",
43758c2ecf20Sopenharmony_ci		    ha->host_no, __func__));
43768c2ecf20Sopenharmony_ci		return status;
43778c2ecf20Sopenharmony_ci	}
43788c2ecf20Sopenharmony_ci
43798c2ecf20Sopenharmony_ci	if (ha->fw_heartbeat_counter == fw_heartbeat_counter) {
43808c2ecf20Sopenharmony_ci		ha->seconds_since_last_heartbeat++;
43818c2ecf20Sopenharmony_ci		/* FW not alive after 2 seconds */
43828c2ecf20Sopenharmony_ci		if (ha->seconds_since_last_heartbeat == 2) {
43838c2ecf20Sopenharmony_ci			ha->seconds_since_last_heartbeat = 0;
43848c2ecf20Sopenharmony_ci			qla4_8xxx_dump_peg_reg(ha);
43858c2ecf20Sopenharmony_ci			status = QLA_ERROR;
43868c2ecf20Sopenharmony_ci		}
43878c2ecf20Sopenharmony_ci	} else
43888c2ecf20Sopenharmony_ci		ha->seconds_since_last_heartbeat = 0;
43898c2ecf20Sopenharmony_ci
43908c2ecf20Sopenharmony_ci	ha->fw_heartbeat_counter = fw_heartbeat_counter;
43918c2ecf20Sopenharmony_ci	return status;
43928c2ecf20Sopenharmony_ci}
43938c2ecf20Sopenharmony_ci
43948c2ecf20Sopenharmony_cistatic void qla4_8xxx_process_fw_error(struct scsi_qla_host *ha)
43958c2ecf20Sopenharmony_ci{
43968c2ecf20Sopenharmony_ci	uint32_t halt_status;
43978c2ecf20Sopenharmony_ci	int halt_status_unrecoverable = 0;
43988c2ecf20Sopenharmony_ci
43998c2ecf20Sopenharmony_ci	halt_status = qla4_8xxx_rd_direct(ha, QLA8XXX_PEG_HALT_STATUS1);
44008c2ecf20Sopenharmony_ci
44018c2ecf20Sopenharmony_ci	if (is_qla8022(ha)) {
44028c2ecf20Sopenharmony_ci		ql4_printk(KERN_INFO, ha, "%s: disabling pause transmit on port 0 & 1.\n",
44038c2ecf20Sopenharmony_ci			   __func__);
44048c2ecf20Sopenharmony_ci		qla4_82xx_wr_32(ha, QLA82XX_CRB_NIU + 0x98,
44058c2ecf20Sopenharmony_ci				CRB_NIU_XG_PAUSE_CTL_P0 |
44068c2ecf20Sopenharmony_ci				CRB_NIU_XG_PAUSE_CTL_P1);
44078c2ecf20Sopenharmony_ci
44088c2ecf20Sopenharmony_ci		if (QLA82XX_FWERROR_CODE(halt_status) == 0x67)
44098c2ecf20Sopenharmony_ci			ql4_printk(KERN_ERR, ha, "%s: Firmware aborted with error code 0x00006700. Device is being reset\n",
44108c2ecf20Sopenharmony_ci				   __func__);
44118c2ecf20Sopenharmony_ci		if (halt_status & HALT_STATUS_UNRECOVERABLE)
44128c2ecf20Sopenharmony_ci			halt_status_unrecoverable = 1;
44138c2ecf20Sopenharmony_ci	} else if (is_qla8032(ha) || is_qla8042(ha)) {
44148c2ecf20Sopenharmony_ci		if (halt_status & QLA83XX_HALT_STATUS_FW_RESET)
44158c2ecf20Sopenharmony_ci			ql4_printk(KERN_ERR, ha, "%s: Firmware error detected device is being reset\n",
44168c2ecf20Sopenharmony_ci				   __func__);
44178c2ecf20Sopenharmony_ci		else if (halt_status & QLA83XX_HALT_STATUS_UNRECOVERABLE)
44188c2ecf20Sopenharmony_ci			halt_status_unrecoverable = 1;
44198c2ecf20Sopenharmony_ci	}
44208c2ecf20Sopenharmony_ci
44218c2ecf20Sopenharmony_ci	/*
44228c2ecf20Sopenharmony_ci	 * Since we cannot change dev_state in interrupt context,
44238c2ecf20Sopenharmony_ci	 * set appropriate DPC flag then wakeup DPC
44248c2ecf20Sopenharmony_ci	 */
44258c2ecf20Sopenharmony_ci	if (halt_status_unrecoverable) {
44268c2ecf20Sopenharmony_ci		set_bit(DPC_HA_UNRECOVERABLE, &ha->dpc_flags);
44278c2ecf20Sopenharmony_ci	} else {
44288c2ecf20Sopenharmony_ci		ql4_printk(KERN_INFO, ha, "%s: detect abort needed!\n",
44298c2ecf20Sopenharmony_ci			   __func__);
44308c2ecf20Sopenharmony_ci		set_bit(DPC_RESET_HA, &ha->dpc_flags);
44318c2ecf20Sopenharmony_ci	}
44328c2ecf20Sopenharmony_ci	qla4xxx_mailbox_premature_completion(ha);
44338c2ecf20Sopenharmony_ci	qla4xxx_wake_dpc(ha);
44348c2ecf20Sopenharmony_ci}
44358c2ecf20Sopenharmony_ci
44368c2ecf20Sopenharmony_ci/**
44378c2ecf20Sopenharmony_ci * qla4_8xxx_watchdog - Poll dev state
44388c2ecf20Sopenharmony_ci * @ha: Pointer to host adapter structure.
44398c2ecf20Sopenharmony_ci *
44408c2ecf20Sopenharmony_ci * Context: Interrupt
44418c2ecf20Sopenharmony_ci **/
44428c2ecf20Sopenharmony_civoid qla4_8xxx_watchdog(struct scsi_qla_host *ha)
44438c2ecf20Sopenharmony_ci{
44448c2ecf20Sopenharmony_ci	uint32_t dev_state;
44458c2ecf20Sopenharmony_ci	uint32_t idc_ctrl;
44468c2ecf20Sopenharmony_ci
44478c2ecf20Sopenharmony_ci	if (is_qla8032(ha) &&
44488c2ecf20Sopenharmony_ci	    (qla4_83xx_is_detached(ha) == QLA_SUCCESS))
44498c2ecf20Sopenharmony_ci		WARN_ONCE(1, "%s: iSCSI function %d marked invisible\n",
44508c2ecf20Sopenharmony_ci			  __func__, ha->func_num);
44518c2ecf20Sopenharmony_ci
44528c2ecf20Sopenharmony_ci	/* don't poll if reset is going on */
44538c2ecf20Sopenharmony_ci	if (!(test_bit(DPC_RESET_ACTIVE, &ha->dpc_flags) ||
44548c2ecf20Sopenharmony_ci	    test_bit(DPC_RESET_HA, &ha->dpc_flags) ||
44558c2ecf20Sopenharmony_ci	    test_bit(DPC_RETRY_RESET_HA, &ha->dpc_flags))) {
44568c2ecf20Sopenharmony_ci		dev_state = qla4_8xxx_rd_direct(ha, QLA8XXX_CRB_DEV_STATE);
44578c2ecf20Sopenharmony_ci
44588c2ecf20Sopenharmony_ci		if (qla4_8xxx_check_temp(ha)) {
44598c2ecf20Sopenharmony_ci			if (is_qla8022(ha)) {
44608c2ecf20Sopenharmony_ci				ql4_printk(KERN_INFO, ha, "disabling pause transmit on port 0 & 1.\n");
44618c2ecf20Sopenharmony_ci				qla4_82xx_wr_32(ha, QLA82XX_CRB_NIU + 0x98,
44628c2ecf20Sopenharmony_ci						CRB_NIU_XG_PAUSE_CTL_P0 |
44638c2ecf20Sopenharmony_ci						CRB_NIU_XG_PAUSE_CTL_P1);
44648c2ecf20Sopenharmony_ci			}
44658c2ecf20Sopenharmony_ci			set_bit(DPC_HA_UNRECOVERABLE, &ha->dpc_flags);
44668c2ecf20Sopenharmony_ci			qla4xxx_wake_dpc(ha);
44678c2ecf20Sopenharmony_ci		} else if (dev_state == QLA8XXX_DEV_NEED_RESET &&
44688c2ecf20Sopenharmony_ci			   !test_bit(DPC_RESET_HA, &ha->dpc_flags)) {
44698c2ecf20Sopenharmony_ci
44708c2ecf20Sopenharmony_ci			ql4_printk(KERN_INFO, ha, "%s: HW State: NEED RESET!\n",
44718c2ecf20Sopenharmony_ci				   __func__);
44728c2ecf20Sopenharmony_ci
44738c2ecf20Sopenharmony_ci			if (is_qla8032(ha) || is_qla8042(ha)) {
44748c2ecf20Sopenharmony_ci				idc_ctrl = qla4_83xx_rd_reg(ha,
44758c2ecf20Sopenharmony_ci							QLA83XX_IDC_DRV_CTRL);
44768c2ecf20Sopenharmony_ci				if (!(idc_ctrl & GRACEFUL_RESET_BIT1)) {
44778c2ecf20Sopenharmony_ci					ql4_printk(KERN_INFO, ha, "%s: Graceful reset bit is not set\n",
44788c2ecf20Sopenharmony_ci						   __func__);
44798c2ecf20Sopenharmony_ci					qla4xxx_mailbox_premature_completion(
44808c2ecf20Sopenharmony_ci									    ha);
44818c2ecf20Sopenharmony_ci				}
44828c2ecf20Sopenharmony_ci			}
44838c2ecf20Sopenharmony_ci
44848c2ecf20Sopenharmony_ci			if ((is_qla8032(ha) || is_qla8042(ha)) ||
44858c2ecf20Sopenharmony_ci			    (is_qla8022(ha) && !ql4xdontresethba)) {
44868c2ecf20Sopenharmony_ci				set_bit(DPC_RESET_HA, &ha->dpc_flags);
44878c2ecf20Sopenharmony_ci				qla4xxx_wake_dpc(ha);
44888c2ecf20Sopenharmony_ci			}
44898c2ecf20Sopenharmony_ci		} else if (dev_state == QLA8XXX_DEV_NEED_QUIESCENT &&
44908c2ecf20Sopenharmony_ci		    !test_bit(DPC_HA_NEED_QUIESCENT, &ha->dpc_flags)) {
44918c2ecf20Sopenharmony_ci			ql4_printk(KERN_INFO, ha, "%s: HW State: NEED QUIES!\n",
44928c2ecf20Sopenharmony_ci			    __func__);
44938c2ecf20Sopenharmony_ci			set_bit(DPC_HA_NEED_QUIESCENT, &ha->dpc_flags);
44948c2ecf20Sopenharmony_ci			qla4xxx_wake_dpc(ha);
44958c2ecf20Sopenharmony_ci		} else  {
44968c2ecf20Sopenharmony_ci			/* Check firmware health */
44978c2ecf20Sopenharmony_ci			if (qla4_8xxx_check_fw_alive(ha))
44988c2ecf20Sopenharmony_ci				qla4_8xxx_process_fw_error(ha);
44998c2ecf20Sopenharmony_ci		}
45008c2ecf20Sopenharmony_ci	}
45018c2ecf20Sopenharmony_ci}
45028c2ecf20Sopenharmony_ci
45038c2ecf20Sopenharmony_cistatic void qla4xxx_check_relogin_flash_ddb(struct iscsi_cls_session *cls_sess)
45048c2ecf20Sopenharmony_ci{
45058c2ecf20Sopenharmony_ci	struct iscsi_session *sess;
45068c2ecf20Sopenharmony_ci	struct ddb_entry *ddb_entry;
45078c2ecf20Sopenharmony_ci	struct scsi_qla_host *ha;
45088c2ecf20Sopenharmony_ci
45098c2ecf20Sopenharmony_ci	sess = cls_sess->dd_data;
45108c2ecf20Sopenharmony_ci	ddb_entry = sess->dd_data;
45118c2ecf20Sopenharmony_ci	ha = ddb_entry->ha;
45128c2ecf20Sopenharmony_ci
45138c2ecf20Sopenharmony_ci	if (!(ddb_entry->ddb_type == FLASH_DDB))
45148c2ecf20Sopenharmony_ci		return;
45158c2ecf20Sopenharmony_ci
45168c2ecf20Sopenharmony_ci	if (adapter_up(ha) && !test_bit(DF_RELOGIN, &ddb_entry->flags) &&
45178c2ecf20Sopenharmony_ci	    !iscsi_is_session_online(cls_sess)) {
45188c2ecf20Sopenharmony_ci		if (atomic_read(&ddb_entry->retry_relogin_timer) !=
45198c2ecf20Sopenharmony_ci		    INVALID_ENTRY) {
45208c2ecf20Sopenharmony_ci			if (atomic_read(&ddb_entry->retry_relogin_timer) ==
45218c2ecf20Sopenharmony_ci					0) {
45228c2ecf20Sopenharmony_ci				atomic_set(&ddb_entry->retry_relogin_timer,
45238c2ecf20Sopenharmony_ci					   INVALID_ENTRY);
45248c2ecf20Sopenharmony_ci				set_bit(DPC_RELOGIN_DEVICE, &ha->dpc_flags);
45258c2ecf20Sopenharmony_ci				set_bit(DF_RELOGIN, &ddb_entry->flags);
45268c2ecf20Sopenharmony_ci				DEBUG2(ql4_printk(KERN_INFO, ha,
45278c2ecf20Sopenharmony_ci				       "%s: index [%d] login device\n",
45288c2ecf20Sopenharmony_ci					__func__, ddb_entry->fw_ddb_index));
45298c2ecf20Sopenharmony_ci			} else
45308c2ecf20Sopenharmony_ci				atomic_dec(&ddb_entry->retry_relogin_timer);
45318c2ecf20Sopenharmony_ci		}
45328c2ecf20Sopenharmony_ci	}
45338c2ecf20Sopenharmony_ci
45348c2ecf20Sopenharmony_ci	/* Wait for relogin to timeout */
45358c2ecf20Sopenharmony_ci	if (atomic_read(&ddb_entry->relogin_timer) &&
45368c2ecf20Sopenharmony_ci	    (atomic_dec_and_test(&ddb_entry->relogin_timer) != 0)) {
45378c2ecf20Sopenharmony_ci		/*
45388c2ecf20Sopenharmony_ci		 * If the relogin times out and the device is
45398c2ecf20Sopenharmony_ci		 * still NOT ONLINE then try and relogin again.
45408c2ecf20Sopenharmony_ci		 */
45418c2ecf20Sopenharmony_ci		if (!iscsi_is_session_online(cls_sess)) {
45428c2ecf20Sopenharmony_ci			/* Reset retry relogin timer */
45438c2ecf20Sopenharmony_ci			atomic_inc(&ddb_entry->relogin_retry_count);
45448c2ecf20Sopenharmony_ci			DEBUG2(ql4_printk(KERN_INFO, ha,
45458c2ecf20Sopenharmony_ci				"%s: index[%d] relogin timed out-retrying"
45468c2ecf20Sopenharmony_ci				" relogin (%d), retry (%d)\n", __func__,
45478c2ecf20Sopenharmony_ci				ddb_entry->fw_ddb_index,
45488c2ecf20Sopenharmony_ci				atomic_read(&ddb_entry->relogin_retry_count),
45498c2ecf20Sopenharmony_ci				ddb_entry->default_time2wait + 4));
45508c2ecf20Sopenharmony_ci			set_bit(DPC_RELOGIN_DEVICE, &ha->dpc_flags);
45518c2ecf20Sopenharmony_ci			atomic_set(&ddb_entry->retry_relogin_timer,
45528c2ecf20Sopenharmony_ci				   ddb_entry->default_time2wait + 4);
45538c2ecf20Sopenharmony_ci		}
45548c2ecf20Sopenharmony_ci	}
45558c2ecf20Sopenharmony_ci}
45568c2ecf20Sopenharmony_ci
45578c2ecf20Sopenharmony_ci/**
45588c2ecf20Sopenharmony_ci * qla4xxx_timer - checks every second for work to do.
45598c2ecf20Sopenharmony_ci * @t: Context to obtain pointer to host adapter structure.
45608c2ecf20Sopenharmony_ci **/
45618c2ecf20Sopenharmony_cistatic void qla4xxx_timer(struct timer_list *t)
45628c2ecf20Sopenharmony_ci{
45638c2ecf20Sopenharmony_ci	struct scsi_qla_host *ha = from_timer(ha, t, timer);
45648c2ecf20Sopenharmony_ci	int start_dpc = 0;
45658c2ecf20Sopenharmony_ci	uint16_t w;
45668c2ecf20Sopenharmony_ci
45678c2ecf20Sopenharmony_ci	iscsi_host_for_each_session(ha->host, qla4xxx_check_relogin_flash_ddb);
45688c2ecf20Sopenharmony_ci
45698c2ecf20Sopenharmony_ci	/* If we are in the middle of AER/EEH processing
45708c2ecf20Sopenharmony_ci	 * skip any processing and reschedule the timer
45718c2ecf20Sopenharmony_ci	 */
45728c2ecf20Sopenharmony_ci	if (test_bit(AF_EEH_BUSY, &ha->flags)) {
45738c2ecf20Sopenharmony_ci		mod_timer(&ha->timer, jiffies + HZ);
45748c2ecf20Sopenharmony_ci		return;
45758c2ecf20Sopenharmony_ci	}
45768c2ecf20Sopenharmony_ci
45778c2ecf20Sopenharmony_ci	/* Hardware read to trigger an EEH error during mailbox waits. */
45788c2ecf20Sopenharmony_ci	if (!pci_channel_offline(ha->pdev))
45798c2ecf20Sopenharmony_ci		pci_read_config_word(ha->pdev, PCI_VENDOR_ID, &w);
45808c2ecf20Sopenharmony_ci
45818c2ecf20Sopenharmony_ci	if (is_qla80XX(ha))
45828c2ecf20Sopenharmony_ci		qla4_8xxx_watchdog(ha);
45838c2ecf20Sopenharmony_ci
45848c2ecf20Sopenharmony_ci	if (is_qla40XX(ha)) {
45858c2ecf20Sopenharmony_ci		/* Check for heartbeat interval. */
45868c2ecf20Sopenharmony_ci		if (ha->firmware_options & FWOPT_HEARTBEAT_ENABLE &&
45878c2ecf20Sopenharmony_ci		    ha->heartbeat_interval != 0) {
45888c2ecf20Sopenharmony_ci			ha->seconds_since_last_heartbeat++;
45898c2ecf20Sopenharmony_ci			if (ha->seconds_since_last_heartbeat >
45908c2ecf20Sopenharmony_ci			    ha->heartbeat_interval + 2)
45918c2ecf20Sopenharmony_ci				set_bit(DPC_RESET_HA, &ha->dpc_flags);
45928c2ecf20Sopenharmony_ci		}
45938c2ecf20Sopenharmony_ci	}
45948c2ecf20Sopenharmony_ci
45958c2ecf20Sopenharmony_ci	/* Process any deferred work. */
45968c2ecf20Sopenharmony_ci	if (!list_empty(&ha->work_list))
45978c2ecf20Sopenharmony_ci		start_dpc++;
45988c2ecf20Sopenharmony_ci
45998c2ecf20Sopenharmony_ci	/* Wakeup the dpc routine for this adapter, if needed. */
46008c2ecf20Sopenharmony_ci	if (start_dpc ||
46018c2ecf20Sopenharmony_ci	     test_bit(DPC_RESET_HA, &ha->dpc_flags) ||
46028c2ecf20Sopenharmony_ci	     test_bit(DPC_RETRY_RESET_HA, &ha->dpc_flags) ||
46038c2ecf20Sopenharmony_ci	     test_bit(DPC_RELOGIN_DEVICE, &ha->dpc_flags) ||
46048c2ecf20Sopenharmony_ci	     test_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags) ||
46058c2ecf20Sopenharmony_ci	     test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags) ||
46068c2ecf20Sopenharmony_ci	     test_bit(DPC_GET_DHCP_IP_ADDR, &ha->dpc_flags) ||
46078c2ecf20Sopenharmony_ci	     test_bit(DPC_LINK_CHANGED, &ha->dpc_flags) ||
46088c2ecf20Sopenharmony_ci	     test_bit(DPC_HA_UNRECOVERABLE, &ha->dpc_flags) ||
46098c2ecf20Sopenharmony_ci	     test_bit(DPC_HA_NEED_QUIESCENT, &ha->dpc_flags) ||
46108c2ecf20Sopenharmony_ci	     test_bit(DPC_SYSFS_DDB_EXPORT, &ha->dpc_flags) ||
46118c2ecf20Sopenharmony_ci	     test_bit(DPC_AEN, &ha->dpc_flags)) {
46128c2ecf20Sopenharmony_ci		DEBUG2(printk("scsi%ld: %s: scheduling dpc routine"
46138c2ecf20Sopenharmony_ci			      " - dpc flags = 0x%lx\n",
46148c2ecf20Sopenharmony_ci			      ha->host_no, __func__, ha->dpc_flags));
46158c2ecf20Sopenharmony_ci		qla4xxx_wake_dpc(ha);
46168c2ecf20Sopenharmony_ci	}
46178c2ecf20Sopenharmony_ci
46188c2ecf20Sopenharmony_ci	/* Reschedule timer thread to call us back in one second */
46198c2ecf20Sopenharmony_ci	mod_timer(&ha->timer, jiffies + HZ);
46208c2ecf20Sopenharmony_ci
46218c2ecf20Sopenharmony_ci	DEBUG2(ha->seconds_since_last_intr++);
46228c2ecf20Sopenharmony_ci}
46238c2ecf20Sopenharmony_ci
46248c2ecf20Sopenharmony_ci/**
46258c2ecf20Sopenharmony_ci * qla4xxx_cmd_wait - waits for all outstanding commands to complete
46268c2ecf20Sopenharmony_ci * @ha: Pointer to host adapter structure.
46278c2ecf20Sopenharmony_ci *
46288c2ecf20Sopenharmony_ci * This routine stalls the driver until all outstanding commands are returned.
46298c2ecf20Sopenharmony_ci * Caller must release the Hardware Lock prior to calling this routine.
46308c2ecf20Sopenharmony_ci **/
46318c2ecf20Sopenharmony_cistatic int qla4xxx_cmd_wait(struct scsi_qla_host *ha)
46328c2ecf20Sopenharmony_ci{
46338c2ecf20Sopenharmony_ci	uint32_t index = 0;
46348c2ecf20Sopenharmony_ci	unsigned long flags;
46358c2ecf20Sopenharmony_ci	struct scsi_cmnd *cmd;
46368c2ecf20Sopenharmony_ci	unsigned long wtime;
46378c2ecf20Sopenharmony_ci	uint32_t wtmo;
46388c2ecf20Sopenharmony_ci
46398c2ecf20Sopenharmony_ci	if (is_qla40XX(ha))
46408c2ecf20Sopenharmony_ci		wtmo = WAIT_CMD_TOV;
46418c2ecf20Sopenharmony_ci	else
46428c2ecf20Sopenharmony_ci		wtmo = ha->nx_reset_timeout / 2;
46438c2ecf20Sopenharmony_ci
46448c2ecf20Sopenharmony_ci	wtime = jiffies + (wtmo * HZ);
46458c2ecf20Sopenharmony_ci
46468c2ecf20Sopenharmony_ci	DEBUG2(ql4_printk(KERN_INFO, ha,
46478c2ecf20Sopenharmony_ci			  "Wait up to %u seconds for cmds to complete\n",
46488c2ecf20Sopenharmony_ci			  wtmo));
46498c2ecf20Sopenharmony_ci
46508c2ecf20Sopenharmony_ci	while (!time_after_eq(jiffies, wtime)) {
46518c2ecf20Sopenharmony_ci		spin_lock_irqsave(&ha->hardware_lock, flags);
46528c2ecf20Sopenharmony_ci		/* Find a command that hasn't completed. */
46538c2ecf20Sopenharmony_ci		for (index = 0; index < ha->host->can_queue; index++) {
46548c2ecf20Sopenharmony_ci			cmd = scsi_host_find_tag(ha->host, index);
46558c2ecf20Sopenharmony_ci			/*
46568c2ecf20Sopenharmony_ci			 * We cannot just check if the index is valid,
46578c2ecf20Sopenharmony_ci			 * becase if we are run from the scsi eh, then
46588c2ecf20Sopenharmony_ci			 * the scsi/block layer is going to prevent
46598c2ecf20Sopenharmony_ci			 * the tag from being released.
46608c2ecf20Sopenharmony_ci			 */
46618c2ecf20Sopenharmony_ci			if (cmd != NULL && CMD_SP(cmd))
46628c2ecf20Sopenharmony_ci				break;
46638c2ecf20Sopenharmony_ci		}
46648c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&ha->hardware_lock, flags);
46658c2ecf20Sopenharmony_ci
46668c2ecf20Sopenharmony_ci		/* If No Commands are pending, wait is complete */
46678c2ecf20Sopenharmony_ci		if (index == ha->host->can_queue)
46688c2ecf20Sopenharmony_ci			return QLA_SUCCESS;
46698c2ecf20Sopenharmony_ci
46708c2ecf20Sopenharmony_ci		msleep(1000);
46718c2ecf20Sopenharmony_ci	}
46728c2ecf20Sopenharmony_ci	/* If we timed out on waiting for commands to come back
46738c2ecf20Sopenharmony_ci	 * return ERROR. */
46748c2ecf20Sopenharmony_ci	return QLA_ERROR;
46758c2ecf20Sopenharmony_ci}
46768c2ecf20Sopenharmony_ci
46778c2ecf20Sopenharmony_ciint qla4xxx_hw_reset(struct scsi_qla_host *ha)
46788c2ecf20Sopenharmony_ci{
46798c2ecf20Sopenharmony_ci	uint32_t ctrl_status;
46808c2ecf20Sopenharmony_ci	unsigned long flags = 0;
46818c2ecf20Sopenharmony_ci
46828c2ecf20Sopenharmony_ci	DEBUG2(printk(KERN_ERR "scsi%ld: %s\n", ha->host_no, __func__));
46838c2ecf20Sopenharmony_ci
46848c2ecf20Sopenharmony_ci	if (ql4xxx_lock_drvr_wait(ha) != QLA_SUCCESS)
46858c2ecf20Sopenharmony_ci		return QLA_ERROR;
46868c2ecf20Sopenharmony_ci
46878c2ecf20Sopenharmony_ci	spin_lock_irqsave(&ha->hardware_lock, flags);
46888c2ecf20Sopenharmony_ci
46898c2ecf20Sopenharmony_ci	/*
46908c2ecf20Sopenharmony_ci	 * If the SCSI Reset Interrupt bit is set, clear it.
46918c2ecf20Sopenharmony_ci	 * Otherwise, the Soft Reset won't work.
46928c2ecf20Sopenharmony_ci	 */
46938c2ecf20Sopenharmony_ci	ctrl_status = readw(&ha->reg->ctrl_status);
46948c2ecf20Sopenharmony_ci	if ((ctrl_status & CSR_SCSI_RESET_INTR) != 0)
46958c2ecf20Sopenharmony_ci		writel(set_rmask(CSR_SCSI_RESET_INTR), &ha->reg->ctrl_status);
46968c2ecf20Sopenharmony_ci
46978c2ecf20Sopenharmony_ci	/* Issue Soft Reset */
46988c2ecf20Sopenharmony_ci	writel(set_rmask(CSR_SOFT_RESET), &ha->reg->ctrl_status);
46998c2ecf20Sopenharmony_ci	readl(&ha->reg->ctrl_status);
47008c2ecf20Sopenharmony_ci
47018c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&ha->hardware_lock, flags);
47028c2ecf20Sopenharmony_ci	return QLA_SUCCESS;
47038c2ecf20Sopenharmony_ci}
47048c2ecf20Sopenharmony_ci
47058c2ecf20Sopenharmony_ci/**
47068c2ecf20Sopenharmony_ci * qla4xxx_soft_reset - performs soft reset.
47078c2ecf20Sopenharmony_ci * @ha: Pointer to host adapter structure.
47088c2ecf20Sopenharmony_ci **/
47098c2ecf20Sopenharmony_ciint qla4xxx_soft_reset(struct scsi_qla_host *ha)
47108c2ecf20Sopenharmony_ci{
47118c2ecf20Sopenharmony_ci	uint32_t max_wait_time;
47128c2ecf20Sopenharmony_ci	unsigned long flags = 0;
47138c2ecf20Sopenharmony_ci	int status;
47148c2ecf20Sopenharmony_ci	uint32_t ctrl_status;
47158c2ecf20Sopenharmony_ci
47168c2ecf20Sopenharmony_ci	status = qla4xxx_hw_reset(ha);
47178c2ecf20Sopenharmony_ci	if (status != QLA_SUCCESS)
47188c2ecf20Sopenharmony_ci		return status;
47198c2ecf20Sopenharmony_ci
47208c2ecf20Sopenharmony_ci	status = QLA_ERROR;
47218c2ecf20Sopenharmony_ci	/* Wait until the Network Reset Intr bit is cleared */
47228c2ecf20Sopenharmony_ci	max_wait_time = RESET_INTR_TOV;
47238c2ecf20Sopenharmony_ci	do {
47248c2ecf20Sopenharmony_ci		spin_lock_irqsave(&ha->hardware_lock, flags);
47258c2ecf20Sopenharmony_ci		ctrl_status = readw(&ha->reg->ctrl_status);
47268c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&ha->hardware_lock, flags);
47278c2ecf20Sopenharmony_ci
47288c2ecf20Sopenharmony_ci		if ((ctrl_status & CSR_NET_RESET_INTR) == 0)
47298c2ecf20Sopenharmony_ci			break;
47308c2ecf20Sopenharmony_ci
47318c2ecf20Sopenharmony_ci		msleep(1000);
47328c2ecf20Sopenharmony_ci	} while ((--max_wait_time));
47338c2ecf20Sopenharmony_ci
47348c2ecf20Sopenharmony_ci	if ((ctrl_status & CSR_NET_RESET_INTR) != 0) {
47358c2ecf20Sopenharmony_ci		DEBUG2(printk(KERN_WARNING
47368c2ecf20Sopenharmony_ci			      "scsi%ld: Network Reset Intr not cleared by "
47378c2ecf20Sopenharmony_ci			      "Network function, clearing it now!\n",
47388c2ecf20Sopenharmony_ci			      ha->host_no));
47398c2ecf20Sopenharmony_ci		spin_lock_irqsave(&ha->hardware_lock, flags);
47408c2ecf20Sopenharmony_ci		writel(set_rmask(CSR_NET_RESET_INTR), &ha->reg->ctrl_status);
47418c2ecf20Sopenharmony_ci		readl(&ha->reg->ctrl_status);
47428c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&ha->hardware_lock, flags);
47438c2ecf20Sopenharmony_ci	}
47448c2ecf20Sopenharmony_ci
47458c2ecf20Sopenharmony_ci	/* Wait until the firmware tells us the Soft Reset is done */
47468c2ecf20Sopenharmony_ci	max_wait_time = SOFT_RESET_TOV;
47478c2ecf20Sopenharmony_ci	do {
47488c2ecf20Sopenharmony_ci		spin_lock_irqsave(&ha->hardware_lock, flags);
47498c2ecf20Sopenharmony_ci		ctrl_status = readw(&ha->reg->ctrl_status);
47508c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&ha->hardware_lock, flags);
47518c2ecf20Sopenharmony_ci
47528c2ecf20Sopenharmony_ci		if ((ctrl_status & CSR_SOFT_RESET) == 0) {
47538c2ecf20Sopenharmony_ci			status = QLA_SUCCESS;
47548c2ecf20Sopenharmony_ci			break;
47558c2ecf20Sopenharmony_ci		}
47568c2ecf20Sopenharmony_ci
47578c2ecf20Sopenharmony_ci		msleep(1000);
47588c2ecf20Sopenharmony_ci	} while ((--max_wait_time));
47598c2ecf20Sopenharmony_ci
47608c2ecf20Sopenharmony_ci	/*
47618c2ecf20Sopenharmony_ci	 * Also, make sure that the SCSI Reset Interrupt bit has been cleared
47628c2ecf20Sopenharmony_ci	 * after the soft reset has taken place.
47638c2ecf20Sopenharmony_ci	 */
47648c2ecf20Sopenharmony_ci	spin_lock_irqsave(&ha->hardware_lock, flags);
47658c2ecf20Sopenharmony_ci	ctrl_status = readw(&ha->reg->ctrl_status);
47668c2ecf20Sopenharmony_ci	if ((ctrl_status & CSR_SCSI_RESET_INTR) != 0) {
47678c2ecf20Sopenharmony_ci		writel(set_rmask(CSR_SCSI_RESET_INTR), &ha->reg->ctrl_status);
47688c2ecf20Sopenharmony_ci		readl(&ha->reg->ctrl_status);
47698c2ecf20Sopenharmony_ci	}
47708c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&ha->hardware_lock, flags);
47718c2ecf20Sopenharmony_ci
47728c2ecf20Sopenharmony_ci	/* If soft reset fails then most probably the bios on other
47738c2ecf20Sopenharmony_ci	 * function is also enabled.
47748c2ecf20Sopenharmony_ci	 * Since the initialization is sequential the other fn
47758c2ecf20Sopenharmony_ci	 * wont be able to acknowledge the soft reset.
47768c2ecf20Sopenharmony_ci	 * Issue a force soft reset to workaround this scenario.
47778c2ecf20Sopenharmony_ci	 */
47788c2ecf20Sopenharmony_ci	if (max_wait_time == 0) {
47798c2ecf20Sopenharmony_ci		/* Issue Force Soft Reset */
47808c2ecf20Sopenharmony_ci		spin_lock_irqsave(&ha->hardware_lock, flags);
47818c2ecf20Sopenharmony_ci		writel(set_rmask(CSR_FORCE_SOFT_RESET), &ha->reg->ctrl_status);
47828c2ecf20Sopenharmony_ci		readl(&ha->reg->ctrl_status);
47838c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&ha->hardware_lock, flags);
47848c2ecf20Sopenharmony_ci		/* Wait until the firmware tells us the Soft Reset is done */
47858c2ecf20Sopenharmony_ci		max_wait_time = SOFT_RESET_TOV;
47868c2ecf20Sopenharmony_ci		do {
47878c2ecf20Sopenharmony_ci			spin_lock_irqsave(&ha->hardware_lock, flags);
47888c2ecf20Sopenharmony_ci			ctrl_status = readw(&ha->reg->ctrl_status);
47898c2ecf20Sopenharmony_ci			spin_unlock_irqrestore(&ha->hardware_lock, flags);
47908c2ecf20Sopenharmony_ci
47918c2ecf20Sopenharmony_ci			if ((ctrl_status & CSR_FORCE_SOFT_RESET) == 0) {
47928c2ecf20Sopenharmony_ci				status = QLA_SUCCESS;
47938c2ecf20Sopenharmony_ci				break;
47948c2ecf20Sopenharmony_ci			}
47958c2ecf20Sopenharmony_ci
47968c2ecf20Sopenharmony_ci			msleep(1000);
47978c2ecf20Sopenharmony_ci		} while ((--max_wait_time));
47988c2ecf20Sopenharmony_ci	}
47998c2ecf20Sopenharmony_ci
48008c2ecf20Sopenharmony_ci	return status;
48018c2ecf20Sopenharmony_ci}
48028c2ecf20Sopenharmony_ci
48038c2ecf20Sopenharmony_ci/**
48048c2ecf20Sopenharmony_ci * qla4xxx_abort_active_cmds - returns all outstanding i/o requests to O.S.
48058c2ecf20Sopenharmony_ci * @ha: Pointer to host adapter structure.
48068c2ecf20Sopenharmony_ci * @res: returned scsi status
48078c2ecf20Sopenharmony_ci *
48088c2ecf20Sopenharmony_ci * This routine is called just prior to a HARD RESET to return all
48098c2ecf20Sopenharmony_ci * outstanding commands back to the Operating System.
48108c2ecf20Sopenharmony_ci * Caller should make sure that the following locks are released
48118c2ecf20Sopenharmony_ci * before this calling routine: Hardware lock, and io_request_lock.
48128c2ecf20Sopenharmony_ci **/
48138c2ecf20Sopenharmony_cistatic void qla4xxx_abort_active_cmds(struct scsi_qla_host *ha, int res)
48148c2ecf20Sopenharmony_ci{
48158c2ecf20Sopenharmony_ci	struct srb *srb;
48168c2ecf20Sopenharmony_ci	int i;
48178c2ecf20Sopenharmony_ci	unsigned long flags;
48188c2ecf20Sopenharmony_ci
48198c2ecf20Sopenharmony_ci	spin_lock_irqsave(&ha->hardware_lock, flags);
48208c2ecf20Sopenharmony_ci	for (i = 0; i < ha->host->can_queue; i++) {
48218c2ecf20Sopenharmony_ci		srb = qla4xxx_del_from_active_array(ha, i);
48228c2ecf20Sopenharmony_ci		if (srb != NULL) {
48238c2ecf20Sopenharmony_ci			srb->cmd->result = res;
48248c2ecf20Sopenharmony_ci			kref_put(&srb->srb_ref, qla4xxx_srb_compl);
48258c2ecf20Sopenharmony_ci		}
48268c2ecf20Sopenharmony_ci	}
48278c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&ha->hardware_lock, flags);
48288c2ecf20Sopenharmony_ci}
48298c2ecf20Sopenharmony_ci
48308c2ecf20Sopenharmony_civoid qla4xxx_dead_adapter_cleanup(struct scsi_qla_host *ha)
48318c2ecf20Sopenharmony_ci{
48328c2ecf20Sopenharmony_ci	clear_bit(AF_ONLINE, &ha->flags);
48338c2ecf20Sopenharmony_ci
48348c2ecf20Sopenharmony_ci	/* Disable the board */
48358c2ecf20Sopenharmony_ci	ql4_printk(KERN_INFO, ha, "Disabling the board\n");
48368c2ecf20Sopenharmony_ci
48378c2ecf20Sopenharmony_ci	qla4xxx_abort_active_cmds(ha, DID_NO_CONNECT << 16);
48388c2ecf20Sopenharmony_ci	qla4xxx_mark_all_devices_missing(ha);
48398c2ecf20Sopenharmony_ci	clear_bit(AF_INIT_DONE, &ha->flags);
48408c2ecf20Sopenharmony_ci}
48418c2ecf20Sopenharmony_ci
48428c2ecf20Sopenharmony_cistatic void qla4xxx_fail_session(struct iscsi_cls_session *cls_session)
48438c2ecf20Sopenharmony_ci{
48448c2ecf20Sopenharmony_ci	struct iscsi_session *sess;
48458c2ecf20Sopenharmony_ci	struct ddb_entry *ddb_entry;
48468c2ecf20Sopenharmony_ci
48478c2ecf20Sopenharmony_ci	sess = cls_session->dd_data;
48488c2ecf20Sopenharmony_ci	ddb_entry = sess->dd_data;
48498c2ecf20Sopenharmony_ci	ddb_entry->fw_ddb_device_state = DDB_DS_SESSION_FAILED;
48508c2ecf20Sopenharmony_ci
48518c2ecf20Sopenharmony_ci	if (ddb_entry->ddb_type == FLASH_DDB)
48528c2ecf20Sopenharmony_ci		iscsi_block_session(ddb_entry->sess);
48538c2ecf20Sopenharmony_ci	else
48548c2ecf20Sopenharmony_ci		iscsi_session_failure(cls_session->dd_data,
48558c2ecf20Sopenharmony_ci				      ISCSI_ERR_CONN_FAILED);
48568c2ecf20Sopenharmony_ci}
48578c2ecf20Sopenharmony_ci
48588c2ecf20Sopenharmony_ci/**
48598c2ecf20Sopenharmony_ci * qla4xxx_recover_adapter - recovers adapter after a fatal error
48608c2ecf20Sopenharmony_ci * @ha: Pointer to host adapter structure.
48618c2ecf20Sopenharmony_ci **/
48628c2ecf20Sopenharmony_cistatic int qla4xxx_recover_adapter(struct scsi_qla_host *ha)
48638c2ecf20Sopenharmony_ci{
48648c2ecf20Sopenharmony_ci	int status = QLA_ERROR;
48658c2ecf20Sopenharmony_ci	uint8_t reset_chip = 0;
48668c2ecf20Sopenharmony_ci	uint32_t dev_state;
48678c2ecf20Sopenharmony_ci	unsigned long wait;
48688c2ecf20Sopenharmony_ci
48698c2ecf20Sopenharmony_ci	/* Stall incoming I/O until we are done */
48708c2ecf20Sopenharmony_ci	scsi_block_requests(ha->host);
48718c2ecf20Sopenharmony_ci	clear_bit(AF_ONLINE, &ha->flags);
48728c2ecf20Sopenharmony_ci	clear_bit(AF_LINK_UP, &ha->flags);
48738c2ecf20Sopenharmony_ci
48748c2ecf20Sopenharmony_ci	DEBUG2(ql4_printk(KERN_INFO, ha, "%s: adapter OFFLINE\n", __func__));
48758c2ecf20Sopenharmony_ci
48768c2ecf20Sopenharmony_ci	set_bit(DPC_RESET_ACTIVE, &ha->dpc_flags);
48778c2ecf20Sopenharmony_ci
48788c2ecf20Sopenharmony_ci	if ((is_qla8032(ha) || is_qla8042(ha)) &&
48798c2ecf20Sopenharmony_ci	    !test_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags)) {
48808c2ecf20Sopenharmony_ci		ql4_printk(KERN_INFO, ha, "%s: disabling pause transmit on port 0 & 1.\n",
48818c2ecf20Sopenharmony_ci			   __func__);
48828c2ecf20Sopenharmony_ci		/* disable pause frame for ISP83xx */
48838c2ecf20Sopenharmony_ci		qla4_83xx_disable_pause(ha);
48848c2ecf20Sopenharmony_ci	}
48858c2ecf20Sopenharmony_ci
48868c2ecf20Sopenharmony_ci	iscsi_host_for_each_session(ha->host, qla4xxx_fail_session);
48878c2ecf20Sopenharmony_ci
48888c2ecf20Sopenharmony_ci	if (test_bit(DPC_RESET_HA, &ha->dpc_flags))
48898c2ecf20Sopenharmony_ci		reset_chip = 1;
48908c2ecf20Sopenharmony_ci
48918c2ecf20Sopenharmony_ci	/* For the DPC_RESET_HA_INTR case (ISP-4xxx specific)
48928c2ecf20Sopenharmony_ci	 * do not reset adapter, jump to initialize_adapter */
48938c2ecf20Sopenharmony_ci	if (test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags)) {
48948c2ecf20Sopenharmony_ci		status = QLA_SUCCESS;
48958c2ecf20Sopenharmony_ci		goto recover_ha_init_adapter;
48968c2ecf20Sopenharmony_ci	}
48978c2ecf20Sopenharmony_ci
48988c2ecf20Sopenharmony_ci	/* For the ISP-8xxx adapter, issue a stop_firmware if invoked
48998c2ecf20Sopenharmony_ci	 * from eh_host_reset or ioctl module */
49008c2ecf20Sopenharmony_ci	if (is_qla80XX(ha) && !reset_chip &&
49018c2ecf20Sopenharmony_ci	    test_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags)) {
49028c2ecf20Sopenharmony_ci
49038c2ecf20Sopenharmony_ci		DEBUG2(ql4_printk(KERN_INFO, ha,
49048c2ecf20Sopenharmony_ci		    "scsi%ld: %s - Performing stop_firmware...\n",
49058c2ecf20Sopenharmony_ci		    ha->host_no, __func__));
49068c2ecf20Sopenharmony_ci		status = ha->isp_ops->reset_firmware(ha);
49078c2ecf20Sopenharmony_ci		if (status == QLA_SUCCESS) {
49088c2ecf20Sopenharmony_ci			ha->isp_ops->disable_intrs(ha);
49098c2ecf20Sopenharmony_ci			qla4xxx_process_aen(ha, FLUSH_DDB_CHANGED_AENS);
49108c2ecf20Sopenharmony_ci			qla4xxx_abort_active_cmds(ha, DID_RESET << 16);
49118c2ecf20Sopenharmony_ci		} else {
49128c2ecf20Sopenharmony_ci			/* If the stop_firmware fails then
49138c2ecf20Sopenharmony_ci			 * reset the entire chip */
49148c2ecf20Sopenharmony_ci			reset_chip = 1;
49158c2ecf20Sopenharmony_ci			clear_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags);
49168c2ecf20Sopenharmony_ci			set_bit(DPC_RESET_HA, &ha->dpc_flags);
49178c2ecf20Sopenharmony_ci		}
49188c2ecf20Sopenharmony_ci	}
49198c2ecf20Sopenharmony_ci
49208c2ecf20Sopenharmony_ci	/* Issue full chip reset if recovering from a catastrophic error,
49218c2ecf20Sopenharmony_ci	 * or if stop_firmware fails for ISP-8xxx.
49228c2ecf20Sopenharmony_ci	 * This is the default case for ISP-4xxx */
49238c2ecf20Sopenharmony_ci	if (is_qla40XX(ha) || reset_chip) {
49248c2ecf20Sopenharmony_ci		if (is_qla40XX(ha))
49258c2ecf20Sopenharmony_ci			goto chip_reset;
49268c2ecf20Sopenharmony_ci
49278c2ecf20Sopenharmony_ci		/* Check if 8XXX firmware is alive or not
49288c2ecf20Sopenharmony_ci		 * We may have arrived here from NEED_RESET
49298c2ecf20Sopenharmony_ci		 * detection only */
49308c2ecf20Sopenharmony_ci		if (test_bit(AF_FW_RECOVERY, &ha->flags))
49318c2ecf20Sopenharmony_ci			goto chip_reset;
49328c2ecf20Sopenharmony_ci
49338c2ecf20Sopenharmony_ci		wait = jiffies + (FW_ALIVE_WAIT_TOV * HZ);
49348c2ecf20Sopenharmony_ci		while (time_before(jiffies, wait)) {
49358c2ecf20Sopenharmony_ci			if (qla4_8xxx_check_fw_alive(ha)) {
49368c2ecf20Sopenharmony_ci				qla4xxx_mailbox_premature_completion(ha);
49378c2ecf20Sopenharmony_ci				break;
49388c2ecf20Sopenharmony_ci			}
49398c2ecf20Sopenharmony_ci
49408c2ecf20Sopenharmony_ci			set_current_state(TASK_UNINTERRUPTIBLE);
49418c2ecf20Sopenharmony_ci			schedule_timeout(HZ);
49428c2ecf20Sopenharmony_ci		}
49438c2ecf20Sopenharmony_cichip_reset:
49448c2ecf20Sopenharmony_ci		if (!test_bit(AF_FW_RECOVERY, &ha->flags))
49458c2ecf20Sopenharmony_ci			qla4xxx_cmd_wait(ha);
49468c2ecf20Sopenharmony_ci
49478c2ecf20Sopenharmony_ci		qla4xxx_process_aen(ha, FLUSH_DDB_CHANGED_AENS);
49488c2ecf20Sopenharmony_ci		DEBUG2(ql4_printk(KERN_INFO, ha,
49498c2ecf20Sopenharmony_ci		    "scsi%ld: %s - Performing chip reset..\n",
49508c2ecf20Sopenharmony_ci		    ha->host_no, __func__));
49518c2ecf20Sopenharmony_ci		status = ha->isp_ops->reset_chip(ha);
49528c2ecf20Sopenharmony_ci		qla4xxx_abort_active_cmds(ha, DID_RESET << 16);
49538c2ecf20Sopenharmony_ci	}
49548c2ecf20Sopenharmony_ci
49558c2ecf20Sopenharmony_ci	/* Flush any pending ddb changed AENs */
49568c2ecf20Sopenharmony_ci	qla4xxx_process_aen(ha, FLUSH_DDB_CHANGED_AENS);
49578c2ecf20Sopenharmony_ci
49588c2ecf20Sopenharmony_cirecover_ha_init_adapter:
49598c2ecf20Sopenharmony_ci	/* Upon successful firmware/chip reset, re-initialize the adapter */
49608c2ecf20Sopenharmony_ci	if (status == QLA_SUCCESS) {
49618c2ecf20Sopenharmony_ci		/* For ISP-4xxx, force function 1 to always initialize
49628c2ecf20Sopenharmony_ci		 * before function 3 to prevent both funcions from
49638c2ecf20Sopenharmony_ci		 * stepping on top of the other */
49648c2ecf20Sopenharmony_ci		if (is_qla40XX(ha) && (ha->mac_index == 3))
49658c2ecf20Sopenharmony_ci			ssleep(6);
49668c2ecf20Sopenharmony_ci
49678c2ecf20Sopenharmony_ci		/* NOTE: AF_ONLINE flag set upon successful completion of
49688c2ecf20Sopenharmony_ci		 * qla4xxx_initialize_adapter */
49698c2ecf20Sopenharmony_ci		status = qla4xxx_initialize_adapter(ha, RESET_ADAPTER);
49708c2ecf20Sopenharmony_ci		if (is_qla80XX(ha) && (status == QLA_ERROR)) {
49718c2ecf20Sopenharmony_ci			status = qla4_8xxx_check_init_adapter_retry(ha);
49728c2ecf20Sopenharmony_ci			if (status == QLA_ERROR) {
49738c2ecf20Sopenharmony_ci				ql4_printk(KERN_INFO, ha, "scsi%ld: %s: Don't retry recover adapter\n",
49748c2ecf20Sopenharmony_ci					   ha->host_no, __func__);
49758c2ecf20Sopenharmony_ci				qla4xxx_dead_adapter_cleanup(ha);
49768c2ecf20Sopenharmony_ci				clear_bit(DPC_RETRY_RESET_HA, &ha->dpc_flags);
49778c2ecf20Sopenharmony_ci				clear_bit(DPC_RESET_HA, &ha->dpc_flags);
49788c2ecf20Sopenharmony_ci				clear_bit(DPC_RESET_HA_FW_CONTEXT,
49798c2ecf20Sopenharmony_ci					  &ha->dpc_flags);
49808c2ecf20Sopenharmony_ci				goto exit_recover;
49818c2ecf20Sopenharmony_ci			}
49828c2ecf20Sopenharmony_ci		}
49838c2ecf20Sopenharmony_ci	}
49848c2ecf20Sopenharmony_ci
49858c2ecf20Sopenharmony_ci	/* Retry failed adapter initialization, if necessary
49868c2ecf20Sopenharmony_ci	 * Do not retry initialize_adapter for RESET_HA_INTR (ISP-4xxx specific)
49878c2ecf20Sopenharmony_ci	 * case to prevent ping-pong resets between functions */
49888c2ecf20Sopenharmony_ci	if (!test_bit(AF_ONLINE, &ha->flags) &&
49898c2ecf20Sopenharmony_ci	    !test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags)) {
49908c2ecf20Sopenharmony_ci		/* Adapter initialization failed, see if we can retry
49918c2ecf20Sopenharmony_ci		 * resetting the ha.
49928c2ecf20Sopenharmony_ci		 * Since we don't want to block the DPC for too long
49938c2ecf20Sopenharmony_ci		 * with multiple resets in the same thread,
49948c2ecf20Sopenharmony_ci		 * utilize DPC to retry */
49958c2ecf20Sopenharmony_ci		if (is_qla80XX(ha)) {
49968c2ecf20Sopenharmony_ci			ha->isp_ops->idc_lock(ha);
49978c2ecf20Sopenharmony_ci			dev_state = qla4_8xxx_rd_direct(ha,
49988c2ecf20Sopenharmony_ci							QLA8XXX_CRB_DEV_STATE);
49998c2ecf20Sopenharmony_ci			ha->isp_ops->idc_unlock(ha);
50008c2ecf20Sopenharmony_ci			if (dev_state == QLA8XXX_DEV_FAILED) {
50018c2ecf20Sopenharmony_ci				ql4_printk(KERN_INFO, ha, "%s: don't retry "
50028c2ecf20Sopenharmony_ci					   "recover adapter. H/W is in Failed "
50038c2ecf20Sopenharmony_ci					   "state\n", __func__);
50048c2ecf20Sopenharmony_ci				qla4xxx_dead_adapter_cleanup(ha);
50058c2ecf20Sopenharmony_ci				clear_bit(DPC_RETRY_RESET_HA, &ha->dpc_flags);
50068c2ecf20Sopenharmony_ci				clear_bit(DPC_RESET_HA, &ha->dpc_flags);
50078c2ecf20Sopenharmony_ci				clear_bit(DPC_RESET_HA_FW_CONTEXT,
50088c2ecf20Sopenharmony_ci						&ha->dpc_flags);
50098c2ecf20Sopenharmony_ci				status = QLA_ERROR;
50108c2ecf20Sopenharmony_ci
50118c2ecf20Sopenharmony_ci				goto exit_recover;
50128c2ecf20Sopenharmony_ci			}
50138c2ecf20Sopenharmony_ci		}
50148c2ecf20Sopenharmony_ci
50158c2ecf20Sopenharmony_ci		if (!test_bit(DPC_RETRY_RESET_HA, &ha->dpc_flags)) {
50168c2ecf20Sopenharmony_ci			ha->retry_reset_ha_cnt = MAX_RESET_HA_RETRIES;
50178c2ecf20Sopenharmony_ci			DEBUG2(printk("scsi%ld: recover adapter - retrying "
50188c2ecf20Sopenharmony_ci				      "(%d) more times\n", ha->host_no,
50198c2ecf20Sopenharmony_ci				      ha->retry_reset_ha_cnt));
50208c2ecf20Sopenharmony_ci			set_bit(DPC_RETRY_RESET_HA, &ha->dpc_flags);
50218c2ecf20Sopenharmony_ci			status = QLA_ERROR;
50228c2ecf20Sopenharmony_ci		} else {
50238c2ecf20Sopenharmony_ci			if (ha->retry_reset_ha_cnt > 0) {
50248c2ecf20Sopenharmony_ci				/* Schedule another Reset HA--DPC will retry */
50258c2ecf20Sopenharmony_ci				ha->retry_reset_ha_cnt--;
50268c2ecf20Sopenharmony_ci				DEBUG2(printk("scsi%ld: recover adapter - "
50278c2ecf20Sopenharmony_ci					      "retry remaining %d\n",
50288c2ecf20Sopenharmony_ci					      ha->host_no,
50298c2ecf20Sopenharmony_ci					      ha->retry_reset_ha_cnt));
50308c2ecf20Sopenharmony_ci				status = QLA_ERROR;
50318c2ecf20Sopenharmony_ci			}
50328c2ecf20Sopenharmony_ci
50338c2ecf20Sopenharmony_ci			if (ha->retry_reset_ha_cnt == 0) {
50348c2ecf20Sopenharmony_ci				/* Recover adapter retries have been exhausted.
50358c2ecf20Sopenharmony_ci				 * Adapter DEAD */
50368c2ecf20Sopenharmony_ci				DEBUG2(printk("scsi%ld: recover adapter "
50378c2ecf20Sopenharmony_ci					      "failed - board disabled\n",
50388c2ecf20Sopenharmony_ci					      ha->host_no));
50398c2ecf20Sopenharmony_ci				qla4xxx_dead_adapter_cleanup(ha);
50408c2ecf20Sopenharmony_ci				clear_bit(DPC_RETRY_RESET_HA, &ha->dpc_flags);
50418c2ecf20Sopenharmony_ci				clear_bit(DPC_RESET_HA, &ha->dpc_flags);
50428c2ecf20Sopenharmony_ci				clear_bit(DPC_RESET_HA_FW_CONTEXT,
50438c2ecf20Sopenharmony_ci					  &ha->dpc_flags);
50448c2ecf20Sopenharmony_ci				status = QLA_ERROR;
50458c2ecf20Sopenharmony_ci			}
50468c2ecf20Sopenharmony_ci		}
50478c2ecf20Sopenharmony_ci	} else {
50488c2ecf20Sopenharmony_ci		clear_bit(DPC_RESET_HA, &ha->dpc_flags);
50498c2ecf20Sopenharmony_ci		clear_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags);
50508c2ecf20Sopenharmony_ci		clear_bit(DPC_RETRY_RESET_HA, &ha->dpc_flags);
50518c2ecf20Sopenharmony_ci	}
50528c2ecf20Sopenharmony_ci
50538c2ecf20Sopenharmony_ciexit_recover:
50548c2ecf20Sopenharmony_ci	ha->adapter_error_count++;
50558c2ecf20Sopenharmony_ci
50568c2ecf20Sopenharmony_ci	if (test_bit(AF_ONLINE, &ha->flags))
50578c2ecf20Sopenharmony_ci		ha->isp_ops->enable_intrs(ha);
50588c2ecf20Sopenharmony_ci
50598c2ecf20Sopenharmony_ci	scsi_unblock_requests(ha->host);
50608c2ecf20Sopenharmony_ci
50618c2ecf20Sopenharmony_ci	clear_bit(DPC_RESET_ACTIVE, &ha->dpc_flags);
50628c2ecf20Sopenharmony_ci	DEBUG2(printk("scsi%ld: recover adapter: %s\n", ha->host_no,
50638c2ecf20Sopenharmony_ci	    status == QLA_ERROR ? "FAILED" : "SUCCEEDED"));
50648c2ecf20Sopenharmony_ci
50658c2ecf20Sopenharmony_ci	return status;
50668c2ecf20Sopenharmony_ci}
50678c2ecf20Sopenharmony_ci
50688c2ecf20Sopenharmony_cistatic void qla4xxx_relogin_devices(struct iscsi_cls_session *cls_session)
50698c2ecf20Sopenharmony_ci{
50708c2ecf20Sopenharmony_ci	struct iscsi_session *sess;
50718c2ecf20Sopenharmony_ci	struct ddb_entry *ddb_entry;
50728c2ecf20Sopenharmony_ci	struct scsi_qla_host *ha;
50738c2ecf20Sopenharmony_ci
50748c2ecf20Sopenharmony_ci	sess = cls_session->dd_data;
50758c2ecf20Sopenharmony_ci	ddb_entry = sess->dd_data;
50768c2ecf20Sopenharmony_ci	ha = ddb_entry->ha;
50778c2ecf20Sopenharmony_ci	if (!iscsi_is_session_online(cls_session)) {
50788c2ecf20Sopenharmony_ci		if (ddb_entry->fw_ddb_device_state == DDB_DS_SESSION_ACTIVE) {
50798c2ecf20Sopenharmony_ci			ql4_printk(KERN_INFO, ha, "scsi%ld: %s: ddb[%d]"
50808c2ecf20Sopenharmony_ci				   " unblock session\n", ha->host_no, __func__,
50818c2ecf20Sopenharmony_ci				   ddb_entry->fw_ddb_index);
50828c2ecf20Sopenharmony_ci			iscsi_unblock_session(ddb_entry->sess);
50838c2ecf20Sopenharmony_ci		} else {
50848c2ecf20Sopenharmony_ci			/* Trigger relogin */
50858c2ecf20Sopenharmony_ci			if (ddb_entry->ddb_type == FLASH_DDB) {
50868c2ecf20Sopenharmony_ci				if (!(test_bit(DF_RELOGIN, &ddb_entry->flags) ||
50878c2ecf20Sopenharmony_ci				      test_bit(DF_DISABLE_RELOGIN,
50888c2ecf20Sopenharmony_ci					       &ddb_entry->flags)))
50898c2ecf20Sopenharmony_ci					qla4xxx_arm_relogin_timer(ddb_entry);
50908c2ecf20Sopenharmony_ci			} else
50918c2ecf20Sopenharmony_ci				iscsi_session_failure(cls_session->dd_data,
50928c2ecf20Sopenharmony_ci						      ISCSI_ERR_CONN_FAILED);
50938c2ecf20Sopenharmony_ci		}
50948c2ecf20Sopenharmony_ci	}
50958c2ecf20Sopenharmony_ci}
50968c2ecf20Sopenharmony_ci
50978c2ecf20Sopenharmony_ciint qla4xxx_unblock_flash_ddb(struct iscsi_cls_session *cls_session)
50988c2ecf20Sopenharmony_ci{
50998c2ecf20Sopenharmony_ci	struct iscsi_session *sess;
51008c2ecf20Sopenharmony_ci	struct ddb_entry *ddb_entry;
51018c2ecf20Sopenharmony_ci	struct scsi_qla_host *ha;
51028c2ecf20Sopenharmony_ci
51038c2ecf20Sopenharmony_ci	sess = cls_session->dd_data;
51048c2ecf20Sopenharmony_ci	ddb_entry = sess->dd_data;
51058c2ecf20Sopenharmony_ci	ha = ddb_entry->ha;
51068c2ecf20Sopenharmony_ci	ql4_printk(KERN_INFO, ha, "scsi%ld: %s: ddb[%d]"
51078c2ecf20Sopenharmony_ci		   " unblock session\n", ha->host_no, __func__,
51088c2ecf20Sopenharmony_ci		   ddb_entry->fw_ddb_index);
51098c2ecf20Sopenharmony_ci
51108c2ecf20Sopenharmony_ci	iscsi_unblock_session(ddb_entry->sess);
51118c2ecf20Sopenharmony_ci
51128c2ecf20Sopenharmony_ci	/* Start scan target */
51138c2ecf20Sopenharmony_ci	if (test_bit(AF_ONLINE, &ha->flags)) {
51148c2ecf20Sopenharmony_ci		ql4_printk(KERN_INFO, ha, "scsi%ld: %s: ddb[%d]"
51158c2ecf20Sopenharmony_ci			   " start scan\n", ha->host_no, __func__,
51168c2ecf20Sopenharmony_ci			   ddb_entry->fw_ddb_index);
51178c2ecf20Sopenharmony_ci		scsi_queue_work(ha->host, &ddb_entry->sess->scan_work);
51188c2ecf20Sopenharmony_ci	}
51198c2ecf20Sopenharmony_ci	return QLA_SUCCESS;
51208c2ecf20Sopenharmony_ci}
51218c2ecf20Sopenharmony_ci
51228c2ecf20Sopenharmony_ciint qla4xxx_unblock_ddb(struct iscsi_cls_session *cls_session)
51238c2ecf20Sopenharmony_ci{
51248c2ecf20Sopenharmony_ci	struct iscsi_session *sess;
51258c2ecf20Sopenharmony_ci	struct ddb_entry *ddb_entry;
51268c2ecf20Sopenharmony_ci	struct scsi_qla_host *ha;
51278c2ecf20Sopenharmony_ci	int status = QLA_SUCCESS;
51288c2ecf20Sopenharmony_ci
51298c2ecf20Sopenharmony_ci	sess = cls_session->dd_data;
51308c2ecf20Sopenharmony_ci	ddb_entry = sess->dd_data;
51318c2ecf20Sopenharmony_ci	ha = ddb_entry->ha;
51328c2ecf20Sopenharmony_ci	ql4_printk(KERN_INFO, ha, "scsi%ld: %s: ddb[%d]"
51338c2ecf20Sopenharmony_ci		   " unblock user space session\n", ha->host_no, __func__,
51348c2ecf20Sopenharmony_ci		   ddb_entry->fw_ddb_index);
51358c2ecf20Sopenharmony_ci
51368c2ecf20Sopenharmony_ci	if (!iscsi_is_session_online(cls_session)) {
51378c2ecf20Sopenharmony_ci		iscsi_conn_start(ddb_entry->conn);
51388c2ecf20Sopenharmony_ci		iscsi_conn_login_event(ddb_entry->conn,
51398c2ecf20Sopenharmony_ci				       ISCSI_CONN_STATE_LOGGED_IN);
51408c2ecf20Sopenharmony_ci	} else {
51418c2ecf20Sopenharmony_ci		ql4_printk(KERN_INFO, ha,
51428c2ecf20Sopenharmony_ci			   "scsi%ld: %s: ddb[%d] session [%d] already logged in\n",
51438c2ecf20Sopenharmony_ci			   ha->host_no, __func__, ddb_entry->fw_ddb_index,
51448c2ecf20Sopenharmony_ci			   cls_session->sid);
51458c2ecf20Sopenharmony_ci		status = QLA_ERROR;
51468c2ecf20Sopenharmony_ci	}
51478c2ecf20Sopenharmony_ci
51488c2ecf20Sopenharmony_ci	return status;
51498c2ecf20Sopenharmony_ci}
51508c2ecf20Sopenharmony_ci
51518c2ecf20Sopenharmony_cistatic void qla4xxx_relogin_all_devices(struct scsi_qla_host *ha)
51528c2ecf20Sopenharmony_ci{
51538c2ecf20Sopenharmony_ci	iscsi_host_for_each_session(ha->host, qla4xxx_relogin_devices);
51548c2ecf20Sopenharmony_ci}
51558c2ecf20Sopenharmony_ci
51568c2ecf20Sopenharmony_cistatic void qla4xxx_relogin_flash_ddb(struct iscsi_cls_session *cls_sess)
51578c2ecf20Sopenharmony_ci{
51588c2ecf20Sopenharmony_ci	uint16_t relogin_timer;
51598c2ecf20Sopenharmony_ci	struct iscsi_session *sess;
51608c2ecf20Sopenharmony_ci	struct ddb_entry *ddb_entry;
51618c2ecf20Sopenharmony_ci	struct scsi_qla_host *ha;
51628c2ecf20Sopenharmony_ci
51638c2ecf20Sopenharmony_ci	sess = cls_sess->dd_data;
51648c2ecf20Sopenharmony_ci	ddb_entry = sess->dd_data;
51658c2ecf20Sopenharmony_ci	ha = ddb_entry->ha;
51668c2ecf20Sopenharmony_ci
51678c2ecf20Sopenharmony_ci	relogin_timer = max(ddb_entry->default_relogin_timeout,
51688c2ecf20Sopenharmony_ci			    (uint16_t)RELOGIN_TOV);
51698c2ecf20Sopenharmony_ci	atomic_set(&ddb_entry->relogin_timer, relogin_timer);
51708c2ecf20Sopenharmony_ci
51718c2ecf20Sopenharmony_ci	DEBUG2(ql4_printk(KERN_INFO, ha,
51728c2ecf20Sopenharmony_ci			  "scsi%ld: Relogin index [%d]. TOV=%d\n", ha->host_no,
51738c2ecf20Sopenharmony_ci			  ddb_entry->fw_ddb_index, relogin_timer));
51748c2ecf20Sopenharmony_ci
51758c2ecf20Sopenharmony_ci	qla4xxx_login_flash_ddb(cls_sess);
51768c2ecf20Sopenharmony_ci}
51778c2ecf20Sopenharmony_ci
51788c2ecf20Sopenharmony_cistatic void qla4xxx_dpc_relogin(struct iscsi_cls_session *cls_sess)
51798c2ecf20Sopenharmony_ci{
51808c2ecf20Sopenharmony_ci	struct iscsi_session *sess;
51818c2ecf20Sopenharmony_ci	struct ddb_entry *ddb_entry;
51828c2ecf20Sopenharmony_ci	struct scsi_qla_host *ha;
51838c2ecf20Sopenharmony_ci
51848c2ecf20Sopenharmony_ci	sess = cls_sess->dd_data;
51858c2ecf20Sopenharmony_ci	ddb_entry = sess->dd_data;
51868c2ecf20Sopenharmony_ci	ha = ddb_entry->ha;
51878c2ecf20Sopenharmony_ci
51888c2ecf20Sopenharmony_ci	if (!(ddb_entry->ddb_type == FLASH_DDB))
51898c2ecf20Sopenharmony_ci		return;
51908c2ecf20Sopenharmony_ci
51918c2ecf20Sopenharmony_ci	if (test_bit(DF_DISABLE_RELOGIN, &ddb_entry->flags))
51928c2ecf20Sopenharmony_ci		return;
51938c2ecf20Sopenharmony_ci
51948c2ecf20Sopenharmony_ci	if (test_and_clear_bit(DF_RELOGIN, &ddb_entry->flags) &&
51958c2ecf20Sopenharmony_ci	    !iscsi_is_session_online(cls_sess)) {
51968c2ecf20Sopenharmony_ci		DEBUG2(ql4_printk(KERN_INFO, ha,
51978c2ecf20Sopenharmony_ci				  "relogin issued\n"));
51988c2ecf20Sopenharmony_ci		qla4xxx_relogin_flash_ddb(cls_sess);
51998c2ecf20Sopenharmony_ci	}
52008c2ecf20Sopenharmony_ci}
52018c2ecf20Sopenharmony_ci
52028c2ecf20Sopenharmony_civoid qla4xxx_wake_dpc(struct scsi_qla_host *ha)
52038c2ecf20Sopenharmony_ci{
52048c2ecf20Sopenharmony_ci	if (ha->dpc_thread)
52058c2ecf20Sopenharmony_ci		queue_work(ha->dpc_thread, &ha->dpc_work);
52068c2ecf20Sopenharmony_ci}
52078c2ecf20Sopenharmony_ci
52088c2ecf20Sopenharmony_cistatic struct qla4_work_evt *
52098c2ecf20Sopenharmony_ciqla4xxx_alloc_work(struct scsi_qla_host *ha, uint32_t data_size,
52108c2ecf20Sopenharmony_ci		   enum qla4_work_type type)
52118c2ecf20Sopenharmony_ci{
52128c2ecf20Sopenharmony_ci	struct qla4_work_evt *e;
52138c2ecf20Sopenharmony_ci	uint32_t size = sizeof(struct qla4_work_evt) + data_size;
52148c2ecf20Sopenharmony_ci
52158c2ecf20Sopenharmony_ci	e = kzalloc(size, GFP_ATOMIC);
52168c2ecf20Sopenharmony_ci	if (!e)
52178c2ecf20Sopenharmony_ci		return NULL;
52188c2ecf20Sopenharmony_ci
52198c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&e->list);
52208c2ecf20Sopenharmony_ci	e->type = type;
52218c2ecf20Sopenharmony_ci	return e;
52228c2ecf20Sopenharmony_ci}
52238c2ecf20Sopenharmony_ci
52248c2ecf20Sopenharmony_cistatic void qla4xxx_post_work(struct scsi_qla_host *ha,
52258c2ecf20Sopenharmony_ci			     struct qla4_work_evt *e)
52268c2ecf20Sopenharmony_ci{
52278c2ecf20Sopenharmony_ci	unsigned long flags;
52288c2ecf20Sopenharmony_ci
52298c2ecf20Sopenharmony_ci	spin_lock_irqsave(&ha->work_lock, flags);
52308c2ecf20Sopenharmony_ci	list_add_tail(&e->list, &ha->work_list);
52318c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&ha->work_lock, flags);
52328c2ecf20Sopenharmony_ci	qla4xxx_wake_dpc(ha);
52338c2ecf20Sopenharmony_ci}
52348c2ecf20Sopenharmony_ci
52358c2ecf20Sopenharmony_ciint qla4xxx_post_aen_work(struct scsi_qla_host *ha,
52368c2ecf20Sopenharmony_ci			  enum iscsi_host_event_code aen_code,
52378c2ecf20Sopenharmony_ci			  uint32_t data_size, uint8_t *data)
52388c2ecf20Sopenharmony_ci{
52398c2ecf20Sopenharmony_ci	struct qla4_work_evt *e;
52408c2ecf20Sopenharmony_ci
52418c2ecf20Sopenharmony_ci	e = qla4xxx_alloc_work(ha, data_size, QLA4_EVENT_AEN);
52428c2ecf20Sopenharmony_ci	if (!e)
52438c2ecf20Sopenharmony_ci		return QLA_ERROR;
52448c2ecf20Sopenharmony_ci
52458c2ecf20Sopenharmony_ci	e->u.aen.code = aen_code;
52468c2ecf20Sopenharmony_ci	e->u.aen.data_size = data_size;
52478c2ecf20Sopenharmony_ci	memcpy(e->u.aen.data, data, data_size);
52488c2ecf20Sopenharmony_ci
52498c2ecf20Sopenharmony_ci	qla4xxx_post_work(ha, e);
52508c2ecf20Sopenharmony_ci
52518c2ecf20Sopenharmony_ci	return QLA_SUCCESS;
52528c2ecf20Sopenharmony_ci}
52538c2ecf20Sopenharmony_ci
52548c2ecf20Sopenharmony_ciint qla4xxx_post_ping_evt_work(struct scsi_qla_host *ha,
52558c2ecf20Sopenharmony_ci			       uint32_t status, uint32_t pid,
52568c2ecf20Sopenharmony_ci			       uint32_t data_size, uint8_t *data)
52578c2ecf20Sopenharmony_ci{
52588c2ecf20Sopenharmony_ci	struct qla4_work_evt *e;
52598c2ecf20Sopenharmony_ci
52608c2ecf20Sopenharmony_ci	e = qla4xxx_alloc_work(ha, data_size, QLA4_EVENT_PING_STATUS);
52618c2ecf20Sopenharmony_ci	if (!e)
52628c2ecf20Sopenharmony_ci		return QLA_ERROR;
52638c2ecf20Sopenharmony_ci
52648c2ecf20Sopenharmony_ci	e->u.ping.status = status;
52658c2ecf20Sopenharmony_ci	e->u.ping.pid = pid;
52668c2ecf20Sopenharmony_ci	e->u.ping.data_size = data_size;
52678c2ecf20Sopenharmony_ci	memcpy(e->u.ping.data, data, data_size);
52688c2ecf20Sopenharmony_ci
52698c2ecf20Sopenharmony_ci	qla4xxx_post_work(ha, e);
52708c2ecf20Sopenharmony_ci
52718c2ecf20Sopenharmony_ci	return QLA_SUCCESS;
52728c2ecf20Sopenharmony_ci}
52738c2ecf20Sopenharmony_ci
52748c2ecf20Sopenharmony_cistatic void qla4xxx_do_work(struct scsi_qla_host *ha)
52758c2ecf20Sopenharmony_ci{
52768c2ecf20Sopenharmony_ci	struct qla4_work_evt *e, *tmp;
52778c2ecf20Sopenharmony_ci	unsigned long flags;
52788c2ecf20Sopenharmony_ci	LIST_HEAD(work);
52798c2ecf20Sopenharmony_ci
52808c2ecf20Sopenharmony_ci	spin_lock_irqsave(&ha->work_lock, flags);
52818c2ecf20Sopenharmony_ci	list_splice_init(&ha->work_list, &work);
52828c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&ha->work_lock, flags);
52838c2ecf20Sopenharmony_ci
52848c2ecf20Sopenharmony_ci	list_for_each_entry_safe(e, tmp, &work, list) {
52858c2ecf20Sopenharmony_ci		list_del_init(&e->list);
52868c2ecf20Sopenharmony_ci
52878c2ecf20Sopenharmony_ci		switch (e->type) {
52888c2ecf20Sopenharmony_ci		case QLA4_EVENT_AEN:
52898c2ecf20Sopenharmony_ci			iscsi_post_host_event(ha->host_no,
52908c2ecf20Sopenharmony_ci					      &qla4xxx_iscsi_transport,
52918c2ecf20Sopenharmony_ci					      e->u.aen.code,
52928c2ecf20Sopenharmony_ci					      e->u.aen.data_size,
52938c2ecf20Sopenharmony_ci					      e->u.aen.data);
52948c2ecf20Sopenharmony_ci			break;
52958c2ecf20Sopenharmony_ci		case QLA4_EVENT_PING_STATUS:
52968c2ecf20Sopenharmony_ci			iscsi_ping_comp_event(ha->host_no,
52978c2ecf20Sopenharmony_ci					      &qla4xxx_iscsi_transport,
52988c2ecf20Sopenharmony_ci					      e->u.ping.status,
52998c2ecf20Sopenharmony_ci					      e->u.ping.pid,
53008c2ecf20Sopenharmony_ci					      e->u.ping.data_size,
53018c2ecf20Sopenharmony_ci					      e->u.ping.data);
53028c2ecf20Sopenharmony_ci			break;
53038c2ecf20Sopenharmony_ci		default:
53048c2ecf20Sopenharmony_ci			ql4_printk(KERN_WARNING, ha, "event type: 0x%x not "
53058c2ecf20Sopenharmony_ci				   "supported", e->type);
53068c2ecf20Sopenharmony_ci		}
53078c2ecf20Sopenharmony_ci		kfree(e);
53088c2ecf20Sopenharmony_ci	}
53098c2ecf20Sopenharmony_ci}
53108c2ecf20Sopenharmony_ci
53118c2ecf20Sopenharmony_ci/**
53128c2ecf20Sopenharmony_ci * qla4xxx_do_dpc - dpc routine
53138c2ecf20Sopenharmony_ci * @work: Context to obtain pointer to host adapter structure.
53148c2ecf20Sopenharmony_ci *
53158c2ecf20Sopenharmony_ci * This routine is a task that is schedule by the interrupt handler
53168c2ecf20Sopenharmony_ci * to perform the background processing for interrupts.  We put it
53178c2ecf20Sopenharmony_ci * on a task queue that is consumed whenever the scheduler runs; that's
53188c2ecf20Sopenharmony_ci * so you can do anything (i.e. put the process to sleep etc).  In fact,
53198c2ecf20Sopenharmony_ci * the mid-level tries to sleep when it reaches the driver threshold
53208c2ecf20Sopenharmony_ci * "host->can_queue". This can cause a panic if we were in our interrupt code.
53218c2ecf20Sopenharmony_ci **/
53228c2ecf20Sopenharmony_cistatic void qla4xxx_do_dpc(struct work_struct *work)
53238c2ecf20Sopenharmony_ci{
53248c2ecf20Sopenharmony_ci	struct scsi_qla_host *ha =
53258c2ecf20Sopenharmony_ci		container_of(work, struct scsi_qla_host, dpc_work);
53268c2ecf20Sopenharmony_ci	int status = QLA_ERROR;
53278c2ecf20Sopenharmony_ci
53288c2ecf20Sopenharmony_ci	DEBUG2(ql4_printk(KERN_INFO, ha,
53298c2ecf20Sopenharmony_ci			  "scsi%ld: %s: DPC handler waking up. flags = 0x%08lx, dpc_flags = 0x%08lx\n",
53308c2ecf20Sopenharmony_ci			  ha->host_no, __func__, ha->flags, ha->dpc_flags));
53318c2ecf20Sopenharmony_ci
53328c2ecf20Sopenharmony_ci	/* Initialization not yet finished. Don't do anything yet. */
53338c2ecf20Sopenharmony_ci	if (!test_bit(AF_INIT_DONE, &ha->flags))
53348c2ecf20Sopenharmony_ci		return;
53358c2ecf20Sopenharmony_ci
53368c2ecf20Sopenharmony_ci	if (test_bit(AF_EEH_BUSY, &ha->flags)) {
53378c2ecf20Sopenharmony_ci		DEBUG2(printk(KERN_INFO "scsi%ld: %s: flags = %lx\n",
53388c2ecf20Sopenharmony_ci		    ha->host_no, __func__, ha->flags));
53398c2ecf20Sopenharmony_ci		return;
53408c2ecf20Sopenharmony_ci	}
53418c2ecf20Sopenharmony_ci
53428c2ecf20Sopenharmony_ci	/* post events to application */
53438c2ecf20Sopenharmony_ci	qla4xxx_do_work(ha);
53448c2ecf20Sopenharmony_ci
53458c2ecf20Sopenharmony_ci	if (is_qla80XX(ha)) {
53468c2ecf20Sopenharmony_ci		if (test_bit(DPC_HA_UNRECOVERABLE, &ha->dpc_flags)) {
53478c2ecf20Sopenharmony_ci			if (is_qla8032(ha) || is_qla8042(ha)) {
53488c2ecf20Sopenharmony_ci				ql4_printk(KERN_INFO, ha, "%s: disabling pause transmit on port 0 & 1.\n",
53498c2ecf20Sopenharmony_ci					   __func__);
53508c2ecf20Sopenharmony_ci				/* disable pause frame for ISP83xx */
53518c2ecf20Sopenharmony_ci				qla4_83xx_disable_pause(ha);
53528c2ecf20Sopenharmony_ci			}
53538c2ecf20Sopenharmony_ci
53548c2ecf20Sopenharmony_ci			ha->isp_ops->idc_lock(ha);
53558c2ecf20Sopenharmony_ci			qla4_8xxx_wr_direct(ha, QLA8XXX_CRB_DEV_STATE,
53568c2ecf20Sopenharmony_ci					    QLA8XXX_DEV_FAILED);
53578c2ecf20Sopenharmony_ci			ha->isp_ops->idc_unlock(ha);
53588c2ecf20Sopenharmony_ci			ql4_printk(KERN_INFO, ha, "HW State: FAILED\n");
53598c2ecf20Sopenharmony_ci			qla4_8xxx_device_state_handler(ha);
53608c2ecf20Sopenharmony_ci		}
53618c2ecf20Sopenharmony_ci
53628c2ecf20Sopenharmony_ci		if (test_bit(DPC_POST_IDC_ACK, &ha->dpc_flags)) {
53638c2ecf20Sopenharmony_ci			if (is_qla8042(ha)) {
53648c2ecf20Sopenharmony_ci				if (ha->idc_info.info2 &
53658c2ecf20Sopenharmony_ci				    ENABLE_INTERNAL_LOOPBACK) {
53668c2ecf20Sopenharmony_ci					ql4_printk(KERN_INFO, ha, "%s: Disabling ACB\n",
53678c2ecf20Sopenharmony_ci						   __func__);
53688c2ecf20Sopenharmony_ci					status = qla4_84xx_config_acb(ha,
53698c2ecf20Sopenharmony_ci							    ACB_CONFIG_DISABLE);
53708c2ecf20Sopenharmony_ci					if (status != QLA_SUCCESS) {
53718c2ecf20Sopenharmony_ci						ql4_printk(KERN_INFO, ha, "%s: ACB config failed\n",
53728c2ecf20Sopenharmony_ci							   __func__);
53738c2ecf20Sopenharmony_ci					}
53748c2ecf20Sopenharmony_ci				}
53758c2ecf20Sopenharmony_ci			}
53768c2ecf20Sopenharmony_ci			qla4_83xx_post_idc_ack(ha);
53778c2ecf20Sopenharmony_ci			clear_bit(DPC_POST_IDC_ACK, &ha->dpc_flags);
53788c2ecf20Sopenharmony_ci		}
53798c2ecf20Sopenharmony_ci
53808c2ecf20Sopenharmony_ci		if (is_qla8042(ha) &&
53818c2ecf20Sopenharmony_ci		    test_bit(DPC_RESTORE_ACB, &ha->dpc_flags)) {
53828c2ecf20Sopenharmony_ci			ql4_printk(KERN_INFO, ha, "%s: Restoring ACB\n",
53838c2ecf20Sopenharmony_ci				   __func__);
53848c2ecf20Sopenharmony_ci			if (qla4_84xx_config_acb(ha, ACB_CONFIG_SET) !=
53858c2ecf20Sopenharmony_ci			    QLA_SUCCESS) {
53868c2ecf20Sopenharmony_ci				ql4_printk(KERN_INFO, ha, "%s: ACB config failed ",
53878c2ecf20Sopenharmony_ci					   __func__);
53888c2ecf20Sopenharmony_ci			}
53898c2ecf20Sopenharmony_ci			clear_bit(DPC_RESTORE_ACB, &ha->dpc_flags);
53908c2ecf20Sopenharmony_ci		}
53918c2ecf20Sopenharmony_ci
53928c2ecf20Sopenharmony_ci		if (test_and_clear_bit(DPC_HA_NEED_QUIESCENT, &ha->dpc_flags)) {
53938c2ecf20Sopenharmony_ci			qla4_8xxx_need_qsnt_handler(ha);
53948c2ecf20Sopenharmony_ci		}
53958c2ecf20Sopenharmony_ci	}
53968c2ecf20Sopenharmony_ci
53978c2ecf20Sopenharmony_ci	if (!test_bit(DPC_RESET_ACTIVE, &ha->dpc_flags) &&
53988c2ecf20Sopenharmony_ci	    (test_bit(DPC_RESET_HA, &ha->dpc_flags) ||
53998c2ecf20Sopenharmony_ci	    test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags) ||
54008c2ecf20Sopenharmony_ci	    test_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags))) {
54018c2ecf20Sopenharmony_ci		if ((is_qla8022(ha) && ql4xdontresethba) ||
54028c2ecf20Sopenharmony_ci		    ((is_qla8032(ha) || is_qla8042(ha)) &&
54038c2ecf20Sopenharmony_ci		     qla4_83xx_idc_dontreset(ha))) {
54048c2ecf20Sopenharmony_ci			DEBUG2(printk("scsi%ld: %s: Don't Reset HBA\n",
54058c2ecf20Sopenharmony_ci			    ha->host_no, __func__));
54068c2ecf20Sopenharmony_ci			clear_bit(DPC_RESET_HA, &ha->dpc_flags);
54078c2ecf20Sopenharmony_ci			clear_bit(DPC_RESET_HA_INTR, &ha->dpc_flags);
54088c2ecf20Sopenharmony_ci			clear_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags);
54098c2ecf20Sopenharmony_ci			goto dpc_post_reset_ha;
54108c2ecf20Sopenharmony_ci		}
54118c2ecf20Sopenharmony_ci		if (test_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags) ||
54128c2ecf20Sopenharmony_ci		    test_bit(DPC_RESET_HA, &ha->dpc_flags))
54138c2ecf20Sopenharmony_ci			qla4xxx_recover_adapter(ha);
54148c2ecf20Sopenharmony_ci
54158c2ecf20Sopenharmony_ci		if (test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags)) {
54168c2ecf20Sopenharmony_ci			uint8_t wait_time = RESET_INTR_TOV;
54178c2ecf20Sopenharmony_ci
54188c2ecf20Sopenharmony_ci			while ((readw(&ha->reg->ctrl_status) &
54198c2ecf20Sopenharmony_ci				(CSR_SOFT_RESET | CSR_FORCE_SOFT_RESET)) != 0) {
54208c2ecf20Sopenharmony_ci				if (--wait_time == 0)
54218c2ecf20Sopenharmony_ci					break;
54228c2ecf20Sopenharmony_ci				msleep(1000);
54238c2ecf20Sopenharmony_ci			}
54248c2ecf20Sopenharmony_ci			if (wait_time == 0)
54258c2ecf20Sopenharmony_ci				DEBUG2(printk("scsi%ld: %s: SR|FSR "
54268c2ecf20Sopenharmony_ci					      "bit not cleared-- resetting\n",
54278c2ecf20Sopenharmony_ci					      ha->host_no, __func__));
54288c2ecf20Sopenharmony_ci			qla4xxx_abort_active_cmds(ha, DID_RESET << 16);
54298c2ecf20Sopenharmony_ci			if (ql4xxx_lock_drvr_wait(ha) == QLA_SUCCESS) {
54308c2ecf20Sopenharmony_ci				qla4xxx_process_aen(ha, FLUSH_DDB_CHANGED_AENS);
54318c2ecf20Sopenharmony_ci				status = qla4xxx_recover_adapter(ha);
54328c2ecf20Sopenharmony_ci			}
54338c2ecf20Sopenharmony_ci			clear_bit(DPC_RESET_HA_INTR, &ha->dpc_flags);
54348c2ecf20Sopenharmony_ci			if (status == QLA_SUCCESS)
54358c2ecf20Sopenharmony_ci				ha->isp_ops->enable_intrs(ha);
54368c2ecf20Sopenharmony_ci		}
54378c2ecf20Sopenharmony_ci	}
54388c2ecf20Sopenharmony_ci
54398c2ecf20Sopenharmony_cidpc_post_reset_ha:
54408c2ecf20Sopenharmony_ci	/* ---- process AEN? --- */
54418c2ecf20Sopenharmony_ci	if (test_and_clear_bit(DPC_AEN, &ha->dpc_flags))
54428c2ecf20Sopenharmony_ci		qla4xxx_process_aen(ha, PROCESS_ALL_AENS);
54438c2ecf20Sopenharmony_ci
54448c2ecf20Sopenharmony_ci	/* ---- Get DHCP IP Address? --- */
54458c2ecf20Sopenharmony_ci	if (test_and_clear_bit(DPC_GET_DHCP_IP_ADDR, &ha->dpc_flags))
54468c2ecf20Sopenharmony_ci		qla4xxx_get_dhcp_ip_address(ha);
54478c2ecf20Sopenharmony_ci
54488c2ecf20Sopenharmony_ci	/* ---- relogin device? --- */
54498c2ecf20Sopenharmony_ci	if (adapter_up(ha) &&
54508c2ecf20Sopenharmony_ci	    test_and_clear_bit(DPC_RELOGIN_DEVICE, &ha->dpc_flags)) {
54518c2ecf20Sopenharmony_ci		iscsi_host_for_each_session(ha->host, qla4xxx_dpc_relogin);
54528c2ecf20Sopenharmony_ci	}
54538c2ecf20Sopenharmony_ci
54548c2ecf20Sopenharmony_ci	/* ---- link change? --- */
54558c2ecf20Sopenharmony_ci	if (!test_bit(AF_LOOPBACK, &ha->flags) &&
54568c2ecf20Sopenharmony_ci	    test_and_clear_bit(DPC_LINK_CHANGED, &ha->dpc_flags)) {
54578c2ecf20Sopenharmony_ci		if (!test_bit(AF_LINK_UP, &ha->flags)) {
54588c2ecf20Sopenharmony_ci			/* ---- link down? --- */
54598c2ecf20Sopenharmony_ci			qla4xxx_mark_all_devices_missing(ha);
54608c2ecf20Sopenharmony_ci		} else {
54618c2ecf20Sopenharmony_ci			/* ---- link up? --- *
54628c2ecf20Sopenharmony_ci			 * F/W will auto login to all devices ONLY ONCE after
54638c2ecf20Sopenharmony_ci			 * link up during driver initialization and runtime
54648c2ecf20Sopenharmony_ci			 * fatal error recovery.  Therefore, the driver must
54658c2ecf20Sopenharmony_ci			 * manually relogin to devices when recovering from
54668c2ecf20Sopenharmony_ci			 * connection failures, logouts, expired KATO, etc. */
54678c2ecf20Sopenharmony_ci			if (test_and_clear_bit(AF_BUILD_DDB_LIST, &ha->flags)) {
54688c2ecf20Sopenharmony_ci				qla4xxx_build_ddb_list(ha, ha->is_reset);
54698c2ecf20Sopenharmony_ci				iscsi_host_for_each_session(ha->host,
54708c2ecf20Sopenharmony_ci						qla4xxx_login_flash_ddb);
54718c2ecf20Sopenharmony_ci			} else
54728c2ecf20Sopenharmony_ci				qla4xxx_relogin_all_devices(ha);
54738c2ecf20Sopenharmony_ci		}
54748c2ecf20Sopenharmony_ci	}
54758c2ecf20Sopenharmony_ci	if (test_and_clear_bit(DPC_SYSFS_DDB_EXPORT, &ha->dpc_flags)) {
54768c2ecf20Sopenharmony_ci		if (qla4xxx_sysfs_ddb_export(ha))
54778c2ecf20Sopenharmony_ci			ql4_printk(KERN_ERR, ha, "%s: Error exporting ddb to sysfs\n",
54788c2ecf20Sopenharmony_ci				   __func__);
54798c2ecf20Sopenharmony_ci	}
54808c2ecf20Sopenharmony_ci}
54818c2ecf20Sopenharmony_ci
54828c2ecf20Sopenharmony_ci/**
54838c2ecf20Sopenharmony_ci * qla4xxx_free_adapter - release the adapter
54848c2ecf20Sopenharmony_ci * @ha: pointer to adapter structure
54858c2ecf20Sopenharmony_ci **/
54868c2ecf20Sopenharmony_cistatic void qla4xxx_free_adapter(struct scsi_qla_host *ha)
54878c2ecf20Sopenharmony_ci{
54888c2ecf20Sopenharmony_ci	qla4xxx_abort_active_cmds(ha, DID_NO_CONNECT << 16);
54898c2ecf20Sopenharmony_ci
54908c2ecf20Sopenharmony_ci	/* Turn-off interrupts on the card. */
54918c2ecf20Sopenharmony_ci	ha->isp_ops->disable_intrs(ha);
54928c2ecf20Sopenharmony_ci
54938c2ecf20Sopenharmony_ci	if (is_qla40XX(ha)) {
54948c2ecf20Sopenharmony_ci		writel(set_rmask(CSR_SCSI_PROCESSOR_INTR),
54958c2ecf20Sopenharmony_ci		       &ha->reg->ctrl_status);
54968c2ecf20Sopenharmony_ci		readl(&ha->reg->ctrl_status);
54978c2ecf20Sopenharmony_ci	} else if (is_qla8022(ha)) {
54988c2ecf20Sopenharmony_ci		writel(0, &ha->qla4_82xx_reg->host_int);
54998c2ecf20Sopenharmony_ci		readl(&ha->qla4_82xx_reg->host_int);
55008c2ecf20Sopenharmony_ci	} else if (is_qla8032(ha) || is_qla8042(ha)) {
55018c2ecf20Sopenharmony_ci		writel(0, &ha->qla4_83xx_reg->risc_intr);
55028c2ecf20Sopenharmony_ci		readl(&ha->qla4_83xx_reg->risc_intr);
55038c2ecf20Sopenharmony_ci	}
55048c2ecf20Sopenharmony_ci
55058c2ecf20Sopenharmony_ci	/* Remove timer thread, if present */
55068c2ecf20Sopenharmony_ci	if (ha->timer_active)
55078c2ecf20Sopenharmony_ci		qla4xxx_stop_timer(ha);
55088c2ecf20Sopenharmony_ci
55098c2ecf20Sopenharmony_ci	/* Kill the kernel thread for this host */
55108c2ecf20Sopenharmony_ci	if (ha->dpc_thread)
55118c2ecf20Sopenharmony_ci		destroy_workqueue(ha->dpc_thread);
55128c2ecf20Sopenharmony_ci
55138c2ecf20Sopenharmony_ci	/* Kill the kernel thread for this host */
55148c2ecf20Sopenharmony_ci	if (ha->task_wq)
55158c2ecf20Sopenharmony_ci		destroy_workqueue(ha->task_wq);
55168c2ecf20Sopenharmony_ci
55178c2ecf20Sopenharmony_ci	/* Put firmware in known state */
55188c2ecf20Sopenharmony_ci	ha->isp_ops->reset_firmware(ha);
55198c2ecf20Sopenharmony_ci
55208c2ecf20Sopenharmony_ci	if (is_qla80XX(ha)) {
55218c2ecf20Sopenharmony_ci		ha->isp_ops->idc_lock(ha);
55228c2ecf20Sopenharmony_ci		qla4_8xxx_clear_drv_active(ha);
55238c2ecf20Sopenharmony_ci		ha->isp_ops->idc_unlock(ha);
55248c2ecf20Sopenharmony_ci	}
55258c2ecf20Sopenharmony_ci
55268c2ecf20Sopenharmony_ci	/* Detach interrupts */
55278c2ecf20Sopenharmony_ci	qla4xxx_free_irqs(ha);
55288c2ecf20Sopenharmony_ci
55298c2ecf20Sopenharmony_ci	/* free extra memory */
55308c2ecf20Sopenharmony_ci	qla4xxx_mem_free(ha);
55318c2ecf20Sopenharmony_ci}
55328c2ecf20Sopenharmony_ci
55338c2ecf20Sopenharmony_ciint qla4_8xxx_iospace_config(struct scsi_qla_host *ha)
55348c2ecf20Sopenharmony_ci{
55358c2ecf20Sopenharmony_ci	int status = 0;
55368c2ecf20Sopenharmony_ci	unsigned long mem_base, mem_len;
55378c2ecf20Sopenharmony_ci	struct pci_dev *pdev = ha->pdev;
55388c2ecf20Sopenharmony_ci
55398c2ecf20Sopenharmony_ci	status = pci_request_regions(pdev, DRIVER_NAME);
55408c2ecf20Sopenharmony_ci	if (status) {
55418c2ecf20Sopenharmony_ci		printk(KERN_WARNING
55428c2ecf20Sopenharmony_ci		    "scsi(%ld) Failed to reserve PIO regions (%s) "
55438c2ecf20Sopenharmony_ci		    "status=%d\n", ha->host_no, pci_name(pdev), status);
55448c2ecf20Sopenharmony_ci		goto iospace_error_exit;
55458c2ecf20Sopenharmony_ci	}
55468c2ecf20Sopenharmony_ci
55478c2ecf20Sopenharmony_ci	DEBUG2(printk(KERN_INFO "%s: revision-id=%d\n",
55488c2ecf20Sopenharmony_ci	    __func__, pdev->revision));
55498c2ecf20Sopenharmony_ci	ha->revision_id = pdev->revision;
55508c2ecf20Sopenharmony_ci
55518c2ecf20Sopenharmony_ci	/* remap phys address */
55528c2ecf20Sopenharmony_ci	mem_base = pci_resource_start(pdev, 0); /* 0 is for BAR 0 */
55538c2ecf20Sopenharmony_ci	mem_len = pci_resource_len(pdev, 0);
55548c2ecf20Sopenharmony_ci	DEBUG2(printk(KERN_INFO "%s: ioremap from %lx a size of %lx\n",
55558c2ecf20Sopenharmony_ci	    __func__, mem_base, mem_len));
55568c2ecf20Sopenharmony_ci
55578c2ecf20Sopenharmony_ci	/* mapping of pcibase pointer */
55588c2ecf20Sopenharmony_ci	ha->nx_pcibase = (unsigned long)ioremap(mem_base, mem_len);
55598c2ecf20Sopenharmony_ci	if (!ha->nx_pcibase) {
55608c2ecf20Sopenharmony_ci		printk(KERN_ERR
55618c2ecf20Sopenharmony_ci		    "cannot remap MMIO (%s), aborting\n", pci_name(pdev));
55628c2ecf20Sopenharmony_ci		pci_release_regions(ha->pdev);
55638c2ecf20Sopenharmony_ci		goto iospace_error_exit;
55648c2ecf20Sopenharmony_ci	}
55658c2ecf20Sopenharmony_ci
55668c2ecf20Sopenharmony_ci	/* Mapping of IO base pointer, door bell read and write pointer */
55678c2ecf20Sopenharmony_ci
55688c2ecf20Sopenharmony_ci	/* mapping of IO base pointer */
55698c2ecf20Sopenharmony_ci	if (is_qla8022(ha)) {
55708c2ecf20Sopenharmony_ci		ha->qla4_82xx_reg = (struct device_reg_82xx  __iomem *)
55718c2ecf20Sopenharmony_ci				    ((uint8_t *)ha->nx_pcibase + 0xbc000 +
55728c2ecf20Sopenharmony_ci				     (ha->pdev->devfn << 11));
55738c2ecf20Sopenharmony_ci		ha->nx_db_wr_ptr = (ha->pdev->devfn == 4 ? QLA82XX_CAM_RAM_DB1 :
55748c2ecf20Sopenharmony_ci				    QLA82XX_CAM_RAM_DB2);
55758c2ecf20Sopenharmony_ci	} else if (is_qla8032(ha) || is_qla8042(ha)) {
55768c2ecf20Sopenharmony_ci		ha->qla4_83xx_reg = (struct device_reg_83xx __iomem *)
55778c2ecf20Sopenharmony_ci				    ((uint8_t *)ha->nx_pcibase);
55788c2ecf20Sopenharmony_ci	}
55798c2ecf20Sopenharmony_ci
55808c2ecf20Sopenharmony_ci	return 0;
55818c2ecf20Sopenharmony_ciiospace_error_exit:
55828c2ecf20Sopenharmony_ci	return -ENOMEM;
55838c2ecf20Sopenharmony_ci}
55848c2ecf20Sopenharmony_ci
55858c2ecf20Sopenharmony_ci/***
55868c2ecf20Sopenharmony_ci * qla4xxx_iospace_config - maps registers
55878c2ecf20Sopenharmony_ci * @ha: pointer to adapter structure
55888c2ecf20Sopenharmony_ci *
55898c2ecf20Sopenharmony_ci * This routines maps HBA's registers from the pci address space
55908c2ecf20Sopenharmony_ci * into the kernel virtual address space for memory mapped i/o.
55918c2ecf20Sopenharmony_ci **/
55928c2ecf20Sopenharmony_ciint qla4xxx_iospace_config(struct scsi_qla_host *ha)
55938c2ecf20Sopenharmony_ci{
55948c2ecf20Sopenharmony_ci	unsigned long pio, pio_len, pio_flags;
55958c2ecf20Sopenharmony_ci	unsigned long mmio, mmio_len, mmio_flags;
55968c2ecf20Sopenharmony_ci
55978c2ecf20Sopenharmony_ci	pio = pci_resource_start(ha->pdev, 0);
55988c2ecf20Sopenharmony_ci	pio_len = pci_resource_len(ha->pdev, 0);
55998c2ecf20Sopenharmony_ci	pio_flags = pci_resource_flags(ha->pdev, 0);
56008c2ecf20Sopenharmony_ci	if (pio_flags & IORESOURCE_IO) {
56018c2ecf20Sopenharmony_ci		if (pio_len < MIN_IOBASE_LEN) {
56028c2ecf20Sopenharmony_ci			ql4_printk(KERN_WARNING, ha,
56038c2ecf20Sopenharmony_ci				"Invalid PCI I/O region size\n");
56048c2ecf20Sopenharmony_ci			pio = 0;
56058c2ecf20Sopenharmony_ci		}
56068c2ecf20Sopenharmony_ci	} else {
56078c2ecf20Sopenharmony_ci		ql4_printk(KERN_WARNING, ha, "region #0 not a PIO resource\n");
56088c2ecf20Sopenharmony_ci		pio = 0;
56098c2ecf20Sopenharmony_ci	}
56108c2ecf20Sopenharmony_ci
56118c2ecf20Sopenharmony_ci	/* Use MMIO operations for all accesses. */
56128c2ecf20Sopenharmony_ci	mmio = pci_resource_start(ha->pdev, 1);
56138c2ecf20Sopenharmony_ci	mmio_len = pci_resource_len(ha->pdev, 1);
56148c2ecf20Sopenharmony_ci	mmio_flags = pci_resource_flags(ha->pdev, 1);
56158c2ecf20Sopenharmony_ci
56168c2ecf20Sopenharmony_ci	if (!(mmio_flags & IORESOURCE_MEM)) {
56178c2ecf20Sopenharmony_ci		ql4_printk(KERN_ERR, ha,
56188c2ecf20Sopenharmony_ci		    "region #0 not an MMIO resource, aborting\n");
56198c2ecf20Sopenharmony_ci
56208c2ecf20Sopenharmony_ci		goto iospace_error_exit;
56218c2ecf20Sopenharmony_ci	}
56228c2ecf20Sopenharmony_ci
56238c2ecf20Sopenharmony_ci	if (mmio_len < MIN_IOBASE_LEN) {
56248c2ecf20Sopenharmony_ci		ql4_printk(KERN_ERR, ha,
56258c2ecf20Sopenharmony_ci		    "Invalid PCI mem region size, aborting\n");
56268c2ecf20Sopenharmony_ci		goto iospace_error_exit;
56278c2ecf20Sopenharmony_ci	}
56288c2ecf20Sopenharmony_ci
56298c2ecf20Sopenharmony_ci	if (pci_request_regions(ha->pdev, DRIVER_NAME)) {
56308c2ecf20Sopenharmony_ci		ql4_printk(KERN_WARNING, ha,
56318c2ecf20Sopenharmony_ci		    "Failed to reserve PIO/MMIO regions\n");
56328c2ecf20Sopenharmony_ci
56338c2ecf20Sopenharmony_ci		goto iospace_error_exit;
56348c2ecf20Sopenharmony_ci	}
56358c2ecf20Sopenharmony_ci
56368c2ecf20Sopenharmony_ci	ha->pio_address = pio;
56378c2ecf20Sopenharmony_ci	ha->pio_length = pio_len;
56388c2ecf20Sopenharmony_ci	ha->reg = ioremap(mmio, MIN_IOBASE_LEN);
56398c2ecf20Sopenharmony_ci	if (!ha->reg) {
56408c2ecf20Sopenharmony_ci		ql4_printk(KERN_ERR, ha,
56418c2ecf20Sopenharmony_ci		    "cannot remap MMIO, aborting\n");
56428c2ecf20Sopenharmony_ci
56438c2ecf20Sopenharmony_ci		goto iospace_error_exit;
56448c2ecf20Sopenharmony_ci	}
56458c2ecf20Sopenharmony_ci
56468c2ecf20Sopenharmony_ci	return 0;
56478c2ecf20Sopenharmony_ci
56488c2ecf20Sopenharmony_ciiospace_error_exit:
56498c2ecf20Sopenharmony_ci	return -ENOMEM;
56508c2ecf20Sopenharmony_ci}
56518c2ecf20Sopenharmony_ci
56528c2ecf20Sopenharmony_cistatic struct isp_operations qla4xxx_isp_ops = {
56538c2ecf20Sopenharmony_ci	.iospace_config         = qla4xxx_iospace_config,
56548c2ecf20Sopenharmony_ci	.pci_config             = qla4xxx_pci_config,
56558c2ecf20Sopenharmony_ci	.disable_intrs          = qla4xxx_disable_intrs,
56568c2ecf20Sopenharmony_ci	.enable_intrs           = qla4xxx_enable_intrs,
56578c2ecf20Sopenharmony_ci	.start_firmware         = qla4xxx_start_firmware,
56588c2ecf20Sopenharmony_ci	.intr_handler           = qla4xxx_intr_handler,
56598c2ecf20Sopenharmony_ci	.interrupt_service_routine = qla4xxx_interrupt_service_routine,
56608c2ecf20Sopenharmony_ci	.reset_chip             = qla4xxx_soft_reset,
56618c2ecf20Sopenharmony_ci	.reset_firmware         = qla4xxx_hw_reset,
56628c2ecf20Sopenharmony_ci	.queue_iocb             = qla4xxx_queue_iocb,
56638c2ecf20Sopenharmony_ci	.complete_iocb          = qla4xxx_complete_iocb,
56648c2ecf20Sopenharmony_ci	.rd_shdw_req_q_out      = qla4xxx_rd_shdw_req_q_out,
56658c2ecf20Sopenharmony_ci	.rd_shdw_rsp_q_in       = qla4xxx_rd_shdw_rsp_q_in,
56668c2ecf20Sopenharmony_ci	.get_sys_info           = qla4xxx_get_sys_info,
56678c2ecf20Sopenharmony_ci	.queue_mailbox_command	= qla4xxx_queue_mbox_cmd,
56688c2ecf20Sopenharmony_ci	.process_mailbox_interrupt = qla4xxx_process_mbox_intr,
56698c2ecf20Sopenharmony_ci};
56708c2ecf20Sopenharmony_ci
56718c2ecf20Sopenharmony_cistatic struct isp_operations qla4_82xx_isp_ops = {
56728c2ecf20Sopenharmony_ci	.iospace_config         = qla4_8xxx_iospace_config,
56738c2ecf20Sopenharmony_ci	.pci_config             = qla4_8xxx_pci_config,
56748c2ecf20Sopenharmony_ci	.disable_intrs          = qla4_82xx_disable_intrs,
56758c2ecf20Sopenharmony_ci	.enable_intrs           = qla4_82xx_enable_intrs,
56768c2ecf20Sopenharmony_ci	.start_firmware         = qla4_8xxx_load_risc,
56778c2ecf20Sopenharmony_ci	.restart_firmware	= qla4_82xx_try_start_fw,
56788c2ecf20Sopenharmony_ci	.intr_handler           = qla4_82xx_intr_handler,
56798c2ecf20Sopenharmony_ci	.interrupt_service_routine = qla4_82xx_interrupt_service_routine,
56808c2ecf20Sopenharmony_ci	.need_reset		= qla4_8xxx_need_reset,
56818c2ecf20Sopenharmony_ci	.reset_chip             = qla4_82xx_isp_reset,
56828c2ecf20Sopenharmony_ci	.reset_firmware         = qla4_8xxx_stop_firmware,
56838c2ecf20Sopenharmony_ci	.queue_iocb             = qla4_82xx_queue_iocb,
56848c2ecf20Sopenharmony_ci	.complete_iocb          = qla4_82xx_complete_iocb,
56858c2ecf20Sopenharmony_ci	.rd_shdw_req_q_out      = qla4_82xx_rd_shdw_req_q_out,
56868c2ecf20Sopenharmony_ci	.rd_shdw_rsp_q_in       = qla4_82xx_rd_shdw_rsp_q_in,
56878c2ecf20Sopenharmony_ci	.get_sys_info           = qla4_8xxx_get_sys_info,
56888c2ecf20Sopenharmony_ci	.rd_reg_direct		= qla4_82xx_rd_32,
56898c2ecf20Sopenharmony_ci	.wr_reg_direct		= qla4_82xx_wr_32,
56908c2ecf20Sopenharmony_ci	.rd_reg_indirect	= qla4_82xx_md_rd_32,
56918c2ecf20Sopenharmony_ci	.wr_reg_indirect	= qla4_82xx_md_wr_32,
56928c2ecf20Sopenharmony_ci	.idc_lock		= qla4_82xx_idc_lock,
56938c2ecf20Sopenharmony_ci	.idc_unlock		= qla4_82xx_idc_unlock,
56948c2ecf20Sopenharmony_ci	.rom_lock_recovery	= qla4_82xx_rom_lock_recovery,
56958c2ecf20Sopenharmony_ci	.queue_mailbox_command	= qla4_82xx_queue_mbox_cmd,
56968c2ecf20Sopenharmony_ci	.process_mailbox_interrupt = qla4_82xx_process_mbox_intr,
56978c2ecf20Sopenharmony_ci};
56988c2ecf20Sopenharmony_ci
56998c2ecf20Sopenharmony_cistatic struct isp_operations qla4_83xx_isp_ops = {
57008c2ecf20Sopenharmony_ci	.iospace_config		= qla4_8xxx_iospace_config,
57018c2ecf20Sopenharmony_ci	.pci_config		= qla4_8xxx_pci_config,
57028c2ecf20Sopenharmony_ci	.disable_intrs		= qla4_83xx_disable_intrs,
57038c2ecf20Sopenharmony_ci	.enable_intrs		= qla4_83xx_enable_intrs,
57048c2ecf20Sopenharmony_ci	.start_firmware		= qla4_8xxx_load_risc,
57058c2ecf20Sopenharmony_ci	.restart_firmware	= qla4_83xx_start_firmware,
57068c2ecf20Sopenharmony_ci	.intr_handler		= qla4_83xx_intr_handler,
57078c2ecf20Sopenharmony_ci	.interrupt_service_routine = qla4_83xx_interrupt_service_routine,
57088c2ecf20Sopenharmony_ci	.need_reset		= qla4_8xxx_need_reset,
57098c2ecf20Sopenharmony_ci	.reset_chip		= qla4_83xx_isp_reset,
57108c2ecf20Sopenharmony_ci	.reset_firmware		= qla4_8xxx_stop_firmware,
57118c2ecf20Sopenharmony_ci	.queue_iocb		= qla4_83xx_queue_iocb,
57128c2ecf20Sopenharmony_ci	.complete_iocb		= qla4_83xx_complete_iocb,
57138c2ecf20Sopenharmony_ci	.rd_shdw_req_q_out	= qla4xxx_rd_shdw_req_q_out,
57148c2ecf20Sopenharmony_ci	.rd_shdw_rsp_q_in	= qla4xxx_rd_shdw_rsp_q_in,
57158c2ecf20Sopenharmony_ci	.get_sys_info		= qla4_8xxx_get_sys_info,
57168c2ecf20Sopenharmony_ci	.rd_reg_direct		= qla4_83xx_rd_reg,
57178c2ecf20Sopenharmony_ci	.wr_reg_direct		= qla4_83xx_wr_reg,
57188c2ecf20Sopenharmony_ci	.rd_reg_indirect	= qla4_83xx_rd_reg_indirect,
57198c2ecf20Sopenharmony_ci	.wr_reg_indirect	= qla4_83xx_wr_reg_indirect,
57208c2ecf20Sopenharmony_ci	.idc_lock		= qla4_83xx_drv_lock,
57218c2ecf20Sopenharmony_ci	.idc_unlock		= qla4_83xx_drv_unlock,
57228c2ecf20Sopenharmony_ci	.rom_lock_recovery	= qla4_83xx_rom_lock_recovery,
57238c2ecf20Sopenharmony_ci	.queue_mailbox_command	= qla4_83xx_queue_mbox_cmd,
57248c2ecf20Sopenharmony_ci	.process_mailbox_interrupt = qla4_83xx_process_mbox_intr,
57258c2ecf20Sopenharmony_ci};
57268c2ecf20Sopenharmony_ci
57278c2ecf20Sopenharmony_ciuint16_t qla4xxx_rd_shdw_req_q_out(struct scsi_qla_host *ha)
57288c2ecf20Sopenharmony_ci{
57298c2ecf20Sopenharmony_ci	return (uint16_t)le32_to_cpu(ha->shadow_regs->req_q_out);
57308c2ecf20Sopenharmony_ci}
57318c2ecf20Sopenharmony_ci
57328c2ecf20Sopenharmony_ciuint16_t qla4_82xx_rd_shdw_req_q_out(struct scsi_qla_host *ha)
57338c2ecf20Sopenharmony_ci{
57348c2ecf20Sopenharmony_ci	return (uint16_t)le32_to_cpu(readl(&ha->qla4_82xx_reg->req_q_out));
57358c2ecf20Sopenharmony_ci}
57368c2ecf20Sopenharmony_ci
57378c2ecf20Sopenharmony_ciuint16_t qla4xxx_rd_shdw_rsp_q_in(struct scsi_qla_host *ha)
57388c2ecf20Sopenharmony_ci{
57398c2ecf20Sopenharmony_ci	return (uint16_t)le32_to_cpu(ha->shadow_regs->rsp_q_in);
57408c2ecf20Sopenharmony_ci}
57418c2ecf20Sopenharmony_ci
57428c2ecf20Sopenharmony_ciuint16_t qla4_82xx_rd_shdw_rsp_q_in(struct scsi_qla_host *ha)
57438c2ecf20Sopenharmony_ci{
57448c2ecf20Sopenharmony_ci	return (uint16_t)le32_to_cpu(readl(&ha->qla4_82xx_reg->rsp_q_in));
57458c2ecf20Sopenharmony_ci}
57468c2ecf20Sopenharmony_ci
57478c2ecf20Sopenharmony_cistatic ssize_t qla4xxx_show_boot_eth_info(void *data, int type, char *buf)
57488c2ecf20Sopenharmony_ci{
57498c2ecf20Sopenharmony_ci	struct scsi_qla_host *ha = data;
57508c2ecf20Sopenharmony_ci	char *str = buf;
57518c2ecf20Sopenharmony_ci	int rc;
57528c2ecf20Sopenharmony_ci
57538c2ecf20Sopenharmony_ci	switch (type) {
57548c2ecf20Sopenharmony_ci	case ISCSI_BOOT_ETH_FLAGS:
57558c2ecf20Sopenharmony_ci		rc = sprintf(str, "%d\n", SYSFS_FLAG_FW_SEL_BOOT);
57568c2ecf20Sopenharmony_ci		break;
57578c2ecf20Sopenharmony_ci	case ISCSI_BOOT_ETH_INDEX:
57588c2ecf20Sopenharmony_ci		rc = sprintf(str, "0\n");
57598c2ecf20Sopenharmony_ci		break;
57608c2ecf20Sopenharmony_ci	case ISCSI_BOOT_ETH_MAC:
57618c2ecf20Sopenharmony_ci		rc = sysfs_format_mac(str, ha->my_mac,
57628c2ecf20Sopenharmony_ci				      MAC_ADDR_LEN);
57638c2ecf20Sopenharmony_ci		break;
57648c2ecf20Sopenharmony_ci	default:
57658c2ecf20Sopenharmony_ci		rc = -ENOSYS;
57668c2ecf20Sopenharmony_ci		break;
57678c2ecf20Sopenharmony_ci	}
57688c2ecf20Sopenharmony_ci	return rc;
57698c2ecf20Sopenharmony_ci}
57708c2ecf20Sopenharmony_ci
57718c2ecf20Sopenharmony_cistatic umode_t qla4xxx_eth_get_attr_visibility(void *data, int type)
57728c2ecf20Sopenharmony_ci{
57738c2ecf20Sopenharmony_ci	int rc;
57748c2ecf20Sopenharmony_ci
57758c2ecf20Sopenharmony_ci	switch (type) {
57768c2ecf20Sopenharmony_ci	case ISCSI_BOOT_ETH_FLAGS:
57778c2ecf20Sopenharmony_ci	case ISCSI_BOOT_ETH_MAC:
57788c2ecf20Sopenharmony_ci	case ISCSI_BOOT_ETH_INDEX:
57798c2ecf20Sopenharmony_ci		rc = S_IRUGO;
57808c2ecf20Sopenharmony_ci		break;
57818c2ecf20Sopenharmony_ci	default:
57828c2ecf20Sopenharmony_ci		rc = 0;
57838c2ecf20Sopenharmony_ci		break;
57848c2ecf20Sopenharmony_ci	}
57858c2ecf20Sopenharmony_ci	return rc;
57868c2ecf20Sopenharmony_ci}
57878c2ecf20Sopenharmony_ci
57888c2ecf20Sopenharmony_cistatic ssize_t qla4xxx_show_boot_ini_info(void *data, int type, char *buf)
57898c2ecf20Sopenharmony_ci{
57908c2ecf20Sopenharmony_ci	struct scsi_qla_host *ha = data;
57918c2ecf20Sopenharmony_ci	char *str = buf;
57928c2ecf20Sopenharmony_ci	int rc;
57938c2ecf20Sopenharmony_ci
57948c2ecf20Sopenharmony_ci	switch (type) {
57958c2ecf20Sopenharmony_ci	case ISCSI_BOOT_INI_INITIATOR_NAME:
57968c2ecf20Sopenharmony_ci		rc = sprintf(str, "%s\n", ha->name_string);
57978c2ecf20Sopenharmony_ci		break;
57988c2ecf20Sopenharmony_ci	default:
57998c2ecf20Sopenharmony_ci		rc = -ENOSYS;
58008c2ecf20Sopenharmony_ci		break;
58018c2ecf20Sopenharmony_ci	}
58028c2ecf20Sopenharmony_ci	return rc;
58038c2ecf20Sopenharmony_ci}
58048c2ecf20Sopenharmony_ci
58058c2ecf20Sopenharmony_cistatic umode_t qla4xxx_ini_get_attr_visibility(void *data, int type)
58068c2ecf20Sopenharmony_ci{
58078c2ecf20Sopenharmony_ci	int rc;
58088c2ecf20Sopenharmony_ci
58098c2ecf20Sopenharmony_ci	switch (type) {
58108c2ecf20Sopenharmony_ci	case ISCSI_BOOT_INI_INITIATOR_NAME:
58118c2ecf20Sopenharmony_ci		rc = S_IRUGO;
58128c2ecf20Sopenharmony_ci		break;
58138c2ecf20Sopenharmony_ci	default:
58148c2ecf20Sopenharmony_ci		rc = 0;
58158c2ecf20Sopenharmony_ci		break;
58168c2ecf20Sopenharmony_ci	}
58178c2ecf20Sopenharmony_ci	return rc;
58188c2ecf20Sopenharmony_ci}
58198c2ecf20Sopenharmony_ci
58208c2ecf20Sopenharmony_cistatic ssize_t
58218c2ecf20Sopenharmony_ciqla4xxx_show_boot_tgt_info(struct ql4_boot_session_info *boot_sess, int type,
58228c2ecf20Sopenharmony_ci			   char *buf)
58238c2ecf20Sopenharmony_ci{
58248c2ecf20Sopenharmony_ci	struct ql4_conn_info *boot_conn = &boot_sess->conn_list[0];
58258c2ecf20Sopenharmony_ci	char *str = buf;
58268c2ecf20Sopenharmony_ci	int rc;
58278c2ecf20Sopenharmony_ci
58288c2ecf20Sopenharmony_ci	switch (type) {
58298c2ecf20Sopenharmony_ci	case ISCSI_BOOT_TGT_NAME:
58308c2ecf20Sopenharmony_ci		rc = sprintf(buf, "%s\n", (char *)&boot_sess->target_name);
58318c2ecf20Sopenharmony_ci		break;
58328c2ecf20Sopenharmony_ci	case ISCSI_BOOT_TGT_IP_ADDR:
58338c2ecf20Sopenharmony_ci		if (boot_sess->conn_list[0].dest_ipaddr.ip_type == 0x1)
58348c2ecf20Sopenharmony_ci			rc = sprintf(buf, "%pI4\n",
58358c2ecf20Sopenharmony_ci				     &boot_conn->dest_ipaddr.ip_address);
58368c2ecf20Sopenharmony_ci		else
58378c2ecf20Sopenharmony_ci			rc = sprintf(str, "%pI6\n",
58388c2ecf20Sopenharmony_ci				     &boot_conn->dest_ipaddr.ip_address);
58398c2ecf20Sopenharmony_ci		break;
58408c2ecf20Sopenharmony_ci	case ISCSI_BOOT_TGT_PORT:
58418c2ecf20Sopenharmony_ci			rc = sprintf(str, "%d\n", boot_conn->dest_port);
58428c2ecf20Sopenharmony_ci		break;
58438c2ecf20Sopenharmony_ci	case ISCSI_BOOT_TGT_CHAP_NAME:
58448c2ecf20Sopenharmony_ci		rc = sprintf(str,  "%.*s\n",
58458c2ecf20Sopenharmony_ci			     boot_conn->chap.target_chap_name_length,
58468c2ecf20Sopenharmony_ci			     (char *)&boot_conn->chap.target_chap_name);
58478c2ecf20Sopenharmony_ci		break;
58488c2ecf20Sopenharmony_ci	case ISCSI_BOOT_TGT_CHAP_SECRET:
58498c2ecf20Sopenharmony_ci		rc = sprintf(str,  "%.*s\n",
58508c2ecf20Sopenharmony_ci			     boot_conn->chap.target_secret_length,
58518c2ecf20Sopenharmony_ci			     (char *)&boot_conn->chap.target_secret);
58528c2ecf20Sopenharmony_ci		break;
58538c2ecf20Sopenharmony_ci	case ISCSI_BOOT_TGT_REV_CHAP_NAME:
58548c2ecf20Sopenharmony_ci		rc = sprintf(str,  "%.*s\n",
58558c2ecf20Sopenharmony_ci			     boot_conn->chap.intr_chap_name_length,
58568c2ecf20Sopenharmony_ci			     (char *)&boot_conn->chap.intr_chap_name);
58578c2ecf20Sopenharmony_ci		break;
58588c2ecf20Sopenharmony_ci	case ISCSI_BOOT_TGT_REV_CHAP_SECRET:
58598c2ecf20Sopenharmony_ci		rc = sprintf(str,  "%.*s\n",
58608c2ecf20Sopenharmony_ci			     boot_conn->chap.intr_secret_length,
58618c2ecf20Sopenharmony_ci			     (char *)&boot_conn->chap.intr_secret);
58628c2ecf20Sopenharmony_ci		break;
58638c2ecf20Sopenharmony_ci	case ISCSI_BOOT_TGT_FLAGS:
58648c2ecf20Sopenharmony_ci		rc = sprintf(str, "%d\n", SYSFS_FLAG_FW_SEL_BOOT);
58658c2ecf20Sopenharmony_ci		break;
58668c2ecf20Sopenharmony_ci	case ISCSI_BOOT_TGT_NIC_ASSOC:
58678c2ecf20Sopenharmony_ci		rc = sprintf(str, "0\n");
58688c2ecf20Sopenharmony_ci		break;
58698c2ecf20Sopenharmony_ci	default:
58708c2ecf20Sopenharmony_ci		rc = -ENOSYS;
58718c2ecf20Sopenharmony_ci		break;
58728c2ecf20Sopenharmony_ci	}
58738c2ecf20Sopenharmony_ci	return rc;
58748c2ecf20Sopenharmony_ci}
58758c2ecf20Sopenharmony_ci
58768c2ecf20Sopenharmony_cistatic ssize_t qla4xxx_show_boot_tgt_pri_info(void *data, int type, char *buf)
58778c2ecf20Sopenharmony_ci{
58788c2ecf20Sopenharmony_ci	struct scsi_qla_host *ha = data;
58798c2ecf20Sopenharmony_ci	struct ql4_boot_session_info *boot_sess = &(ha->boot_tgt.boot_pri_sess);
58808c2ecf20Sopenharmony_ci
58818c2ecf20Sopenharmony_ci	return qla4xxx_show_boot_tgt_info(boot_sess, type, buf);
58828c2ecf20Sopenharmony_ci}
58838c2ecf20Sopenharmony_ci
58848c2ecf20Sopenharmony_cistatic ssize_t qla4xxx_show_boot_tgt_sec_info(void *data, int type, char *buf)
58858c2ecf20Sopenharmony_ci{
58868c2ecf20Sopenharmony_ci	struct scsi_qla_host *ha = data;
58878c2ecf20Sopenharmony_ci	struct ql4_boot_session_info *boot_sess = &(ha->boot_tgt.boot_sec_sess);
58888c2ecf20Sopenharmony_ci
58898c2ecf20Sopenharmony_ci	return qla4xxx_show_boot_tgt_info(boot_sess, type, buf);
58908c2ecf20Sopenharmony_ci}
58918c2ecf20Sopenharmony_ci
58928c2ecf20Sopenharmony_cistatic umode_t qla4xxx_tgt_get_attr_visibility(void *data, int type)
58938c2ecf20Sopenharmony_ci{
58948c2ecf20Sopenharmony_ci	int rc;
58958c2ecf20Sopenharmony_ci
58968c2ecf20Sopenharmony_ci	switch (type) {
58978c2ecf20Sopenharmony_ci	case ISCSI_BOOT_TGT_NAME:
58988c2ecf20Sopenharmony_ci	case ISCSI_BOOT_TGT_IP_ADDR:
58998c2ecf20Sopenharmony_ci	case ISCSI_BOOT_TGT_PORT:
59008c2ecf20Sopenharmony_ci	case ISCSI_BOOT_TGT_CHAP_NAME:
59018c2ecf20Sopenharmony_ci	case ISCSI_BOOT_TGT_CHAP_SECRET:
59028c2ecf20Sopenharmony_ci	case ISCSI_BOOT_TGT_REV_CHAP_NAME:
59038c2ecf20Sopenharmony_ci	case ISCSI_BOOT_TGT_REV_CHAP_SECRET:
59048c2ecf20Sopenharmony_ci	case ISCSI_BOOT_TGT_NIC_ASSOC:
59058c2ecf20Sopenharmony_ci	case ISCSI_BOOT_TGT_FLAGS:
59068c2ecf20Sopenharmony_ci		rc = S_IRUGO;
59078c2ecf20Sopenharmony_ci		break;
59088c2ecf20Sopenharmony_ci	default:
59098c2ecf20Sopenharmony_ci		rc = 0;
59108c2ecf20Sopenharmony_ci		break;
59118c2ecf20Sopenharmony_ci	}
59128c2ecf20Sopenharmony_ci	return rc;
59138c2ecf20Sopenharmony_ci}
59148c2ecf20Sopenharmony_ci
59158c2ecf20Sopenharmony_cistatic void qla4xxx_boot_release(void *data)
59168c2ecf20Sopenharmony_ci{
59178c2ecf20Sopenharmony_ci	struct scsi_qla_host *ha = data;
59188c2ecf20Sopenharmony_ci
59198c2ecf20Sopenharmony_ci	scsi_host_put(ha->host);
59208c2ecf20Sopenharmony_ci}
59218c2ecf20Sopenharmony_ci
59228c2ecf20Sopenharmony_cistatic int get_fw_boot_info(struct scsi_qla_host *ha, uint16_t ddb_index[])
59238c2ecf20Sopenharmony_ci{
59248c2ecf20Sopenharmony_ci	dma_addr_t buf_dma;
59258c2ecf20Sopenharmony_ci	uint32_t addr, pri_addr, sec_addr;
59268c2ecf20Sopenharmony_ci	uint32_t offset;
59278c2ecf20Sopenharmony_ci	uint16_t func_num;
59288c2ecf20Sopenharmony_ci	uint8_t val;
59298c2ecf20Sopenharmony_ci	uint8_t *buf = NULL;
59308c2ecf20Sopenharmony_ci	size_t size = 13 * sizeof(uint8_t);
59318c2ecf20Sopenharmony_ci	int ret = QLA_SUCCESS;
59328c2ecf20Sopenharmony_ci
59338c2ecf20Sopenharmony_ci	func_num = PCI_FUNC(ha->pdev->devfn);
59348c2ecf20Sopenharmony_ci
59358c2ecf20Sopenharmony_ci	ql4_printk(KERN_INFO, ha, "%s: Get FW boot info for 0x%x func %d\n",
59368c2ecf20Sopenharmony_ci		   __func__, ha->pdev->device, func_num);
59378c2ecf20Sopenharmony_ci
59388c2ecf20Sopenharmony_ci	if (is_qla40XX(ha)) {
59398c2ecf20Sopenharmony_ci		if (func_num == 1) {
59408c2ecf20Sopenharmony_ci			addr = NVRAM_PORT0_BOOT_MODE;
59418c2ecf20Sopenharmony_ci			pri_addr = NVRAM_PORT0_BOOT_PRI_TGT;
59428c2ecf20Sopenharmony_ci			sec_addr = NVRAM_PORT0_BOOT_SEC_TGT;
59438c2ecf20Sopenharmony_ci		} else if (func_num == 3) {
59448c2ecf20Sopenharmony_ci			addr = NVRAM_PORT1_BOOT_MODE;
59458c2ecf20Sopenharmony_ci			pri_addr = NVRAM_PORT1_BOOT_PRI_TGT;
59468c2ecf20Sopenharmony_ci			sec_addr = NVRAM_PORT1_BOOT_SEC_TGT;
59478c2ecf20Sopenharmony_ci		} else {
59488c2ecf20Sopenharmony_ci			ret = QLA_ERROR;
59498c2ecf20Sopenharmony_ci			goto exit_boot_info;
59508c2ecf20Sopenharmony_ci		}
59518c2ecf20Sopenharmony_ci
59528c2ecf20Sopenharmony_ci		/* Check Boot Mode */
59538c2ecf20Sopenharmony_ci		val = rd_nvram_byte(ha, addr);
59548c2ecf20Sopenharmony_ci		if (!(val & 0x07)) {
59558c2ecf20Sopenharmony_ci			DEBUG2(ql4_printk(KERN_INFO, ha, "%s: Adapter boot "
59568c2ecf20Sopenharmony_ci					  "options : 0x%x\n", __func__, val));
59578c2ecf20Sopenharmony_ci			ret = QLA_ERROR;
59588c2ecf20Sopenharmony_ci			goto exit_boot_info;
59598c2ecf20Sopenharmony_ci		}
59608c2ecf20Sopenharmony_ci
59618c2ecf20Sopenharmony_ci		/* get primary valid target index */
59628c2ecf20Sopenharmony_ci		val = rd_nvram_byte(ha, pri_addr);
59638c2ecf20Sopenharmony_ci		if (val & BIT_7)
59648c2ecf20Sopenharmony_ci			ddb_index[0] = (val & 0x7f);
59658c2ecf20Sopenharmony_ci
59668c2ecf20Sopenharmony_ci		/* get secondary valid target index */
59678c2ecf20Sopenharmony_ci		val = rd_nvram_byte(ha, sec_addr);
59688c2ecf20Sopenharmony_ci		if (val & BIT_7)
59698c2ecf20Sopenharmony_ci			ddb_index[1] = (val & 0x7f);
59708c2ecf20Sopenharmony_ci		goto exit_boot_info;
59718c2ecf20Sopenharmony_ci	} else if (is_qla80XX(ha)) {
59728c2ecf20Sopenharmony_ci		buf = dma_alloc_coherent(&ha->pdev->dev, size,
59738c2ecf20Sopenharmony_ci					 &buf_dma, GFP_KERNEL);
59748c2ecf20Sopenharmony_ci		if (!buf) {
59758c2ecf20Sopenharmony_ci			DEBUG2(ql4_printk(KERN_ERR, ha,
59768c2ecf20Sopenharmony_ci					  "%s: Unable to allocate dma buffer\n",
59778c2ecf20Sopenharmony_ci					   __func__));
59788c2ecf20Sopenharmony_ci			ret = QLA_ERROR;
59798c2ecf20Sopenharmony_ci			goto exit_boot_info;
59808c2ecf20Sopenharmony_ci		}
59818c2ecf20Sopenharmony_ci
59828c2ecf20Sopenharmony_ci		if (ha->port_num == 0)
59838c2ecf20Sopenharmony_ci			offset = BOOT_PARAM_OFFSET_PORT0;
59848c2ecf20Sopenharmony_ci		else if (ha->port_num == 1)
59858c2ecf20Sopenharmony_ci			offset = BOOT_PARAM_OFFSET_PORT1;
59868c2ecf20Sopenharmony_ci		else {
59878c2ecf20Sopenharmony_ci			ret = QLA_ERROR;
59888c2ecf20Sopenharmony_ci			goto exit_boot_info_free;
59898c2ecf20Sopenharmony_ci		}
59908c2ecf20Sopenharmony_ci		addr = FLASH_RAW_ACCESS_ADDR + (ha->hw.flt_iscsi_param * 4) +
59918c2ecf20Sopenharmony_ci		       offset;
59928c2ecf20Sopenharmony_ci		if (qla4xxx_get_flash(ha, buf_dma, addr,
59938c2ecf20Sopenharmony_ci				      13 * sizeof(uint8_t)) != QLA_SUCCESS) {
59948c2ecf20Sopenharmony_ci			DEBUG2(ql4_printk(KERN_ERR, ha, "scsi%ld: %s: Get Flash"
59958c2ecf20Sopenharmony_ci					  " failed\n", ha->host_no, __func__));
59968c2ecf20Sopenharmony_ci			ret = QLA_ERROR;
59978c2ecf20Sopenharmony_ci			goto exit_boot_info_free;
59988c2ecf20Sopenharmony_ci		}
59998c2ecf20Sopenharmony_ci		/* Check Boot Mode */
60008c2ecf20Sopenharmony_ci		if (!(buf[1] & 0x07)) {
60018c2ecf20Sopenharmony_ci			DEBUG2(ql4_printk(KERN_INFO, ha, "Firmware boot options"
60028c2ecf20Sopenharmony_ci					  " : 0x%x\n", buf[1]));
60038c2ecf20Sopenharmony_ci			ret = QLA_ERROR;
60048c2ecf20Sopenharmony_ci			goto exit_boot_info_free;
60058c2ecf20Sopenharmony_ci		}
60068c2ecf20Sopenharmony_ci
60078c2ecf20Sopenharmony_ci		/* get primary valid target index */
60088c2ecf20Sopenharmony_ci		if (buf[2] & BIT_7)
60098c2ecf20Sopenharmony_ci			ddb_index[0] = buf[2] & 0x7f;
60108c2ecf20Sopenharmony_ci
60118c2ecf20Sopenharmony_ci		/* get secondary valid target index */
60128c2ecf20Sopenharmony_ci		if (buf[11] & BIT_7)
60138c2ecf20Sopenharmony_ci			ddb_index[1] = buf[11] & 0x7f;
60148c2ecf20Sopenharmony_ci	} else {
60158c2ecf20Sopenharmony_ci		ret = QLA_ERROR;
60168c2ecf20Sopenharmony_ci		goto exit_boot_info;
60178c2ecf20Sopenharmony_ci	}
60188c2ecf20Sopenharmony_ci
60198c2ecf20Sopenharmony_ci	DEBUG2(ql4_printk(KERN_INFO, ha, "%s: Primary target ID %d, Secondary"
60208c2ecf20Sopenharmony_ci			  " target ID %d\n", __func__, ddb_index[0],
60218c2ecf20Sopenharmony_ci			  ddb_index[1]));
60228c2ecf20Sopenharmony_ci
60238c2ecf20Sopenharmony_ciexit_boot_info_free:
60248c2ecf20Sopenharmony_ci	dma_free_coherent(&ha->pdev->dev, size, buf, buf_dma);
60258c2ecf20Sopenharmony_ciexit_boot_info:
60268c2ecf20Sopenharmony_ci	ha->pri_ddb_idx = ddb_index[0];
60278c2ecf20Sopenharmony_ci	ha->sec_ddb_idx = ddb_index[1];
60288c2ecf20Sopenharmony_ci	return ret;
60298c2ecf20Sopenharmony_ci}
60308c2ecf20Sopenharmony_ci
60318c2ecf20Sopenharmony_ci/**
60328c2ecf20Sopenharmony_ci * qla4xxx_get_bidi_chap - Get a BIDI CHAP user and password
60338c2ecf20Sopenharmony_ci * @ha: pointer to adapter structure
60348c2ecf20Sopenharmony_ci * @username: CHAP username to be returned
60358c2ecf20Sopenharmony_ci * @password: CHAP password to be returned
60368c2ecf20Sopenharmony_ci *
60378c2ecf20Sopenharmony_ci * If a boot entry has BIDI CHAP enabled then we need to set the BIDI CHAP
60388c2ecf20Sopenharmony_ci * user and password in the sysfs entry in /sys/firmware/iscsi_boot#/.
60398c2ecf20Sopenharmony_ci * So from the CHAP cache find the first BIDI CHAP entry and set it
60408c2ecf20Sopenharmony_ci * to the boot record in sysfs.
60418c2ecf20Sopenharmony_ci **/
60428c2ecf20Sopenharmony_cistatic int qla4xxx_get_bidi_chap(struct scsi_qla_host *ha, char *username,
60438c2ecf20Sopenharmony_ci			    char *password)
60448c2ecf20Sopenharmony_ci{
60458c2ecf20Sopenharmony_ci	int i, ret = -EINVAL;
60468c2ecf20Sopenharmony_ci	int max_chap_entries = 0;
60478c2ecf20Sopenharmony_ci	struct ql4_chap_table *chap_table;
60488c2ecf20Sopenharmony_ci
60498c2ecf20Sopenharmony_ci	if (is_qla80XX(ha))
60508c2ecf20Sopenharmony_ci		max_chap_entries = (ha->hw.flt_chap_size / 2) /
60518c2ecf20Sopenharmony_ci						sizeof(struct ql4_chap_table);
60528c2ecf20Sopenharmony_ci	else
60538c2ecf20Sopenharmony_ci		max_chap_entries = MAX_CHAP_ENTRIES_40XX;
60548c2ecf20Sopenharmony_ci
60558c2ecf20Sopenharmony_ci	if (!ha->chap_list) {
60568c2ecf20Sopenharmony_ci		ql4_printk(KERN_ERR, ha, "Do not have CHAP table cache\n");
60578c2ecf20Sopenharmony_ci		return ret;
60588c2ecf20Sopenharmony_ci	}
60598c2ecf20Sopenharmony_ci
60608c2ecf20Sopenharmony_ci	mutex_lock(&ha->chap_sem);
60618c2ecf20Sopenharmony_ci	for (i = 0; i < max_chap_entries; i++) {
60628c2ecf20Sopenharmony_ci		chap_table = (struct ql4_chap_table *)ha->chap_list + i;
60638c2ecf20Sopenharmony_ci		if (chap_table->cookie !=
60648c2ecf20Sopenharmony_ci		    __constant_cpu_to_le16(CHAP_VALID_COOKIE)) {
60658c2ecf20Sopenharmony_ci			continue;
60668c2ecf20Sopenharmony_ci		}
60678c2ecf20Sopenharmony_ci
60688c2ecf20Sopenharmony_ci		if (chap_table->flags & BIT_7) /* local */
60698c2ecf20Sopenharmony_ci			continue;
60708c2ecf20Sopenharmony_ci
60718c2ecf20Sopenharmony_ci		if (!(chap_table->flags & BIT_6)) /* Not BIDI */
60728c2ecf20Sopenharmony_ci			continue;
60738c2ecf20Sopenharmony_ci
60748c2ecf20Sopenharmony_ci		strlcpy(password, chap_table->secret, QL4_CHAP_MAX_SECRET_LEN);
60758c2ecf20Sopenharmony_ci		strlcpy(username, chap_table->name, QL4_CHAP_MAX_NAME_LEN);
60768c2ecf20Sopenharmony_ci		ret = 0;
60778c2ecf20Sopenharmony_ci		break;
60788c2ecf20Sopenharmony_ci	}
60798c2ecf20Sopenharmony_ci	mutex_unlock(&ha->chap_sem);
60808c2ecf20Sopenharmony_ci
60818c2ecf20Sopenharmony_ci	return ret;
60828c2ecf20Sopenharmony_ci}
60838c2ecf20Sopenharmony_ci
60848c2ecf20Sopenharmony_ci
60858c2ecf20Sopenharmony_cistatic int qla4xxx_get_boot_target(struct scsi_qla_host *ha,
60868c2ecf20Sopenharmony_ci				   struct ql4_boot_session_info *boot_sess,
60878c2ecf20Sopenharmony_ci				   uint16_t ddb_index)
60888c2ecf20Sopenharmony_ci{
60898c2ecf20Sopenharmony_ci	struct ql4_conn_info *boot_conn = &boot_sess->conn_list[0];
60908c2ecf20Sopenharmony_ci	struct dev_db_entry *fw_ddb_entry;
60918c2ecf20Sopenharmony_ci	dma_addr_t fw_ddb_entry_dma;
60928c2ecf20Sopenharmony_ci	uint16_t idx;
60938c2ecf20Sopenharmony_ci	uint16_t options;
60948c2ecf20Sopenharmony_ci	int ret = QLA_SUCCESS;
60958c2ecf20Sopenharmony_ci
60968c2ecf20Sopenharmony_ci	fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
60978c2ecf20Sopenharmony_ci					  &fw_ddb_entry_dma, GFP_KERNEL);
60988c2ecf20Sopenharmony_ci	if (!fw_ddb_entry) {
60998c2ecf20Sopenharmony_ci		DEBUG2(ql4_printk(KERN_ERR, ha,
61008c2ecf20Sopenharmony_ci				  "%s: Unable to allocate dma buffer.\n",
61018c2ecf20Sopenharmony_ci				  __func__));
61028c2ecf20Sopenharmony_ci		ret = QLA_ERROR;
61038c2ecf20Sopenharmony_ci		return ret;
61048c2ecf20Sopenharmony_ci	}
61058c2ecf20Sopenharmony_ci
61068c2ecf20Sopenharmony_ci	if (qla4xxx_bootdb_by_index(ha, fw_ddb_entry,
61078c2ecf20Sopenharmony_ci				   fw_ddb_entry_dma, ddb_index)) {
61088c2ecf20Sopenharmony_ci		DEBUG2(ql4_printk(KERN_INFO, ha, "%s: No Flash DDB found at "
61098c2ecf20Sopenharmony_ci				  "index [%d]\n", __func__, ddb_index));
61108c2ecf20Sopenharmony_ci		ret = QLA_ERROR;
61118c2ecf20Sopenharmony_ci		goto exit_boot_target;
61128c2ecf20Sopenharmony_ci	}
61138c2ecf20Sopenharmony_ci
61148c2ecf20Sopenharmony_ci	/* Update target name and IP from DDB */
61158c2ecf20Sopenharmony_ci	memcpy(boot_sess->target_name, fw_ddb_entry->iscsi_name,
61168c2ecf20Sopenharmony_ci	       min(sizeof(boot_sess->target_name),
61178c2ecf20Sopenharmony_ci		   sizeof(fw_ddb_entry->iscsi_name)));
61188c2ecf20Sopenharmony_ci
61198c2ecf20Sopenharmony_ci	options = le16_to_cpu(fw_ddb_entry->options);
61208c2ecf20Sopenharmony_ci	if (options & DDB_OPT_IPV6_DEVICE) {
61218c2ecf20Sopenharmony_ci		memcpy(&boot_conn->dest_ipaddr.ip_address,
61228c2ecf20Sopenharmony_ci		       &fw_ddb_entry->ip_addr[0], IPv6_ADDR_LEN);
61238c2ecf20Sopenharmony_ci	} else {
61248c2ecf20Sopenharmony_ci		boot_conn->dest_ipaddr.ip_type = 0x1;
61258c2ecf20Sopenharmony_ci		memcpy(&boot_conn->dest_ipaddr.ip_address,
61268c2ecf20Sopenharmony_ci		       &fw_ddb_entry->ip_addr[0], IP_ADDR_LEN);
61278c2ecf20Sopenharmony_ci	}
61288c2ecf20Sopenharmony_ci
61298c2ecf20Sopenharmony_ci	boot_conn->dest_port = le16_to_cpu(fw_ddb_entry->port);
61308c2ecf20Sopenharmony_ci
61318c2ecf20Sopenharmony_ci	/* update chap information */
61328c2ecf20Sopenharmony_ci	idx = __le16_to_cpu(fw_ddb_entry->chap_tbl_idx);
61338c2ecf20Sopenharmony_ci
61348c2ecf20Sopenharmony_ci	if (BIT_7 & le16_to_cpu(fw_ddb_entry->iscsi_options))	{
61358c2ecf20Sopenharmony_ci
61368c2ecf20Sopenharmony_ci		DEBUG2(ql4_printk(KERN_INFO, ha, "Setting chap\n"));
61378c2ecf20Sopenharmony_ci
61388c2ecf20Sopenharmony_ci		ret = qla4xxx_get_chap(ha, (char *)&boot_conn->chap.
61398c2ecf20Sopenharmony_ci				       target_chap_name,
61408c2ecf20Sopenharmony_ci				       (char *)&boot_conn->chap.target_secret,
61418c2ecf20Sopenharmony_ci				       idx);
61428c2ecf20Sopenharmony_ci		if (ret) {
61438c2ecf20Sopenharmony_ci			ql4_printk(KERN_ERR, ha, "Failed to set chap\n");
61448c2ecf20Sopenharmony_ci			ret = QLA_ERROR;
61458c2ecf20Sopenharmony_ci			goto exit_boot_target;
61468c2ecf20Sopenharmony_ci		}
61478c2ecf20Sopenharmony_ci
61488c2ecf20Sopenharmony_ci		boot_conn->chap.target_chap_name_length = QL4_CHAP_MAX_NAME_LEN;
61498c2ecf20Sopenharmony_ci		boot_conn->chap.target_secret_length = QL4_CHAP_MAX_SECRET_LEN;
61508c2ecf20Sopenharmony_ci	}
61518c2ecf20Sopenharmony_ci
61528c2ecf20Sopenharmony_ci	if (BIT_4 & le16_to_cpu(fw_ddb_entry->iscsi_options)) {
61538c2ecf20Sopenharmony_ci
61548c2ecf20Sopenharmony_ci		DEBUG2(ql4_printk(KERN_INFO, ha, "Setting BIDI chap\n"));
61558c2ecf20Sopenharmony_ci
61568c2ecf20Sopenharmony_ci		ret = qla4xxx_get_bidi_chap(ha,
61578c2ecf20Sopenharmony_ci				    (char *)&boot_conn->chap.intr_chap_name,
61588c2ecf20Sopenharmony_ci				    (char *)&boot_conn->chap.intr_secret);
61598c2ecf20Sopenharmony_ci
61608c2ecf20Sopenharmony_ci		if (ret) {
61618c2ecf20Sopenharmony_ci			ql4_printk(KERN_ERR, ha, "Failed to set BIDI chap\n");
61628c2ecf20Sopenharmony_ci			ret = QLA_ERROR;
61638c2ecf20Sopenharmony_ci			goto exit_boot_target;
61648c2ecf20Sopenharmony_ci		}
61658c2ecf20Sopenharmony_ci
61668c2ecf20Sopenharmony_ci		boot_conn->chap.intr_chap_name_length = QL4_CHAP_MAX_NAME_LEN;
61678c2ecf20Sopenharmony_ci		boot_conn->chap.intr_secret_length = QL4_CHAP_MAX_SECRET_LEN;
61688c2ecf20Sopenharmony_ci	}
61698c2ecf20Sopenharmony_ci
61708c2ecf20Sopenharmony_ciexit_boot_target:
61718c2ecf20Sopenharmony_ci	dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
61728c2ecf20Sopenharmony_ci			  fw_ddb_entry, fw_ddb_entry_dma);
61738c2ecf20Sopenharmony_ci	return ret;
61748c2ecf20Sopenharmony_ci}
61758c2ecf20Sopenharmony_ci
61768c2ecf20Sopenharmony_cistatic int qla4xxx_get_boot_info(struct scsi_qla_host *ha)
61778c2ecf20Sopenharmony_ci{
61788c2ecf20Sopenharmony_ci	uint16_t ddb_index[2];
61798c2ecf20Sopenharmony_ci	int ret = QLA_ERROR;
61808c2ecf20Sopenharmony_ci	int rval;
61818c2ecf20Sopenharmony_ci
61828c2ecf20Sopenharmony_ci	memset(ddb_index, 0, sizeof(ddb_index));
61838c2ecf20Sopenharmony_ci	ddb_index[0] = 0xffff;
61848c2ecf20Sopenharmony_ci	ddb_index[1] = 0xffff;
61858c2ecf20Sopenharmony_ci	ret = get_fw_boot_info(ha, ddb_index);
61868c2ecf20Sopenharmony_ci	if (ret != QLA_SUCCESS) {
61878c2ecf20Sopenharmony_ci		DEBUG2(ql4_printk(KERN_INFO, ha,
61888c2ecf20Sopenharmony_ci				"%s: No boot target configured.\n", __func__));
61898c2ecf20Sopenharmony_ci		return ret;
61908c2ecf20Sopenharmony_ci	}
61918c2ecf20Sopenharmony_ci
61928c2ecf20Sopenharmony_ci	if (ql4xdisablesysfsboot)
61938c2ecf20Sopenharmony_ci		return QLA_SUCCESS;
61948c2ecf20Sopenharmony_ci
61958c2ecf20Sopenharmony_ci	if (ddb_index[0] == 0xffff)
61968c2ecf20Sopenharmony_ci		goto sec_target;
61978c2ecf20Sopenharmony_ci
61988c2ecf20Sopenharmony_ci	rval = qla4xxx_get_boot_target(ha, &(ha->boot_tgt.boot_pri_sess),
61998c2ecf20Sopenharmony_ci				      ddb_index[0]);
62008c2ecf20Sopenharmony_ci	if (rval != QLA_SUCCESS) {
62018c2ecf20Sopenharmony_ci		DEBUG2(ql4_printk(KERN_INFO, ha, "%s: Primary boot target not "
62028c2ecf20Sopenharmony_ci				  "configured\n", __func__));
62038c2ecf20Sopenharmony_ci	} else
62048c2ecf20Sopenharmony_ci		ret = QLA_SUCCESS;
62058c2ecf20Sopenharmony_ci
62068c2ecf20Sopenharmony_cisec_target:
62078c2ecf20Sopenharmony_ci	if (ddb_index[1] == 0xffff)
62088c2ecf20Sopenharmony_ci		goto exit_get_boot_info;
62098c2ecf20Sopenharmony_ci
62108c2ecf20Sopenharmony_ci	rval = qla4xxx_get_boot_target(ha, &(ha->boot_tgt.boot_sec_sess),
62118c2ecf20Sopenharmony_ci				      ddb_index[1]);
62128c2ecf20Sopenharmony_ci	if (rval != QLA_SUCCESS) {
62138c2ecf20Sopenharmony_ci		DEBUG2(ql4_printk(KERN_INFO, ha, "%s: Secondary boot target not"
62148c2ecf20Sopenharmony_ci				  " configured\n", __func__));
62158c2ecf20Sopenharmony_ci	} else
62168c2ecf20Sopenharmony_ci		ret = QLA_SUCCESS;
62178c2ecf20Sopenharmony_ci
62188c2ecf20Sopenharmony_ciexit_get_boot_info:
62198c2ecf20Sopenharmony_ci	return ret;
62208c2ecf20Sopenharmony_ci}
62218c2ecf20Sopenharmony_ci
62228c2ecf20Sopenharmony_cistatic int qla4xxx_setup_boot_info(struct scsi_qla_host *ha)
62238c2ecf20Sopenharmony_ci{
62248c2ecf20Sopenharmony_ci	struct iscsi_boot_kobj *boot_kobj;
62258c2ecf20Sopenharmony_ci
62268c2ecf20Sopenharmony_ci	if (qla4xxx_get_boot_info(ha) != QLA_SUCCESS)
62278c2ecf20Sopenharmony_ci		return QLA_ERROR;
62288c2ecf20Sopenharmony_ci
62298c2ecf20Sopenharmony_ci	if (ql4xdisablesysfsboot) {
62308c2ecf20Sopenharmony_ci		ql4_printk(KERN_INFO, ha,
62318c2ecf20Sopenharmony_ci			   "%s: syfsboot disabled - driver will trigger login "
62328c2ecf20Sopenharmony_ci			   "and publish session for discovery .\n", __func__);
62338c2ecf20Sopenharmony_ci		return QLA_SUCCESS;
62348c2ecf20Sopenharmony_ci	}
62358c2ecf20Sopenharmony_ci
62368c2ecf20Sopenharmony_ci
62378c2ecf20Sopenharmony_ci	ha->boot_kset = iscsi_boot_create_host_kset(ha->host->host_no);
62388c2ecf20Sopenharmony_ci	if (!ha->boot_kset)
62398c2ecf20Sopenharmony_ci		goto kset_free;
62408c2ecf20Sopenharmony_ci
62418c2ecf20Sopenharmony_ci	if (!scsi_host_get(ha->host))
62428c2ecf20Sopenharmony_ci		goto kset_free;
62438c2ecf20Sopenharmony_ci	boot_kobj = iscsi_boot_create_target(ha->boot_kset, 0, ha,
62448c2ecf20Sopenharmony_ci					     qla4xxx_show_boot_tgt_pri_info,
62458c2ecf20Sopenharmony_ci					     qla4xxx_tgt_get_attr_visibility,
62468c2ecf20Sopenharmony_ci					     qla4xxx_boot_release);
62478c2ecf20Sopenharmony_ci	if (!boot_kobj)
62488c2ecf20Sopenharmony_ci		goto put_host;
62498c2ecf20Sopenharmony_ci
62508c2ecf20Sopenharmony_ci	if (!scsi_host_get(ha->host))
62518c2ecf20Sopenharmony_ci		goto kset_free;
62528c2ecf20Sopenharmony_ci	boot_kobj = iscsi_boot_create_target(ha->boot_kset, 1, ha,
62538c2ecf20Sopenharmony_ci					     qla4xxx_show_boot_tgt_sec_info,
62548c2ecf20Sopenharmony_ci					     qla4xxx_tgt_get_attr_visibility,
62558c2ecf20Sopenharmony_ci					     qla4xxx_boot_release);
62568c2ecf20Sopenharmony_ci	if (!boot_kobj)
62578c2ecf20Sopenharmony_ci		goto put_host;
62588c2ecf20Sopenharmony_ci
62598c2ecf20Sopenharmony_ci	if (!scsi_host_get(ha->host))
62608c2ecf20Sopenharmony_ci		goto kset_free;
62618c2ecf20Sopenharmony_ci	boot_kobj = iscsi_boot_create_initiator(ha->boot_kset, 0, ha,
62628c2ecf20Sopenharmony_ci					       qla4xxx_show_boot_ini_info,
62638c2ecf20Sopenharmony_ci					       qla4xxx_ini_get_attr_visibility,
62648c2ecf20Sopenharmony_ci					       qla4xxx_boot_release);
62658c2ecf20Sopenharmony_ci	if (!boot_kobj)
62668c2ecf20Sopenharmony_ci		goto put_host;
62678c2ecf20Sopenharmony_ci
62688c2ecf20Sopenharmony_ci	if (!scsi_host_get(ha->host))
62698c2ecf20Sopenharmony_ci		goto kset_free;
62708c2ecf20Sopenharmony_ci	boot_kobj = iscsi_boot_create_ethernet(ha->boot_kset, 0, ha,
62718c2ecf20Sopenharmony_ci					       qla4xxx_show_boot_eth_info,
62728c2ecf20Sopenharmony_ci					       qla4xxx_eth_get_attr_visibility,
62738c2ecf20Sopenharmony_ci					       qla4xxx_boot_release);
62748c2ecf20Sopenharmony_ci	if (!boot_kobj)
62758c2ecf20Sopenharmony_ci		goto put_host;
62768c2ecf20Sopenharmony_ci
62778c2ecf20Sopenharmony_ci	return QLA_SUCCESS;
62788c2ecf20Sopenharmony_ci
62798c2ecf20Sopenharmony_ciput_host:
62808c2ecf20Sopenharmony_ci	scsi_host_put(ha->host);
62818c2ecf20Sopenharmony_cikset_free:
62828c2ecf20Sopenharmony_ci	iscsi_boot_destroy_kset(ha->boot_kset);
62838c2ecf20Sopenharmony_ci	return -ENOMEM;
62848c2ecf20Sopenharmony_ci}
62858c2ecf20Sopenharmony_ci
62868c2ecf20Sopenharmony_ci
62878c2ecf20Sopenharmony_cistatic void qla4xxx_get_param_ddb(struct ddb_entry *ddb_entry,
62888c2ecf20Sopenharmony_ci				  struct ql4_tuple_ddb *tddb)
62898c2ecf20Sopenharmony_ci{
62908c2ecf20Sopenharmony_ci	struct iscsi_cls_session *cls_sess;
62918c2ecf20Sopenharmony_ci	struct iscsi_cls_conn *cls_conn;
62928c2ecf20Sopenharmony_ci	struct iscsi_session *sess;
62938c2ecf20Sopenharmony_ci	struct iscsi_conn *conn;
62948c2ecf20Sopenharmony_ci
62958c2ecf20Sopenharmony_ci	DEBUG2(printk(KERN_INFO "Func: %s\n", __func__));
62968c2ecf20Sopenharmony_ci	cls_sess = ddb_entry->sess;
62978c2ecf20Sopenharmony_ci	sess = cls_sess->dd_data;
62988c2ecf20Sopenharmony_ci	cls_conn = ddb_entry->conn;
62998c2ecf20Sopenharmony_ci	conn = cls_conn->dd_data;
63008c2ecf20Sopenharmony_ci
63018c2ecf20Sopenharmony_ci	tddb->tpgt = sess->tpgt;
63028c2ecf20Sopenharmony_ci	tddb->port = conn->persistent_port;
63038c2ecf20Sopenharmony_ci	strlcpy(tddb->iscsi_name, sess->targetname, ISCSI_NAME_SIZE);
63048c2ecf20Sopenharmony_ci	strlcpy(tddb->ip_addr, conn->persistent_address, DDB_IPADDR_LEN);
63058c2ecf20Sopenharmony_ci}
63068c2ecf20Sopenharmony_ci
63078c2ecf20Sopenharmony_cistatic void qla4xxx_convert_param_ddb(struct dev_db_entry *fw_ddb_entry,
63088c2ecf20Sopenharmony_ci				      struct ql4_tuple_ddb *tddb,
63098c2ecf20Sopenharmony_ci				      uint8_t *flash_isid)
63108c2ecf20Sopenharmony_ci{
63118c2ecf20Sopenharmony_ci	uint16_t options = 0;
63128c2ecf20Sopenharmony_ci
63138c2ecf20Sopenharmony_ci	tddb->tpgt = le32_to_cpu(fw_ddb_entry->tgt_portal_grp);
63148c2ecf20Sopenharmony_ci	memcpy(&tddb->iscsi_name[0], &fw_ddb_entry->iscsi_name[0],
63158c2ecf20Sopenharmony_ci	       min(sizeof(tddb->iscsi_name), sizeof(fw_ddb_entry->iscsi_name)));
63168c2ecf20Sopenharmony_ci
63178c2ecf20Sopenharmony_ci	options = le16_to_cpu(fw_ddb_entry->options);
63188c2ecf20Sopenharmony_ci	if (options & DDB_OPT_IPV6_DEVICE)
63198c2ecf20Sopenharmony_ci		sprintf(tddb->ip_addr, "%pI6", fw_ddb_entry->ip_addr);
63208c2ecf20Sopenharmony_ci	else
63218c2ecf20Sopenharmony_ci		sprintf(tddb->ip_addr, "%pI4", fw_ddb_entry->ip_addr);
63228c2ecf20Sopenharmony_ci
63238c2ecf20Sopenharmony_ci	tddb->port = le16_to_cpu(fw_ddb_entry->port);
63248c2ecf20Sopenharmony_ci
63258c2ecf20Sopenharmony_ci	if (flash_isid == NULL)
63268c2ecf20Sopenharmony_ci		memcpy(&tddb->isid[0], &fw_ddb_entry->isid[0],
63278c2ecf20Sopenharmony_ci		       sizeof(tddb->isid));
63288c2ecf20Sopenharmony_ci	else
63298c2ecf20Sopenharmony_ci		memcpy(&tddb->isid[0], &flash_isid[0], sizeof(tddb->isid));
63308c2ecf20Sopenharmony_ci}
63318c2ecf20Sopenharmony_ci
63328c2ecf20Sopenharmony_cistatic int qla4xxx_compare_tuple_ddb(struct scsi_qla_host *ha,
63338c2ecf20Sopenharmony_ci				     struct ql4_tuple_ddb *old_tddb,
63348c2ecf20Sopenharmony_ci				     struct ql4_tuple_ddb *new_tddb,
63358c2ecf20Sopenharmony_ci				     uint8_t is_isid_compare)
63368c2ecf20Sopenharmony_ci{
63378c2ecf20Sopenharmony_ci	if (strcmp(old_tddb->iscsi_name, new_tddb->iscsi_name))
63388c2ecf20Sopenharmony_ci		return QLA_ERROR;
63398c2ecf20Sopenharmony_ci
63408c2ecf20Sopenharmony_ci	if (strcmp(old_tddb->ip_addr, new_tddb->ip_addr))
63418c2ecf20Sopenharmony_ci		return QLA_ERROR;
63428c2ecf20Sopenharmony_ci
63438c2ecf20Sopenharmony_ci	if (old_tddb->port != new_tddb->port)
63448c2ecf20Sopenharmony_ci		return QLA_ERROR;
63458c2ecf20Sopenharmony_ci
63468c2ecf20Sopenharmony_ci	/* For multi sessions, driver generates the ISID, so do not compare
63478c2ecf20Sopenharmony_ci	 * ISID in reset path since it would be a comparison between the
63488c2ecf20Sopenharmony_ci	 * driver generated ISID and firmware generated ISID. This could
63498c2ecf20Sopenharmony_ci	 * lead to adding duplicated DDBs in the list as driver generated
63508c2ecf20Sopenharmony_ci	 * ISID would not match firmware generated ISID.
63518c2ecf20Sopenharmony_ci	 */
63528c2ecf20Sopenharmony_ci	if (is_isid_compare) {
63538c2ecf20Sopenharmony_ci		DEBUG2(ql4_printk(KERN_INFO, ha,
63548c2ecf20Sopenharmony_ci			"%s: old ISID [%pmR] New ISID [%pmR]\n",
63558c2ecf20Sopenharmony_ci			__func__, old_tddb->isid, new_tddb->isid));
63568c2ecf20Sopenharmony_ci
63578c2ecf20Sopenharmony_ci		if (memcmp(&old_tddb->isid[0], &new_tddb->isid[0],
63588c2ecf20Sopenharmony_ci			   sizeof(old_tddb->isid)))
63598c2ecf20Sopenharmony_ci			return QLA_ERROR;
63608c2ecf20Sopenharmony_ci	}
63618c2ecf20Sopenharmony_ci
63628c2ecf20Sopenharmony_ci	DEBUG2(ql4_printk(KERN_INFO, ha,
63638c2ecf20Sopenharmony_ci			  "Match Found, fw[%d,%d,%s,%s], [%d,%d,%s,%s]",
63648c2ecf20Sopenharmony_ci			  old_tddb->port, old_tddb->tpgt, old_tddb->ip_addr,
63658c2ecf20Sopenharmony_ci			  old_tddb->iscsi_name, new_tddb->port, new_tddb->tpgt,
63668c2ecf20Sopenharmony_ci			  new_tddb->ip_addr, new_tddb->iscsi_name));
63678c2ecf20Sopenharmony_ci
63688c2ecf20Sopenharmony_ci	return QLA_SUCCESS;
63698c2ecf20Sopenharmony_ci}
63708c2ecf20Sopenharmony_ci
63718c2ecf20Sopenharmony_cistatic int qla4xxx_is_session_exists(struct scsi_qla_host *ha,
63728c2ecf20Sopenharmony_ci				     struct dev_db_entry *fw_ddb_entry,
63738c2ecf20Sopenharmony_ci				     uint32_t *index)
63748c2ecf20Sopenharmony_ci{
63758c2ecf20Sopenharmony_ci	struct ddb_entry *ddb_entry;
63768c2ecf20Sopenharmony_ci	struct ql4_tuple_ddb *fw_tddb = NULL;
63778c2ecf20Sopenharmony_ci	struct ql4_tuple_ddb *tmp_tddb = NULL;
63788c2ecf20Sopenharmony_ci	int idx;
63798c2ecf20Sopenharmony_ci	int ret = QLA_ERROR;
63808c2ecf20Sopenharmony_ci
63818c2ecf20Sopenharmony_ci	fw_tddb = vzalloc(sizeof(*fw_tddb));
63828c2ecf20Sopenharmony_ci	if (!fw_tddb) {
63838c2ecf20Sopenharmony_ci		DEBUG2(ql4_printk(KERN_WARNING, ha,
63848c2ecf20Sopenharmony_ci				  "Memory Allocation failed.\n"));
63858c2ecf20Sopenharmony_ci		ret = QLA_SUCCESS;
63868c2ecf20Sopenharmony_ci		goto exit_check;
63878c2ecf20Sopenharmony_ci	}
63888c2ecf20Sopenharmony_ci
63898c2ecf20Sopenharmony_ci	tmp_tddb = vzalloc(sizeof(*tmp_tddb));
63908c2ecf20Sopenharmony_ci	if (!tmp_tddb) {
63918c2ecf20Sopenharmony_ci		DEBUG2(ql4_printk(KERN_WARNING, ha,
63928c2ecf20Sopenharmony_ci				  "Memory Allocation failed.\n"));
63938c2ecf20Sopenharmony_ci		ret = QLA_SUCCESS;
63948c2ecf20Sopenharmony_ci		goto exit_check;
63958c2ecf20Sopenharmony_ci	}
63968c2ecf20Sopenharmony_ci
63978c2ecf20Sopenharmony_ci	qla4xxx_convert_param_ddb(fw_ddb_entry, fw_tddb, NULL);
63988c2ecf20Sopenharmony_ci
63998c2ecf20Sopenharmony_ci	for (idx = 0; idx < MAX_DDB_ENTRIES; idx++) {
64008c2ecf20Sopenharmony_ci		ddb_entry = qla4xxx_lookup_ddb_by_fw_index(ha, idx);
64018c2ecf20Sopenharmony_ci		if (ddb_entry == NULL)
64028c2ecf20Sopenharmony_ci			continue;
64038c2ecf20Sopenharmony_ci
64048c2ecf20Sopenharmony_ci		qla4xxx_get_param_ddb(ddb_entry, tmp_tddb);
64058c2ecf20Sopenharmony_ci		if (!qla4xxx_compare_tuple_ddb(ha, fw_tddb, tmp_tddb, false)) {
64068c2ecf20Sopenharmony_ci			ret = QLA_SUCCESS; /* found */
64078c2ecf20Sopenharmony_ci			if (index != NULL)
64088c2ecf20Sopenharmony_ci				*index = idx;
64098c2ecf20Sopenharmony_ci			goto exit_check;
64108c2ecf20Sopenharmony_ci		}
64118c2ecf20Sopenharmony_ci	}
64128c2ecf20Sopenharmony_ci
64138c2ecf20Sopenharmony_ciexit_check:
64148c2ecf20Sopenharmony_ci	if (fw_tddb)
64158c2ecf20Sopenharmony_ci		vfree(fw_tddb);
64168c2ecf20Sopenharmony_ci	if (tmp_tddb)
64178c2ecf20Sopenharmony_ci		vfree(tmp_tddb);
64188c2ecf20Sopenharmony_ci	return ret;
64198c2ecf20Sopenharmony_ci}
64208c2ecf20Sopenharmony_ci
64218c2ecf20Sopenharmony_ci/**
64228c2ecf20Sopenharmony_ci * qla4xxx_check_existing_isid - check if target with same isid exist
64238c2ecf20Sopenharmony_ci *				 in target list
64248c2ecf20Sopenharmony_ci * @list_nt: list of target
64258c2ecf20Sopenharmony_ci * @isid: isid to check
64268c2ecf20Sopenharmony_ci *
64278c2ecf20Sopenharmony_ci * This routine return QLA_SUCCESS if target with same isid exist
64288c2ecf20Sopenharmony_ci **/
64298c2ecf20Sopenharmony_cistatic int qla4xxx_check_existing_isid(struct list_head *list_nt, uint8_t *isid)
64308c2ecf20Sopenharmony_ci{
64318c2ecf20Sopenharmony_ci	struct qla_ddb_index *nt_ddb_idx, *nt_ddb_idx_tmp;
64328c2ecf20Sopenharmony_ci	struct dev_db_entry *fw_ddb_entry;
64338c2ecf20Sopenharmony_ci
64348c2ecf20Sopenharmony_ci	list_for_each_entry_safe(nt_ddb_idx, nt_ddb_idx_tmp, list_nt, list) {
64358c2ecf20Sopenharmony_ci		fw_ddb_entry = &nt_ddb_idx->fw_ddb;
64368c2ecf20Sopenharmony_ci
64378c2ecf20Sopenharmony_ci		if (memcmp(&fw_ddb_entry->isid[0], &isid[0],
64388c2ecf20Sopenharmony_ci			   sizeof(nt_ddb_idx->fw_ddb.isid)) == 0) {
64398c2ecf20Sopenharmony_ci			return QLA_SUCCESS;
64408c2ecf20Sopenharmony_ci		}
64418c2ecf20Sopenharmony_ci	}
64428c2ecf20Sopenharmony_ci	return QLA_ERROR;
64438c2ecf20Sopenharmony_ci}
64448c2ecf20Sopenharmony_ci
64458c2ecf20Sopenharmony_ci/**
64468c2ecf20Sopenharmony_ci * qla4xxx_update_isid - compare ddbs and updated isid
64478c2ecf20Sopenharmony_ci * @ha: Pointer to host adapter structure.
64488c2ecf20Sopenharmony_ci * @list_nt: list of nt target
64498c2ecf20Sopenharmony_ci * @fw_ddb_entry: firmware ddb entry
64508c2ecf20Sopenharmony_ci *
64518c2ecf20Sopenharmony_ci * This routine update isid if ddbs have same iqn, same isid and
64528c2ecf20Sopenharmony_ci * different IP addr.
64538c2ecf20Sopenharmony_ci * Return QLA_SUCCESS if isid is updated.
64548c2ecf20Sopenharmony_ci **/
64558c2ecf20Sopenharmony_cistatic int qla4xxx_update_isid(struct scsi_qla_host *ha,
64568c2ecf20Sopenharmony_ci			       struct list_head *list_nt,
64578c2ecf20Sopenharmony_ci			       struct dev_db_entry *fw_ddb_entry)
64588c2ecf20Sopenharmony_ci{
64598c2ecf20Sopenharmony_ci	uint8_t base_value, i;
64608c2ecf20Sopenharmony_ci
64618c2ecf20Sopenharmony_ci	base_value = fw_ddb_entry->isid[1] & 0x1f;
64628c2ecf20Sopenharmony_ci	for (i = 0; i < 8; i++) {
64638c2ecf20Sopenharmony_ci		fw_ddb_entry->isid[1] = (base_value | (i << 5));
64648c2ecf20Sopenharmony_ci		if (qla4xxx_check_existing_isid(list_nt, fw_ddb_entry->isid))
64658c2ecf20Sopenharmony_ci			break;
64668c2ecf20Sopenharmony_ci	}
64678c2ecf20Sopenharmony_ci
64688c2ecf20Sopenharmony_ci	if (!qla4xxx_check_existing_isid(list_nt, fw_ddb_entry->isid))
64698c2ecf20Sopenharmony_ci		return QLA_ERROR;
64708c2ecf20Sopenharmony_ci
64718c2ecf20Sopenharmony_ci	return QLA_SUCCESS;
64728c2ecf20Sopenharmony_ci}
64738c2ecf20Sopenharmony_ci
64748c2ecf20Sopenharmony_ci/**
64758c2ecf20Sopenharmony_ci * qla4xxx_should_update_isid - check if isid need to update
64768c2ecf20Sopenharmony_ci * @ha: Pointer to host adapter structure.
64778c2ecf20Sopenharmony_ci * @old_tddb: ddb tuple
64788c2ecf20Sopenharmony_ci * @new_tddb: ddb tuple
64798c2ecf20Sopenharmony_ci *
64808c2ecf20Sopenharmony_ci * Return QLA_SUCCESS if different IP, different PORT, same iqn,
64818c2ecf20Sopenharmony_ci * same isid
64828c2ecf20Sopenharmony_ci **/
64838c2ecf20Sopenharmony_cistatic int qla4xxx_should_update_isid(struct scsi_qla_host *ha,
64848c2ecf20Sopenharmony_ci				      struct ql4_tuple_ddb *old_tddb,
64858c2ecf20Sopenharmony_ci				      struct ql4_tuple_ddb *new_tddb)
64868c2ecf20Sopenharmony_ci{
64878c2ecf20Sopenharmony_ci	if (strcmp(old_tddb->ip_addr, new_tddb->ip_addr) == 0) {
64888c2ecf20Sopenharmony_ci		/* Same ip */
64898c2ecf20Sopenharmony_ci		if (old_tddb->port == new_tddb->port)
64908c2ecf20Sopenharmony_ci			return QLA_ERROR;
64918c2ecf20Sopenharmony_ci	}
64928c2ecf20Sopenharmony_ci
64938c2ecf20Sopenharmony_ci	if (strcmp(old_tddb->iscsi_name, new_tddb->iscsi_name))
64948c2ecf20Sopenharmony_ci		/* different iqn */
64958c2ecf20Sopenharmony_ci		return QLA_ERROR;
64968c2ecf20Sopenharmony_ci
64978c2ecf20Sopenharmony_ci	if (memcmp(&old_tddb->isid[0], &new_tddb->isid[0],
64988c2ecf20Sopenharmony_ci		   sizeof(old_tddb->isid)))
64998c2ecf20Sopenharmony_ci		/* different isid */
65008c2ecf20Sopenharmony_ci		return QLA_ERROR;
65018c2ecf20Sopenharmony_ci
65028c2ecf20Sopenharmony_ci	return QLA_SUCCESS;
65038c2ecf20Sopenharmony_ci}
65048c2ecf20Sopenharmony_ci
65058c2ecf20Sopenharmony_ci/**
65068c2ecf20Sopenharmony_ci * qla4xxx_is_flash_ddb_exists - check if fw_ddb_entry already exists in list_nt
65078c2ecf20Sopenharmony_ci * @ha: Pointer to host adapter structure.
65088c2ecf20Sopenharmony_ci * @list_nt: list of nt target.
65098c2ecf20Sopenharmony_ci * @fw_ddb_entry: firmware ddb entry.
65108c2ecf20Sopenharmony_ci *
65118c2ecf20Sopenharmony_ci * This routine check if fw_ddb_entry already exists in list_nt to avoid
65128c2ecf20Sopenharmony_ci * duplicate ddb in list_nt.
65138c2ecf20Sopenharmony_ci * Return QLA_SUCCESS if duplicate ddb exit in list_nl.
65148c2ecf20Sopenharmony_ci * Note: This function also update isid of DDB if required.
65158c2ecf20Sopenharmony_ci **/
65168c2ecf20Sopenharmony_ci
65178c2ecf20Sopenharmony_cistatic int qla4xxx_is_flash_ddb_exists(struct scsi_qla_host *ha,
65188c2ecf20Sopenharmony_ci				       struct list_head *list_nt,
65198c2ecf20Sopenharmony_ci				       struct dev_db_entry *fw_ddb_entry)
65208c2ecf20Sopenharmony_ci{
65218c2ecf20Sopenharmony_ci	struct qla_ddb_index  *nt_ddb_idx, *nt_ddb_idx_tmp;
65228c2ecf20Sopenharmony_ci	struct ql4_tuple_ddb *fw_tddb = NULL;
65238c2ecf20Sopenharmony_ci	struct ql4_tuple_ddb *tmp_tddb = NULL;
65248c2ecf20Sopenharmony_ci	int rval, ret = QLA_ERROR;
65258c2ecf20Sopenharmony_ci
65268c2ecf20Sopenharmony_ci	fw_tddb = vzalloc(sizeof(*fw_tddb));
65278c2ecf20Sopenharmony_ci	if (!fw_tddb) {
65288c2ecf20Sopenharmony_ci		DEBUG2(ql4_printk(KERN_WARNING, ha,
65298c2ecf20Sopenharmony_ci				  "Memory Allocation failed.\n"));
65308c2ecf20Sopenharmony_ci		ret = QLA_SUCCESS;
65318c2ecf20Sopenharmony_ci		goto exit_check;
65328c2ecf20Sopenharmony_ci	}
65338c2ecf20Sopenharmony_ci
65348c2ecf20Sopenharmony_ci	tmp_tddb = vzalloc(sizeof(*tmp_tddb));
65358c2ecf20Sopenharmony_ci	if (!tmp_tddb) {
65368c2ecf20Sopenharmony_ci		DEBUG2(ql4_printk(KERN_WARNING, ha,
65378c2ecf20Sopenharmony_ci				  "Memory Allocation failed.\n"));
65388c2ecf20Sopenharmony_ci		ret = QLA_SUCCESS;
65398c2ecf20Sopenharmony_ci		goto exit_check;
65408c2ecf20Sopenharmony_ci	}
65418c2ecf20Sopenharmony_ci
65428c2ecf20Sopenharmony_ci	qla4xxx_convert_param_ddb(fw_ddb_entry, fw_tddb, NULL);
65438c2ecf20Sopenharmony_ci
65448c2ecf20Sopenharmony_ci	list_for_each_entry_safe(nt_ddb_idx, nt_ddb_idx_tmp, list_nt, list) {
65458c2ecf20Sopenharmony_ci		qla4xxx_convert_param_ddb(&nt_ddb_idx->fw_ddb, tmp_tddb,
65468c2ecf20Sopenharmony_ci					  nt_ddb_idx->flash_isid);
65478c2ecf20Sopenharmony_ci		ret = qla4xxx_compare_tuple_ddb(ha, fw_tddb, tmp_tddb, true);
65488c2ecf20Sopenharmony_ci		/* found duplicate ddb */
65498c2ecf20Sopenharmony_ci		if (ret == QLA_SUCCESS)
65508c2ecf20Sopenharmony_ci			goto exit_check;
65518c2ecf20Sopenharmony_ci	}
65528c2ecf20Sopenharmony_ci
65538c2ecf20Sopenharmony_ci	list_for_each_entry_safe(nt_ddb_idx, nt_ddb_idx_tmp, list_nt, list) {
65548c2ecf20Sopenharmony_ci		qla4xxx_convert_param_ddb(&nt_ddb_idx->fw_ddb, tmp_tddb, NULL);
65558c2ecf20Sopenharmony_ci
65568c2ecf20Sopenharmony_ci		ret = qla4xxx_should_update_isid(ha, tmp_tddb, fw_tddb);
65578c2ecf20Sopenharmony_ci		if (ret == QLA_SUCCESS) {
65588c2ecf20Sopenharmony_ci			rval = qla4xxx_update_isid(ha, list_nt, fw_ddb_entry);
65598c2ecf20Sopenharmony_ci			if (rval == QLA_SUCCESS)
65608c2ecf20Sopenharmony_ci				ret = QLA_ERROR;
65618c2ecf20Sopenharmony_ci			else
65628c2ecf20Sopenharmony_ci				ret = QLA_SUCCESS;
65638c2ecf20Sopenharmony_ci
65648c2ecf20Sopenharmony_ci			goto exit_check;
65658c2ecf20Sopenharmony_ci		}
65668c2ecf20Sopenharmony_ci	}
65678c2ecf20Sopenharmony_ci
65688c2ecf20Sopenharmony_ciexit_check:
65698c2ecf20Sopenharmony_ci	if (fw_tddb)
65708c2ecf20Sopenharmony_ci		vfree(fw_tddb);
65718c2ecf20Sopenharmony_ci	if (tmp_tddb)
65728c2ecf20Sopenharmony_ci		vfree(tmp_tddb);
65738c2ecf20Sopenharmony_ci	return ret;
65748c2ecf20Sopenharmony_ci}
65758c2ecf20Sopenharmony_ci
65768c2ecf20Sopenharmony_cistatic void qla4xxx_free_ddb_list(struct list_head *list_ddb)
65778c2ecf20Sopenharmony_ci{
65788c2ecf20Sopenharmony_ci	struct qla_ddb_index  *ddb_idx, *ddb_idx_tmp;
65798c2ecf20Sopenharmony_ci
65808c2ecf20Sopenharmony_ci	list_for_each_entry_safe(ddb_idx, ddb_idx_tmp, list_ddb, list) {
65818c2ecf20Sopenharmony_ci		list_del_init(&ddb_idx->list);
65828c2ecf20Sopenharmony_ci		vfree(ddb_idx);
65838c2ecf20Sopenharmony_ci	}
65848c2ecf20Sopenharmony_ci}
65858c2ecf20Sopenharmony_ci
65868c2ecf20Sopenharmony_cistatic struct iscsi_endpoint *qla4xxx_get_ep_fwdb(struct scsi_qla_host *ha,
65878c2ecf20Sopenharmony_ci					struct dev_db_entry *fw_ddb_entry)
65888c2ecf20Sopenharmony_ci{
65898c2ecf20Sopenharmony_ci	struct iscsi_endpoint *ep;
65908c2ecf20Sopenharmony_ci	struct sockaddr_in *addr;
65918c2ecf20Sopenharmony_ci	struct sockaddr_in6 *addr6;
65928c2ecf20Sopenharmony_ci	struct sockaddr *t_addr;
65938c2ecf20Sopenharmony_ci	struct sockaddr_storage *dst_addr;
65948c2ecf20Sopenharmony_ci	char *ip;
65958c2ecf20Sopenharmony_ci
65968c2ecf20Sopenharmony_ci	/* TODO: need to destroy on unload iscsi_endpoint*/
65978c2ecf20Sopenharmony_ci	dst_addr = vmalloc(sizeof(*dst_addr));
65988c2ecf20Sopenharmony_ci	if (!dst_addr)
65998c2ecf20Sopenharmony_ci		return NULL;
66008c2ecf20Sopenharmony_ci
66018c2ecf20Sopenharmony_ci	if (fw_ddb_entry->options & DDB_OPT_IPV6_DEVICE) {
66028c2ecf20Sopenharmony_ci		t_addr = (struct sockaddr *)dst_addr;
66038c2ecf20Sopenharmony_ci		t_addr->sa_family = AF_INET6;
66048c2ecf20Sopenharmony_ci		addr6 = (struct sockaddr_in6 *)dst_addr;
66058c2ecf20Sopenharmony_ci		ip = (char *)&addr6->sin6_addr;
66068c2ecf20Sopenharmony_ci		memcpy(ip, fw_ddb_entry->ip_addr, IPv6_ADDR_LEN);
66078c2ecf20Sopenharmony_ci		addr6->sin6_port = htons(le16_to_cpu(fw_ddb_entry->port));
66088c2ecf20Sopenharmony_ci
66098c2ecf20Sopenharmony_ci	} else {
66108c2ecf20Sopenharmony_ci		t_addr = (struct sockaddr *)dst_addr;
66118c2ecf20Sopenharmony_ci		t_addr->sa_family = AF_INET;
66128c2ecf20Sopenharmony_ci		addr = (struct sockaddr_in *)dst_addr;
66138c2ecf20Sopenharmony_ci		ip = (char *)&addr->sin_addr;
66148c2ecf20Sopenharmony_ci		memcpy(ip, fw_ddb_entry->ip_addr, IP_ADDR_LEN);
66158c2ecf20Sopenharmony_ci		addr->sin_port = htons(le16_to_cpu(fw_ddb_entry->port));
66168c2ecf20Sopenharmony_ci	}
66178c2ecf20Sopenharmony_ci
66188c2ecf20Sopenharmony_ci	ep = qla4xxx_ep_connect(ha->host, (struct sockaddr *)dst_addr, 0);
66198c2ecf20Sopenharmony_ci	vfree(dst_addr);
66208c2ecf20Sopenharmony_ci	return ep;
66218c2ecf20Sopenharmony_ci}
66228c2ecf20Sopenharmony_ci
66238c2ecf20Sopenharmony_cistatic int qla4xxx_verify_boot_idx(struct scsi_qla_host *ha, uint16_t idx)
66248c2ecf20Sopenharmony_ci{
66258c2ecf20Sopenharmony_ci	if (ql4xdisablesysfsboot)
66268c2ecf20Sopenharmony_ci		return QLA_SUCCESS;
66278c2ecf20Sopenharmony_ci	if (idx == ha->pri_ddb_idx || idx == ha->sec_ddb_idx)
66288c2ecf20Sopenharmony_ci		return QLA_ERROR;
66298c2ecf20Sopenharmony_ci	return QLA_SUCCESS;
66308c2ecf20Sopenharmony_ci}
66318c2ecf20Sopenharmony_ci
66328c2ecf20Sopenharmony_cistatic void qla4xxx_setup_flash_ddb_entry(struct scsi_qla_host *ha,
66338c2ecf20Sopenharmony_ci					  struct ddb_entry *ddb_entry,
66348c2ecf20Sopenharmony_ci					  uint16_t idx)
66358c2ecf20Sopenharmony_ci{
66368c2ecf20Sopenharmony_ci	uint16_t def_timeout;
66378c2ecf20Sopenharmony_ci
66388c2ecf20Sopenharmony_ci	ddb_entry->ddb_type = FLASH_DDB;
66398c2ecf20Sopenharmony_ci	ddb_entry->fw_ddb_index = INVALID_ENTRY;
66408c2ecf20Sopenharmony_ci	ddb_entry->fw_ddb_device_state = DDB_DS_NO_CONNECTION_ACTIVE;
66418c2ecf20Sopenharmony_ci	ddb_entry->ha = ha;
66428c2ecf20Sopenharmony_ci	ddb_entry->unblock_sess = qla4xxx_unblock_flash_ddb;
66438c2ecf20Sopenharmony_ci	ddb_entry->ddb_change = qla4xxx_flash_ddb_change;
66448c2ecf20Sopenharmony_ci	ddb_entry->chap_tbl_idx = INVALID_ENTRY;
66458c2ecf20Sopenharmony_ci
66468c2ecf20Sopenharmony_ci	atomic_set(&ddb_entry->retry_relogin_timer, INVALID_ENTRY);
66478c2ecf20Sopenharmony_ci	atomic_set(&ddb_entry->relogin_timer, 0);
66488c2ecf20Sopenharmony_ci	atomic_set(&ddb_entry->relogin_retry_count, 0);
66498c2ecf20Sopenharmony_ci	def_timeout = le16_to_cpu(ddb_entry->fw_ddb_entry.def_timeout);
66508c2ecf20Sopenharmony_ci	ddb_entry->default_relogin_timeout =
66518c2ecf20Sopenharmony_ci		(def_timeout > LOGIN_TOV) && (def_timeout < LOGIN_TOV * 10) ?
66528c2ecf20Sopenharmony_ci		def_timeout : LOGIN_TOV;
66538c2ecf20Sopenharmony_ci	ddb_entry->default_time2wait =
66548c2ecf20Sopenharmony_ci		le16_to_cpu(ddb_entry->fw_ddb_entry.iscsi_def_time2wait);
66558c2ecf20Sopenharmony_ci
66568c2ecf20Sopenharmony_ci	if (ql4xdisablesysfsboot &&
66578c2ecf20Sopenharmony_ci	    (idx == ha->pri_ddb_idx || idx == ha->sec_ddb_idx))
66588c2ecf20Sopenharmony_ci		set_bit(DF_BOOT_TGT, &ddb_entry->flags);
66598c2ecf20Sopenharmony_ci}
66608c2ecf20Sopenharmony_ci
66618c2ecf20Sopenharmony_cistatic void qla4xxx_wait_for_ip_configuration(struct scsi_qla_host *ha)
66628c2ecf20Sopenharmony_ci{
66638c2ecf20Sopenharmony_ci	uint32_t idx = 0;
66648c2ecf20Sopenharmony_ci	uint32_t ip_idx[IP_ADDR_COUNT] = {0, 1, 2, 3}; /* 4 IP interfaces */
66658c2ecf20Sopenharmony_ci	uint32_t sts[MBOX_REG_COUNT];
66668c2ecf20Sopenharmony_ci	uint32_t ip_state;
66678c2ecf20Sopenharmony_ci	unsigned long wtime;
66688c2ecf20Sopenharmony_ci	int ret;
66698c2ecf20Sopenharmony_ci
66708c2ecf20Sopenharmony_ci	wtime = jiffies + (HZ * IP_CONFIG_TOV);
66718c2ecf20Sopenharmony_ci	do {
66728c2ecf20Sopenharmony_ci		for (idx = 0; idx < IP_ADDR_COUNT; idx++) {
66738c2ecf20Sopenharmony_ci			if (ip_idx[idx] == -1)
66748c2ecf20Sopenharmony_ci				continue;
66758c2ecf20Sopenharmony_ci
66768c2ecf20Sopenharmony_ci			ret = qla4xxx_get_ip_state(ha, 0, ip_idx[idx], sts);
66778c2ecf20Sopenharmony_ci
66788c2ecf20Sopenharmony_ci			if (ret == QLA_ERROR) {
66798c2ecf20Sopenharmony_ci				ip_idx[idx] = -1;
66808c2ecf20Sopenharmony_ci				continue;
66818c2ecf20Sopenharmony_ci			}
66828c2ecf20Sopenharmony_ci
66838c2ecf20Sopenharmony_ci			ip_state = (sts[1] & IP_STATE_MASK) >> IP_STATE_SHIFT;
66848c2ecf20Sopenharmony_ci
66858c2ecf20Sopenharmony_ci			DEBUG2(ql4_printk(KERN_INFO, ha,
66868c2ecf20Sopenharmony_ci					  "Waiting for IP state for idx = %d, state = 0x%x\n",
66878c2ecf20Sopenharmony_ci					  ip_idx[idx], ip_state));
66888c2ecf20Sopenharmony_ci			if (ip_state == IP_ADDRSTATE_UNCONFIGURED ||
66898c2ecf20Sopenharmony_ci			    ip_state == IP_ADDRSTATE_INVALID ||
66908c2ecf20Sopenharmony_ci			    ip_state == IP_ADDRSTATE_PREFERRED ||
66918c2ecf20Sopenharmony_ci			    ip_state == IP_ADDRSTATE_DEPRICATED ||
66928c2ecf20Sopenharmony_ci			    ip_state == IP_ADDRSTATE_DISABLING)
66938c2ecf20Sopenharmony_ci				ip_idx[idx] = -1;
66948c2ecf20Sopenharmony_ci		}
66958c2ecf20Sopenharmony_ci
66968c2ecf20Sopenharmony_ci		/* Break if all IP states checked */
66978c2ecf20Sopenharmony_ci		if ((ip_idx[0] == -1) &&
66988c2ecf20Sopenharmony_ci		    (ip_idx[1] == -1) &&
66998c2ecf20Sopenharmony_ci		    (ip_idx[2] == -1) &&
67008c2ecf20Sopenharmony_ci		    (ip_idx[3] == -1))
67018c2ecf20Sopenharmony_ci			break;
67028c2ecf20Sopenharmony_ci		schedule_timeout_uninterruptible(HZ);
67038c2ecf20Sopenharmony_ci	} while (time_after(wtime, jiffies));
67048c2ecf20Sopenharmony_ci}
67058c2ecf20Sopenharmony_ci
67068c2ecf20Sopenharmony_cistatic int qla4xxx_cmp_fw_stentry(struct dev_db_entry *fw_ddb_entry,
67078c2ecf20Sopenharmony_ci				  struct dev_db_entry *flash_ddb_entry)
67088c2ecf20Sopenharmony_ci{
67098c2ecf20Sopenharmony_ci	uint16_t options = 0;
67108c2ecf20Sopenharmony_ci	size_t ip_len = IP_ADDR_LEN;
67118c2ecf20Sopenharmony_ci
67128c2ecf20Sopenharmony_ci	options = le16_to_cpu(fw_ddb_entry->options);
67138c2ecf20Sopenharmony_ci	if (options & DDB_OPT_IPV6_DEVICE)
67148c2ecf20Sopenharmony_ci		ip_len = IPv6_ADDR_LEN;
67158c2ecf20Sopenharmony_ci
67168c2ecf20Sopenharmony_ci	if (memcmp(fw_ddb_entry->ip_addr, flash_ddb_entry->ip_addr, ip_len))
67178c2ecf20Sopenharmony_ci		return QLA_ERROR;
67188c2ecf20Sopenharmony_ci
67198c2ecf20Sopenharmony_ci	if (memcmp(&fw_ddb_entry->isid[0], &flash_ddb_entry->isid[0],
67208c2ecf20Sopenharmony_ci		   sizeof(fw_ddb_entry->isid)))
67218c2ecf20Sopenharmony_ci		return QLA_ERROR;
67228c2ecf20Sopenharmony_ci
67238c2ecf20Sopenharmony_ci	if (memcmp(&fw_ddb_entry->port, &flash_ddb_entry->port,
67248c2ecf20Sopenharmony_ci		   sizeof(fw_ddb_entry->port)))
67258c2ecf20Sopenharmony_ci		return QLA_ERROR;
67268c2ecf20Sopenharmony_ci
67278c2ecf20Sopenharmony_ci	return QLA_SUCCESS;
67288c2ecf20Sopenharmony_ci}
67298c2ecf20Sopenharmony_ci
67308c2ecf20Sopenharmony_cistatic int qla4xxx_find_flash_st_idx(struct scsi_qla_host *ha,
67318c2ecf20Sopenharmony_ci				     struct dev_db_entry *fw_ddb_entry,
67328c2ecf20Sopenharmony_ci				     uint32_t fw_idx, uint32_t *flash_index)
67338c2ecf20Sopenharmony_ci{
67348c2ecf20Sopenharmony_ci	struct dev_db_entry *flash_ddb_entry;
67358c2ecf20Sopenharmony_ci	dma_addr_t flash_ddb_entry_dma;
67368c2ecf20Sopenharmony_ci	uint32_t idx = 0;
67378c2ecf20Sopenharmony_ci	int max_ddbs;
67388c2ecf20Sopenharmony_ci	int ret = QLA_ERROR, status;
67398c2ecf20Sopenharmony_ci
67408c2ecf20Sopenharmony_ci	max_ddbs =  is_qla40XX(ha) ? MAX_DEV_DB_ENTRIES_40XX :
67418c2ecf20Sopenharmony_ci				     MAX_DEV_DB_ENTRIES;
67428c2ecf20Sopenharmony_ci
67438c2ecf20Sopenharmony_ci	flash_ddb_entry = dma_pool_alloc(ha->fw_ddb_dma_pool, GFP_KERNEL,
67448c2ecf20Sopenharmony_ci					 &flash_ddb_entry_dma);
67458c2ecf20Sopenharmony_ci	if (flash_ddb_entry == NULL || fw_ddb_entry == NULL) {
67468c2ecf20Sopenharmony_ci		ql4_printk(KERN_ERR, ha, "Out of memory\n");
67478c2ecf20Sopenharmony_ci		goto exit_find_st_idx;
67488c2ecf20Sopenharmony_ci	}
67498c2ecf20Sopenharmony_ci
67508c2ecf20Sopenharmony_ci	status = qla4xxx_flashdb_by_index(ha, flash_ddb_entry,
67518c2ecf20Sopenharmony_ci					  flash_ddb_entry_dma, fw_idx);
67528c2ecf20Sopenharmony_ci	if (status == QLA_SUCCESS) {
67538c2ecf20Sopenharmony_ci		status = qla4xxx_cmp_fw_stentry(fw_ddb_entry, flash_ddb_entry);
67548c2ecf20Sopenharmony_ci		if (status == QLA_SUCCESS) {
67558c2ecf20Sopenharmony_ci			*flash_index = fw_idx;
67568c2ecf20Sopenharmony_ci			ret = QLA_SUCCESS;
67578c2ecf20Sopenharmony_ci			goto exit_find_st_idx;
67588c2ecf20Sopenharmony_ci		}
67598c2ecf20Sopenharmony_ci	}
67608c2ecf20Sopenharmony_ci
67618c2ecf20Sopenharmony_ci	for (idx = 0; idx < max_ddbs; idx++) {
67628c2ecf20Sopenharmony_ci		status = qla4xxx_flashdb_by_index(ha, flash_ddb_entry,
67638c2ecf20Sopenharmony_ci						  flash_ddb_entry_dma, idx);
67648c2ecf20Sopenharmony_ci		if (status == QLA_ERROR)
67658c2ecf20Sopenharmony_ci			continue;
67668c2ecf20Sopenharmony_ci
67678c2ecf20Sopenharmony_ci		status = qla4xxx_cmp_fw_stentry(fw_ddb_entry, flash_ddb_entry);
67688c2ecf20Sopenharmony_ci		if (status == QLA_SUCCESS) {
67698c2ecf20Sopenharmony_ci			*flash_index = idx;
67708c2ecf20Sopenharmony_ci			ret = QLA_SUCCESS;
67718c2ecf20Sopenharmony_ci			goto exit_find_st_idx;
67728c2ecf20Sopenharmony_ci		}
67738c2ecf20Sopenharmony_ci	}
67748c2ecf20Sopenharmony_ci
67758c2ecf20Sopenharmony_ci	if (idx == max_ddbs)
67768c2ecf20Sopenharmony_ci		ql4_printk(KERN_ERR, ha, "Failed to find ST [%d] in flash\n",
67778c2ecf20Sopenharmony_ci			   fw_idx);
67788c2ecf20Sopenharmony_ci
67798c2ecf20Sopenharmony_ciexit_find_st_idx:
67808c2ecf20Sopenharmony_ci	if (flash_ddb_entry)
67818c2ecf20Sopenharmony_ci		dma_pool_free(ha->fw_ddb_dma_pool, flash_ddb_entry,
67828c2ecf20Sopenharmony_ci			      flash_ddb_entry_dma);
67838c2ecf20Sopenharmony_ci
67848c2ecf20Sopenharmony_ci	return ret;
67858c2ecf20Sopenharmony_ci}
67868c2ecf20Sopenharmony_ci
67878c2ecf20Sopenharmony_cistatic void qla4xxx_build_st_list(struct scsi_qla_host *ha,
67888c2ecf20Sopenharmony_ci				  struct list_head *list_st)
67898c2ecf20Sopenharmony_ci{
67908c2ecf20Sopenharmony_ci	struct qla_ddb_index  *st_ddb_idx;
67918c2ecf20Sopenharmony_ci	int max_ddbs;
67928c2ecf20Sopenharmony_ci	int fw_idx_size;
67938c2ecf20Sopenharmony_ci	struct dev_db_entry *fw_ddb_entry;
67948c2ecf20Sopenharmony_ci	dma_addr_t fw_ddb_dma;
67958c2ecf20Sopenharmony_ci	int ret;
67968c2ecf20Sopenharmony_ci	uint32_t idx = 0, next_idx = 0;
67978c2ecf20Sopenharmony_ci	uint32_t state = 0, conn_err = 0;
67988c2ecf20Sopenharmony_ci	uint32_t flash_index = -1;
67998c2ecf20Sopenharmony_ci	uint16_t conn_id = 0;
68008c2ecf20Sopenharmony_ci
68018c2ecf20Sopenharmony_ci	fw_ddb_entry = dma_pool_alloc(ha->fw_ddb_dma_pool, GFP_KERNEL,
68028c2ecf20Sopenharmony_ci				      &fw_ddb_dma);
68038c2ecf20Sopenharmony_ci	if (fw_ddb_entry == NULL) {
68048c2ecf20Sopenharmony_ci		DEBUG2(ql4_printk(KERN_ERR, ha, "Out of memory\n"));
68058c2ecf20Sopenharmony_ci		goto exit_st_list;
68068c2ecf20Sopenharmony_ci	}
68078c2ecf20Sopenharmony_ci
68088c2ecf20Sopenharmony_ci	max_ddbs =  is_qla40XX(ha) ? MAX_DEV_DB_ENTRIES_40XX :
68098c2ecf20Sopenharmony_ci				     MAX_DEV_DB_ENTRIES;
68108c2ecf20Sopenharmony_ci	fw_idx_size = sizeof(struct qla_ddb_index);
68118c2ecf20Sopenharmony_ci
68128c2ecf20Sopenharmony_ci	for (idx = 0; idx < max_ddbs; idx = next_idx) {
68138c2ecf20Sopenharmony_ci		ret = qla4xxx_get_fwddb_entry(ha, idx, fw_ddb_entry, fw_ddb_dma,
68148c2ecf20Sopenharmony_ci					      NULL, &next_idx, &state,
68158c2ecf20Sopenharmony_ci					      &conn_err, NULL, &conn_id);
68168c2ecf20Sopenharmony_ci		if (ret == QLA_ERROR)
68178c2ecf20Sopenharmony_ci			break;
68188c2ecf20Sopenharmony_ci
68198c2ecf20Sopenharmony_ci		/* Ignore DDB if invalid state (unassigned) */
68208c2ecf20Sopenharmony_ci		if (state == DDB_DS_UNASSIGNED)
68218c2ecf20Sopenharmony_ci			goto continue_next_st;
68228c2ecf20Sopenharmony_ci
68238c2ecf20Sopenharmony_ci		/* Check if ST, add to the list_st */
68248c2ecf20Sopenharmony_ci		if (strlen((char *) fw_ddb_entry->iscsi_name) != 0)
68258c2ecf20Sopenharmony_ci			goto continue_next_st;
68268c2ecf20Sopenharmony_ci
68278c2ecf20Sopenharmony_ci		st_ddb_idx = vzalloc(fw_idx_size);
68288c2ecf20Sopenharmony_ci		if (!st_ddb_idx)
68298c2ecf20Sopenharmony_ci			break;
68308c2ecf20Sopenharmony_ci
68318c2ecf20Sopenharmony_ci		ret = qla4xxx_find_flash_st_idx(ha, fw_ddb_entry, idx,
68328c2ecf20Sopenharmony_ci						&flash_index);
68338c2ecf20Sopenharmony_ci		if (ret == QLA_ERROR) {
68348c2ecf20Sopenharmony_ci			ql4_printk(KERN_ERR, ha,
68358c2ecf20Sopenharmony_ci				   "No flash entry for ST at idx [%d]\n", idx);
68368c2ecf20Sopenharmony_ci			st_ddb_idx->flash_ddb_idx = idx;
68378c2ecf20Sopenharmony_ci		} else {
68388c2ecf20Sopenharmony_ci			ql4_printk(KERN_INFO, ha,
68398c2ecf20Sopenharmony_ci				   "ST at idx [%d] is stored at flash [%d]\n",
68408c2ecf20Sopenharmony_ci				   idx, flash_index);
68418c2ecf20Sopenharmony_ci			st_ddb_idx->flash_ddb_idx = flash_index;
68428c2ecf20Sopenharmony_ci		}
68438c2ecf20Sopenharmony_ci
68448c2ecf20Sopenharmony_ci		st_ddb_idx->fw_ddb_idx = idx;
68458c2ecf20Sopenharmony_ci
68468c2ecf20Sopenharmony_ci		list_add_tail(&st_ddb_idx->list, list_st);
68478c2ecf20Sopenharmony_cicontinue_next_st:
68488c2ecf20Sopenharmony_ci		if (next_idx == 0)
68498c2ecf20Sopenharmony_ci			break;
68508c2ecf20Sopenharmony_ci	}
68518c2ecf20Sopenharmony_ci
68528c2ecf20Sopenharmony_ciexit_st_list:
68538c2ecf20Sopenharmony_ci	if (fw_ddb_entry)
68548c2ecf20Sopenharmony_ci		dma_pool_free(ha->fw_ddb_dma_pool, fw_ddb_entry, fw_ddb_dma);
68558c2ecf20Sopenharmony_ci}
68568c2ecf20Sopenharmony_ci
68578c2ecf20Sopenharmony_ci/**
68588c2ecf20Sopenharmony_ci * qla4xxx_remove_failed_ddb - Remove inactive or failed ddb from list
68598c2ecf20Sopenharmony_ci * @ha: pointer to adapter structure
68608c2ecf20Sopenharmony_ci * @list_ddb: List from which failed ddb to be removed
68618c2ecf20Sopenharmony_ci *
68628c2ecf20Sopenharmony_ci * Iterate over the list of DDBs and find and remove DDBs that are either in
68638c2ecf20Sopenharmony_ci * no connection active state or failed state
68648c2ecf20Sopenharmony_ci **/
68658c2ecf20Sopenharmony_cistatic void qla4xxx_remove_failed_ddb(struct scsi_qla_host *ha,
68668c2ecf20Sopenharmony_ci				      struct list_head *list_ddb)
68678c2ecf20Sopenharmony_ci{
68688c2ecf20Sopenharmony_ci	struct qla_ddb_index  *ddb_idx, *ddb_idx_tmp;
68698c2ecf20Sopenharmony_ci	uint32_t next_idx = 0;
68708c2ecf20Sopenharmony_ci	uint32_t state = 0, conn_err = 0;
68718c2ecf20Sopenharmony_ci	int ret;
68728c2ecf20Sopenharmony_ci
68738c2ecf20Sopenharmony_ci	list_for_each_entry_safe(ddb_idx, ddb_idx_tmp, list_ddb, list) {
68748c2ecf20Sopenharmony_ci		ret = qla4xxx_get_fwddb_entry(ha, ddb_idx->fw_ddb_idx,
68758c2ecf20Sopenharmony_ci					      NULL, 0, NULL, &next_idx, &state,
68768c2ecf20Sopenharmony_ci					      &conn_err, NULL, NULL);
68778c2ecf20Sopenharmony_ci		if (ret == QLA_ERROR)
68788c2ecf20Sopenharmony_ci			continue;
68798c2ecf20Sopenharmony_ci
68808c2ecf20Sopenharmony_ci		if (state == DDB_DS_NO_CONNECTION_ACTIVE ||
68818c2ecf20Sopenharmony_ci		    state == DDB_DS_SESSION_FAILED) {
68828c2ecf20Sopenharmony_ci			list_del_init(&ddb_idx->list);
68838c2ecf20Sopenharmony_ci			vfree(ddb_idx);
68848c2ecf20Sopenharmony_ci		}
68858c2ecf20Sopenharmony_ci	}
68868c2ecf20Sopenharmony_ci}
68878c2ecf20Sopenharmony_ci
68888c2ecf20Sopenharmony_cistatic void qla4xxx_update_sess_disc_idx(struct scsi_qla_host *ha,
68898c2ecf20Sopenharmony_ci					 struct ddb_entry *ddb_entry,
68908c2ecf20Sopenharmony_ci					 struct dev_db_entry *fw_ddb_entry)
68918c2ecf20Sopenharmony_ci{
68928c2ecf20Sopenharmony_ci	struct iscsi_cls_session *cls_sess;
68938c2ecf20Sopenharmony_ci	struct iscsi_session *sess;
68948c2ecf20Sopenharmony_ci	uint32_t max_ddbs = 0;
68958c2ecf20Sopenharmony_ci	uint16_t ddb_link = -1;
68968c2ecf20Sopenharmony_ci
68978c2ecf20Sopenharmony_ci	max_ddbs =  is_qla40XX(ha) ? MAX_DEV_DB_ENTRIES_40XX :
68988c2ecf20Sopenharmony_ci				     MAX_DEV_DB_ENTRIES;
68998c2ecf20Sopenharmony_ci
69008c2ecf20Sopenharmony_ci	cls_sess = ddb_entry->sess;
69018c2ecf20Sopenharmony_ci	sess = cls_sess->dd_data;
69028c2ecf20Sopenharmony_ci
69038c2ecf20Sopenharmony_ci	ddb_link = le16_to_cpu(fw_ddb_entry->ddb_link);
69048c2ecf20Sopenharmony_ci	if (ddb_link < max_ddbs)
69058c2ecf20Sopenharmony_ci		sess->discovery_parent_idx = ddb_link;
69068c2ecf20Sopenharmony_ci	else
69078c2ecf20Sopenharmony_ci		sess->discovery_parent_idx = DDB_NO_LINK;
69088c2ecf20Sopenharmony_ci}
69098c2ecf20Sopenharmony_ci
69108c2ecf20Sopenharmony_cistatic int qla4xxx_sess_conn_setup(struct scsi_qla_host *ha,
69118c2ecf20Sopenharmony_ci				   struct dev_db_entry *fw_ddb_entry,
69128c2ecf20Sopenharmony_ci				   int is_reset, uint16_t idx)
69138c2ecf20Sopenharmony_ci{
69148c2ecf20Sopenharmony_ci	struct iscsi_cls_session *cls_sess;
69158c2ecf20Sopenharmony_ci	struct iscsi_session *sess;
69168c2ecf20Sopenharmony_ci	struct iscsi_cls_conn *cls_conn;
69178c2ecf20Sopenharmony_ci	struct iscsi_endpoint *ep;
69188c2ecf20Sopenharmony_ci	uint16_t cmds_max = 32;
69198c2ecf20Sopenharmony_ci	uint16_t conn_id = 0;
69208c2ecf20Sopenharmony_ci	uint32_t initial_cmdsn = 0;
69218c2ecf20Sopenharmony_ci	int ret = QLA_SUCCESS;
69228c2ecf20Sopenharmony_ci
69238c2ecf20Sopenharmony_ci	struct ddb_entry *ddb_entry = NULL;
69248c2ecf20Sopenharmony_ci
69258c2ecf20Sopenharmony_ci	/* Create session object, with INVALID_ENTRY,
69268c2ecf20Sopenharmony_ci	 * the targer_id would get set when we issue the login
69278c2ecf20Sopenharmony_ci	 */
69288c2ecf20Sopenharmony_ci	cls_sess = iscsi_session_setup(&qla4xxx_iscsi_transport, ha->host,
69298c2ecf20Sopenharmony_ci				       cmds_max, sizeof(struct ddb_entry),
69308c2ecf20Sopenharmony_ci				       sizeof(struct ql4_task_data),
69318c2ecf20Sopenharmony_ci				       initial_cmdsn, INVALID_ENTRY);
69328c2ecf20Sopenharmony_ci	if (!cls_sess) {
69338c2ecf20Sopenharmony_ci		ret = QLA_ERROR;
69348c2ecf20Sopenharmony_ci		goto exit_setup;
69358c2ecf20Sopenharmony_ci	}
69368c2ecf20Sopenharmony_ci
69378c2ecf20Sopenharmony_ci	/*
69388c2ecf20Sopenharmony_ci	 * so calling module_put function to decrement the
69398c2ecf20Sopenharmony_ci	 * reference count.
69408c2ecf20Sopenharmony_ci	 **/
69418c2ecf20Sopenharmony_ci	module_put(qla4xxx_iscsi_transport.owner);
69428c2ecf20Sopenharmony_ci	sess = cls_sess->dd_data;
69438c2ecf20Sopenharmony_ci	ddb_entry = sess->dd_data;
69448c2ecf20Sopenharmony_ci	ddb_entry->sess = cls_sess;
69458c2ecf20Sopenharmony_ci
69468c2ecf20Sopenharmony_ci	cls_sess->recovery_tmo = ql4xsess_recovery_tmo;
69478c2ecf20Sopenharmony_ci	memcpy(&ddb_entry->fw_ddb_entry, fw_ddb_entry,
69488c2ecf20Sopenharmony_ci	       sizeof(struct dev_db_entry));
69498c2ecf20Sopenharmony_ci
69508c2ecf20Sopenharmony_ci	qla4xxx_setup_flash_ddb_entry(ha, ddb_entry, idx);
69518c2ecf20Sopenharmony_ci
69528c2ecf20Sopenharmony_ci	cls_conn = iscsi_conn_setup(cls_sess, sizeof(struct qla_conn), conn_id);
69538c2ecf20Sopenharmony_ci
69548c2ecf20Sopenharmony_ci	if (!cls_conn) {
69558c2ecf20Sopenharmony_ci		ret = QLA_ERROR;
69568c2ecf20Sopenharmony_ci		goto exit_setup;
69578c2ecf20Sopenharmony_ci	}
69588c2ecf20Sopenharmony_ci
69598c2ecf20Sopenharmony_ci	ddb_entry->conn = cls_conn;
69608c2ecf20Sopenharmony_ci
69618c2ecf20Sopenharmony_ci	/* Setup ep, for displaying attributes in sysfs */
69628c2ecf20Sopenharmony_ci	ep = qla4xxx_get_ep_fwdb(ha, fw_ddb_entry);
69638c2ecf20Sopenharmony_ci	if (ep) {
69648c2ecf20Sopenharmony_ci		ep->conn = cls_conn;
69658c2ecf20Sopenharmony_ci		cls_conn->ep = ep;
69668c2ecf20Sopenharmony_ci	} else {
69678c2ecf20Sopenharmony_ci		DEBUG2(ql4_printk(KERN_ERR, ha, "Unable to get ep\n"));
69688c2ecf20Sopenharmony_ci		ret = QLA_ERROR;
69698c2ecf20Sopenharmony_ci		goto exit_setup;
69708c2ecf20Sopenharmony_ci	}
69718c2ecf20Sopenharmony_ci
69728c2ecf20Sopenharmony_ci	/* Update sess/conn params */
69738c2ecf20Sopenharmony_ci	qla4xxx_copy_fwddb_param(ha, fw_ddb_entry, cls_sess, cls_conn);
69748c2ecf20Sopenharmony_ci	qla4xxx_update_sess_disc_idx(ha, ddb_entry, fw_ddb_entry);
69758c2ecf20Sopenharmony_ci
69768c2ecf20Sopenharmony_ci	if (is_reset == RESET_ADAPTER) {
69778c2ecf20Sopenharmony_ci		iscsi_block_session(cls_sess);
69788c2ecf20Sopenharmony_ci		/* Use the relogin path to discover new devices
69798c2ecf20Sopenharmony_ci		 *  by short-circuting the logic of setting
69808c2ecf20Sopenharmony_ci		 *  timer to relogin - instead set the flags
69818c2ecf20Sopenharmony_ci		 *  to initiate login right away.
69828c2ecf20Sopenharmony_ci		 */
69838c2ecf20Sopenharmony_ci		set_bit(DPC_RELOGIN_DEVICE, &ha->dpc_flags);
69848c2ecf20Sopenharmony_ci		set_bit(DF_RELOGIN, &ddb_entry->flags);
69858c2ecf20Sopenharmony_ci	}
69868c2ecf20Sopenharmony_ci
69878c2ecf20Sopenharmony_ciexit_setup:
69888c2ecf20Sopenharmony_ci	return ret;
69898c2ecf20Sopenharmony_ci}
69908c2ecf20Sopenharmony_ci
69918c2ecf20Sopenharmony_cistatic void qla4xxx_update_fw_ddb_link(struct scsi_qla_host *ha,
69928c2ecf20Sopenharmony_ci				       struct list_head *list_ddb,
69938c2ecf20Sopenharmony_ci				       struct dev_db_entry *fw_ddb_entry)
69948c2ecf20Sopenharmony_ci{
69958c2ecf20Sopenharmony_ci	struct qla_ddb_index  *ddb_idx, *ddb_idx_tmp;
69968c2ecf20Sopenharmony_ci	uint16_t ddb_link;
69978c2ecf20Sopenharmony_ci
69988c2ecf20Sopenharmony_ci	ddb_link = le16_to_cpu(fw_ddb_entry->ddb_link);
69998c2ecf20Sopenharmony_ci
70008c2ecf20Sopenharmony_ci	list_for_each_entry_safe(ddb_idx, ddb_idx_tmp, list_ddb, list) {
70018c2ecf20Sopenharmony_ci		if (ddb_idx->fw_ddb_idx == ddb_link) {
70028c2ecf20Sopenharmony_ci			DEBUG2(ql4_printk(KERN_INFO, ha,
70038c2ecf20Sopenharmony_ci					  "Updating NT parent idx from [%d] to [%d]\n",
70048c2ecf20Sopenharmony_ci					  ddb_link, ddb_idx->flash_ddb_idx));
70058c2ecf20Sopenharmony_ci			fw_ddb_entry->ddb_link =
70068c2ecf20Sopenharmony_ci					    cpu_to_le16(ddb_idx->flash_ddb_idx);
70078c2ecf20Sopenharmony_ci			return;
70088c2ecf20Sopenharmony_ci		}
70098c2ecf20Sopenharmony_ci	}
70108c2ecf20Sopenharmony_ci}
70118c2ecf20Sopenharmony_ci
70128c2ecf20Sopenharmony_cistatic void qla4xxx_build_nt_list(struct scsi_qla_host *ha,
70138c2ecf20Sopenharmony_ci				  struct list_head *list_nt,
70148c2ecf20Sopenharmony_ci				  struct list_head *list_st,
70158c2ecf20Sopenharmony_ci				  int is_reset)
70168c2ecf20Sopenharmony_ci{
70178c2ecf20Sopenharmony_ci	struct dev_db_entry *fw_ddb_entry;
70188c2ecf20Sopenharmony_ci	struct ddb_entry *ddb_entry = NULL;
70198c2ecf20Sopenharmony_ci	dma_addr_t fw_ddb_dma;
70208c2ecf20Sopenharmony_ci	int max_ddbs;
70218c2ecf20Sopenharmony_ci	int fw_idx_size;
70228c2ecf20Sopenharmony_ci	int ret;
70238c2ecf20Sopenharmony_ci	uint32_t idx = 0, next_idx = 0;
70248c2ecf20Sopenharmony_ci	uint32_t state = 0, conn_err = 0;
70258c2ecf20Sopenharmony_ci	uint32_t ddb_idx = -1;
70268c2ecf20Sopenharmony_ci	uint16_t conn_id = 0;
70278c2ecf20Sopenharmony_ci	uint16_t ddb_link = -1;
70288c2ecf20Sopenharmony_ci	struct qla_ddb_index  *nt_ddb_idx;
70298c2ecf20Sopenharmony_ci
70308c2ecf20Sopenharmony_ci	fw_ddb_entry = dma_pool_alloc(ha->fw_ddb_dma_pool, GFP_KERNEL,
70318c2ecf20Sopenharmony_ci				      &fw_ddb_dma);
70328c2ecf20Sopenharmony_ci	if (fw_ddb_entry == NULL) {
70338c2ecf20Sopenharmony_ci		DEBUG2(ql4_printk(KERN_ERR, ha, "Out of memory\n"));
70348c2ecf20Sopenharmony_ci		goto exit_nt_list;
70358c2ecf20Sopenharmony_ci	}
70368c2ecf20Sopenharmony_ci	max_ddbs =  is_qla40XX(ha) ? MAX_DEV_DB_ENTRIES_40XX :
70378c2ecf20Sopenharmony_ci				     MAX_DEV_DB_ENTRIES;
70388c2ecf20Sopenharmony_ci	fw_idx_size = sizeof(struct qla_ddb_index);
70398c2ecf20Sopenharmony_ci
70408c2ecf20Sopenharmony_ci	for (idx = 0; idx < max_ddbs; idx = next_idx) {
70418c2ecf20Sopenharmony_ci		ret = qla4xxx_get_fwddb_entry(ha, idx, fw_ddb_entry, fw_ddb_dma,
70428c2ecf20Sopenharmony_ci					      NULL, &next_idx, &state,
70438c2ecf20Sopenharmony_ci					      &conn_err, NULL, &conn_id);
70448c2ecf20Sopenharmony_ci		if (ret == QLA_ERROR)
70458c2ecf20Sopenharmony_ci			break;
70468c2ecf20Sopenharmony_ci
70478c2ecf20Sopenharmony_ci		if (qla4xxx_verify_boot_idx(ha, idx) != QLA_SUCCESS)
70488c2ecf20Sopenharmony_ci			goto continue_next_nt;
70498c2ecf20Sopenharmony_ci
70508c2ecf20Sopenharmony_ci		/* Check if NT, then add to list it */
70518c2ecf20Sopenharmony_ci		if (strlen((char *) fw_ddb_entry->iscsi_name) == 0)
70528c2ecf20Sopenharmony_ci			goto continue_next_nt;
70538c2ecf20Sopenharmony_ci
70548c2ecf20Sopenharmony_ci		ddb_link = le16_to_cpu(fw_ddb_entry->ddb_link);
70558c2ecf20Sopenharmony_ci		if (ddb_link < max_ddbs)
70568c2ecf20Sopenharmony_ci			qla4xxx_update_fw_ddb_link(ha, list_st, fw_ddb_entry);
70578c2ecf20Sopenharmony_ci
70588c2ecf20Sopenharmony_ci		if (!(state == DDB_DS_NO_CONNECTION_ACTIVE ||
70598c2ecf20Sopenharmony_ci		    state == DDB_DS_SESSION_FAILED) &&
70608c2ecf20Sopenharmony_ci		    (is_reset == INIT_ADAPTER))
70618c2ecf20Sopenharmony_ci			goto continue_next_nt;
70628c2ecf20Sopenharmony_ci
70638c2ecf20Sopenharmony_ci		DEBUG2(ql4_printk(KERN_INFO, ha,
70648c2ecf20Sopenharmony_ci				  "Adding  DDB to session = 0x%x\n", idx));
70658c2ecf20Sopenharmony_ci
70668c2ecf20Sopenharmony_ci		if (is_reset == INIT_ADAPTER) {
70678c2ecf20Sopenharmony_ci			nt_ddb_idx = vmalloc(fw_idx_size);
70688c2ecf20Sopenharmony_ci			if (!nt_ddb_idx)
70698c2ecf20Sopenharmony_ci				break;
70708c2ecf20Sopenharmony_ci
70718c2ecf20Sopenharmony_ci			nt_ddb_idx->fw_ddb_idx = idx;
70728c2ecf20Sopenharmony_ci
70738c2ecf20Sopenharmony_ci			/* Copy original isid as it may get updated in function
70748c2ecf20Sopenharmony_ci			 * qla4xxx_update_isid(). We need original isid in
70758c2ecf20Sopenharmony_ci			 * function qla4xxx_compare_tuple_ddb to find duplicate
70768c2ecf20Sopenharmony_ci			 * target */
70778c2ecf20Sopenharmony_ci			memcpy(&nt_ddb_idx->flash_isid[0],
70788c2ecf20Sopenharmony_ci			       &fw_ddb_entry->isid[0],
70798c2ecf20Sopenharmony_ci			       sizeof(nt_ddb_idx->flash_isid));
70808c2ecf20Sopenharmony_ci
70818c2ecf20Sopenharmony_ci			ret = qla4xxx_is_flash_ddb_exists(ha, list_nt,
70828c2ecf20Sopenharmony_ci							  fw_ddb_entry);
70838c2ecf20Sopenharmony_ci			if (ret == QLA_SUCCESS) {
70848c2ecf20Sopenharmony_ci				/* free nt_ddb_idx and do not add to list_nt */
70858c2ecf20Sopenharmony_ci				vfree(nt_ddb_idx);
70868c2ecf20Sopenharmony_ci				goto continue_next_nt;
70878c2ecf20Sopenharmony_ci			}
70888c2ecf20Sopenharmony_ci
70898c2ecf20Sopenharmony_ci			/* Copy updated isid */
70908c2ecf20Sopenharmony_ci			memcpy(&nt_ddb_idx->fw_ddb, fw_ddb_entry,
70918c2ecf20Sopenharmony_ci			       sizeof(struct dev_db_entry));
70928c2ecf20Sopenharmony_ci
70938c2ecf20Sopenharmony_ci			list_add_tail(&nt_ddb_idx->list, list_nt);
70948c2ecf20Sopenharmony_ci		} else if (is_reset == RESET_ADAPTER) {
70958c2ecf20Sopenharmony_ci			ret = qla4xxx_is_session_exists(ha, fw_ddb_entry,
70968c2ecf20Sopenharmony_ci							&ddb_idx);
70978c2ecf20Sopenharmony_ci			if (ret == QLA_SUCCESS) {
70988c2ecf20Sopenharmony_ci				ddb_entry = qla4xxx_lookup_ddb_by_fw_index(ha,
70998c2ecf20Sopenharmony_ci								       ddb_idx);
71008c2ecf20Sopenharmony_ci				if (ddb_entry != NULL)
71018c2ecf20Sopenharmony_ci					qla4xxx_update_sess_disc_idx(ha,
71028c2ecf20Sopenharmony_ci								     ddb_entry,
71038c2ecf20Sopenharmony_ci								  fw_ddb_entry);
71048c2ecf20Sopenharmony_ci				goto continue_next_nt;
71058c2ecf20Sopenharmony_ci			}
71068c2ecf20Sopenharmony_ci		}
71078c2ecf20Sopenharmony_ci
71088c2ecf20Sopenharmony_ci		ret = qla4xxx_sess_conn_setup(ha, fw_ddb_entry, is_reset, idx);
71098c2ecf20Sopenharmony_ci		if (ret == QLA_ERROR)
71108c2ecf20Sopenharmony_ci			goto exit_nt_list;
71118c2ecf20Sopenharmony_ci
71128c2ecf20Sopenharmony_cicontinue_next_nt:
71138c2ecf20Sopenharmony_ci		if (next_idx == 0)
71148c2ecf20Sopenharmony_ci			break;
71158c2ecf20Sopenharmony_ci	}
71168c2ecf20Sopenharmony_ci
71178c2ecf20Sopenharmony_ciexit_nt_list:
71188c2ecf20Sopenharmony_ci	if (fw_ddb_entry)
71198c2ecf20Sopenharmony_ci		dma_pool_free(ha->fw_ddb_dma_pool, fw_ddb_entry, fw_ddb_dma);
71208c2ecf20Sopenharmony_ci}
71218c2ecf20Sopenharmony_ci
71228c2ecf20Sopenharmony_cistatic void qla4xxx_build_new_nt_list(struct scsi_qla_host *ha,
71238c2ecf20Sopenharmony_ci				      struct list_head *list_nt,
71248c2ecf20Sopenharmony_ci				      uint16_t target_id)
71258c2ecf20Sopenharmony_ci{
71268c2ecf20Sopenharmony_ci	struct dev_db_entry *fw_ddb_entry;
71278c2ecf20Sopenharmony_ci	dma_addr_t fw_ddb_dma;
71288c2ecf20Sopenharmony_ci	int max_ddbs;
71298c2ecf20Sopenharmony_ci	int fw_idx_size;
71308c2ecf20Sopenharmony_ci	int ret;
71318c2ecf20Sopenharmony_ci	uint32_t idx = 0, next_idx = 0;
71328c2ecf20Sopenharmony_ci	uint32_t state = 0, conn_err = 0;
71338c2ecf20Sopenharmony_ci	uint16_t conn_id = 0;
71348c2ecf20Sopenharmony_ci	struct qla_ddb_index  *nt_ddb_idx;
71358c2ecf20Sopenharmony_ci
71368c2ecf20Sopenharmony_ci	fw_ddb_entry = dma_pool_alloc(ha->fw_ddb_dma_pool, GFP_KERNEL,
71378c2ecf20Sopenharmony_ci				      &fw_ddb_dma);
71388c2ecf20Sopenharmony_ci	if (fw_ddb_entry == NULL) {
71398c2ecf20Sopenharmony_ci		DEBUG2(ql4_printk(KERN_ERR, ha, "Out of memory\n"));
71408c2ecf20Sopenharmony_ci		goto exit_new_nt_list;
71418c2ecf20Sopenharmony_ci	}
71428c2ecf20Sopenharmony_ci	max_ddbs =  is_qla40XX(ha) ? MAX_DEV_DB_ENTRIES_40XX :
71438c2ecf20Sopenharmony_ci				     MAX_DEV_DB_ENTRIES;
71448c2ecf20Sopenharmony_ci	fw_idx_size = sizeof(struct qla_ddb_index);
71458c2ecf20Sopenharmony_ci
71468c2ecf20Sopenharmony_ci	for (idx = 0; idx < max_ddbs; idx = next_idx) {
71478c2ecf20Sopenharmony_ci		ret = qla4xxx_get_fwddb_entry(ha, idx, fw_ddb_entry, fw_ddb_dma,
71488c2ecf20Sopenharmony_ci					      NULL, &next_idx, &state,
71498c2ecf20Sopenharmony_ci					      &conn_err, NULL, &conn_id);
71508c2ecf20Sopenharmony_ci		if (ret == QLA_ERROR)
71518c2ecf20Sopenharmony_ci			break;
71528c2ecf20Sopenharmony_ci
71538c2ecf20Sopenharmony_ci		/* Check if NT, then add it to list */
71548c2ecf20Sopenharmony_ci		if (strlen((char *)fw_ddb_entry->iscsi_name) == 0)
71558c2ecf20Sopenharmony_ci			goto continue_next_new_nt;
71568c2ecf20Sopenharmony_ci
71578c2ecf20Sopenharmony_ci		if (!(state == DDB_DS_NO_CONNECTION_ACTIVE))
71588c2ecf20Sopenharmony_ci			goto continue_next_new_nt;
71598c2ecf20Sopenharmony_ci
71608c2ecf20Sopenharmony_ci		DEBUG2(ql4_printk(KERN_INFO, ha,
71618c2ecf20Sopenharmony_ci				  "Adding  DDB to session = 0x%x\n", idx));
71628c2ecf20Sopenharmony_ci
71638c2ecf20Sopenharmony_ci		nt_ddb_idx = vmalloc(fw_idx_size);
71648c2ecf20Sopenharmony_ci		if (!nt_ddb_idx)
71658c2ecf20Sopenharmony_ci			break;
71668c2ecf20Sopenharmony_ci
71678c2ecf20Sopenharmony_ci		nt_ddb_idx->fw_ddb_idx = idx;
71688c2ecf20Sopenharmony_ci
71698c2ecf20Sopenharmony_ci		ret = qla4xxx_is_session_exists(ha, fw_ddb_entry, NULL);
71708c2ecf20Sopenharmony_ci		if (ret == QLA_SUCCESS) {
71718c2ecf20Sopenharmony_ci			/* free nt_ddb_idx and do not add to list_nt */
71728c2ecf20Sopenharmony_ci			vfree(nt_ddb_idx);
71738c2ecf20Sopenharmony_ci			goto continue_next_new_nt;
71748c2ecf20Sopenharmony_ci		}
71758c2ecf20Sopenharmony_ci
71768c2ecf20Sopenharmony_ci		if (target_id < max_ddbs)
71778c2ecf20Sopenharmony_ci			fw_ddb_entry->ddb_link = cpu_to_le16(target_id);
71788c2ecf20Sopenharmony_ci
71798c2ecf20Sopenharmony_ci		list_add_tail(&nt_ddb_idx->list, list_nt);
71808c2ecf20Sopenharmony_ci
71818c2ecf20Sopenharmony_ci		ret = qla4xxx_sess_conn_setup(ha, fw_ddb_entry, RESET_ADAPTER,
71828c2ecf20Sopenharmony_ci					      idx);
71838c2ecf20Sopenharmony_ci		if (ret == QLA_ERROR)
71848c2ecf20Sopenharmony_ci			goto exit_new_nt_list;
71858c2ecf20Sopenharmony_ci
71868c2ecf20Sopenharmony_cicontinue_next_new_nt:
71878c2ecf20Sopenharmony_ci		if (next_idx == 0)
71888c2ecf20Sopenharmony_ci			break;
71898c2ecf20Sopenharmony_ci	}
71908c2ecf20Sopenharmony_ci
71918c2ecf20Sopenharmony_ciexit_new_nt_list:
71928c2ecf20Sopenharmony_ci	if (fw_ddb_entry)
71938c2ecf20Sopenharmony_ci		dma_pool_free(ha->fw_ddb_dma_pool, fw_ddb_entry, fw_ddb_dma);
71948c2ecf20Sopenharmony_ci}
71958c2ecf20Sopenharmony_ci
71968c2ecf20Sopenharmony_ci/**
71978c2ecf20Sopenharmony_ci * qla4xxx_sysfs_ddb_is_non_persistent - check for non-persistence of ddb entry
71988c2ecf20Sopenharmony_ci * @dev: dev associated with the sysfs entry
71998c2ecf20Sopenharmony_ci * @data: pointer to flashnode session object
72008c2ecf20Sopenharmony_ci *
72018c2ecf20Sopenharmony_ci * Returns:
72028c2ecf20Sopenharmony_ci *	1: if flashnode entry is non-persistent
72038c2ecf20Sopenharmony_ci *	0: if flashnode entry is persistent
72048c2ecf20Sopenharmony_ci **/
72058c2ecf20Sopenharmony_cistatic int qla4xxx_sysfs_ddb_is_non_persistent(struct device *dev, void *data)
72068c2ecf20Sopenharmony_ci{
72078c2ecf20Sopenharmony_ci	struct iscsi_bus_flash_session *fnode_sess;
72088c2ecf20Sopenharmony_ci
72098c2ecf20Sopenharmony_ci	if (!iscsi_flashnode_bus_match(dev, NULL))
72108c2ecf20Sopenharmony_ci		return 0;
72118c2ecf20Sopenharmony_ci
72128c2ecf20Sopenharmony_ci	fnode_sess = iscsi_dev_to_flash_session(dev);
72138c2ecf20Sopenharmony_ci
72148c2ecf20Sopenharmony_ci	return (fnode_sess->flash_state == DEV_DB_NON_PERSISTENT);
72158c2ecf20Sopenharmony_ci}
72168c2ecf20Sopenharmony_ci
72178c2ecf20Sopenharmony_ci/**
72188c2ecf20Sopenharmony_ci * qla4xxx_sysfs_ddb_tgt_create - Create sysfs entry for target
72198c2ecf20Sopenharmony_ci * @ha: pointer to host
72208c2ecf20Sopenharmony_ci * @fw_ddb_entry: flash ddb data
72218c2ecf20Sopenharmony_ci * @idx: target index
72228c2ecf20Sopenharmony_ci * @user: if set then this call is made from userland else from kernel
72238c2ecf20Sopenharmony_ci *
72248c2ecf20Sopenharmony_ci * Returns:
72258c2ecf20Sopenharmony_ci * On sucess: QLA_SUCCESS
72268c2ecf20Sopenharmony_ci * On failure: QLA_ERROR
72278c2ecf20Sopenharmony_ci *
72288c2ecf20Sopenharmony_ci * This create separate sysfs entries for session and connection attributes of
72298c2ecf20Sopenharmony_ci * the given fw ddb entry.
72308c2ecf20Sopenharmony_ci * If this is invoked as a result of a userspace call then the entry is marked
72318c2ecf20Sopenharmony_ci * as nonpersistent using flash_state field.
72328c2ecf20Sopenharmony_ci **/
72338c2ecf20Sopenharmony_cistatic int qla4xxx_sysfs_ddb_tgt_create(struct scsi_qla_host *ha,
72348c2ecf20Sopenharmony_ci					struct dev_db_entry *fw_ddb_entry,
72358c2ecf20Sopenharmony_ci					uint16_t *idx, int user)
72368c2ecf20Sopenharmony_ci{
72378c2ecf20Sopenharmony_ci	struct iscsi_bus_flash_session *fnode_sess = NULL;
72388c2ecf20Sopenharmony_ci	struct iscsi_bus_flash_conn *fnode_conn = NULL;
72398c2ecf20Sopenharmony_ci	int rc = QLA_ERROR;
72408c2ecf20Sopenharmony_ci
72418c2ecf20Sopenharmony_ci	fnode_sess = iscsi_create_flashnode_sess(ha->host, *idx,
72428c2ecf20Sopenharmony_ci						 &qla4xxx_iscsi_transport, 0);
72438c2ecf20Sopenharmony_ci	if (!fnode_sess) {
72448c2ecf20Sopenharmony_ci		ql4_printk(KERN_ERR, ha,
72458c2ecf20Sopenharmony_ci			   "%s: Unable to create session sysfs entry for flashnode %d of host%lu\n",
72468c2ecf20Sopenharmony_ci			   __func__, *idx, ha->host_no);
72478c2ecf20Sopenharmony_ci		goto exit_tgt_create;
72488c2ecf20Sopenharmony_ci	}
72498c2ecf20Sopenharmony_ci
72508c2ecf20Sopenharmony_ci	fnode_conn = iscsi_create_flashnode_conn(ha->host, fnode_sess,
72518c2ecf20Sopenharmony_ci						 &qla4xxx_iscsi_transport, 0);
72528c2ecf20Sopenharmony_ci	if (!fnode_conn) {
72538c2ecf20Sopenharmony_ci		ql4_printk(KERN_ERR, ha,
72548c2ecf20Sopenharmony_ci			   "%s: Unable to create conn sysfs entry for flashnode %d of host%lu\n",
72558c2ecf20Sopenharmony_ci			   __func__, *idx, ha->host_no);
72568c2ecf20Sopenharmony_ci		goto free_sess;
72578c2ecf20Sopenharmony_ci	}
72588c2ecf20Sopenharmony_ci
72598c2ecf20Sopenharmony_ci	if (user) {
72608c2ecf20Sopenharmony_ci		fnode_sess->flash_state = DEV_DB_NON_PERSISTENT;
72618c2ecf20Sopenharmony_ci	} else {
72628c2ecf20Sopenharmony_ci		fnode_sess->flash_state = DEV_DB_PERSISTENT;
72638c2ecf20Sopenharmony_ci
72648c2ecf20Sopenharmony_ci		if (*idx == ha->pri_ddb_idx || *idx == ha->sec_ddb_idx)
72658c2ecf20Sopenharmony_ci			fnode_sess->is_boot_target = 1;
72668c2ecf20Sopenharmony_ci		else
72678c2ecf20Sopenharmony_ci			fnode_sess->is_boot_target = 0;
72688c2ecf20Sopenharmony_ci	}
72698c2ecf20Sopenharmony_ci
72708c2ecf20Sopenharmony_ci	rc = qla4xxx_copy_from_fwddb_param(fnode_sess, fnode_conn,
72718c2ecf20Sopenharmony_ci					   fw_ddb_entry);
72728c2ecf20Sopenharmony_ci	if (rc)
72738c2ecf20Sopenharmony_ci		goto free_sess;
72748c2ecf20Sopenharmony_ci
72758c2ecf20Sopenharmony_ci	ql4_printk(KERN_INFO, ha, "%s: sysfs entry %s created\n",
72768c2ecf20Sopenharmony_ci		   __func__, fnode_sess->dev.kobj.name);
72778c2ecf20Sopenharmony_ci
72788c2ecf20Sopenharmony_ci	ql4_printk(KERN_INFO, ha, "%s: sysfs entry %s created\n",
72798c2ecf20Sopenharmony_ci		   __func__, fnode_conn->dev.kobj.name);
72808c2ecf20Sopenharmony_ci
72818c2ecf20Sopenharmony_ci	return QLA_SUCCESS;
72828c2ecf20Sopenharmony_ci
72838c2ecf20Sopenharmony_cifree_sess:
72848c2ecf20Sopenharmony_ci	iscsi_destroy_flashnode_sess(fnode_sess);
72858c2ecf20Sopenharmony_ci
72868c2ecf20Sopenharmony_ciexit_tgt_create:
72878c2ecf20Sopenharmony_ci	return QLA_ERROR;
72888c2ecf20Sopenharmony_ci}
72898c2ecf20Sopenharmony_ci
72908c2ecf20Sopenharmony_ci/**
72918c2ecf20Sopenharmony_ci * qla4xxx_sysfs_ddb_add - Add new ddb entry in flash
72928c2ecf20Sopenharmony_ci * @shost: pointer to host
72938c2ecf20Sopenharmony_ci * @buf: type of ddb entry (ipv4/ipv6)
72948c2ecf20Sopenharmony_ci * @len: length of buf
72958c2ecf20Sopenharmony_ci *
72968c2ecf20Sopenharmony_ci * This creates new ddb entry in the flash by finding first free index and
72978c2ecf20Sopenharmony_ci * storing default ddb there. And then create sysfs entry for the new ddb entry.
72988c2ecf20Sopenharmony_ci **/
72998c2ecf20Sopenharmony_cistatic int qla4xxx_sysfs_ddb_add(struct Scsi_Host *shost, const char *buf,
73008c2ecf20Sopenharmony_ci				 int len)
73018c2ecf20Sopenharmony_ci{
73028c2ecf20Sopenharmony_ci	struct scsi_qla_host *ha = to_qla_host(shost);
73038c2ecf20Sopenharmony_ci	struct dev_db_entry *fw_ddb_entry = NULL;
73048c2ecf20Sopenharmony_ci	dma_addr_t fw_ddb_entry_dma;
73058c2ecf20Sopenharmony_ci	struct device *dev;
73068c2ecf20Sopenharmony_ci	uint16_t idx = 0;
73078c2ecf20Sopenharmony_ci	uint16_t max_ddbs = 0;
73088c2ecf20Sopenharmony_ci	uint32_t options = 0;
73098c2ecf20Sopenharmony_ci	uint32_t rval = QLA_ERROR;
73108c2ecf20Sopenharmony_ci
73118c2ecf20Sopenharmony_ci	if (strncasecmp(PORTAL_TYPE_IPV4, buf, 4) &&
73128c2ecf20Sopenharmony_ci	    strncasecmp(PORTAL_TYPE_IPV6, buf, 4)) {
73138c2ecf20Sopenharmony_ci		DEBUG2(ql4_printk(KERN_ERR, ha, "%s: Invalid portal type\n",
73148c2ecf20Sopenharmony_ci				  __func__));
73158c2ecf20Sopenharmony_ci		goto exit_ddb_add;
73168c2ecf20Sopenharmony_ci	}
73178c2ecf20Sopenharmony_ci
73188c2ecf20Sopenharmony_ci	max_ddbs =  is_qla40XX(ha) ? MAX_PRST_DEV_DB_ENTRIES :
73198c2ecf20Sopenharmony_ci				     MAX_DEV_DB_ENTRIES;
73208c2ecf20Sopenharmony_ci
73218c2ecf20Sopenharmony_ci	fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
73228c2ecf20Sopenharmony_ci					  &fw_ddb_entry_dma, GFP_KERNEL);
73238c2ecf20Sopenharmony_ci	if (!fw_ddb_entry) {
73248c2ecf20Sopenharmony_ci		DEBUG2(ql4_printk(KERN_ERR, ha,
73258c2ecf20Sopenharmony_ci				  "%s: Unable to allocate dma buffer\n",
73268c2ecf20Sopenharmony_ci				  __func__));
73278c2ecf20Sopenharmony_ci		goto exit_ddb_add;
73288c2ecf20Sopenharmony_ci	}
73298c2ecf20Sopenharmony_ci
73308c2ecf20Sopenharmony_ci	dev = iscsi_find_flashnode_sess(ha->host, NULL,
73318c2ecf20Sopenharmony_ci					qla4xxx_sysfs_ddb_is_non_persistent);
73328c2ecf20Sopenharmony_ci	if (dev) {
73338c2ecf20Sopenharmony_ci		ql4_printk(KERN_ERR, ha,
73348c2ecf20Sopenharmony_ci			   "%s: A non-persistent entry %s found\n",
73358c2ecf20Sopenharmony_ci			   __func__, dev->kobj.name);
73368c2ecf20Sopenharmony_ci		put_device(dev);
73378c2ecf20Sopenharmony_ci		goto exit_ddb_add;
73388c2ecf20Sopenharmony_ci	}
73398c2ecf20Sopenharmony_ci
73408c2ecf20Sopenharmony_ci	/* Index 0 and 1 are reserved for boot target entries */
73418c2ecf20Sopenharmony_ci	for (idx = 2; idx < max_ddbs; idx++) {
73428c2ecf20Sopenharmony_ci		if (qla4xxx_flashdb_by_index(ha, fw_ddb_entry,
73438c2ecf20Sopenharmony_ci					     fw_ddb_entry_dma, idx))
73448c2ecf20Sopenharmony_ci			break;
73458c2ecf20Sopenharmony_ci	}
73468c2ecf20Sopenharmony_ci
73478c2ecf20Sopenharmony_ci	if (idx == max_ddbs)
73488c2ecf20Sopenharmony_ci		goto exit_ddb_add;
73498c2ecf20Sopenharmony_ci
73508c2ecf20Sopenharmony_ci	if (!strncasecmp("ipv6", buf, 4))
73518c2ecf20Sopenharmony_ci		options |= IPV6_DEFAULT_DDB_ENTRY;
73528c2ecf20Sopenharmony_ci
73538c2ecf20Sopenharmony_ci	rval = qla4xxx_get_default_ddb(ha, options, fw_ddb_entry_dma);
73548c2ecf20Sopenharmony_ci	if (rval == QLA_ERROR)
73558c2ecf20Sopenharmony_ci		goto exit_ddb_add;
73568c2ecf20Sopenharmony_ci
73578c2ecf20Sopenharmony_ci	rval = qla4xxx_sysfs_ddb_tgt_create(ha, fw_ddb_entry, &idx, 1);
73588c2ecf20Sopenharmony_ci
73598c2ecf20Sopenharmony_ciexit_ddb_add:
73608c2ecf20Sopenharmony_ci	if (fw_ddb_entry)
73618c2ecf20Sopenharmony_ci		dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
73628c2ecf20Sopenharmony_ci				  fw_ddb_entry, fw_ddb_entry_dma);
73638c2ecf20Sopenharmony_ci	if (rval == QLA_SUCCESS)
73648c2ecf20Sopenharmony_ci		return idx;
73658c2ecf20Sopenharmony_ci	else
73668c2ecf20Sopenharmony_ci		return -EIO;
73678c2ecf20Sopenharmony_ci}
73688c2ecf20Sopenharmony_ci
73698c2ecf20Sopenharmony_ci/**
73708c2ecf20Sopenharmony_ci * qla4xxx_sysfs_ddb_apply - write the target ddb contents to Flash
73718c2ecf20Sopenharmony_ci * @fnode_sess: pointer to session attrs of flash ddb entry
73728c2ecf20Sopenharmony_ci * @fnode_conn: pointer to connection attrs of flash ddb entry
73738c2ecf20Sopenharmony_ci *
73748c2ecf20Sopenharmony_ci * This writes the contents of target ddb buffer to Flash with a valid cookie
73758c2ecf20Sopenharmony_ci * value in order to make the ddb entry persistent.
73768c2ecf20Sopenharmony_ci **/
73778c2ecf20Sopenharmony_cistatic int  qla4xxx_sysfs_ddb_apply(struct iscsi_bus_flash_session *fnode_sess,
73788c2ecf20Sopenharmony_ci				    struct iscsi_bus_flash_conn *fnode_conn)
73798c2ecf20Sopenharmony_ci{
73808c2ecf20Sopenharmony_ci	struct Scsi_Host *shost = iscsi_flash_session_to_shost(fnode_sess);
73818c2ecf20Sopenharmony_ci	struct scsi_qla_host *ha = to_qla_host(shost);
73828c2ecf20Sopenharmony_ci	uint32_t dev_db_start_offset = FLASH_OFFSET_DB_INFO;
73838c2ecf20Sopenharmony_ci	struct dev_db_entry *fw_ddb_entry = NULL;
73848c2ecf20Sopenharmony_ci	dma_addr_t fw_ddb_entry_dma;
73858c2ecf20Sopenharmony_ci	uint32_t options = 0;
73868c2ecf20Sopenharmony_ci	int rval = 0;
73878c2ecf20Sopenharmony_ci
73888c2ecf20Sopenharmony_ci	fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
73898c2ecf20Sopenharmony_ci					  &fw_ddb_entry_dma, GFP_KERNEL);
73908c2ecf20Sopenharmony_ci	if (!fw_ddb_entry) {
73918c2ecf20Sopenharmony_ci		DEBUG2(ql4_printk(KERN_ERR, ha,
73928c2ecf20Sopenharmony_ci				  "%s: Unable to allocate dma buffer\n",
73938c2ecf20Sopenharmony_ci				  __func__));
73948c2ecf20Sopenharmony_ci		rval = -ENOMEM;
73958c2ecf20Sopenharmony_ci		goto exit_ddb_apply;
73968c2ecf20Sopenharmony_ci	}
73978c2ecf20Sopenharmony_ci
73988c2ecf20Sopenharmony_ci	if (!strncasecmp(fnode_sess->portal_type, PORTAL_TYPE_IPV6, 4))
73998c2ecf20Sopenharmony_ci		options |= IPV6_DEFAULT_DDB_ENTRY;
74008c2ecf20Sopenharmony_ci
74018c2ecf20Sopenharmony_ci	rval = qla4xxx_get_default_ddb(ha, options, fw_ddb_entry_dma);
74028c2ecf20Sopenharmony_ci	if (rval == QLA_ERROR)
74038c2ecf20Sopenharmony_ci		goto exit_ddb_apply;
74048c2ecf20Sopenharmony_ci
74058c2ecf20Sopenharmony_ci	dev_db_start_offset += (fnode_sess->target_id *
74068c2ecf20Sopenharmony_ci				sizeof(*fw_ddb_entry));
74078c2ecf20Sopenharmony_ci
74088c2ecf20Sopenharmony_ci	qla4xxx_copy_to_fwddb_param(fnode_sess, fnode_conn, fw_ddb_entry);
74098c2ecf20Sopenharmony_ci	fw_ddb_entry->cookie = DDB_VALID_COOKIE;
74108c2ecf20Sopenharmony_ci
74118c2ecf20Sopenharmony_ci	rval = qla4xxx_set_flash(ha, fw_ddb_entry_dma, dev_db_start_offset,
74128c2ecf20Sopenharmony_ci				 sizeof(*fw_ddb_entry), FLASH_OPT_RMW_COMMIT);
74138c2ecf20Sopenharmony_ci
74148c2ecf20Sopenharmony_ci	if (rval == QLA_SUCCESS) {
74158c2ecf20Sopenharmony_ci		fnode_sess->flash_state = DEV_DB_PERSISTENT;
74168c2ecf20Sopenharmony_ci		ql4_printk(KERN_INFO, ha,
74178c2ecf20Sopenharmony_ci			   "%s: flash node %u of host %lu written to flash\n",
74188c2ecf20Sopenharmony_ci			   __func__, fnode_sess->target_id, ha->host_no);
74198c2ecf20Sopenharmony_ci	} else {
74208c2ecf20Sopenharmony_ci		rval = -EIO;
74218c2ecf20Sopenharmony_ci		ql4_printk(KERN_ERR, ha,
74228c2ecf20Sopenharmony_ci			   "%s: Error while writing flash node %u of host %lu to flash\n",
74238c2ecf20Sopenharmony_ci			   __func__, fnode_sess->target_id, ha->host_no);
74248c2ecf20Sopenharmony_ci	}
74258c2ecf20Sopenharmony_ci
74268c2ecf20Sopenharmony_ciexit_ddb_apply:
74278c2ecf20Sopenharmony_ci	if (fw_ddb_entry)
74288c2ecf20Sopenharmony_ci		dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
74298c2ecf20Sopenharmony_ci				  fw_ddb_entry, fw_ddb_entry_dma);
74308c2ecf20Sopenharmony_ci	return rval;
74318c2ecf20Sopenharmony_ci}
74328c2ecf20Sopenharmony_ci
74338c2ecf20Sopenharmony_cistatic ssize_t qla4xxx_sysfs_ddb_conn_open(struct scsi_qla_host *ha,
74348c2ecf20Sopenharmony_ci					   struct dev_db_entry *fw_ddb_entry,
74358c2ecf20Sopenharmony_ci					   uint16_t idx)
74368c2ecf20Sopenharmony_ci{
74378c2ecf20Sopenharmony_ci	struct dev_db_entry *ddb_entry = NULL;
74388c2ecf20Sopenharmony_ci	dma_addr_t ddb_entry_dma;
74398c2ecf20Sopenharmony_ci	unsigned long wtime;
74408c2ecf20Sopenharmony_ci	uint32_t mbx_sts = 0;
74418c2ecf20Sopenharmony_ci	uint32_t state = 0, conn_err = 0;
74428c2ecf20Sopenharmony_ci	uint16_t tmo = 0;
74438c2ecf20Sopenharmony_ci	int ret = 0;
74448c2ecf20Sopenharmony_ci
74458c2ecf20Sopenharmony_ci	ddb_entry = dma_alloc_coherent(&ha->pdev->dev, sizeof(*ddb_entry),
74468c2ecf20Sopenharmony_ci				       &ddb_entry_dma, GFP_KERNEL);
74478c2ecf20Sopenharmony_ci	if (!ddb_entry) {
74488c2ecf20Sopenharmony_ci		DEBUG2(ql4_printk(KERN_ERR, ha,
74498c2ecf20Sopenharmony_ci				  "%s: Unable to allocate dma buffer\n",
74508c2ecf20Sopenharmony_ci				  __func__));
74518c2ecf20Sopenharmony_ci		return QLA_ERROR;
74528c2ecf20Sopenharmony_ci	}
74538c2ecf20Sopenharmony_ci
74548c2ecf20Sopenharmony_ci	memcpy(ddb_entry, fw_ddb_entry, sizeof(*ddb_entry));
74558c2ecf20Sopenharmony_ci
74568c2ecf20Sopenharmony_ci	ret = qla4xxx_set_ddb_entry(ha, idx, ddb_entry_dma, &mbx_sts);
74578c2ecf20Sopenharmony_ci	if (ret != QLA_SUCCESS) {
74588c2ecf20Sopenharmony_ci		DEBUG2(ql4_printk(KERN_ERR, ha,
74598c2ecf20Sopenharmony_ci				  "%s: Unable to set ddb entry for index %d\n",
74608c2ecf20Sopenharmony_ci				  __func__, idx));
74618c2ecf20Sopenharmony_ci		goto exit_ddb_conn_open;
74628c2ecf20Sopenharmony_ci	}
74638c2ecf20Sopenharmony_ci
74648c2ecf20Sopenharmony_ci	qla4xxx_conn_open(ha, idx);
74658c2ecf20Sopenharmony_ci
74668c2ecf20Sopenharmony_ci	/* To ensure that sendtargets is done, wait for at least 12 secs */
74678c2ecf20Sopenharmony_ci	tmo = ((ha->def_timeout > LOGIN_TOV) &&
74688c2ecf20Sopenharmony_ci	       (ha->def_timeout < LOGIN_TOV * 10) ?
74698c2ecf20Sopenharmony_ci	       ha->def_timeout : LOGIN_TOV);
74708c2ecf20Sopenharmony_ci
74718c2ecf20Sopenharmony_ci	DEBUG2(ql4_printk(KERN_INFO, ha,
74728c2ecf20Sopenharmony_ci			  "Default time to wait for login to ddb %d\n", tmo));
74738c2ecf20Sopenharmony_ci
74748c2ecf20Sopenharmony_ci	wtime = jiffies + (HZ * tmo);
74758c2ecf20Sopenharmony_ci	do {
74768c2ecf20Sopenharmony_ci		ret = qla4xxx_get_fwddb_entry(ha, idx, NULL, 0, NULL,
74778c2ecf20Sopenharmony_ci					      NULL, &state, &conn_err, NULL,
74788c2ecf20Sopenharmony_ci					      NULL);
74798c2ecf20Sopenharmony_ci		if (ret == QLA_ERROR)
74808c2ecf20Sopenharmony_ci			continue;
74818c2ecf20Sopenharmony_ci
74828c2ecf20Sopenharmony_ci		if (state == DDB_DS_NO_CONNECTION_ACTIVE ||
74838c2ecf20Sopenharmony_ci		    state == DDB_DS_SESSION_FAILED)
74848c2ecf20Sopenharmony_ci			break;
74858c2ecf20Sopenharmony_ci
74868c2ecf20Sopenharmony_ci		schedule_timeout_uninterruptible(HZ / 10);
74878c2ecf20Sopenharmony_ci	} while (time_after(wtime, jiffies));
74888c2ecf20Sopenharmony_ci
74898c2ecf20Sopenharmony_ciexit_ddb_conn_open:
74908c2ecf20Sopenharmony_ci	if (ddb_entry)
74918c2ecf20Sopenharmony_ci		dma_free_coherent(&ha->pdev->dev, sizeof(*ddb_entry),
74928c2ecf20Sopenharmony_ci				  ddb_entry, ddb_entry_dma);
74938c2ecf20Sopenharmony_ci	return ret;
74948c2ecf20Sopenharmony_ci}
74958c2ecf20Sopenharmony_ci
74968c2ecf20Sopenharmony_cistatic int qla4xxx_ddb_login_st(struct scsi_qla_host *ha,
74978c2ecf20Sopenharmony_ci				struct dev_db_entry *fw_ddb_entry,
74988c2ecf20Sopenharmony_ci				uint16_t target_id)
74998c2ecf20Sopenharmony_ci{
75008c2ecf20Sopenharmony_ci	struct qla_ddb_index *ddb_idx, *ddb_idx_tmp;
75018c2ecf20Sopenharmony_ci	struct list_head list_nt;
75028c2ecf20Sopenharmony_ci	uint16_t ddb_index;
75038c2ecf20Sopenharmony_ci	int ret = 0;
75048c2ecf20Sopenharmony_ci
75058c2ecf20Sopenharmony_ci	if (test_bit(AF_ST_DISCOVERY_IN_PROGRESS, &ha->flags)) {
75068c2ecf20Sopenharmony_ci		ql4_printk(KERN_WARNING, ha,
75078c2ecf20Sopenharmony_ci			   "%s: A discovery already in progress!\n", __func__);
75088c2ecf20Sopenharmony_ci		return QLA_ERROR;
75098c2ecf20Sopenharmony_ci	}
75108c2ecf20Sopenharmony_ci
75118c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&list_nt);
75128c2ecf20Sopenharmony_ci
75138c2ecf20Sopenharmony_ci	set_bit(AF_ST_DISCOVERY_IN_PROGRESS, &ha->flags);
75148c2ecf20Sopenharmony_ci
75158c2ecf20Sopenharmony_ci	ret = qla4xxx_get_ddb_index(ha, &ddb_index);
75168c2ecf20Sopenharmony_ci	if (ret == QLA_ERROR)
75178c2ecf20Sopenharmony_ci		goto exit_login_st_clr_bit;
75188c2ecf20Sopenharmony_ci
75198c2ecf20Sopenharmony_ci	ret = qla4xxx_sysfs_ddb_conn_open(ha, fw_ddb_entry, ddb_index);
75208c2ecf20Sopenharmony_ci	if (ret == QLA_ERROR)
75218c2ecf20Sopenharmony_ci		goto exit_login_st;
75228c2ecf20Sopenharmony_ci
75238c2ecf20Sopenharmony_ci	qla4xxx_build_new_nt_list(ha, &list_nt, target_id);
75248c2ecf20Sopenharmony_ci
75258c2ecf20Sopenharmony_ci	list_for_each_entry_safe(ddb_idx, ddb_idx_tmp, &list_nt, list) {
75268c2ecf20Sopenharmony_ci		list_del_init(&ddb_idx->list);
75278c2ecf20Sopenharmony_ci		qla4xxx_clear_ddb_entry(ha, ddb_idx->fw_ddb_idx);
75288c2ecf20Sopenharmony_ci		vfree(ddb_idx);
75298c2ecf20Sopenharmony_ci	}
75308c2ecf20Sopenharmony_ci
75318c2ecf20Sopenharmony_ciexit_login_st:
75328c2ecf20Sopenharmony_ci	if (qla4xxx_clear_ddb_entry(ha, ddb_index) == QLA_ERROR) {
75338c2ecf20Sopenharmony_ci		ql4_printk(KERN_ERR, ha,
75348c2ecf20Sopenharmony_ci			   "Unable to clear DDB index = 0x%x\n", ddb_index);
75358c2ecf20Sopenharmony_ci	}
75368c2ecf20Sopenharmony_ci
75378c2ecf20Sopenharmony_ci	clear_bit(ddb_index, ha->ddb_idx_map);
75388c2ecf20Sopenharmony_ci
75398c2ecf20Sopenharmony_ciexit_login_st_clr_bit:
75408c2ecf20Sopenharmony_ci	clear_bit(AF_ST_DISCOVERY_IN_PROGRESS, &ha->flags);
75418c2ecf20Sopenharmony_ci	return ret;
75428c2ecf20Sopenharmony_ci}
75438c2ecf20Sopenharmony_ci
75448c2ecf20Sopenharmony_cistatic int qla4xxx_ddb_login_nt(struct scsi_qla_host *ha,
75458c2ecf20Sopenharmony_ci				struct dev_db_entry *fw_ddb_entry,
75468c2ecf20Sopenharmony_ci				uint16_t idx)
75478c2ecf20Sopenharmony_ci{
75488c2ecf20Sopenharmony_ci	int ret = QLA_ERROR;
75498c2ecf20Sopenharmony_ci
75508c2ecf20Sopenharmony_ci	ret = qla4xxx_is_session_exists(ha, fw_ddb_entry, NULL);
75518c2ecf20Sopenharmony_ci	if (ret != QLA_SUCCESS)
75528c2ecf20Sopenharmony_ci		ret = qla4xxx_sess_conn_setup(ha, fw_ddb_entry, RESET_ADAPTER,
75538c2ecf20Sopenharmony_ci					      idx);
75548c2ecf20Sopenharmony_ci	else
75558c2ecf20Sopenharmony_ci		ret = -EPERM;
75568c2ecf20Sopenharmony_ci
75578c2ecf20Sopenharmony_ci	return ret;
75588c2ecf20Sopenharmony_ci}
75598c2ecf20Sopenharmony_ci
75608c2ecf20Sopenharmony_ci/**
75618c2ecf20Sopenharmony_ci * qla4xxx_sysfs_ddb_login - Login to the specified target
75628c2ecf20Sopenharmony_ci * @fnode_sess: pointer to session attrs of flash ddb entry
75638c2ecf20Sopenharmony_ci * @fnode_conn: pointer to connection attrs of flash ddb entry
75648c2ecf20Sopenharmony_ci *
75658c2ecf20Sopenharmony_ci * This logs in to the specified target
75668c2ecf20Sopenharmony_ci **/
75678c2ecf20Sopenharmony_cistatic int qla4xxx_sysfs_ddb_login(struct iscsi_bus_flash_session *fnode_sess,
75688c2ecf20Sopenharmony_ci				   struct iscsi_bus_flash_conn *fnode_conn)
75698c2ecf20Sopenharmony_ci{
75708c2ecf20Sopenharmony_ci	struct Scsi_Host *shost = iscsi_flash_session_to_shost(fnode_sess);
75718c2ecf20Sopenharmony_ci	struct scsi_qla_host *ha = to_qla_host(shost);
75728c2ecf20Sopenharmony_ci	struct dev_db_entry *fw_ddb_entry = NULL;
75738c2ecf20Sopenharmony_ci	dma_addr_t fw_ddb_entry_dma;
75748c2ecf20Sopenharmony_ci	uint32_t options = 0;
75758c2ecf20Sopenharmony_ci	int ret = 0;
75768c2ecf20Sopenharmony_ci
75778c2ecf20Sopenharmony_ci	if (fnode_sess->flash_state == DEV_DB_NON_PERSISTENT) {
75788c2ecf20Sopenharmony_ci		ql4_printk(KERN_ERR, ha,
75798c2ecf20Sopenharmony_ci			   "%s: Target info is not persistent\n", __func__);
75808c2ecf20Sopenharmony_ci		ret = -EIO;
75818c2ecf20Sopenharmony_ci		goto exit_ddb_login;
75828c2ecf20Sopenharmony_ci	}
75838c2ecf20Sopenharmony_ci
75848c2ecf20Sopenharmony_ci	fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
75858c2ecf20Sopenharmony_ci					  &fw_ddb_entry_dma, GFP_KERNEL);
75868c2ecf20Sopenharmony_ci	if (!fw_ddb_entry) {
75878c2ecf20Sopenharmony_ci		DEBUG2(ql4_printk(KERN_ERR, ha,
75888c2ecf20Sopenharmony_ci				  "%s: Unable to allocate dma buffer\n",
75898c2ecf20Sopenharmony_ci				  __func__));
75908c2ecf20Sopenharmony_ci		ret = -ENOMEM;
75918c2ecf20Sopenharmony_ci		goto exit_ddb_login;
75928c2ecf20Sopenharmony_ci	}
75938c2ecf20Sopenharmony_ci
75948c2ecf20Sopenharmony_ci	if (!strncasecmp(fnode_sess->portal_type, PORTAL_TYPE_IPV6, 4))
75958c2ecf20Sopenharmony_ci		options |= IPV6_DEFAULT_DDB_ENTRY;
75968c2ecf20Sopenharmony_ci
75978c2ecf20Sopenharmony_ci	ret = qla4xxx_get_default_ddb(ha, options, fw_ddb_entry_dma);
75988c2ecf20Sopenharmony_ci	if (ret == QLA_ERROR)
75998c2ecf20Sopenharmony_ci		goto exit_ddb_login;
76008c2ecf20Sopenharmony_ci
76018c2ecf20Sopenharmony_ci	qla4xxx_copy_to_fwddb_param(fnode_sess, fnode_conn, fw_ddb_entry);
76028c2ecf20Sopenharmony_ci	fw_ddb_entry->cookie = DDB_VALID_COOKIE;
76038c2ecf20Sopenharmony_ci
76048c2ecf20Sopenharmony_ci	if (strlen((char *)fw_ddb_entry->iscsi_name) == 0)
76058c2ecf20Sopenharmony_ci		ret = qla4xxx_ddb_login_st(ha, fw_ddb_entry,
76068c2ecf20Sopenharmony_ci					   fnode_sess->target_id);
76078c2ecf20Sopenharmony_ci	else
76088c2ecf20Sopenharmony_ci		ret = qla4xxx_ddb_login_nt(ha, fw_ddb_entry,
76098c2ecf20Sopenharmony_ci					   fnode_sess->target_id);
76108c2ecf20Sopenharmony_ci
76118c2ecf20Sopenharmony_ci	if (ret > 0)
76128c2ecf20Sopenharmony_ci		ret = -EIO;
76138c2ecf20Sopenharmony_ci
76148c2ecf20Sopenharmony_ciexit_ddb_login:
76158c2ecf20Sopenharmony_ci	if (fw_ddb_entry)
76168c2ecf20Sopenharmony_ci		dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
76178c2ecf20Sopenharmony_ci				  fw_ddb_entry, fw_ddb_entry_dma);
76188c2ecf20Sopenharmony_ci	return ret;
76198c2ecf20Sopenharmony_ci}
76208c2ecf20Sopenharmony_ci
76218c2ecf20Sopenharmony_ci/**
76228c2ecf20Sopenharmony_ci * qla4xxx_sysfs_ddb_logout_sid - Logout session for the specified target
76238c2ecf20Sopenharmony_ci * @cls_sess: pointer to session to be logged out
76248c2ecf20Sopenharmony_ci *
76258c2ecf20Sopenharmony_ci * This performs session log out from the specified target
76268c2ecf20Sopenharmony_ci **/
76278c2ecf20Sopenharmony_cistatic int qla4xxx_sysfs_ddb_logout_sid(struct iscsi_cls_session *cls_sess)
76288c2ecf20Sopenharmony_ci{
76298c2ecf20Sopenharmony_ci	struct iscsi_session *sess;
76308c2ecf20Sopenharmony_ci	struct ddb_entry *ddb_entry = NULL;
76318c2ecf20Sopenharmony_ci	struct scsi_qla_host *ha;
76328c2ecf20Sopenharmony_ci	struct dev_db_entry *fw_ddb_entry = NULL;
76338c2ecf20Sopenharmony_ci	dma_addr_t fw_ddb_entry_dma;
76348c2ecf20Sopenharmony_ci	unsigned long flags;
76358c2ecf20Sopenharmony_ci	unsigned long wtime;
76368c2ecf20Sopenharmony_ci	uint32_t ddb_state;
76378c2ecf20Sopenharmony_ci	int options;
76388c2ecf20Sopenharmony_ci	int ret = 0;
76398c2ecf20Sopenharmony_ci
76408c2ecf20Sopenharmony_ci	sess = cls_sess->dd_data;
76418c2ecf20Sopenharmony_ci	ddb_entry = sess->dd_data;
76428c2ecf20Sopenharmony_ci	ha = ddb_entry->ha;
76438c2ecf20Sopenharmony_ci
76448c2ecf20Sopenharmony_ci	if (ddb_entry->ddb_type != FLASH_DDB) {
76458c2ecf20Sopenharmony_ci		ql4_printk(KERN_ERR, ha, "%s: Not a flash node session\n",
76468c2ecf20Sopenharmony_ci			   __func__);
76478c2ecf20Sopenharmony_ci		ret = -ENXIO;
76488c2ecf20Sopenharmony_ci		goto exit_ddb_logout;
76498c2ecf20Sopenharmony_ci	}
76508c2ecf20Sopenharmony_ci
76518c2ecf20Sopenharmony_ci	if (test_bit(DF_BOOT_TGT, &ddb_entry->flags)) {
76528c2ecf20Sopenharmony_ci		ql4_printk(KERN_ERR, ha,
76538c2ecf20Sopenharmony_ci			   "%s: Logout from boot target entry is not permitted.\n",
76548c2ecf20Sopenharmony_ci			   __func__);
76558c2ecf20Sopenharmony_ci		ret = -EPERM;
76568c2ecf20Sopenharmony_ci		goto exit_ddb_logout;
76578c2ecf20Sopenharmony_ci	}
76588c2ecf20Sopenharmony_ci
76598c2ecf20Sopenharmony_ci	fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
76608c2ecf20Sopenharmony_ci					  &fw_ddb_entry_dma, GFP_KERNEL);
76618c2ecf20Sopenharmony_ci	if (!fw_ddb_entry) {
76628c2ecf20Sopenharmony_ci		ql4_printk(KERN_ERR, ha,
76638c2ecf20Sopenharmony_ci			   "%s: Unable to allocate dma buffer\n", __func__);
76648c2ecf20Sopenharmony_ci		ret = -ENOMEM;
76658c2ecf20Sopenharmony_ci		goto exit_ddb_logout;
76668c2ecf20Sopenharmony_ci	}
76678c2ecf20Sopenharmony_ci
76688c2ecf20Sopenharmony_ci	if (test_and_set_bit(DF_DISABLE_RELOGIN, &ddb_entry->flags))
76698c2ecf20Sopenharmony_ci		goto ddb_logout_init;
76708c2ecf20Sopenharmony_ci
76718c2ecf20Sopenharmony_ci	ret = qla4xxx_get_fwddb_entry(ha, ddb_entry->fw_ddb_index,
76728c2ecf20Sopenharmony_ci				      fw_ddb_entry, fw_ddb_entry_dma,
76738c2ecf20Sopenharmony_ci				      NULL, NULL, &ddb_state, NULL,
76748c2ecf20Sopenharmony_ci				      NULL, NULL);
76758c2ecf20Sopenharmony_ci	if (ret == QLA_ERROR)
76768c2ecf20Sopenharmony_ci		goto ddb_logout_init;
76778c2ecf20Sopenharmony_ci
76788c2ecf20Sopenharmony_ci	if (ddb_state == DDB_DS_SESSION_ACTIVE)
76798c2ecf20Sopenharmony_ci		goto ddb_logout_init;
76808c2ecf20Sopenharmony_ci
76818c2ecf20Sopenharmony_ci	/* wait until next relogin is triggered using DF_RELOGIN and
76828c2ecf20Sopenharmony_ci	 * clear DF_RELOGIN to avoid invocation of further relogin
76838c2ecf20Sopenharmony_ci	 */
76848c2ecf20Sopenharmony_ci	wtime = jiffies + (HZ * RELOGIN_TOV);
76858c2ecf20Sopenharmony_ci	do {
76868c2ecf20Sopenharmony_ci		if (test_and_clear_bit(DF_RELOGIN, &ddb_entry->flags))
76878c2ecf20Sopenharmony_ci			goto ddb_logout_init;
76888c2ecf20Sopenharmony_ci
76898c2ecf20Sopenharmony_ci		schedule_timeout_uninterruptible(HZ);
76908c2ecf20Sopenharmony_ci	} while ((time_after(wtime, jiffies)));
76918c2ecf20Sopenharmony_ci
76928c2ecf20Sopenharmony_ciddb_logout_init:
76938c2ecf20Sopenharmony_ci	atomic_set(&ddb_entry->retry_relogin_timer, INVALID_ENTRY);
76948c2ecf20Sopenharmony_ci	atomic_set(&ddb_entry->relogin_timer, 0);
76958c2ecf20Sopenharmony_ci
76968c2ecf20Sopenharmony_ci	options = LOGOUT_OPTION_CLOSE_SESSION;
76978c2ecf20Sopenharmony_ci	qla4xxx_session_logout_ddb(ha, ddb_entry, options);
76988c2ecf20Sopenharmony_ci
76998c2ecf20Sopenharmony_ci	memset(fw_ddb_entry, 0, sizeof(*fw_ddb_entry));
77008c2ecf20Sopenharmony_ci	wtime = jiffies + (HZ * LOGOUT_TOV);
77018c2ecf20Sopenharmony_ci	do {
77028c2ecf20Sopenharmony_ci		ret = qla4xxx_get_fwddb_entry(ha, ddb_entry->fw_ddb_index,
77038c2ecf20Sopenharmony_ci					      fw_ddb_entry, fw_ddb_entry_dma,
77048c2ecf20Sopenharmony_ci					      NULL, NULL, &ddb_state, NULL,
77058c2ecf20Sopenharmony_ci					      NULL, NULL);
77068c2ecf20Sopenharmony_ci		if (ret == QLA_ERROR)
77078c2ecf20Sopenharmony_ci			goto ddb_logout_clr_sess;
77088c2ecf20Sopenharmony_ci
77098c2ecf20Sopenharmony_ci		if ((ddb_state == DDB_DS_NO_CONNECTION_ACTIVE) ||
77108c2ecf20Sopenharmony_ci		    (ddb_state == DDB_DS_SESSION_FAILED))
77118c2ecf20Sopenharmony_ci			goto ddb_logout_clr_sess;
77128c2ecf20Sopenharmony_ci
77138c2ecf20Sopenharmony_ci		schedule_timeout_uninterruptible(HZ);
77148c2ecf20Sopenharmony_ci	} while ((time_after(wtime, jiffies)));
77158c2ecf20Sopenharmony_ci
77168c2ecf20Sopenharmony_ciddb_logout_clr_sess:
77178c2ecf20Sopenharmony_ci	qla4xxx_clear_ddb_entry(ha, ddb_entry->fw_ddb_index);
77188c2ecf20Sopenharmony_ci	/*
77198c2ecf20Sopenharmony_ci	 * we have decremented the reference count of the driver
77208c2ecf20Sopenharmony_ci	 * when we setup the session to have the driver unload
77218c2ecf20Sopenharmony_ci	 * to be seamless without actually destroying the
77228c2ecf20Sopenharmony_ci	 * session
77238c2ecf20Sopenharmony_ci	 **/
77248c2ecf20Sopenharmony_ci	try_module_get(qla4xxx_iscsi_transport.owner);
77258c2ecf20Sopenharmony_ci	iscsi_destroy_endpoint(ddb_entry->conn->ep);
77268c2ecf20Sopenharmony_ci
77278c2ecf20Sopenharmony_ci	spin_lock_irqsave(&ha->hardware_lock, flags);
77288c2ecf20Sopenharmony_ci	qla4xxx_free_ddb(ha, ddb_entry);
77298c2ecf20Sopenharmony_ci	clear_bit(ddb_entry->fw_ddb_index, ha->ddb_idx_map);
77308c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&ha->hardware_lock, flags);
77318c2ecf20Sopenharmony_ci
77328c2ecf20Sopenharmony_ci	iscsi_session_teardown(ddb_entry->sess);
77338c2ecf20Sopenharmony_ci
77348c2ecf20Sopenharmony_ci	clear_bit(DF_DISABLE_RELOGIN, &ddb_entry->flags);
77358c2ecf20Sopenharmony_ci	ret = QLA_SUCCESS;
77368c2ecf20Sopenharmony_ci
77378c2ecf20Sopenharmony_ciexit_ddb_logout:
77388c2ecf20Sopenharmony_ci	if (fw_ddb_entry)
77398c2ecf20Sopenharmony_ci		dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
77408c2ecf20Sopenharmony_ci				  fw_ddb_entry, fw_ddb_entry_dma);
77418c2ecf20Sopenharmony_ci	return ret;
77428c2ecf20Sopenharmony_ci}
77438c2ecf20Sopenharmony_ci
77448c2ecf20Sopenharmony_ci/**
77458c2ecf20Sopenharmony_ci * qla4xxx_sysfs_ddb_logout - Logout from the specified target
77468c2ecf20Sopenharmony_ci * @fnode_sess: pointer to session attrs of flash ddb entry
77478c2ecf20Sopenharmony_ci * @fnode_conn: pointer to connection attrs of flash ddb entry
77488c2ecf20Sopenharmony_ci *
77498c2ecf20Sopenharmony_ci * This performs log out from the specified target
77508c2ecf20Sopenharmony_ci **/
77518c2ecf20Sopenharmony_cistatic int qla4xxx_sysfs_ddb_logout(struct iscsi_bus_flash_session *fnode_sess,
77528c2ecf20Sopenharmony_ci				    struct iscsi_bus_flash_conn *fnode_conn)
77538c2ecf20Sopenharmony_ci{
77548c2ecf20Sopenharmony_ci	struct Scsi_Host *shost = iscsi_flash_session_to_shost(fnode_sess);
77558c2ecf20Sopenharmony_ci	struct scsi_qla_host *ha = to_qla_host(shost);
77568c2ecf20Sopenharmony_ci	struct ql4_tuple_ddb *flash_tddb = NULL;
77578c2ecf20Sopenharmony_ci	struct ql4_tuple_ddb *tmp_tddb = NULL;
77588c2ecf20Sopenharmony_ci	struct dev_db_entry *fw_ddb_entry = NULL;
77598c2ecf20Sopenharmony_ci	struct ddb_entry *ddb_entry = NULL;
77608c2ecf20Sopenharmony_ci	dma_addr_t fw_ddb_dma;
77618c2ecf20Sopenharmony_ci	uint32_t next_idx = 0;
77628c2ecf20Sopenharmony_ci	uint32_t state = 0, conn_err = 0;
77638c2ecf20Sopenharmony_ci	uint16_t conn_id = 0;
77648c2ecf20Sopenharmony_ci	int idx, index;
77658c2ecf20Sopenharmony_ci	int status, ret = 0;
77668c2ecf20Sopenharmony_ci
77678c2ecf20Sopenharmony_ci	fw_ddb_entry = dma_pool_alloc(ha->fw_ddb_dma_pool, GFP_KERNEL,
77688c2ecf20Sopenharmony_ci				      &fw_ddb_dma);
77698c2ecf20Sopenharmony_ci	if (fw_ddb_entry == NULL) {
77708c2ecf20Sopenharmony_ci		ql4_printk(KERN_ERR, ha, "%s:Out of memory\n", __func__);
77718c2ecf20Sopenharmony_ci		ret = -ENOMEM;
77728c2ecf20Sopenharmony_ci		goto exit_ddb_logout;
77738c2ecf20Sopenharmony_ci	}
77748c2ecf20Sopenharmony_ci
77758c2ecf20Sopenharmony_ci	flash_tddb = vzalloc(sizeof(*flash_tddb));
77768c2ecf20Sopenharmony_ci	if (!flash_tddb) {
77778c2ecf20Sopenharmony_ci		ql4_printk(KERN_WARNING, ha,
77788c2ecf20Sopenharmony_ci			   "%s:Memory Allocation failed.\n", __func__);
77798c2ecf20Sopenharmony_ci		ret = -ENOMEM;
77808c2ecf20Sopenharmony_ci		goto exit_ddb_logout;
77818c2ecf20Sopenharmony_ci	}
77828c2ecf20Sopenharmony_ci
77838c2ecf20Sopenharmony_ci	tmp_tddb = vzalloc(sizeof(*tmp_tddb));
77848c2ecf20Sopenharmony_ci	if (!tmp_tddb) {
77858c2ecf20Sopenharmony_ci		ql4_printk(KERN_WARNING, ha,
77868c2ecf20Sopenharmony_ci			   "%s:Memory Allocation failed.\n", __func__);
77878c2ecf20Sopenharmony_ci		ret = -ENOMEM;
77888c2ecf20Sopenharmony_ci		goto exit_ddb_logout;
77898c2ecf20Sopenharmony_ci	}
77908c2ecf20Sopenharmony_ci
77918c2ecf20Sopenharmony_ci	if (!fnode_sess->targetname) {
77928c2ecf20Sopenharmony_ci		ql4_printk(KERN_ERR, ha,
77938c2ecf20Sopenharmony_ci			   "%s:Cannot logout from SendTarget entry\n",
77948c2ecf20Sopenharmony_ci			   __func__);
77958c2ecf20Sopenharmony_ci		ret = -EPERM;
77968c2ecf20Sopenharmony_ci		goto exit_ddb_logout;
77978c2ecf20Sopenharmony_ci	}
77988c2ecf20Sopenharmony_ci
77998c2ecf20Sopenharmony_ci	if (fnode_sess->is_boot_target) {
78008c2ecf20Sopenharmony_ci		ql4_printk(KERN_ERR, ha,
78018c2ecf20Sopenharmony_ci			   "%s: Logout from boot target entry is not permitted.\n",
78028c2ecf20Sopenharmony_ci			   __func__);
78038c2ecf20Sopenharmony_ci		ret = -EPERM;
78048c2ecf20Sopenharmony_ci		goto exit_ddb_logout;
78058c2ecf20Sopenharmony_ci	}
78068c2ecf20Sopenharmony_ci
78078c2ecf20Sopenharmony_ci	strlcpy(flash_tddb->iscsi_name, fnode_sess->targetname,
78088c2ecf20Sopenharmony_ci		ISCSI_NAME_SIZE);
78098c2ecf20Sopenharmony_ci
78108c2ecf20Sopenharmony_ci	if (!strncmp(fnode_sess->portal_type, PORTAL_TYPE_IPV6, 4))
78118c2ecf20Sopenharmony_ci		sprintf(flash_tddb->ip_addr, "%pI6", fnode_conn->ipaddress);
78128c2ecf20Sopenharmony_ci	else
78138c2ecf20Sopenharmony_ci		sprintf(flash_tddb->ip_addr, "%pI4", fnode_conn->ipaddress);
78148c2ecf20Sopenharmony_ci
78158c2ecf20Sopenharmony_ci	flash_tddb->tpgt = fnode_sess->tpgt;
78168c2ecf20Sopenharmony_ci	flash_tddb->port = fnode_conn->port;
78178c2ecf20Sopenharmony_ci
78188c2ecf20Sopenharmony_ci	COPY_ISID(flash_tddb->isid, fnode_sess->isid);
78198c2ecf20Sopenharmony_ci
78208c2ecf20Sopenharmony_ci	for (idx = 0; idx < MAX_DDB_ENTRIES; idx++) {
78218c2ecf20Sopenharmony_ci		ddb_entry = qla4xxx_lookup_ddb_by_fw_index(ha, idx);
78228c2ecf20Sopenharmony_ci		if (ddb_entry == NULL)
78238c2ecf20Sopenharmony_ci			continue;
78248c2ecf20Sopenharmony_ci
78258c2ecf20Sopenharmony_ci		if (ddb_entry->ddb_type != FLASH_DDB)
78268c2ecf20Sopenharmony_ci			continue;
78278c2ecf20Sopenharmony_ci
78288c2ecf20Sopenharmony_ci		index = ddb_entry->sess->target_id;
78298c2ecf20Sopenharmony_ci		status = qla4xxx_get_fwddb_entry(ha, index, fw_ddb_entry,
78308c2ecf20Sopenharmony_ci						 fw_ddb_dma, NULL, &next_idx,
78318c2ecf20Sopenharmony_ci						 &state, &conn_err, NULL,
78328c2ecf20Sopenharmony_ci						 &conn_id);
78338c2ecf20Sopenharmony_ci		if (status == QLA_ERROR) {
78348c2ecf20Sopenharmony_ci			ret = -ENOMEM;
78358c2ecf20Sopenharmony_ci			break;
78368c2ecf20Sopenharmony_ci		}
78378c2ecf20Sopenharmony_ci
78388c2ecf20Sopenharmony_ci		qla4xxx_convert_param_ddb(fw_ddb_entry, tmp_tddb, NULL);
78398c2ecf20Sopenharmony_ci
78408c2ecf20Sopenharmony_ci		status = qla4xxx_compare_tuple_ddb(ha, flash_tddb, tmp_tddb,
78418c2ecf20Sopenharmony_ci						   true);
78428c2ecf20Sopenharmony_ci		if (status == QLA_SUCCESS) {
78438c2ecf20Sopenharmony_ci			ret = qla4xxx_sysfs_ddb_logout_sid(ddb_entry->sess);
78448c2ecf20Sopenharmony_ci			break;
78458c2ecf20Sopenharmony_ci		}
78468c2ecf20Sopenharmony_ci	}
78478c2ecf20Sopenharmony_ci
78488c2ecf20Sopenharmony_ci	if (idx == MAX_DDB_ENTRIES)
78498c2ecf20Sopenharmony_ci		ret = -ESRCH;
78508c2ecf20Sopenharmony_ci
78518c2ecf20Sopenharmony_ciexit_ddb_logout:
78528c2ecf20Sopenharmony_ci	if (flash_tddb)
78538c2ecf20Sopenharmony_ci		vfree(flash_tddb);
78548c2ecf20Sopenharmony_ci	if (tmp_tddb)
78558c2ecf20Sopenharmony_ci		vfree(tmp_tddb);
78568c2ecf20Sopenharmony_ci	if (fw_ddb_entry)
78578c2ecf20Sopenharmony_ci		dma_pool_free(ha->fw_ddb_dma_pool, fw_ddb_entry, fw_ddb_dma);
78588c2ecf20Sopenharmony_ci
78598c2ecf20Sopenharmony_ci	return ret;
78608c2ecf20Sopenharmony_ci}
78618c2ecf20Sopenharmony_ci
78628c2ecf20Sopenharmony_cistatic int
78638c2ecf20Sopenharmony_ciqla4xxx_sysfs_ddb_get_param(struct iscsi_bus_flash_session *fnode_sess,
78648c2ecf20Sopenharmony_ci			    int param, char *buf)
78658c2ecf20Sopenharmony_ci{
78668c2ecf20Sopenharmony_ci	struct Scsi_Host *shost = iscsi_flash_session_to_shost(fnode_sess);
78678c2ecf20Sopenharmony_ci	struct scsi_qla_host *ha = to_qla_host(shost);
78688c2ecf20Sopenharmony_ci	struct iscsi_bus_flash_conn *fnode_conn;
78698c2ecf20Sopenharmony_ci	struct ql4_chap_table chap_tbl;
78708c2ecf20Sopenharmony_ci	struct device *dev;
78718c2ecf20Sopenharmony_ci	int parent_type;
78728c2ecf20Sopenharmony_ci	int rc = 0;
78738c2ecf20Sopenharmony_ci
78748c2ecf20Sopenharmony_ci	dev = iscsi_find_flashnode_conn(fnode_sess);
78758c2ecf20Sopenharmony_ci	if (!dev)
78768c2ecf20Sopenharmony_ci		return -EIO;
78778c2ecf20Sopenharmony_ci
78788c2ecf20Sopenharmony_ci	fnode_conn = iscsi_dev_to_flash_conn(dev);
78798c2ecf20Sopenharmony_ci
78808c2ecf20Sopenharmony_ci	switch (param) {
78818c2ecf20Sopenharmony_ci	case ISCSI_FLASHNODE_IS_FW_ASSIGNED_IPV6:
78828c2ecf20Sopenharmony_ci		rc = sprintf(buf, "%u\n", fnode_conn->is_fw_assigned_ipv6);
78838c2ecf20Sopenharmony_ci		break;
78848c2ecf20Sopenharmony_ci	case ISCSI_FLASHNODE_PORTAL_TYPE:
78858c2ecf20Sopenharmony_ci		rc = sprintf(buf, "%s\n", fnode_sess->portal_type);
78868c2ecf20Sopenharmony_ci		break;
78878c2ecf20Sopenharmony_ci	case ISCSI_FLASHNODE_AUTO_SND_TGT_DISABLE:
78888c2ecf20Sopenharmony_ci		rc = sprintf(buf, "%u\n", fnode_sess->auto_snd_tgt_disable);
78898c2ecf20Sopenharmony_ci		break;
78908c2ecf20Sopenharmony_ci	case ISCSI_FLASHNODE_DISCOVERY_SESS:
78918c2ecf20Sopenharmony_ci		rc = sprintf(buf, "%u\n", fnode_sess->discovery_sess);
78928c2ecf20Sopenharmony_ci		break;
78938c2ecf20Sopenharmony_ci	case ISCSI_FLASHNODE_ENTRY_EN:
78948c2ecf20Sopenharmony_ci		rc = sprintf(buf, "%u\n", fnode_sess->entry_state);
78958c2ecf20Sopenharmony_ci		break;
78968c2ecf20Sopenharmony_ci	case ISCSI_FLASHNODE_HDR_DGST_EN:
78978c2ecf20Sopenharmony_ci		rc = sprintf(buf, "%u\n", fnode_conn->hdrdgst_en);
78988c2ecf20Sopenharmony_ci		break;
78998c2ecf20Sopenharmony_ci	case ISCSI_FLASHNODE_DATA_DGST_EN:
79008c2ecf20Sopenharmony_ci		rc = sprintf(buf, "%u\n", fnode_conn->datadgst_en);
79018c2ecf20Sopenharmony_ci		break;
79028c2ecf20Sopenharmony_ci	case ISCSI_FLASHNODE_IMM_DATA_EN:
79038c2ecf20Sopenharmony_ci		rc = sprintf(buf, "%u\n", fnode_sess->imm_data_en);
79048c2ecf20Sopenharmony_ci		break;
79058c2ecf20Sopenharmony_ci	case ISCSI_FLASHNODE_INITIAL_R2T_EN:
79068c2ecf20Sopenharmony_ci		rc = sprintf(buf, "%u\n", fnode_sess->initial_r2t_en);
79078c2ecf20Sopenharmony_ci		break;
79088c2ecf20Sopenharmony_ci	case ISCSI_FLASHNODE_DATASEQ_INORDER:
79098c2ecf20Sopenharmony_ci		rc = sprintf(buf, "%u\n", fnode_sess->dataseq_inorder_en);
79108c2ecf20Sopenharmony_ci		break;
79118c2ecf20Sopenharmony_ci	case ISCSI_FLASHNODE_PDU_INORDER:
79128c2ecf20Sopenharmony_ci		rc = sprintf(buf, "%u\n", fnode_sess->pdu_inorder_en);
79138c2ecf20Sopenharmony_ci		break;
79148c2ecf20Sopenharmony_ci	case ISCSI_FLASHNODE_CHAP_AUTH_EN:
79158c2ecf20Sopenharmony_ci		rc = sprintf(buf, "%u\n", fnode_sess->chap_auth_en);
79168c2ecf20Sopenharmony_ci		break;
79178c2ecf20Sopenharmony_ci	case ISCSI_FLASHNODE_SNACK_REQ_EN:
79188c2ecf20Sopenharmony_ci		rc = sprintf(buf, "%u\n", fnode_conn->snack_req_en);
79198c2ecf20Sopenharmony_ci		break;
79208c2ecf20Sopenharmony_ci	case ISCSI_FLASHNODE_DISCOVERY_LOGOUT_EN:
79218c2ecf20Sopenharmony_ci		rc = sprintf(buf, "%u\n", fnode_sess->discovery_logout_en);
79228c2ecf20Sopenharmony_ci		break;
79238c2ecf20Sopenharmony_ci	case ISCSI_FLASHNODE_BIDI_CHAP_EN:
79248c2ecf20Sopenharmony_ci		rc = sprintf(buf, "%u\n", fnode_sess->bidi_chap_en);
79258c2ecf20Sopenharmony_ci		break;
79268c2ecf20Sopenharmony_ci	case ISCSI_FLASHNODE_DISCOVERY_AUTH_OPTIONAL:
79278c2ecf20Sopenharmony_ci		rc = sprintf(buf, "%u\n", fnode_sess->discovery_auth_optional);
79288c2ecf20Sopenharmony_ci		break;
79298c2ecf20Sopenharmony_ci	case ISCSI_FLASHNODE_ERL:
79308c2ecf20Sopenharmony_ci		rc = sprintf(buf, "%u\n", fnode_sess->erl);
79318c2ecf20Sopenharmony_ci		break;
79328c2ecf20Sopenharmony_ci	case ISCSI_FLASHNODE_TCP_TIMESTAMP_STAT:
79338c2ecf20Sopenharmony_ci		rc = sprintf(buf, "%u\n", fnode_conn->tcp_timestamp_stat);
79348c2ecf20Sopenharmony_ci		break;
79358c2ecf20Sopenharmony_ci	case ISCSI_FLASHNODE_TCP_NAGLE_DISABLE:
79368c2ecf20Sopenharmony_ci		rc = sprintf(buf, "%u\n", fnode_conn->tcp_nagle_disable);
79378c2ecf20Sopenharmony_ci		break;
79388c2ecf20Sopenharmony_ci	case ISCSI_FLASHNODE_TCP_WSF_DISABLE:
79398c2ecf20Sopenharmony_ci		rc = sprintf(buf, "%u\n", fnode_conn->tcp_wsf_disable);
79408c2ecf20Sopenharmony_ci		break;
79418c2ecf20Sopenharmony_ci	case ISCSI_FLASHNODE_TCP_TIMER_SCALE:
79428c2ecf20Sopenharmony_ci		rc = sprintf(buf, "%u\n", fnode_conn->tcp_timer_scale);
79438c2ecf20Sopenharmony_ci		break;
79448c2ecf20Sopenharmony_ci	case ISCSI_FLASHNODE_TCP_TIMESTAMP_EN:
79458c2ecf20Sopenharmony_ci		rc = sprintf(buf, "%u\n", fnode_conn->tcp_timestamp_en);
79468c2ecf20Sopenharmony_ci		break;
79478c2ecf20Sopenharmony_ci	case ISCSI_FLASHNODE_IP_FRAG_DISABLE:
79488c2ecf20Sopenharmony_ci		rc = sprintf(buf, "%u\n", fnode_conn->fragment_disable);
79498c2ecf20Sopenharmony_ci		break;
79508c2ecf20Sopenharmony_ci	case ISCSI_FLASHNODE_MAX_RECV_DLENGTH:
79518c2ecf20Sopenharmony_ci		rc = sprintf(buf, "%u\n", fnode_conn->max_recv_dlength);
79528c2ecf20Sopenharmony_ci		break;
79538c2ecf20Sopenharmony_ci	case ISCSI_FLASHNODE_MAX_XMIT_DLENGTH:
79548c2ecf20Sopenharmony_ci		rc = sprintf(buf, "%u\n", fnode_conn->max_xmit_dlength);
79558c2ecf20Sopenharmony_ci		break;
79568c2ecf20Sopenharmony_ci	case ISCSI_FLASHNODE_FIRST_BURST:
79578c2ecf20Sopenharmony_ci		rc = sprintf(buf, "%u\n", fnode_sess->first_burst);
79588c2ecf20Sopenharmony_ci		break;
79598c2ecf20Sopenharmony_ci	case ISCSI_FLASHNODE_DEF_TIME2WAIT:
79608c2ecf20Sopenharmony_ci		rc = sprintf(buf, "%u\n", fnode_sess->time2wait);
79618c2ecf20Sopenharmony_ci		break;
79628c2ecf20Sopenharmony_ci	case ISCSI_FLASHNODE_DEF_TIME2RETAIN:
79638c2ecf20Sopenharmony_ci		rc = sprintf(buf, "%u\n", fnode_sess->time2retain);
79648c2ecf20Sopenharmony_ci		break;
79658c2ecf20Sopenharmony_ci	case ISCSI_FLASHNODE_MAX_R2T:
79668c2ecf20Sopenharmony_ci		rc = sprintf(buf, "%u\n", fnode_sess->max_r2t);
79678c2ecf20Sopenharmony_ci		break;
79688c2ecf20Sopenharmony_ci	case ISCSI_FLASHNODE_KEEPALIVE_TMO:
79698c2ecf20Sopenharmony_ci		rc = sprintf(buf, "%u\n", fnode_conn->keepalive_timeout);
79708c2ecf20Sopenharmony_ci		break;
79718c2ecf20Sopenharmony_ci	case ISCSI_FLASHNODE_ISID:
79728c2ecf20Sopenharmony_ci		rc = sprintf(buf, "%pm\n", fnode_sess->isid);
79738c2ecf20Sopenharmony_ci		break;
79748c2ecf20Sopenharmony_ci	case ISCSI_FLASHNODE_TSID:
79758c2ecf20Sopenharmony_ci		rc = sprintf(buf, "%u\n", fnode_sess->tsid);
79768c2ecf20Sopenharmony_ci		break;
79778c2ecf20Sopenharmony_ci	case ISCSI_FLASHNODE_PORT:
79788c2ecf20Sopenharmony_ci		rc = sprintf(buf, "%d\n", fnode_conn->port);
79798c2ecf20Sopenharmony_ci		break;
79808c2ecf20Sopenharmony_ci	case ISCSI_FLASHNODE_MAX_BURST:
79818c2ecf20Sopenharmony_ci		rc = sprintf(buf, "%u\n", fnode_sess->max_burst);
79828c2ecf20Sopenharmony_ci		break;
79838c2ecf20Sopenharmony_ci	case ISCSI_FLASHNODE_DEF_TASKMGMT_TMO:
79848c2ecf20Sopenharmony_ci		rc = sprintf(buf, "%u\n",
79858c2ecf20Sopenharmony_ci			     fnode_sess->default_taskmgmt_timeout);
79868c2ecf20Sopenharmony_ci		break;
79878c2ecf20Sopenharmony_ci	case ISCSI_FLASHNODE_IPADDR:
79888c2ecf20Sopenharmony_ci		if (!strncmp(fnode_sess->portal_type, PORTAL_TYPE_IPV6, 4))
79898c2ecf20Sopenharmony_ci			rc = sprintf(buf, "%pI6\n", fnode_conn->ipaddress);
79908c2ecf20Sopenharmony_ci		else
79918c2ecf20Sopenharmony_ci			rc = sprintf(buf, "%pI4\n", fnode_conn->ipaddress);
79928c2ecf20Sopenharmony_ci		break;
79938c2ecf20Sopenharmony_ci	case ISCSI_FLASHNODE_ALIAS:
79948c2ecf20Sopenharmony_ci		if (fnode_sess->targetalias)
79958c2ecf20Sopenharmony_ci			rc = sprintf(buf, "%s\n", fnode_sess->targetalias);
79968c2ecf20Sopenharmony_ci		else
79978c2ecf20Sopenharmony_ci			rc = sprintf(buf, "\n");
79988c2ecf20Sopenharmony_ci		break;
79998c2ecf20Sopenharmony_ci	case ISCSI_FLASHNODE_REDIRECT_IPADDR:
80008c2ecf20Sopenharmony_ci		if (!strncmp(fnode_sess->portal_type, PORTAL_TYPE_IPV6, 4))
80018c2ecf20Sopenharmony_ci			rc = sprintf(buf, "%pI6\n",
80028c2ecf20Sopenharmony_ci				     fnode_conn->redirect_ipaddr);
80038c2ecf20Sopenharmony_ci		else
80048c2ecf20Sopenharmony_ci			rc = sprintf(buf, "%pI4\n",
80058c2ecf20Sopenharmony_ci				     fnode_conn->redirect_ipaddr);
80068c2ecf20Sopenharmony_ci		break;
80078c2ecf20Sopenharmony_ci	case ISCSI_FLASHNODE_MAX_SEGMENT_SIZE:
80088c2ecf20Sopenharmony_ci		rc = sprintf(buf, "%u\n", fnode_conn->max_segment_size);
80098c2ecf20Sopenharmony_ci		break;
80108c2ecf20Sopenharmony_ci	case ISCSI_FLASHNODE_LOCAL_PORT:
80118c2ecf20Sopenharmony_ci		rc = sprintf(buf, "%u\n", fnode_conn->local_port);
80128c2ecf20Sopenharmony_ci		break;
80138c2ecf20Sopenharmony_ci	case ISCSI_FLASHNODE_IPV4_TOS:
80148c2ecf20Sopenharmony_ci		rc = sprintf(buf, "%u\n", fnode_conn->ipv4_tos);
80158c2ecf20Sopenharmony_ci		break;
80168c2ecf20Sopenharmony_ci	case ISCSI_FLASHNODE_IPV6_TC:
80178c2ecf20Sopenharmony_ci		if (!strncmp(fnode_sess->portal_type, PORTAL_TYPE_IPV6, 4))
80188c2ecf20Sopenharmony_ci			rc = sprintf(buf, "%u\n",
80198c2ecf20Sopenharmony_ci				     fnode_conn->ipv6_traffic_class);
80208c2ecf20Sopenharmony_ci		else
80218c2ecf20Sopenharmony_ci			rc = sprintf(buf, "\n");
80228c2ecf20Sopenharmony_ci		break;
80238c2ecf20Sopenharmony_ci	case ISCSI_FLASHNODE_IPV6_FLOW_LABEL:
80248c2ecf20Sopenharmony_ci		rc = sprintf(buf, "%u\n", fnode_conn->ipv6_flow_label);
80258c2ecf20Sopenharmony_ci		break;
80268c2ecf20Sopenharmony_ci	case ISCSI_FLASHNODE_LINK_LOCAL_IPV6:
80278c2ecf20Sopenharmony_ci		if (!strncmp(fnode_sess->portal_type, PORTAL_TYPE_IPV6, 4))
80288c2ecf20Sopenharmony_ci			rc = sprintf(buf, "%pI6\n",
80298c2ecf20Sopenharmony_ci				     fnode_conn->link_local_ipv6_addr);
80308c2ecf20Sopenharmony_ci		else
80318c2ecf20Sopenharmony_ci			rc = sprintf(buf, "\n");
80328c2ecf20Sopenharmony_ci		break;
80338c2ecf20Sopenharmony_ci	case ISCSI_FLASHNODE_DISCOVERY_PARENT_IDX:
80348c2ecf20Sopenharmony_ci		rc = sprintf(buf, "%u\n", fnode_sess->discovery_parent_idx);
80358c2ecf20Sopenharmony_ci		break;
80368c2ecf20Sopenharmony_ci	case ISCSI_FLASHNODE_DISCOVERY_PARENT_TYPE:
80378c2ecf20Sopenharmony_ci		if (fnode_sess->discovery_parent_type == DDB_ISNS)
80388c2ecf20Sopenharmony_ci			parent_type = ISCSI_DISC_PARENT_ISNS;
80398c2ecf20Sopenharmony_ci		else if (fnode_sess->discovery_parent_type == DDB_NO_LINK)
80408c2ecf20Sopenharmony_ci			parent_type = ISCSI_DISC_PARENT_UNKNOWN;
80418c2ecf20Sopenharmony_ci		else if (fnode_sess->discovery_parent_type < MAX_DDB_ENTRIES)
80428c2ecf20Sopenharmony_ci			parent_type = ISCSI_DISC_PARENT_SENDTGT;
80438c2ecf20Sopenharmony_ci		else
80448c2ecf20Sopenharmony_ci			parent_type = ISCSI_DISC_PARENT_UNKNOWN;
80458c2ecf20Sopenharmony_ci
80468c2ecf20Sopenharmony_ci		rc = sprintf(buf, "%s\n",
80478c2ecf20Sopenharmony_ci			     iscsi_get_discovery_parent_name(parent_type));
80488c2ecf20Sopenharmony_ci		break;
80498c2ecf20Sopenharmony_ci	case ISCSI_FLASHNODE_NAME:
80508c2ecf20Sopenharmony_ci		if (fnode_sess->targetname)
80518c2ecf20Sopenharmony_ci			rc = sprintf(buf, "%s\n", fnode_sess->targetname);
80528c2ecf20Sopenharmony_ci		else
80538c2ecf20Sopenharmony_ci			rc = sprintf(buf, "\n");
80548c2ecf20Sopenharmony_ci		break;
80558c2ecf20Sopenharmony_ci	case ISCSI_FLASHNODE_TPGT:
80568c2ecf20Sopenharmony_ci		rc = sprintf(buf, "%u\n", fnode_sess->tpgt);
80578c2ecf20Sopenharmony_ci		break;
80588c2ecf20Sopenharmony_ci	case ISCSI_FLASHNODE_TCP_XMIT_WSF:
80598c2ecf20Sopenharmony_ci		rc = sprintf(buf, "%u\n", fnode_conn->tcp_xmit_wsf);
80608c2ecf20Sopenharmony_ci		break;
80618c2ecf20Sopenharmony_ci	case ISCSI_FLASHNODE_TCP_RECV_WSF:
80628c2ecf20Sopenharmony_ci		rc = sprintf(buf, "%u\n", fnode_conn->tcp_recv_wsf);
80638c2ecf20Sopenharmony_ci		break;
80648c2ecf20Sopenharmony_ci	case ISCSI_FLASHNODE_CHAP_OUT_IDX:
80658c2ecf20Sopenharmony_ci		rc = sprintf(buf, "%u\n", fnode_sess->chap_out_idx);
80668c2ecf20Sopenharmony_ci		break;
80678c2ecf20Sopenharmony_ci	case ISCSI_FLASHNODE_USERNAME:
80688c2ecf20Sopenharmony_ci		if (fnode_sess->chap_auth_en) {
80698c2ecf20Sopenharmony_ci			qla4xxx_get_uni_chap_at_index(ha,
80708c2ecf20Sopenharmony_ci						      chap_tbl.name,
80718c2ecf20Sopenharmony_ci						      chap_tbl.secret,
80728c2ecf20Sopenharmony_ci						      fnode_sess->chap_out_idx);
80738c2ecf20Sopenharmony_ci			rc = sprintf(buf, "%s\n", chap_tbl.name);
80748c2ecf20Sopenharmony_ci		} else {
80758c2ecf20Sopenharmony_ci			rc = sprintf(buf, "\n");
80768c2ecf20Sopenharmony_ci		}
80778c2ecf20Sopenharmony_ci		break;
80788c2ecf20Sopenharmony_ci	case ISCSI_FLASHNODE_PASSWORD:
80798c2ecf20Sopenharmony_ci		if (fnode_sess->chap_auth_en) {
80808c2ecf20Sopenharmony_ci			qla4xxx_get_uni_chap_at_index(ha,
80818c2ecf20Sopenharmony_ci						      chap_tbl.name,
80828c2ecf20Sopenharmony_ci						      chap_tbl.secret,
80838c2ecf20Sopenharmony_ci						      fnode_sess->chap_out_idx);
80848c2ecf20Sopenharmony_ci			rc = sprintf(buf, "%s\n", chap_tbl.secret);
80858c2ecf20Sopenharmony_ci		} else {
80868c2ecf20Sopenharmony_ci			rc = sprintf(buf, "\n");
80878c2ecf20Sopenharmony_ci		}
80888c2ecf20Sopenharmony_ci		break;
80898c2ecf20Sopenharmony_ci	case ISCSI_FLASHNODE_STATSN:
80908c2ecf20Sopenharmony_ci		rc = sprintf(buf, "%u\n", fnode_conn->statsn);
80918c2ecf20Sopenharmony_ci		break;
80928c2ecf20Sopenharmony_ci	case ISCSI_FLASHNODE_EXP_STATSN:
80938c2ecf20Sopenharmony_ci		rc = sprintf(buf, "%u\n", fnode_conn->exp_statsn);
80948c2ecf20Sopenharmony_ci		break;
80958c2ecf20Sopenharmony_ci	case ISCSI_FLASHNODE_IS_BOOT_TGT:
80968c2ecf20Sopenharmony_ci		rc = sprintf(buf, "%u\n", fnode_sess->is_boot_target);
80978c2ecf20Sopenharmony_ci		break;
80988c2ecf20Sopenharmony_ci	default:
80998c2ecf20Sopenharmony_ci		rc = -ENOSYS;
81008c2ecf20Sopenharmony_ci		break;
81018c2ecf20Sopenharmony_ci	}
81028c2ecf20Sopenharmony_ci
81038c2ecf20Sopenharmony_ci	put_device(dev);
81048c2ecf20Sopenharmony_ci	return rc;
81058c2ecf20Sopenharmony_ci}
81068c2ecf20Sopenharmony_ci
81078c2ecf20Sopenharmony_ci/**
81088c2ecf20Sopenharmony_ci * qla4xxx_sysfs_ddb_set_param - Set parameter for firmware DDB entry
81098c2ecf20Sopenharmony_ci * @fnode_sess: pointer to session attrs of flash ddb entry
81108c2ecf20Sopenharmony_ci * @fnode_conn: pointer to connection attrs of flash ddb entry
81118c2ecf20Sopenharmony_ci * @data: Parameters and their values to update
81128c2ecf20Sopenharmony_ci * @len: len of data
81138c2ecf20Sopenharmony_ci *
81148c2ecf20Sopenharmony_ci * This sets the parameter of flash ddb entry and writes them to flash
81158c2ecf20Sopenharmony_ci **/
81168c2ecf20Sopenharmony_cistatic int
81178c2ecf20Sopenharmony_ciqla4xxx_sysfs_ddb_set_param(struct iscsi_bus_flash_session *fnode_sess,
81188c2ecf20Sopenharmony_ci			    struct iscsi_bus_flash_conn *fnode_conn,
81198c2ecf20Sopenharmony_ci			    void *data, int len)
81208c2ecf20Sopenharmony_ci{
81218c2ecf20Sopenharmony_ci	struct Scsi_Host *shost = iscsi_flash_session_to_shost(fnode_sess);
81228c2ecf20Sopenharmony_ci	struct scsi_qla_host *ha = to_qla_host(shost);
81238c2ecf20Sopenharmony_ci	struct iscsi_flashnode_param_info *fnode_param;
81248c2ecf20Sopenharmony_ci	struct ql4_chap_table chap_tbl;
81258c2ecf20Sopenharmony_ci	struct nlattr *attr;
81268c2ecf20Sopenharmony_ci	uint16_t chap_out_idx = INVALID_ENTRY;
81278c2ecf20Sopenharmony_ci	int rc = QLA_ERROR;
81288c2ecf20Sopenharmony_ci	uint32_t rem = len;
81298c2ecf20Sopenharmony_ci
81308c2ecf20Sopenharmony_ci	memset((void *)&chap_tbl, 0, sizeof(chap_tbl));
81318c2ecf20Sopenharmony_ci	nla_for_each_attr(attr, data, len, rem) {
81328c2ecf20Sopenharmony_ci		if (nla_len(attr) < sizeof(*fnode_param)) {
81338c2ecf20Sopenharmony_ci			rc = -EINVAL;
81348c2ecf20Sopenharmony_ci			goto exit_set_param;
81358c2ecf20Sopenharmony_ci		}
81368c2ecf20Sopenharmony_ci
81378c2ecf20Sopenharmony_ci		fnode_param = nla_data(attr);
81388c2ecf20Sopenharmony_ci
81398c2ecf20Sopenharmony_ci		switch (fnode_param->param) {
81408c2ecf20Sopenharmony_ci		case ISCSI_FLASHNODE_IS_FW_ASSIGNED_IPV6:
81418c2ecf20Sopenharmony_ci			fnode_conn->is_fw_assigned_ipv6 = fnode_param->value[0];
81428c2ecf20Sopenharmony_ci			break;
81438c2ecf20Sopenharmony_ci		case ISCSI_FLASHNODE_PORTAL_TYPE:
81448c2ecf20Sopenharmony_ci			memcpy(fnode_sess->portal_type, fnode_param->value,
81458c2ecf20Sopenharmony_ci			       strlen(fnode_sess->portal_type));
81468c2ecf20Sopenharmony_ci			break;
81478c2ecf20Sopenharmony_ci		case ISCSI_FLASHNODE_AUTO_SND_TGT_DISABLE:
81488c2ecf20Sopenharmony_ci			fnode_sess->auto_snd_tgt_disable =
81498c2ecf20Sopenharmony_ci							fnode_param->value[0];
81508c2ecf20Sopenharmony_ci			break;
81518c2ecf20Sopenharmony_ci		case ISCSI_FLASHNODE_DISCOVERY_SESS:
81528c2ecf20Sopenharmony_ci			fnode_sess->discovery_sess = fnode_param->value[0];
81538c2ecf20Sopenharmony_ci			break;
81548c2ecf20Sopenharmony_ci		case ISCSI_FLASHNODE_ENTRY_EN:
81558c2ecf20Sopenharmony_ci			fnode_sess->entry_state = fnode_param->value[0];
81568c2ecf20Sopenharmony_ci			break;
81578c2ecf20Sopenharmony_ci		case ISCSI_FLASHNODE_HDR_DGST_EN:
81588c2ecf20Sopenharmony_ci			fnode_conn->hdrdgst_en = fnode_param->value[0];
81598c2ecf20Sopenharmony_ci			break;
81608c2ecf20Sopenharmony_ci		case ISCSI_FLASHNODE_DATA_DGST_EN:
81618c2ecf20Sopenharmony_ci			fnode_conn->datadgst_en = fnode_param->value[0];
81628c2ecf20Sopenharmony_ci			break;
81638c2ecf20Sopenharmony_ci		case ISCSI_FLASHNODE_IMM_DATA_EN:
81648c2ecf20Sopenharmony_ci			fnode_sess->imm_data_en = fnode_param->value[0];
81658c2ecf20Sopenharmony_ci			break;
81668c2ecf20Sopenharmony_ci		case ISCSI_FLASHNODE_INITIAL_R2T_EN:
81678c2ecf20Sopenharmony_ci			fnode_sess->initial_r2t_en = fnode_param->value[0];
81688c2ecf20Sopenharmony_ci			break;
81698c2ecf20Sopenharmony_ci		case ISCSI_FLASHNODE_DATASEQ_INORDER:
81708c2ecf20Sopenharmony_ci			fnode_sess->dataseq_inorder_en = fnode_param->value[0];
81718c2ecf20Sopenharmony_ci			break;
81728c2ecf20Sopenharmony_ci		case ISCSI_FLASHNODE_PDU_INORDER:
81738c2ecf20Sopenharmony_ci			fnode_sess->pdu_inorder_en = fnode_param->value[0];
81748c2ecf20Sopenharmony_ci			break;
81758c2ecf20Sopenharmony_ci		case ISCSI_FLASHNODE_CHAP_AUTH_EN:
81768c2ecf20Sopenharmony_ci			fnode_sess->chap_auth_en = fnode_param->value[0];
81778c2ecf20Sopenharmony_ci			/* Invalidate chap index if chap auth is disabled */
81788c2ecf20Sopenharmony_ci			if (!fnode_sess->chap_auth_en)
81798c2ecf20Sopenharmony_ci				fnode_sess->chap_out_idx = INVALID_ENTRY;
81808c2ecf20Sopenharmony_ci
81818c2ecf20Sopenharmony_ci			break;
81828c2ecf20Sopenharmony_ci		case ISCSI_FLASHNODE_SNACK_REQ_EN:
81838c2ecf20Sopenharmony_ci			fnode_conn->snack_req_en = fnode_param->value[0];
81848c2ecf20Sopenharmony_ci			break;
81858c2ecf20Sopenharmony_ci		case ISCSI_FLASHNODE_DISCOVERY_LOGOUT_EN:
81868c2ecf20Sopenharmony_ci			fnode_sess->discovery_logout_en = fnode_param->value[0];
81878c2ecf20Sopenharmony_ci			break;
81888c2ecf20Sopenharmony_ci		case ISCSI_FLASHNODE_BIDI_CHAP_EN:
81898c2ecf20Sopenharmony_ci			fnode_sess->bidi_chap_en = fnode_param->value[0];
81908c2ecf20Sopenharmony_ci			break;
81918c2ecf20Sopenharmony_ci		case ISCSI_FLASHNODE_DISCOVERY_AUTH_OPTIONAL:
81928c2ecf20Sopenharmony_ci			fnode_sess->discovery_auth_optional =
81938c2ecf20Sopenharmony_ci							fnode_param->value[0];
81948c2ecf20Sopenharmony_ci			break;
81958c2ecf20Sopenharmony_ci		case ISCSI_FLASHNODE_ERL:
81968c2ecf20Sopenharmony_ci			fnode_sess->erl = fnode_param->value[0];
81978c2ecf20Sopenharmony_ci			break;
81988c2ecf20Sopenharmony_ci		case ISCSI_FLASHNODE_TCP_TIMESTAMP_STAT:
81998c2ecf20Sopenharmony_ci			fnode_conn->tcp_timestamp_stat = fnode_param->value[0];
82008c2ecf20Sopenharmony_ci			break;
82018c2ecf20Sopenharmony_ci		case ISCSI_FLASHNODE_TCP_NAGLE_DISABLE:
82028c2ecf20Sopenharmony_ci			fnode_conn->tcp_nagle_disable = fnode_param->value[0];
82038c2ecf20Sopenharmony_ci			break;
82048c2ecf20Sopenharmony_ci		case ISCSI_FLASHNODE_TCP_WSF_DISABLE:
82058c2ecf20Sopenharmony_ci			fnode_conn->tcp_wsf_disable = fnode_param->value[0];
82068c2ecf20Sopenharmony_ci			break;
82078c2ecf20Sopenharmony_ci		case ISCSI_FLASHNODE_TCP_TIMER_SCALE:
82088c2ecf20Sopenharmony_ci			fnode_conn->tcp_timer_scale = fnode_param->value[0];
82098c2ecf20Sopenharmony_ci			break;
82108c2ecf20Sopenharmony_ci		case ISCSI_FLASHNODE_TCP_TIMESTAMP_EN:
82118c2ecf20Sopenharmony_ci			fnode_conn->tcp_timestamp_en = fnode_param->value[0];
82128c2ecf20Sopenharmony_ci			break;
82138c2ecf20Sopenharmony_ci		case ISCSI_FLASHNODE_IP_FRAG_DISABLE:
82148c2ecf20Sopenharmony_ci			fnode_conn->fragment_disable = fnode_param->value[0];
82158c2ecf20Sopenharmony_ci			break;
82168c2ecf20Sopenharmony_ci		case ISCSI_FLASHNODE_MAX_RECV_DLENGTH:
82178c2ecf20Sopenharmony_ci			fnode_conn->max_recv_dlength =
82188c2ecf20Sopenharmony_ci					*(unsigned *)fnode_param->value;
82198c2ecf20Sopenharmony_ci			break;
82208c2ecf20Sopenharmony_ci		case ISCSI_FLASHNODE_MAX_XMIT_DLENGTH:
82218c2ecf20Sopenharmony_ci			fnode_conn->max_xmit_dlength =
82228c2ecf20Sopenharmony_ci					*(unsigned *)fnode_param->value;
82238c2ecf20Sopenharmony_ci			break;
82248c2ecf20Sopenharmony_ci		case ISCSI_FLASHNODE_FIRST_BURST:
82258c2ecf20Sopenharmony_ci			fnode_sess->first_burst =
82268c2ecf20Sopenharmony_ci					*(unsigned *)fnode_param->value;
82278c2ecf20Sopenharmony_ci			break;
82288c2ecf20Sopenharmony_ci		case ISCSI_FLASHNODE_DEF_TIME2WAIT:
82298c2ecf20Sopenharmony_ci			fnode_sess->time2wait = *(uint16_t *)fnode_param->value;
82308c2ecf20Sopenharmony_ci			break;
82318c2ecf20Sopenharmony_ci		case ISCSI_FLASHNODE_DEF_TIME2RETAIN:
82328c2ecf20Sopenharmony_ci			fnode_sess->time2retain =
82338c2ecf20Sopenharmony_ci						*(uint16_t *)fnode_param->value;
82348c2ecf20Sopenharmony_ci			break;
82358c2ecf20Sopenharmony_ci		case ISCSI_FLASHNODE_MAX_R2T:
82368c2ecf20Sopenharmony_ci			fnode_sess->max_r2t =
82378c2ecf20Sopenharmony_ci					*(uint16_t *)fnode_param->value;
82388c2ecf20Sopenharmony_ci			break;
82398c2ecf20Sopenharmony_ci		case ISCSI_FLASHNODE_KEEPALIVE_TMO:
82408c2ecf20Sopenharmony_ci			fnode_conn->keepalive_timeout =
82418c2ecf20Sopenharmony_ci				*(uint16_t *)fnode_param->value;
82428c2ecf20Sopenharmony_ci			break;
82438c2ecf20Sopenharmony_ci		case ISCSI_FLASHNODE_ISID:
82448c2ecf20Sopenharmony_ci			memcpy(fnode_sess->isid, fnode_param->value,
82458c2ecf20Sopenharmony_ci			       sizeof(fnode_sess->isid));
82468c2ecf20Sopenharmony_ci			break;
82478c2ecf20Sopenharmony_ci		case ISCSI_FLASHNODE_TSID:
82488c2ecf20Sopenharmony_ci			fnode_sess->tsid = *(uint16_t *)fnode_param->value;
82498c2ecf20Sopenharmony_ci			break;
82508c2ecf20Sopenharmony_ci		case ISCSI_FLASHNODE_PORT:
82518c2ecf20Sopenharmony_ci			fnode_conn->port = *(uint16_t *)fnode_param->value;
82528c2ecf20Sopenharmony_ci			break;
82538c2ecf20Sopenharmony_ci		case ISCSI_FLASHNODE_MAX_BURST:
82548c2ecf20Sopenharmony_ci			fnode_sess->max_burst = *(unsigned *)fnode_param->value;
82558c2ecf20Sopenharmony_ci			break;
82568c2ecf20Sopenharmony_ci		case ISCSI_FLASHNODE_DEF_TASKMGMT_TMO:
82578c2ecf20Sopenharmony_ci			fnode_sess->default_taskmgmt_timeout =
82588c2ecf20Sopenharmony_ci						*(uint16_t *)fnode_param->value;
82598c2ecf20Sopenharmony_ci			break;
82608c2ecf20Sopenharmony_ci		case ISCSI_FLASHNODE_IPADDR:
82618c2ecf20Sopenharmony_ci			memcpy(fnode_conn->ipaddress, fnode_param->value,
82628c2ecf20Sopenharmony_ci			       IPv6_ADDR_LEN);
82638c2ecf20Sopenharmony_ci			break;
82648c2ecf20Sopenharmony_ci		case ISCSI_FLASHNODE_ALIAS:
82658c2ecf20Sopenharmony_ci			rc = iscsi_switch_str_param(&fnode_sess->targetalias,
82668c2ecf20Sopenharmony_ci						    (char *)fnode_param->value);
82678c2ecf20Sopenharmony_ci			break;
82688c2ecf20Sopenharmony_ci		case ISCSI_FLASHNODE_REDIRECT_IPADDR:
82698c2ecf20Sopenharmony_ci			memcpy(fnode_conn->redirect_ipaddr, fnode_param->value,
82708c2ecf20Sopenharmony_ci			       IPv6_ADDR_LEN);
82718c2ecf20Sopenharmony_ci			break;
82728c2ecf20Sopenharmony_ci		case ISCSI_FLASHNODE_MAX_SEGMENT_SIZE:
82738c2ecf20Sopenharmony_ci			fnode_conn->max_segment_size =
82748c2ecf20Sopenharmony_ci					*(unsigned *)fnode_param->value;
82758c2ecf20Sopenharmony_ci			break;
82768c2ecf20Sopenharmony_ci		case ISCSI_FLASHNODE_LOCAL_PORT:
82778c2ecf20Sopenharmony_ci			fnode_conn->local_port =
82788c2ecf20Sopenharmony_ci						*(uint16_t *)fnode_param->value;
82798c2ecf20Sopenharmony_ci			break;
82808c2ecf20Sopenharmony_ci		case ISCSI_FLASHNODE_IPV4_TOS:
82818c2ecf20Sopenharmony_ci			fnode_conn->ipv4_tos = fnode_param->value[0];
82828c2ecf20Sopenharmony_ci			break;
82838c2ecf20Sopenharmony_ci		case ISCSI_FLASHNODE_IPV6_TC:
82848c2ecf20Sopenharmony_ci			fnode_conn->ipv6_traffic_class = fnode_param->value[0];
82858c2ecf20Sopenharmony_ci			break;
82868c2ecf20Sopenharmony_ci		case ISCSI_FLASHNODE_IPV6_FLOW_LABEL:
82878c2ecf20Sopenharmony_ci			fnode_conn->ipv6_flow_label = fnode_param->value[0];
82888c2ecf20Sopenharmony_ci			break;
82898c2ecf20Sopenharmony_ci		case ISCSI_FLASHNODE_NAME:
82908c2ecf20Sopenharmony_ci			rc = iscsi_switch_str_param(&fnode_sess->targetname,
82918c2ecf20Sopenharmony_ci						    (char *)fnode_param->value);
82928c2ecf20Sopenharmony_ci			break;
82938c2ecf20Sopenharmony_ci		case ISCSI_FLASHNODE_TPGT:
82948c2ecf20Sopenharmony_ci			fnode_sess->tpgt = *(uint16_t *)fnode_param->value;
82958c2ecf20Sopenharmony_ci			break;
82968c2ecf20Sopenharmony_ci		case ISCSI_FLASHNODE_LINK_LOCAL_IPV6:
82978c2ecf20Sopenharmony_ci			memcpy(fnode_conn->link_local_ipv6_addr,
82988c2ecf20Sopenharmony_ci			       fnode_param->value, IPv6_ADDR_LEN);
82998c2ecf20Sopenharmony_ci			break;
83008c2ecf20Sopenharmony_ci		case ISCSI_FLASHNODE_DISCOVERY_PARENT_IDX:
83018c2ecf20Sopenharmony_ci			fnode_sess->discovery_parent_idx =
83028c2ecf20Sopenharmony_ci						*(uint16_t *)fnode_param->value;
83038c2ecf20Sopenharmony_ci			break;
83048c2ecf20Sopenharmony_ci		case ISCSI_FLASHNODE_TCP_XMIT_WSF:
83058c2ecf20Sopenharmony_ci			fnode_conn->tcp_xmit_wsf =
83068c2ecf20Sopenharmony_ci						*(uint8_t *)fnode_param->value;
83078c2ecf20Sopenharmony_ci			break;
83088c2ecf20Sopenharmony_ci		case ISCSI_FLASHNODE_TCP_RECV_WSF:
83098c2ecf20Sopenharmony_ci			fnode_conn->tcp_recv_wsf =
83108c2ecf20Sopenharmony_ci						*(uint8_t *)fnode_param->value;
83118c2ecf20Sopenharmony_ci			break;
83128c2ecf20Sopenharmony_ci		case ISCSI_FLASHNODE_STATSN:
83138c2ecf20Sopenharmony_ci			fnode_conn->statsn = *(uint32_t *)fnode_param->value;
83148c2ecf20Sopenharmony_ci			break;
83158c2ecf20Sopenharmony_ci		case ISCSI_FLASHNODE_EXP_STATSN:
83168c2ecf20Sopenharmony_ci			fnode_conn->exp_statsn =
83178c2ecf20Sopenharmony_ci						*(uint32_t *)fnode_param->value;
83188c2ecf20Sopenharmony_ci			break;
83198c2ecf20Sopenharmony_ci		case ISCSI_FLASHNODE_CHAP_OUT_IDX:
83208c2ecf20Sopenharmony_ci			chap_out_idx = *(uint16_t *)fnode_param->value;
83218c2ecf20Sopenharmony_ci			if (!qla4xxx_get_uni_chap_at_index(ha,
83228c2ecf20Sopenharmony_ci							   chap_tbl.name,
83238c2ecf20Sopenharmony_ci							   chap_tbl.secret,
83248c2ecf20Sopenharmony_ci							   chap_out_idx)) {
83258c2ecf20Sopenharmony_ci				fnode_sess->chap_out_idx = chap_out_idx;
83268c2ecf20Sopenharmony_ci				/* Enable chap auth if chap index is valid */
83278c2ecf20Sopenharmony_ci				fnode_sess->chap_auth_en = QL4_PARAM_ENABLE;
83288c2ecf20Sopenharmony_ci			}
83298c2ecf20Sopenharmony_ci			break;
83308c2ecf20Sopenharmony_ci		default:
83318c2ecf20Sopenharmony_ci			ql4_printk(KERN_ERR, ha,
83328c2ecf20Sopenharmony_ci				   "%s: No such sysfs attribute\n", __func__);
83338c2ecf20Sopenharmony_ci			rc = -ENOSYS;
83348c2ecf20Sopenharmony_ci			goto exit_set_param;
83358c2ecf20Sopenharmony_ci		}
83368c2ecf20Sopenharmony_ci	}
83378c2ecf20Sopenharmony_ci
83388c2ecf20Sopenharmony_ci	rc = qla4xxx_sysfs_ddb_apply(fnode_sess, fnode_conn);
83398c2ecf20Sopenharmony_ci
83408c2ecf20Sopenharmony_ciexit_set_param:
83418c2ecf20Sopenharmony_ci	return rc;
83428c2ecf20Sopenharmony_ci}
83438c2ecf20Sopenharmony_ci
83448c2ecf20Sopenharmony_ci/**
83458c2ecf20Sopenharmony_ci * qla4xxx_sysfs_ddb_delete - Delete firmware DDB entry
83468c2ecf20Sopenharmony_ci * @fnode_sess: pointer to session attrs of flash ddb entry
83478c2ecf20Sopenharmony_ci *
83488c2ecf20Sopenharmony_ci * This invalidates the flash ddb entry at the given index
83498c2ecf20Sopenharmony_ci **/
83508c2ecf20Sopenharmony_cistatic int qla4xxx_sysfs_ddb_delete(struct iscsi_bus_flash_session *fnode_sess)
83518c2ecf20Sopenharmony_ci{
83528c2ecf20Sopenharmony_ci	struct Scsi_Host *shost = iscsi_flash_session_to_shost(fnode_sess);
83538c2ecf20Sopenharmony_ci	struct scsi_qla_host *ha = to_qla_host(shost);
83548c2ecf20Sopenharmony_ci	uint32_t dev_db_start_offset;
83558c2ecf20Sopenharmony_ci	uint32_t dev_db_end_offset;
83568c2ecf20Sopenharmony_ci	struct dev_db_entry *fw_ddb_entry = NULL;
83578c2ecf20Sopenharmony_ci	dma_addr_t fw_ddb_entry_dma;
83588c2ecf20Sopenharmony_ci	uint16_t *ddb_cookie = NULL;
83598c2ecf20Sopenharmony_ci	size_t ddb_size = 0;
83608c2ecf20Sopenharmony_ci	void *pddb = NULL;
83618c2ecf20Sopenharmony_ci	int target_id;
83628c2ecf20Sopenharmony_ci	int rc = 0;
83638c2ecf20Sopenharmony_ci
83648c2ecf20Sopenharmony_ci	if (fnode_sess->is_boot_target) {
83658c2ecf20Sopenharmony_ci		rc = -EPERM;
83668c2ecf20Sopenharmony_ci		DEBUG2(ql4_printk(KERN_ERR, ha,
83678c2ecf20Sopenharmony_ci				  "%s: Deletion of boot target entry is not permitted.\n",
83688c2ecf20Sopenharmony_ci				  __func__));
83698c2ecf20Sopenharmony_ci		goto exit_ddb_del;
83708c2ecf20Sopenharmony_ci	}
83718c2ecf20Sopenharmony_ci
83728c2ecf20Sopenharmony_ci	if (fnode_sess->flash_state == DEV_DB_NON_PERSISTENT)
83738c2ecf20Sopenharmony_ci		goto sysfs_ddb_del;
83748c2ecf20Sopenharmony_ci
83758c2ecf20Sopenharmony_ci	if (is_qla40XX(ha)) {
83768c2ecf20Sopenharmony_ci		dev_db_start_offset = FLASH_OFFSET_DB_INFO;
83778c2ecf20Sopenharmony_ci		dev_db_end_offset = FLASH_OFFSET_DB_END;
83788c2ecf20Sopenharmony_ci		dev_db_start_offset += (fnode_sess->target_id *
83798c2ecf20Sopenharmony_ci				       sizeof(*fw_ddb_entry));
83808c2ecf20Sopenharmony_ci		ddb_size = sizeof(*fw_ddb_entry);
83818c2ecf20Sopenharmony_ci	} else {
83828c2ecf20Sopenharmony_ci		dev_db_start_offset = FLASH_RAW_ACCESS_ADDR +
83838c2ecf20Sopenharmony_ci				      (ha->hw.flt_region_ddb << 2);
83848c2ecf20Sopenharmony_ci		/* flt_ddb_size is DDB table size for both ports
83858c2ecf20Sopenharmony_ci		 * so divide it by 2 to calculate the offset for second port
83868c2ecf20Sopenharmony_ci		 */
83878c2ecf20Sopenharmony_ci		if (ha->port_num == 1)
83888c2ecf20Sopenharmony_ci			dev_db_start_offset += (ha->hw.flt_ddb_size / 2);
83898c2ecf20Sopenharmony_ci
83908c2ecf20Sopenharmony_ci		dev_db_end_offset = dev_db_start_offset +
83918c2ecf20Sopenharmony_ci				    (ha->hw.flt_ddb_size / 2);
83928c2ecf20Sopenharmony_ci
83938c2ecf20Sopenharmony_ci		dev_db_start_offset += (fnode_sess->target_id *
83948c2ecf20Sopenharmony_ci				       sizeof(*fw_ddb_entry));
83958c2ecf20Sopenharmony_ci		dev_db_start_offset += offsetof(struct dev_db_entry, cookie);
83968c2ecf20Sopenharmony_ci
83978c2ecf20Sopenharmony_ci		ddb_size = sizeof(*ddb_cookie);
83988c2ecf20Sopenharmony_ci	}
83998c2ecf20Sopenharmony_ci
84008c2ecf20Sopenharmony_ci	DEBUG2(ql4_printk(KERN_ERR, ha, "%s: start offset=%u, end offset=%u\n",
84018c2ecf20Sopenharmony_ci			  __func__, dev_db_start_offset, dev_db_end_offset));
84028c2ecf20Sopenharmony_ci
84038c2ecf20Sopenharmony_ci	if (dev_db_start_offset > dev_db_end_offset) {
84048c2ecf20Sopenharmony_ci		rc = -EIO;
84058c2ecf20Sopenharmony_ci		DEBUG2(ql4_printk(KERN_ERR, ha, "%s:Invalid DDB index %u\n",
84068c2ecf20Sopenharmony_ci				  __func__, fnode_sess->target_id));
84078c2ecf20Sopenharmony_ci		goto exit_ddb_del;
84088c2ecf20Sopenharmony_ci	}
84098c2ecf20Sopenharmony_ci
84108c2ecf20Sopenharmony_ci	pddb = dma_alloc_coherent(&ha->pdev->dev, ddb_size,
84118c2ecf20Sopenharmony_ci				  &fw_ddb_entry_dma, GFP_KERNEL);
84128c2ecf20Sopenharmony_ci	if (!pddb) {
84138c2ecf20Sopenharmony_ci		rc = -ENOMEM;
84148c2ecf20Sopenharmony_ci		DEBUG2(ql4_printk(KERN_ERR, ha,
84158c2ecf20Sopenharmony_ci				  "%s: Unable to allocate dma buffer\n",
84168c2ecf20Sopenharmony_ci				  __func__));
84178c2ecf20Sopenharmony_ci		goto exit_ddb_del;
84188c2ecf20Sopenharmony_ci	}
84198c2ecf20Sopenharmony_ci
84208c2ecf20Sopenharmony_ci	if (is_qla40XX(ha)) {
84218c2ecf20Sopenharmony_ci		fw_ddb_entry = pddb;
84228c2ecf20Sopenharmony_ci		memset(fw_ddb_entry, 0, ddb_size);
84238c2ecf20Sopenharmony_ci		ddb_cookie = &fw_ddb_entry->cookie;
84248c2ecf20Sopenharmony_ci	} else {
84258c2ecf20Sopenharmony_ci		ddb_cookie = pddb;
84268c2ecf20Sopenharmony_ci	}
84278c2ecf20Sopenharmony_ci
84288c2ecf20Sopenharmony_ci	/* invalidate the cookie */
84298c2ecf20Sopenharmony_ci	*ddb_cookie = 0xFFEE;
84308c2ecf20Sopenharmony_ci	qla4xxx_set_flash(ha, fw_ddb_entry_dma, dev_db_start_offset,
84318c2ecf20Sopenharmony_ci			  ddb_size, FLASH_OPT_RMW_COMMIT);
84328c2ecf20Sopenharmony_ci
84338c2ecf20Sopenharmony_cisysfs_ddb_del:
84348c2ecf20Sopenharmony_ci	target_id = fnode_sess->target_id;
84358c2ecf20Sopenharmony_ci	iscsi_destroy_flashnode_sess(fnode_sess);
84368c2ecf20Sopenharmony_ci	ql4_printk(KERN_INFO, ha,
84378c2ecf20Sopenharmony_ci		   "%s: session and conn entries for flashnode %u of host %lu deleted\n",
84388c2ecf20Sopenharmony_ci		   __func__, target_id, ha->host_no);
84398c2ecf20Sopenharmony_ciexit_ddb_del:
84408c2ecf20Sopenharmony_ci	if (pddb)
84418c2ecf20Sopenharmony_ci		dma_free_coherent(&ha->pdev->dev, ddb_size, pddb,
84428c2ecf20Sopenharmony_ci				  fw_ddb_entry_dma);
84438c2ecf20Sopenharmony_ci	return rc;
84448c2ecf20Sopenharmony_ci}
84458c2ecf20Sopenharmony_ci
84468c2ecf20Sopenharmony_ci/**
84478c2ecf20Sopenharmony_ci * qla4xxx_sysfs_ddb_export - Create sysfs entries for firmware DDBs
84488c2ecf20Sopenharmony_ci * @ha: pointer to adapter structure
84498c2ecf20Sopenharmony_ci *
84508c2ecf20Sopenharmony_ci * Export the firmware DDB for all send targets and normal targets to sysfs.
84518c2ecf20Sopenharmony_ci **/
84528c2ecf20Sopenharmony_ciint qla4xxx_sysfs_ddb_export(struct scsi_qla_host *ha)
84538c2ecf20Sopenharmony_ci{
84548c2ecf20Sopenharmony_ci	struct dev_db_entry *fw_ddb_entry = NULL;
84558c2ecf20Sopenharmony_ci	dma_addr_t fw_ddb_entry_dma;
84568c2ecf20Sopenharmony_ci	uint16_t max_ddbs;
84578c2ecf20Sopenharmony_ci	uint16_t idx = 0;
84588c2ecf20Sopenharmony_ci	int ret = QLA_SUCCESS;
84598c2ecf20Sopenharmony_ci
84608c2ecf20Sopenharmony_ci	fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev,
84618c2ecf20Sopenharmony_ci					  sizeof(*fw_ddb_entry),
84628c2ecf20Sopenharmony_ci					  &fw_ddb_entry_dma, GFP_KERNEL);
84638c2ecf20Sopenharmony_ci	if (!fw_ddb_entry) {
84648c2ecf20Sopenharmony_ci		DEBUG2(ql4_printk(KERN_ERR, ha,
84658c2ecf20Sopenharmony_ci				  "%s: Unable to allocate dma buffer\n",
84668c2ecf20Sopenharmony_ci				  __func__));
84678c2ecf20Sopenharmony_ci		return -ENOMEM;
84688c2ecf20Sopenharmony_ci	}
84698c2ecf20Sopenharmony_ci
84708c2ecf20Sopenharmony_ci	max_ddbs =  is_qla40XX(ha) ? MAX_PRST_DEV_DB_ENTRIES :
84718c2ecf20Sopenharmony_ci				     MAX_DEV_DB_ENTRIES;
84728c2ecf20Sopenharmony_ci
84738c2ecf20Sopenharmony_ci	for (idx = 0; idx < max_ddbs; idx++) {
84748c2ecf20Sopenharmony_ci		if (qla4xxx_flashdb_by_index(ha, fw_ddb_entry, fw_ddb_entry_dma,
84758c2ecf20Sopenharmony_ci					     idx))
84768c2ecf20Sopenharmony_ci			continue;
84778c2ecf20Sopenharmony_ci
84788c2ecf20Sopenharmony_ci		ret = qla4xxx_sysfs_ddb_tgt_create(ha, fw_ddb_entry, &idx, 0);
84798c2ecf20Sopenharmony_ci		if (ret) {
84808c2ecf20Sopenharmony_ci			ret = -EIO;
84818c2ecf20Sopenharmony_ci			break;
84828c2ecf20Sopenharmony_ci		}
84838c2ecf20Sopenharmony_ci	}
84848c2ecf20Sopenharmony_ci
84858c2ecf20Sopenharmony_ci	dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), fw_ddb_entry,
84868c2ecf20Sopenharmony_ci			  fw_ddb_entry_dma);
84878c2ecf20Sopenharmony_ci
84888c2ecf20Sopenharmony_ci	return ret;
84898c2ecf20Sopenharmony_ci}
84908c2ecf20Sopenharmony_ci
84918c2ecf20Sopenharmony_cistatic void qla4xxx_sysfs_ddb_remove(struct scsi_qla_host *ha)
84928c2ecf20Sopenharmony_ci{
84938c2ecf20Sopenharmony_ci	iscsi_destroy_all_flashnode(ha->host);
84948c2ecf20Sopenharmony_ci}
84958c2ecf20Sopenharmony_ci
84968c2ecf20Sopenharmony_ci/**
84978c2ecf20Sopenharmony_ci * qla4xxx_build_ddb_list - Build ddb list and setup sessions
84988c2ecf20Sopenharmony_ci * @ha: pointer to adapter structure
84998c2ecf20Sopenharmony_ci * @is_reset: Is this init path or reset path
85008c2ecf20Sopenharmony_ci *
85018c2ecf20Sopenharmony_ci * Create a list of sendtargets (st) from firmware DDBs, issue send targets
85028c2ecf20Sopenharmony_ci * using connection open, then create the list of normal targets (nt)
85038c2ecf20Sopenharmony_ci * from firmware DDBs. Based on the list of nt setup session and connection
85048c2ecf20Sopenharmony_ci * objects.
85058c2ecf20Sopenharmony_ci **/
85068c2ecf20Sopenharmony_civoid qla4xxx_build_ddb_list(struct scsi_qla_host *ha, int is_reset)
85078c2ecf20Sopenharmony_ci{
85088c2ecf20Sopenharmony_ci	uint16_t tmo = 0;
85098c2ecf20Sopenharmony_ci	struct list_head list_st, list_nt;
85108c2ecf20Sopenharmony_ci	struct qla_ddb_index  *st_ddb_idx, *st_ddb_idx_tmp;
85118c2ecf20Sopenharmony_ci	unsigned long wtime;
85128c2ecf20Sopenharmony_ci
85138c2ecf20Sopenharmony_ci	if (!test_bit(AF_LINK_UP, &ha->flags)) {
85148c2ecf20Sopenharmony_ci		set_bit(AF_BUILD_DDB_LIST, &ha->flags);
85158c2ecf20Sopenharmony_ci		ha->is_reset = is_reset;
85168c2ecf20Sopenharmony_ci		return;
85178c2ecf20Sopenharmony_ci	}
85188c2ecf20Sopenharmony_ci
85198c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&list_st);
85208c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&list_nt);
85218c2ecf20Sopenharmony_ci
85228c2ecf20Sopenharmony_ci	qla4xxx_build_st_list(ha, &list_st);
85238c2ecf20Sopenharmony_ci
85248c2ecf20Sopenharmony_ci	/* Before issuing conn open mbox, ensure all IPs states are configured
85258c2ecf20Sopenharmony_ci	 * Note, conn open fails if IPs are not configured
85268c2ecf20Sopenharmony_ci	 */
85278c2ecf20Sopenharmony_ci	qla4xxx_wait_for_ip_configuration(ha);
85288c2ecf20Sopenharmony_ci
85298c2ecf20Sopenharmony_ci	/* Go thru the STs and fire the sendtargets by issuing conn open mbx */
85308c2ecf20Sopenharmony_ci	list_for_each_entry_safe(st_ddb_idx, st_ddb_idx_tmp, &list_st, list) {
85318c2ecf20Sopenharmony_ci		qla4xxx_conn_open(ha, st_ddb_idx->fw_ddb_idx);
85328c2ecf20Sopenharmony_ci	}
85338c2ecf20Sopenharmony_ci
85348c2ecf20Sopenharmony_ci	/* Wait to ensure all sendtargets are done for min 12 sec wait */
85358c2ecf20Sopenharmony_ci	tmo = ((ha->def_timeout > LOGIN_TOV) &&
85368c2ecf20Sopenharmony_ci	       (ha->def_timeout < LOGIN_TOV * 10) ?
85378c2ecf20Sopenharmony_ci	       ha->def_timeout : LOGIN_TOV);
85388c2ecf20Sopenharmony_ci
85398c2ecf20Sopenharmony_ci	DEBUG2(ql4_printk(KERN_INFO, ha,
85408c2ecf20Sopenharmony_ci			  "Default time to wait for build ddb %d\n", tmo));
85418c2ecf20Sopenharmony_ci
85428c2ecf20Sopenharmony_ci	wtime = jiffies + (HZ * tmo);
85438c2ecf20Sopenharmony_ci	do {
85448c2ecf20Sopenharmony_ci		if (list_empty(&list_st))
85458c2ecf20Sopenharmony_ci			break;
85468c2ecf20Sopenharmony_ci
85478c2ecf20Sopenharmony_ci		qla4xxx_remove_failed_ddb(ha, &list_st);
85488c2ecf20Sopenharmony_ci		schedule_timeout_uninterruptible(HZ / 10);
85498c2ecf20Sopenharmony_ci	} while (time_after(wtime, jiffies));
85508c2ecf20Sopenharmony_ci
85518c2ecf20Sopenharmony_ci
85528c2ecf20Sopenharmony_ci	qla4xxx_build_nt_list(ha, &list_nt, &list_st, is_reset);
85538c2ecf20Sopenharmony_ci
85548c2ecf20Sopenharmony_ci	qla4xxx_free_ddb_list(&list_st);
85558c2ecf20Sopenharmony_ci	qla4xxx_free_ddb_list(&list_nt);
85568c2ecf20Sopenharmony_ci
85578c2ecf20Sopenharmony_ci	qla4xxx_free_ddb_index(ha);
85588c2ecf20Sopenharmony_ci}
85598c2ecf20Sopenharmony_ci
85608c2ecf20Sopenharmony_ci/**
85618c2ecf20Sopenharmony_ci * qla4xxx_wait_login_resp_boot_tgt -  Wait for iSCSI boot target login
85628c2ecf20Sopenharmony_ci * response.
85638c2ecf20Sopenharmony_ci * @ha: pointer to adapter structure
85648c2ecf20Sopenharmony_ci *
85658c2ecf20Sopenharmony_ci * When the boot entry is normal iSCSI target then DF_BOOT_TGT flag will be
85668c2ecf20Sopenharmony_ci * set in DDB and we will wait for login response of boot targets during
85678c2ecf20Sopenharmony_ci * probe.
85688c2ecf20Sopenharmony_ci **/
85698c2ecf20Sopenharmony_cistatic void qla4xxx_wait_login_resp_boot_tgt(struct scsi_qla_host *ha)
85708c2ecf20Sopenharmony_ci{
85718c2ecf20Sopenharmony_ci	struct ddb_entry *ddb_entry;
85728c2ecf20Sopenharmony_ci	struct dev_db_entry *fw_ddb_entry = NULL;
85738c2ecf20Sopenharmony_ci	dma_addr_t fw_ddb_entry_dma;
85748c2ecf20Sopenharmony_ci	unsigned long wtime;
85758c2ecf20Sopenharmony_ci	uint32_t ddb_state;
85768c2ecf20Sopenharmony_ci	int max_ddbs, idx, ret;
85778c2ecf20Sopenharmony_ci
85788c2ecf20Sopenharmony_ci	max_ddbs =  is_qla40XX(ha) ? MAX_DEV_DB_ENTRIES_40XX :
85798c2ecf20Sopenharmony_ci				     MAX_DEV_DB_ENTRIES;
85808c2ecf20Sopenharmony_ci
85818c2ecf20Sopenharmony_ci	fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
85828c2ecf20Sopenharmony_ci					  &fw_ddb_entry_dma, GFP_KERNEL);
85838c2ecf20Sopenharmony_ci	if (!fw_ddb_entry) {
85848c2ecf20Sopenharmony_ci		ql4_printk(KERN_ERR, ha,
85858c2ecf20Sopenharmony_ci			   "%s: Unable to allocate dma buffer\n", __func__);
85868c2ecf20Sopenharmony_ci		goto exit_login_resp;
85878c2ecf20Sopenharmony_ci	}
85888c2ecf20Sopenharmony_ci
85898c2ecf20Sopenharmony_ci	wtime = jiffies + (HZ * BOOT_LOGIN_RESP_TOV);
85908c2ecf20Sopenharmony_ci
85918c2ecf20Sopenharmony_ci	for (idx = 0; idx < max_ddbs; idx++) {
85928c2ecf20Sopenharmony_ci		ddb_entry = qla4xxx_lookup_ddb_by_fw_index(ha, idx);
85938c2ecf20Sopenharmony_ci		if (ddb_entry == NULL)
85948c2ecf20Sopenharmony_ci			continue;
85958c2ecf20Sopenharmony_ci
85968c2ecf20Sopenharmony_ci		if (test_bit(DF_BOOT_TGT, &ddb_entry->flags)) {
85978c2ecf20Sopenharmony_ci			DEBUG2(ql4_printk(KERN_INFO, ha,
85988c2ecf20Sopenharmony_ci					  "%s: DDB index [%d]\n", __func__,
85998c2ecf20Sopenharmony_ci					  ddb_entry->fw_ddb_index));
86008c2ecf20Sopenharmony_ci			do {
86018c2ecf20Sopenharmony_ci				ret = qla4xxx_get_fwddb_entry(ha,
86028c2ecf20Sopenharmony_ci						ddb_entry->fw_ddb_index,
86038c2ecf20Sopenharmony_ci						fw_ddb_entry, fw_ddb_entry_dma,
86048c2ecf20Sopenharmony_ci						NULL, NULL, &ddb_state, NULL,
86058c2ecf20Sopenharmony_ci						NULL, NULL);
86068c2ecf20Sopenharmony_ci				if (ret == QLA_ERROR)
86078c2ecf20Sopenharmony_ci					goto exit_login_resp;
86088c2ecf20Sopenharmony_ci
86098c2ecf20Sopenharmony_ci				if ((ddb_state == DDB_DS_SESSION_ACTIVE) ||
86108c2ecf20Sopenharmony_ci				    (ddb_state == DDB_DS_SESSION_FAILED))
86118c2ecf20Sopenharmony_ci					break;
86128c2ecf20Sopenharmony_ci
86138c2ecf20Sopenharmony_ci				schedule_timeout_uninterruptible(HZ);
86148c2ecf20Sopenharmony_ci
86158c2ecf20Sopenharmony_ci			} while ((time_after(wtime, jiffies)));
86168c2ecf20Sopenharmony_ci
86178c2ecf20Sopenharmony_ci			if (!time_after(wtime, jiffies)) {
86188c2ecf20Sopenharmony_ci				DEBUG2(ql4_printk(KERN_INFO, ha,
86198c2ecf20Sopenharmony_ci						  "%s: Login response wait timer expired\n",
86208c2ecf20Sopenharmony_ci						  __func__));
86218c2ecf20Sopenharmony_ci				 goto exit_login_resp;
86228c2ecf20Sopenharmony_ci			}
86238c2ecf20Sopenharmony_ci		}
86248c2ecf20Sopenharmony_ci	}
86258c2ecf20Sopenharmony_ci
86268c2ecf20Sopenharmony_ciexit_login_resp:
86278c2ecf20Sopenharmony_ci	if (fw_ddb_entry)
86288c2ecf20Sopenharmony_ci		dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
86298c2ecf20Sopenharmony_ci				  fw_ddb_entry, fw_ddb_entry_dma);
86308c2ecf20Sopenharmony_ci}
86318c2ecf20Sopenharmony_ci
86328c2ecf20Sopenharmony_ci/**
86338c2ecf20Sopenharmony_ci * qla4xxx_probe_adapter - callback function to probe HBA
86348c2ecf20Sopenharmony_ci * @pdev: pointer to pci_dev structure
86358c2ecf20Sopenharmony_ci * @ent: pointer to pci_device entry
86368c2ecf20Sopenharmony_ci *
86378c2ecf20Sopenharmony_ci * This routine will probe for Qlogic 4xxx iSCSI host adapters.
86388c2ecf20Sopenharmony_ci * It returns zero if successful. It also initializes all data necessary for
86398c2ecf20Sopenharmony_ci * the driver.
86408c2ecf20Sopenharmony_ci **/
86418c2ecf20Sopenharmony_cistatic int qla4xxx_probe_adapter(struct pci_dev *pdev,
86428c2ecf20Sopenharmony_ci				 const struct pci_device_id *ent)
86438c2ecf20Sopenharmony_ci{
86448c2ecf20Sopenharmony_ci	int ret = -ENODEV, status;
86458c2ecf20Sopenharmony_ci	struct Scsi_Host *host;
86468c2ecf20Sopenharmony_ci	struct scsi_qla_host *ha;
86478c2ecf20Sopenharmony_ci	uint8_t init_retry_count = 0;
86488c2ecf20Sopenharmony_ci	char buf[34];
86498c2ecf20Sopenharmony_ci	struct qla4_8xxx_legacy_intr_set *nx_legacy_intr;
86508c2ecf20Sopenharmony_ci	uint32_t dev_state;
86518c2ecf20Sopenharmony_ci
86528c2ecf20Sopenharmony_ci	if (pci_enable_device(pdev))
86538c2ecf20Sopenharmony_ci		return -1;
86548c2ecf20Sopenharmony_ci
86558c2ecf20Sopenharmony_ci	host = iscsi_host_alloc(&qla4xxx_driver_template, sizeof(*ha), 0);
86568c2ecf20Sopenharmony_ci	if (host == NULL) {
86578c2ecf20Sopenharmony_ci		printk(KERN_WARNING
86588c2ecf20Sopenharmony_ci		       "qla4xxx: Couldn't allocate host from scsi layer!\n");
86598c2ecf20Sopenharmony_ci		goto probe_disable_device;
86608c2ecf20Sopenharmony_ci	}
86618c2ecf20Sopenharmony_ci
86628c2ecf20Sopenharmony_ci	/* Clear our data area */
86638c2ecf20Sopenharmony_ci	ha = to_qla_host(host);
86648c2ecf20Sopenharmony_ci	memset(ha, 0, sizeof(*ha));
86658c2ecf20Sopenharmony_ci
86668c2ecf20Sopenharmony_ci	/* Save the information from PCI BIOS.	*/
86678c2ecf20Sopenharmony_ci	ha->pdev = pdev;
86688c2ecf20Sopenharmony_ci	ha->host = host;
86698c2ecf20Sopenharmony_ci	ha->host_no = host->host_no;
86708c2ecf20Sopenharmony_ci	ha->func_num = PCI_FUNC(ha->pdev->devfn);
86718c2ecf20Sopenharmony_ci
86728c2ecf20Sopenharmony_ci	pci_enable_pcie_error_reporting(pdev);
86738c2ecf20Sopenharmony_ci
86748c2ecf20Sopenharmony_ci	/* Setup Runtime configurable options */
86758c2ecf20Sopenharmony_ci	if (is_qla8022(ha)) {
86768c2ecf20Sopenharmony_ci		ha->isp_ops = &qla4_82xx_isp_ops;
86778c2ecf20Sopenharmony_ci		ha->reg_tbl = (uint32_t *) qla4_82xx_reg_tbl;
86788c2ecf20Sopenharmony_ci		ha->qdr_sn_window = -1;
86798c2ecf20Sopenharmony_ci		ha->ddr_mn_window = -1;
86808c2ecf20Sopenharmony_ci		ha->curr_window = 255;
86818c2ecf20Sopenharmony_ci		nx_legacy_intr = &legacy_intr[ha->func_num];
86828c2ecf20Sopenharmony_ci		ha->nx_legacy_intr.int_vec_bit = nx_legacy_intr->int_vec_bit;
86838c2ecf20Sopenharmony_ci		ha->nx_legacy_intr.tgt_status_reg =
86848c2ecf20Sopenharmony_ci			nx_legacy_intr->tgt_status_reg;
86858c2ecf20Sopenharmony_ci		ha->nx_legacy_intr.tgt_mask_reg = nx_legacy_intr->tgt_mask_reg;
86868c2ecf20Sopenharmony_ci		ha->nx_legacy_intr.pci_int_reg = nx_legacy_intr->pci_int_reg;
86878c2ecf20Sopenharmony_ci	} else if (is_qla8032(ha) || is_qla8042(ha)) {
86888c2ecf20Sopenharmony_ci		ha->isp_ops = &qla4_83xx_isp_ops;
86898c2ecf20Sopenharmony_ci		ha->reg_tbl = (uint32_t *)qla4_83xx_reg_tbl;
86908c2ecf20Sopenharmony_ci	} else {
86918c2ecf20Sopenharmony_ci		ha->isp_ops = &qla4xxx_isp_ops;
86928c2ecf20Sopenharmony_ci	}
86938c2ecf20Sopenharmony_ci
86948c2ecf20Sopenharmony_ci	if (is_qla80XX(ha)) {
86958c2ecf20Sopenharmony_ci		rwlock_init(&ha->hw_lock);
86968c2ecf20Sopenharmony_ci		ha->pf_bit = ha->func_num << 16;
86978c2ecf20Sopenharmony_ci		/* Set EEH reset type to fundamental if required by hba */
86988c2ecf20Sopenharmony_ci		pdev->needs_freset = 1;
86998c2ecf20Sopenharmony_ci	}
87008c2ecf20Sopenharmony_ci
87018c2ecf20Sopenharmony_ci	/* Configure PCI I/O space. */
87028c2ecf20Sopenharmony_ci	ret = ha->isp_ops->iospace_config(ha);
87038c2ecf20Sopenharmony_ci	if (ret)
87048c2ecf20Sopenharmony_ci		goto probe_failed_ioconfig;
87058c2ecf20Sopenharmony_ci
87068c2ecf20Sopenharmony_ci	ql4_printk(KERN_INFO, ha, "Found an ISP%04x, irq %d, iobase 0x%p\n",
87078c2ecf20Sopenharmony_ci		   pdev->device, pdev->irq, ha->reg);
87088c2ecf20Sopenharmony_ci
87098c2ecf20Sopenharmony_ci	qla4xxx_config_dma_addressing(ha);
87108c2ecf20Sopenharmony_ci
87118c2ecf20Sopenharmony_ci	/* Initialize lists and spinlocks. */
87128c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&ha->free_srb_q);
87138c2ecf20Sopenharmony_ci
87148c2ecf20Sopenharmony_ci	mutex_init(&ha->mbox_sem);
87158c2ecf20Sopenharmony_ci	mutex_init(&ha->chap_sem);
87168c2ecf20Sopenharmony_ci	init_completion(&ha->mbx_intr_comp);
87178c2ecf20Sopenharmony_ci	init_completion(&ha->disable_acb_comp);
87188c2ecf20Sopenharmony_ci	init_completion(&ha->idc_comp);
87198c2ecf20Sopenharmony_ci	init_completion(&ha->link_up_comp);
87208c2ecf20Sopenharmony_ci
87218c2ecf20Sopenharmony_ci	spin_lock_init(&ha->hardware_lock);
87228c2ecf20Sopenharmony_ci	spin_lock_init(&ha->work_lock);
87238c2ecf20Sopenharmony_ci
87248c2ecf20Sopenharmony_ci	/* Initialize work list */
87258c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&ha->work_list);
87268c2ecf20Sopenharmony_ci
87278c2ecf20Sopenharmony_ci	/* Allocate dma buffers */
87288c2ecf20Sopenharmony_ci	if (qla4xxx_mem_alloc(ha)) {
87298c2ecf20Sopenharmony_ci		ql4_printk(KERN_WARNING, ha,
87308c2ecf20Sopenharmony_ci		    "[ERROR] Failed to allocate memory for adapter\n");
87318c2ecf20Sopenharmony_ci
87328c2ecf20Sopenharmony_ci		ret = -ENOMEM;
87338c2ecf20Sopenharmony_ci		goto probe_failed;
87348c2ecf20Sopenharmony_ci	}
87358c2ecf20Sopenharmony_ci
87368c2ecf20Sopenharmony_ci	host->cmd_per_lun = 3;
87378c2ecf20Sopenharmony_ci	host->max_channel = 0;
87388c2ecf20Sopenharmony_ci	host->max_lun = MAX_LUNS - 1;
87398c2ecf20Sopenharmony_ci	host->max_id = MAX_TARGETS;
87408c2ecf20Sopenharmony_ci	host->max_cmd_len = IOCB_MAX_CDB_LEN;
87418c2ecf20Sopenharmony_ci	host->can_queue = MAX_SRBS ;
87428c2ecf20Sopenharmony_ci	host->transportt = qla4xxx_scsi_transport;
87438c2ecf20Sopenharmony_ci
87448c2ecf20Sopenharmony_ci	pci_set_drvdata(pdev, ha);
87458c2ecf20Sopenharmony_ci
87468c2ecf20Sopenharmony_ci	ret = scsi_add_host(host, &pdev->dev);
87478c2ecf20Sopenharmony_ci	if (ret)
87488c2ecf20Sopenharmony_ci		goto probe_failed;
87498c2ecf20Sopenharmony_ci
87508c2ecf20Sopenharmony_ci	if (is_qla80XX(ha))
87518c2ecf20Sopenharmony_ci		qla4_8xxx_get_flash_info(ha);
87528c2ecf20Sopenharmony_ci
87538c2ecf20Sopenharmony_ci	if (is_qla8032(ha) || is_qla8042(ha)) {
87548c2ecf20Sopenharmony_ci		qla4_83xx_read_reset_template(ha);
87558c2ecf20Sopenharmony_ci		/*
87568c2ecf20Sopenharmony_ci		 * NOTE: If ql4dontresethba==1, set IDC_CTRL DONTRESET_BIT0.
87578c2ecf20Sopenharmony_ci		 * If DONRESET_BIT0 is set, drivers should not set dev_state
87588c2ecf20Sopenharmony_ci		 * to NEED_RESET. But if NEED_RESET is set, drivers should
87598c2ecf20Sopenharmony_ci		 * should honor the reset.
87608c2ecf20Sopenharmony_ci		 */
87618c2ecf20Sopenharmony_ci		if (ql4xdontresethba == 1)
87628c2ecf20Sopenharmony_ci			qla4_83xx_set_idc_dontreset(ha);
87638c2ecf20Sopenharmony_ci	}
87648c2ecf20Sopenharmony_ci
87658c2ecf20Sopenharmony_ci	/*
87668c2ecf20Sopenharmony_ci	 * Initialize the Host adapter request/response queues and
87678c2ecf20Sopenharmony_ci	 * firmware
87688c2ecf20Sopenharmony_ci	 * NOTE: interrupts enabled upon successful completion
87698c2ecf20Sopenharmony_ci	 */
87708c2ecf20Sopenharmony_ci	status = qla4xxx_initialize_adapter(ha, INIT_ADAPTER);
87718c2ecf20Sopenharmony_ci
87728c2ecf20Sopenharmony_ci	/* Dont retry adapter initialization if IRQ allocation failed */
87738c2ecf20Sopenharmony_ci	if (is_qla80XX(ha) && (status == QLA_ERROR))
87748c2ecf20Sopenharmony_ci		goto skip_retry_init;
87758c2ecf20Sopenharmony_ci
87768c2ecf20Sopenharmony_ci	while ((!test_bit(AF_ONLINE, &ha->flags)) &&
87778c2ecf20Sopenharmony_ci	    init_retry_count++ < MAX_INIT_RETRIES) {
87788c2ecf20Sopenharmony_ci
87798c2ecf20Sopenharmony_ci		if (is_qla80XX(ha)) {
87808c2ecf20Sopenharmony_ci			ha->isp_ops->idc_lock(ha);
87818c2ecf20Sopenharmony_ci			dev_state = qla4_8xxx_rd_direct(ha,
87828c2ecf20Sopenharmony_ci							QLA8XXX_CRB_DEV_STATE);
87838c2ecf20Sopenharmony_ci			ha->isp_ops->idc_unlock(ha);
87848c2ecf20Sopenharmony_ci			if (dev_state == QLA8XXX_DEV_FAILED) {
87858c2ecf20Sopenharmony_ci				ql4_printk(KERN_WARNING, ha, "%s: don't retry "
87868c2ecf20Sopenharmony_ci				    "initialize adapter. H/W is in failed state\n",
87878c2ecf20Sopenharmony_ci				    __func__);
87888c2ecf20Sopenharmony_ci				break;
87898c2ecf20Sopenharmony_ci			}
87908c2ecf20Sopenharmony_ci		}
87918c2ecf20Sopenharmony_ci		DEBUG2(printk("scsi: %s: retrying adapter initialization "
87928c2ecf20Sopenharmony_ci			      "(%d)\n", __func__, init_retry_count));
87938c2ecf20Sopenharmony_ci
87948c2ecf20Sopenharmony_ci		if (ha->isp_ops->reset_chip(ha) == QLA_ERROR)
87958c2ecf20Sopenharmony_ci			continue;
87968c2ecf20Sopenharmony_ci
87978c2ecf20Sopenharmony_ci		status = qla4xxx_initialize_adapter(ha, INIT_ADAPTER);
87988c2ecf20Sopenharmony_ci		if (is_qla80XX(ha) && (status == QLA_ERROR)) {
87998c2ecf20Sopenharmony_ci			if (qla4_8xxx_check_init_adapter_retry(ha) == QLA_ERROR)
88008c2ecf20Sopenharmony_ci				goto skip_retry_init;
88018c2ecf20Sopenharmony_ci		}
88028c2ecf20Sopenharmony_ci	}
88038c2ecf20Sopenharmony_ci
88048c2ecf20Sopenharmony_ciskip_retry_init:
88058c2ecf20Sopenharmony_ci	if (!test_bit(AF_ONLINE, &ha->flags)) {
88068c2ecf20Sopenharmony_ci		ql4_printk(KERN_WARNING, ha, "Failed to initialize adapter\n");
88078c2ecf20Sopenharmony_ci
88088c2ecf20Sopenharmony_ci		if ((is_qla8022(ha) && ql4xdontresethba) ||
88098c2ecf20Sopenharmony_ci		    ((is_qla8032(ha) || is_qla8042(ha)) &&
88108c2ecf20Sopenharmony_ci		     qla4_83xx_idc_dontreset(ha))) {
88118c2ecf20Sopenharmony_ci			/* Put the device in failed state. */
88128c2ecf20Sopenharmony_ci			DEBUG2(printk(KERN_ERR "HW STATE: FAILED\n"));
88138c2ecf20Sopenharmony_ci			ha->isp_ops->idc_lock(ha);
88148c2ecf20Sopenharmony_ci			qla4_8xxx_wr_direct(ha, QLA8XXX_CRB_DEV_STATE,
88158c2ecf20Sopenharmony_ci					    QLA8XXX_DEV_FAILED);
88168c2ecf20Sopenharmony_ci			ha->isp_ops->idc_unlock(ha);
88178c2ecf20Sopenharmony_ci		}
88188c2ecf20Sopenharmony_ci		ret = -ENODEV;
88198c2ecf20Sopenharmony_ci		goto remove_host;
88208c2ecf20Sopenharmony_ci	}
88218c2ecf20Sopenharmony_ci
88228c2ecf20Sopenharmony_ci	/* Startup the kernel thread for this host adapter. */
88238c2ecf20Sopenharmony_ci	DEBUG2(printk("scsi: %s: Starting kernel thread for "
88248c2ecf20Sopenharmony_ci		      "qla4xxx_dpc\n", __func__));
88258c2ecf20Sopenharmony_ci	sprintf(buf, "qla4xxx_%lu_dpc", ha->host_no);
88268c2ecf20Sopenharmony_ci	ha->dpc_thread = create_singlethread_workqueue(buf);
88278c2ecf20Sopenharmony_ci	if (!ha->dpc_thread) {
88288c2ecf20Sopenharmony_ci		ql4_printk(KERN_WARNING, ha, "Unable to start DPC thread!\n");
88298c2ecf20Sopenharmony_ci		ret = -ENODEV;
88308c2ecf20Sopenharmony_ci		goto remove_host;
88318c2ecf20Sopenharmony_ci	}
88328c2ecf20Sopenharmony_ci	INIT_WORK(&ha->dpc_work, qla4xxx_do_dpc);
88338c2ecf20Sopenharmony_ci
88348c2ecf20Sopenharmony_ci	ha->task_wq = alloc_workqueue("qla4xxx_%lu_task", WQ_MEM_RECLAIM, 1,
88358c2ecf20Sopenharmony_ci				      ha->host_no);
88368c2ecf20Sopenharmony_ci	if (!ha->task_wq) {
88378c2ecf20Sopenharmony_ci		ql4_printk(KERN_WARNING, ha, "Unable to start task thread!\n");
88388c2ecf20Sopenharmony_ci		ret = -ENODEV;
88398c2ecf20Sopenharmony_ci		goto remove_host;
88408c2ecf20Sopenharmony_ci	}
88418c2ecf20Sopenharmony_ci
88428c2ecf20Sopenharmony_ci	/*
88438c2ecf20Sopenharmony_ci	 * For ISP-8XXX, request_irqs is called in qla4_8xxx_load_risc
88448c2ecf20Sopenharmony_ci	 * (which is called indirectly by qla4xxx_initialize_adapter),
88458c2ecf20Sopenharmony_ci	 * so that irqs will be registered after crbinit but before
88468c2ecf20Sopenharmony_ci	 * mbx_intr_enable.
88478c2ecf20Sopenharmony_ci	 */
88488c2ecf20Sopenharmony_ci	if (is_qla40XX(ha)) {
88498c2ecf20Sopenharmony_ci		ret = qla4xxx_request_irqs(ha);
88508c2ecf20Sopenharmony_ci		if (ret) {
88518c2ecf20Sopenharmony_ci			ql4_printk(KERN_WARNING, ha, "Failed to reserve "
88528c2ecf20Sopenharmony_ci			    "interrupt %d already in use.\n", pdev->irq);
88538c2ecf20Sopenharmony_ci			goto remove_host;
88548c2ecf20Sopenharmony_ci		}
88558c2ecf20Sopenharmony_ci	}
88568c2ecf20Sopenharmony_ci
88578c2ecf20Sopenharmony_ci	pci_save_state(ha->pdev);
88588c2ecf20Sopenharmony_ci	ha->isp_ops->enable_intrs(ha);
88598c2ecf20Sopenharmony_ci
88608c2ecf20Sopenharmony_ci	/* Start timer thread. */
88618c2ecf20Sopenharmony_ci	qla4xxx_start_timer(ha, 1);
88628c2ecf20Sopenharmony_ci
88638c2ecf20Sopenharmony_ci	set_bit(AF_INIT_DONE, &ha->flags);
88648c2ecf20Sopenharmony_ci
88658c2ecf20Sopenharmony_ci	qla4_8xxx_alloc_sysfs_attr(ha);
88668c2ecf20Sopenharmony_ci
88678c2ecf20Sopenharmony_ci	printk(KERN_INFO
88688c2ecf20Sopenharmony_ci	       " QLogic iSCSI HBA Driver version: %s\n"
88698c2ecf20Sopenharmony_ci	       "  QLogic ISP%04x @ %s, host#=%ld, fw=%02d.%02d.%02d.%02d\n",
88708c2ecf20Sopenharmony_ci	       qla4xxx_version_str, ha->pdev->device, pci_name(ha->pdev),
88718c2ecf20Sopenharmony_ci	       ha->host_no, ha->fw_info.fw_major, ha->fw_info.fw_minor,
88728c2ecf20Sopenharmony_ci	       ha->fw_info.fw_patch, ha->fw_info.fw_build);
88738c2ecf20Sopenharmony_ci
88748c2ecf20Sopenharmony_ci	/* Set the driver version */
88758c2ecf20Sopenharmony_ci	if (is_qla80XX(ha))
88768c2ecf20Sopenharmony_ci		qla4_8xxx_set_param(ha, SET_DRVR_VERSION);
88778c2ecf20Sopenharmony_ci
88788c2ecf20Sopenharmony_ci	if (qla4xxx_setup_boot_info(ha))
88798c2ecf20Sopenharmony_ci		ql4_printk(KERN_ERR, ha,
88808c2ecf20Sopenharmony_ci			   "%s: No iSCSI boot target configured\n", __func__);
88818c2ecf20Sopenharmony_ci
88828c2ecf20Sopenharmony_ci	set_bit(DPC_SYSFS_DDB_EXPORT, &ha->dpc_flags);
88838c2ecf20Sopenharmony_ci	/* Perform the build ddb list and login to each */
88848c2ecf20Sopenharmony_ci	qla4xxx_build_ddb_list(ha, INIT_ADAPTER);
88858c2ecf20Sopenharmony_ci	iscsi_host_for_each_session(ha->host, qla4xxx_login_flash_ddb);
88868c2ecf20Sopenharmony_ci	qla4xxx_wait_login_resp_boot_tgt(ha);
88878c2ecf20Sopenharmony_ci
88888c2ecf20Sopenharmony_ci	qla4xxx_create_chap_list(ha);
88898c2ecf20Sopenharmony_ci
88908c2ecf20Sopenharmony_ci	qla4xxx_create_ifaces(ha);
88918c2ecf20Sopenharmony_ci	return 0;
88928c2ecf20Sopenharmony_ci
88938c2ecf20Sopenharmony_ciremove_host:
88948c2ecf20Sopenharmony_ci	scsi_remove_host(ha->host);
88958c2ecf20Sopenharmony_ci
88968c2ecf20Sopenharmony_ciprobe_failed:
88978c2ecf20Sopenharmony_ci	qla4xxx_free_adapter(ha);
88988c2ecf20Sopenharmony_ci
88998c2ecf20Sopenharmony_ciprobe_failed_ioconfig:
89008c2ecf20Sopenharmony_ci	pci_disable_pcie_error_reporting(pdev);
89018c2ecf20Sopenharmony_ci	scsi_host_put(ha->host);
89028c2ecf20Sopenharmony_ci
89038c2ecf20Sopenharmony_ciprobe_disable_device:
89048c2ecf20Sopenharmony_ci	pci_disable_device(pdev);
89058c2ecf20Sopenharmony_ci
89068c2ecf20Sopenharmony_ci	return ret;
89078c2ecf20Sopenharmony_ci}
89088c2ecf20Sopenharmony_ci
89098c2ecf20Sopenharmony_ci/**
89108c2ecf20Sopenharmony_ci * qla4xxx_prevent_other_port_reinit - prevent other port from re-initialize
89118c2ecf20Sopenharmony_ci * @ha: pointer to adapter structure
89128c2ecf20Sopenharmony_ci *
89138c2ecf20Sopenharmony_ci * Mark the other ISP-4xxx port to indicate that the driver is being removed,
89148c2ecf20Sopenharmony_ci * so that the other port will not re-initialize while in the process of
89158c2ecf20Sopenharmony_ci * removing the ha due to driver unload or hba hotplug.
89168c2ecf20Sopenharmony_ci **/
89178c2ecf20Sopenharmony_cistatic void qla4xxx_prevent_other_port_reinit(struct scsi_qla_host *ha)
89188c2ecf20Sopenharmony_ci{
89198c2ecf20Sopenharmony_ci	struct scsi_qla_host *other_ha = NULL;
89208c2ecf20Sopenharmony_ci	struct pci_dev *other_pdev = NULL;
89218c2ecf20Sopenharmony_ci	int fn = ISP4XXX_PCI_FN_2;
89228c2ecf20Sopenharmony_ci
89238c2ecf20Sopenharmony_ci	/*iscsi function numbers for ISP4xxx is 1 and 3*/
89248c2ecf20Sopenharmony_ci	if (PCI_FUNC(ha->pdev->devfn) & BIT_1)
89258c2ecf20Sopenharmony_ci		fn = ISP4XXX_PCI_FN_1;
89268c2ecf20Sopenharmony_ci
89278c2ecf20Sopenharmony_ci	other_pdev =
89288c2ecf20Sopenharmony_ci		pci_get_domain_bus_and_slot(pci_domain_nr(ha->pdev->bus),
89298c2ecf20Sopenharmony_ci		ha->pdev->bus->number, PCI_DEVFN(PCI_SLOT(ha->pdev->devfn),
89308c2ecf20Sopenharmony_ci		fn));
89318c2ecf20Sopenharmony_ci
89328c2ecf20Sopenharmony_ci	/* Get other_ha if other_pdev is valid and state is enable*/
89338c2ecf20Sopenharmony_ci	if (other_pdev) {
89348c2ecf20Sopenharmony_ci		if (atomic_read(&other_pdev->enable_cnt)) {
89358c2ecf20Sopenharmony_ci			other_ha = pci_get_drvdata(other_pdev);
89368c2ecf20Sopenharmony_ci			if (other_ha) {
89378c2ecf20Sopenharmony_ci				set_bit(AF_HA_REMOVAL, &other_ha->flags);
89388c2ecf20Sopenharmony_ci				DEBUG2(ql4_printk(KERN_INFO, ha, "%s: "
89398c2ecf20Sopenharmony_ci				    "Prevent %s reinit\n", __func__,
89408c2ecf20Sopenharmony_ci				    dev_name(&other_ha->pdev->dev)));
89418c2ecf20Sopenharmony_ci			}
89428c2ecf20Sopenharmony_ci		}
89438c2ecf20Sopenharmony_ci		pci_dev_put(other_pdev);
89448c2ecf20Sopenharmony_ci	}
89458c2ecf20Sopenharmony_ci}
89468c2ecf20Sopenharmony_ci
89478c2ecf20Sopenharmony_cistatic void qla4xxx_destroy_ddb(struct scsi_qla_host *ha,
89488c2ecf20Sopenharmony_ci		struct ddb_entry *ddb_entry)
89498c2ecf20Sopenharmony_ci{
89508c2ecf20Sopenharmony_ci	struct dev_db_entry *fw_ddb_entry = NULL;
89518c2ecf20Sopenharmony_ci	dma_addr_t fw_ddb_entry_dma;
89528c2ecf20Sopenharmony_ci	unsigned long wtime;
89538c2ecf20Sopenharmony_ci	uint32_t ddb_state;
89548c2ecf20Sopenharmony_ci	int options;
89558c2ecf20Sopenharmony_ci	int status;
89568c2ecf20Sopenharmony_ci
89578c2ecf20Sopenharmony_ci	options = LOGOUT_OPTION_CLOSE_SESSION;
89588c2ecf20Sopenharmony_ci	if (qla4xxx_session_logout_ddb(ha, ddb_entry, options) == QLA_ERROR) {
89598c2ecf20Sopenharmony_ci		ql4_printk(KERN_ERR, ha, "%s: Logout failed\n", __func__);
89608c2ecf20Sopenharmony_ci		goto clear_ddb;
89618c2ecf20Sopenharmony_ci	}
89628c2ecf20Sopenharmony_ci
89638c2ecf20Sopenharmony_ci	fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
89648c2ecf20Sopenharmony_ci					  &fw_ddb_entry_dma, GFP_KERNEL);
89658c2ecf20Sopenharmony_ci	if (!fw_ddb_entry) {
89668c2ecf20Sopenharmony_ci		ql4_printk(KERN_ERR, ha,
89678c2ecf20Sopenharmony_ci			   "%s: Unable to allocate dma buffer\n", __func__);
89688c2ecf20Sopenharmony_ci		goto clear_ddb;
89698c2ecf20Sopenharmony_ci	}
89708c2ecf20Sopenharmony_ci
89718c2ecf20Sopenharmony_ci	wtime = jiffies + (HZ * LOGOUT_TOV);
89728c2ecf20Sopenharmony_ci	do {
89738c2ecf20Sopenharmony_ci		status = qla4xxx_get_fwddb_entry(ha, ddb_entry->fw_ddb_index,
89748c2ecf20Sopenharmony_ci						 fw_ddb_entry, fw_ddb_entry_dma,
89758c2ecf20Sopenharmony_ci						 NULL, NULL, &ddb_state, NULL,
89768c2ecf20Sopenharmony_ci						 NULL, NULL);
89778c2ecf20Sopenharmony_ci		if (status == QLA_ERROR)
89788c2ecf20Sopenharmony_ci			goto free_ddb;
89798c2ecf20Sopenharmony_ci
89808c2ecf20Sopenharmony_ci		if ((ddb_state == DDB_DS_NO_CONNECTION_ACTIVE) ||
89818c2ecf20Sopenharmony_ci		    (ddb_state == DDB_DS_SESSION_FAILED))
89828c2ecf20Sopenharmony_ci			goto free_ddb;
89838c2ecf20Sopenharmony_ci
89848c2ecf20Sopenharmony_ci		schedule_timeout_uninterruptible(HZ);
89858c2ecf20Sopenharmony_ci	} while ((time_after(wtime, jiffies)));
89868c2ecf20Sopenharmony_ci
89878c2ecf20Sopenharmony_cifree_ddb:
89888c2ecf20Sopenharmony_ci	dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
89898c2ecf20Sopenharmony_ci			  fw_ddb_entry, fw_ddb_entry_dma);
89908c2ecf20Sopenharmony_ciclear_ddb:
89918c2ecf20Sopenharmony_ci	qla4xxx_clear_ddb_entry(ha, ddb_entry->fw_ddb_index);
89928c2ecf20Sopenharmony_ci}
89938c2ecf20Sopenharmony_ci
89948c2ecf20Sopenharmony_cistatic void qla4xxx_destroy_fw_ddb_session(struct scsi_qla_host *ha)
89958c2ecf20Sopenharmony_ci{
89968c2ecf20Sopenharmony_ci	struct ddb_entry *ddb_entry;
89978c2ecf20Sopenharmony_ci	int idx;
89988c2ecf20Sopenharmony_ci
89998c2ecf20Sopenharmony_ci	for (idx = 0; idx < MAX_DDB_ENTRIES; idx++) {
90008c2ecf20Sopenharmony_ci
90018c2ecf20Sopenharmony_ci		ddb_entry = qla4xxx_lookup_ddb_by_fw_index(ha, idx);
90028c2ecf20Sopenharmony_ci		if ((ddb_entry != NULL) &&
90038c2ecf20Sopenharmony_ci		    (ddb_entry->ddb_type == FLASH_DDB)) {
90048c2ecf20Sopenharmony_ci
90058c2ecf20Sopenharmony_ci			qla4xxx_destroy_ddb(ha, ddb_entry);
90068c2ecf20Sopenharmony_ci			/*
90078c2ecf20Sopenharmony_ci			 * we have decremented the reference count of the driver
90088c2ecf20Sopenharmony_ci			 * when we setup the session to have the driver unload
90098c2ecf20Sopenharmony_ci			 * to be seamless without actually destroying the
90108c2ecf20Sopenharmony_ci			 * session
90118c2ecf20Sopenharmony_ci			 **/
90128c2ecf20Sopenharmony_ci			try_module_get(qla4xxx_iscsi_transport.owner);
90138c2ecf20Sopenharmony_ci			iscsi_destroy_endpoint(ddb_entry->conn->ep);
90148c2ecf20Sopenharmony_ci			qla4xxx_free_ddb(ha, ddb_entry);
90158c2ecf20Sopenharmony_ci			iscsi_session_teardown(ddb_entry->sess);
90168c2ecf20Sopenharmony_ci		}
90178c2ecf20Sopenharmony_ci	}
90188c2ecf20Sopenharmony_ci}
90198c2ecf20Sopenharmony_ci/**
90208c2ecf20Sopenharmony_ci * qla4xxx_remove_adapter - callback function to remove adapter.
90218c2ecf20Sopenharmony_ci * @pdev: PCI device pointer
90228c2ecf20Sopenharmony_ci **/
90238c2ecf20Sopenharmony_cistatic void qla4xxx_remove_adapter(struct pci_dev *pdev)
90248c2ecf20Sopenharmony_ci{
90258c2ecf20Sopenharmony_ci	struct scsi_qla_host *ha;
90268c2ecf20Sopenharmony_ci
90278c2ecf20Sopenharmony_ci	/*
90288c2ecf20Sopenharmony_ci	 * If the PCI device is disabled then it means probe_adapter had
90298c2ecf20Sopenharmony_ci	 * failed and resources already cleaned up on probe_adapter exit.
90308c2ecf20Sopenharmony_ci	 */
90318c2ecf20Sopenharmony_ci	if (!pci_is_enabled(pdev))
90328c2ecf20Sopenharmony_ci		return;
90338c2ecf20Sopenharmony_ci
90348c2ecf20Sopenharmony_ci	ha = pci_get_drvdata(pdev);
90358c2ecf20Sopenharmony_ci
90368c2ecf20Sopenharmony_ci	if (is_qla40XX(ha))
90378c2ecf20Sopenharmony_ci		qla4xxx_prevent_other_port_reinit(ha);
90388c2ecf20Sopenharmony_ci
90398c2ecf20Sopenharmony_ci	/* destroy iface from sysfs */
90408c2ecf20Sopenharmony_ci	qla4xxx_destroy_ifaces(ha);
90418c2ecf20Sopenharmony_ci
90428c2ecf20Sopenharmony_ci	if ((!ql4xdisablesysfsboot) && ha->boot_kset)
90438c2ecf20Sopenharmony_ci		iscsi_boot_destroy_kset(ha->boot_kset);
90448c2ecf20Sopenharmony_ci
90458c2ecf20Sopenharmony_ci	qla4xxx_destroy_fw_ddb_session(ha);
90468c2ecf20Sopenharmony_ci	qla4_8xxx_free_sysfs_attr(ha);
90478c2ecf20Sopenharmony_ci
90488c2ecf20Sopenharmony_ci	qla4xxx_sysfs_ddb_remove(ha);
90498c2ecf20Sopenharmony_ci	scsi_remove_host(ha->host);
90508c2ecf20Sopenharmony_ci
90518c2ecf20Sopenharmony_ci	qla4xxx_free_adapter(ha);
90528c2ecf20Sopenharmony_ci
90538c2ecf20Sopenharmony_ci	scsi_host_put(ha->host);
90548c2ecf20Sopenharmony_ci
90558c2ecf20Sopenharmony_ci	pci_disable_pcie_error_reporting(pdev);
90568c2ecf20Sopenharmony_ci	pci_disable_device(pdev);
90578c2ecf20Sopenharmony_ci}
90588c2ecf20Sopenharmony_ci
90598c2ecf20Sopenharmony_ci/**
90608c2ecf20Sopenharmony_ci * qla4xxx_config_dma_addressing() - Configure OS DMA addressing method.
90618c2ecf20Sopenharmony_ci * @ha: HA context
90628c2ecf20Sopenharmony_ci */
90638c2ecf20Sopenharmony_cistatic void qla4xxx_config_dma_addressing(struct scsi_qla_host *ha)
90648c2ecf20Sopenharmony_ci{
90658c2ecf20Sopenharmony_ci	/* Update our PCI device dma_mask for full 64 bit mask */
90668c2ecf20Sopenharmony_ci	if (dma_set_mask_and_coherent(&ha->pdev->dev, DMA_BIT_MASK(64))) {
90678c2ecf20Sopenharmony_ci		dev_dbg(&ha->pdev->dev,
90688c2ecf20Sopenharmony_ci			  "Failed to set 64 bit PCI consistent mask; "
90698c2ecf20Sopenharmony_ci			   "using 32 bit.\n");
90708c2ecf20Sopenharmony_ci		dma_set_mask_and_coherent(&ha->pdev->dev, DMA_BIT_MASK(32));
90718c2ecf20Sopenharmony_ci	}
90728c2ecf20Sopenharmony_ci}
90738c2ecf20Sopenharmony_ci
90748c2ecf20Sopenharmony_cistatic int qla4xxx_slave_alloc(struct scsi_device *sdev)
90758c2ecf20Sopenharmony_ci{
90768c2ecf20Sopenharmony_ci	struct iscsi_cls_session *cls_sess;
90778c2ecf20Sopenharmony_ci	struct iscsi_session *sess;
90788c2ecf20Sopenharmony_ci	struct ddb_entry *ddb;
90798c2ecf20Sopenharmony_ci	int queue_depth = QL4_DEF_QDEPTH;
90808c2ecf20Sopenharmony_ci
90818c2ecf20Sopenharmony_ci	cls_sess = starget_to_session(sdev->sdev_target);
90828c2ecf20Sopenharmony_ci	sess = cls_sess->dd_data;
90838c2ecf20Sopenharmony_ci	ddb = sess->dd_data;
90848c2ecf20Sopenharmony_ci
90858c2ecf20Sopenharmony_ci	sdev->hostdata = ddb;
90868c2ecf20Sopenharmony_ci
90878c2ecf20Sopenharmony_ci	if (ql4xmaxqdepth != 0 && ql4xmaxqdepth <= 0xffffU)
90888c2ecf20Sopenharmony_ci		queue_depth = ql4xmaxqdepth;
90898c2ecf20Sopenharmony_ci
90908c2ecf20Sopenharmony_ci	scsi_change_queue_depth(sdev, queue_depth);
90918c2ecf20Sopenharmony_ci	return 0;
90928c2ecf20Sopenharmony_ci}
90938c2ecf20Sopenharmony_ci
90948c2ecf20Sopenharmony_ci/**
90958c2ecf20Sopenharmony_ci * qla4xxx_del_from_active_array - returns an active srb
90968c2ecf20Sopenharmony_ci * @ha: Pointer to host adapter structure.
90978c2ecf20Sopenharmony_ci * @index: index into the active_array
90988c2ecf20Sopenharmony_ci *
90998c2ecf20Sopenharmony_ci * This routine removes and returns the srb at the specified index
91008c2ecf20Sopenharmony_ci **/
91018c2ecf20Sopenharmony_cistruct srb *qla4xxx_del_from_active_array(struct scsi_qla_host *ha,
91028c2ecf20Sopenharmony_ci    uint32_t index)
91038c2ecf20Sopenharmony_ci{
91048c2ecf20Sopenharmony_ci	struct srb *srb = NULL;
91058c2ecf20Sopenharmony_ci	struct scsi_cmnd *cmd = NULL;
91068c2ecf20Sopenharmony_ci
91078c2ecf20Sopenharmony_ci	cmd = scsi_host_find_tag(ha->host, index);
91088c2ecf20Sopenharmony_ci	if (!cmd)
91098c2ecf20Sopenharmony_ci		return srb;
91108c2ecf20Sopenharmony_ci
91118c2ecf20Sopenharmony_ci	srb = (struct srb *)CMD_SP(cmd);
91128c2ecf20Sopenharmony_ci	if (!srb)
91138c2ecf20Sopenharmony_ci		return srb;
91148c2ecf20Sopenharmony_ci
91158c2ecf20Sopenharmony_ci	/* update counters */
91168c2ecf20Sopenharmony_ci	if (srb->flags & SRB_DMA_VALID) {
91178c2ecf20Sopenharmony_ci		ha->iocb_cnt -= srb->iocb_cnt;
91188c2ecf20Sopenharmony_ci		if (srb->cmd)
91198c2ecf20Sopenharmony_ci			srb->cmd->host_scribble =
91208c2ecf20Sopenharmony_ci				(unsigned char *)(unsigned long) MAX_SRBS;
91218c2ecf20Sopenharmony_ci	}
91228c2ecf20Sopenharmony_ci	return srb;
91238c2ecf20Sopenharmony_ci}
91248c2ecf20Sopenharmony_ci
91258c2ecf20Sopenharmony_ci/**
91268c2ecf20Sopenharmony_ci * qla4xxx_eh_wait_on_command - waits for command to be returned by firmware
91278c2ecf20Sopenharmony_ci * @ha: Pointer to host adapter structure.
91288c2ecf20Sopenharmony_ci * @cmd: Scsi Command to wait on.
91298c2ecf20Sopenharmony_ci *
91308c2ecf20Sopenharmony_ci * This routine waits for the command to be returned by the Firmware
91318c2ecf20Sopenharmony_ci * for some max time.
91328c2ecf20Sopenharmony_ci **/
91338c2ecf20Sopenharmony_cistatic int qla4xxx_eh_wait_on_command(struct scsi_qla_host *ha,
91348c2ecf20Sopenharmony_ci				      struct scsi_cmnd *cmd)
91358c2ecf20Sopenharmony_ci{
91368c2ecf20Sopenharmony_ci	int done = 0;
91378c2ecf20Sopenharmony_ci	struct srb *rp;
91388c2ecf20Sopenharmony_ci	uint32_t max_wait_time = EH_WAIT_CMD_TOV;
91398c2ecf20Sopenharmony_ci	int ret = SUCCESS;
91408c2ecf20Sopenharmony_ci
91418c2ecf20Sopenharmony_ci	/* Dont wait on command if PCI error is being handled
91428c2ecf20Sopenharmony_ci	 * by PCI AER driver
91438c2ecf20Sopenharmony_ci	 */
91448c2ecf20Sopenharmony_ci	if (unlikely(pci_channel_offline(ha->pdev)) ||
91458c2ecf20Sopenharmony_ci	    (test_bit(AF_EEH_BUSY, &ha->flags))) {
91468c2ecf20Sopenharmony_ci		ql4_printk(KERN_WARNING, ha, "scsi%ld: Return from %s\n",
91478c2ecf20Sopenharmony_ci		    ha->host_no, __func__);
91488c2ecf20Sopenharmony_ci		return ret;
91498c2ecf20Sopenharmony_ci	}
91508c2ecf20Sopenharmony_ci
91518c2ecf20Sopenharmony_ci	do {
91528c2ecf20Sopenharmony_ci		/* Checking to see if its returned to OS */
91538c2ecf20Sopenharmony_ci		rp = (struct srb *) CMD_SP(cmd);
91548c2ecf20Sopenharmony_ci		if (rp == NULL) {
91558c2ecf20Sopenharmony_ci			done++;
91568c2ecf20Sopenharmony_ci			break;
91578c2ecf20Sopenharmony_ci		}
91588c2ecf20Sopenharmony_ci
91598c2ecf20Sopenharmony_ci		msleep(2000);
91608c2ecf20Sopenharmony_ci	} while (max_wait_time--);
91618c2ecf20Sopenharmony_ci
91628c2ecf20Sopenharmony_ci	return done;
91638c2ecf20Sopenharmony_ci}
91648c2ecf20Sopenharmony_ci
91658c2ecf20Sopenharmony_ci/**
91668c2ecf20Sopenharmony_ci * qla4xxx_wait_for_hba_online - waits for HBA to come online
91678c2ecf20Sopenharmony_ci * @ha: Pointer to host adapter structure
91688c2ecf20Sopenharmony_ci **/
91698c2ecf20Sopenharmony_cistatic int qla4xxx_wait_for_hba_online(struct scsi_qla_host *ha)
91708c2ecf20Sopenharmony_ci{
91718c2ecf20Sopenharmony_ci	unsigned long wait_online;
91728c2ecf20Sopenharmony_ci
91738c2ecf20Sopenharmony_ci	wait_online = jiffies + (HBA_ONLINE_TOV * HZ);
91748c2ecf20Sopenharmony_ci	while (time_before(jiffies, wait_online)) {
91758c2ecf20Sopenharmony_ci
91768c2ecf20Sopenharmony_ci		if (adapter_up(ha))
91778c2ecf20Sopenharmony_ci			return QLA_SUCCESS;
91788c2ecf20Sopenharmony_ci
91798c2ecf20Sopenharmony_ci		msleep(2000);
91808c2ecf20Sopenharmony_ci	}
91818c2ecf20Sopenharmony_ci
91828c2ecf20Sopenharmony_ci	return QLA_ERROR;
91838c2ecf20Sopenharmony_ci}
91848c2ecf20Sopenharmony_ci
91858c2ecf20Sopenharmony_ci/**
91868c2ecf20Sopenharmony_ci * qla4xxx_eh_wait_for_commands - wait for active cmds to finish.
91878c2ecf20Sopenharmony_ci * @ha: pointer to HBA
91888c2ecf20Sopenharmony_ci * @stgt: pointer to SCSI target
91898c2ecf20Sopenharmony_ci * @sdev: pointer to SCSI device
91908c2ecf20Sopenharmony_ci *
91918c2ecf20Sopenharmony_ci * This function waits for all outstanding commands to a lun to complete. It
91928c2ecf20Sopenharmony_ci * returns 0 if all pending commands are returned and 1 otherwise.
91938c2ecf20Sopenharmony_ci **/
91948c2ecf20Sopenharmony_cistatic int qla4xxx_eh_wait_for_commands(struct scsi_qla_host *ha,
91958c2ecf20Sopenharmony_ci					struct scsi_target *stgt,
91968c2ecf20Sopenharmony_ci					struct scsi_device *sdev)
91978c2ecf20Sopenharmony_ci{
91988c2ecf20Sopenharmony_ci	int cnt;
91998c2ecf20Sopenharmony_ci	int status = 0;
92008c2ecf20Sopenharmony_ci	struct scsi_cmnd *cmd;
92018c2ecf20Sopenharmony_ci
92028c2ecf20Sopenharmony_ci	/*
92038c2ecf20Sopenharmony_ci	 * Waiting for all commands for the designated target or dev
92048c2ecf20Sopenharmony_ci	 * in the active array
92058c2ecf20Sopenharmony_ci	 */
92068c2ecf20Sopenharmony_ci	for (cnt = 0; cnt < ha->host->can_queue; cnt++) {
92078c2ecf20Sopenharmony_ci		cmd = scsi_host_find_tag(ha->host, cnt);
92088c2ecf20Sopenharmony_ci		if (cmd && stgt == scsi_target(cmd->device) &&
92098c2ecf20Sopenharmony_ci		    (!sdev || sdev == cmd->device)) {
92108c2ecf20Sopenharmony_ci			if (!qla4xxx_eh_wait_on_command(ha, cmd)) {
92118c2ecf20Sopenharmony_ci				status++;
92128c2ecf20Sopenharmony_ci				break;
92138c2ecf20Sopenharmony_ci			}
92148c2ecf20Sopenharmony_ci		}
92158c2ecf20Sopenharmony_ci	}
92168c2ecf20Sopenharmony_ci	return status;
92178c2ecf20Sopenharmony_ci}
92188c2ecf20Sopenharmony_ci
92198c2ecf20Sopenharmony_ci/**
92208c2ecf20Sopenharmony_ci * qla4xxx_eh_abort - callback for abort task.
92218c2ecf20Sopenharmony_ci * @cmd: Pointer to Linux's SCSI command structure
92228c2ecf20Sopenharmony_ci *
92238c2ecf20Sopenharmony_ci * This routine is called by the Linux OS to abort the specified
92248c2ecf20Sopenharmony_ci * command.
92258c2ecf20Sopenharmony_ci **/
92268c2ecf20Sopenharmony_cistatic int qla4xxx_eh_abort(struct scsi_cmnd *cmd)
92278c2ecf20Sopenharmony_ci{
92288c2ecf20Sopenharmony_ci	struct scsi_qla_host *ha = to_qla_host(cmd->device->host);
92298c2ecf20Sopenharmony_ci	unsigned int id = cmd->device->id;
92308c2ecf20Sopenharmony_ci	uint64_t lun = cmd->device->lun;
92318c2ecf20Sopenharmony_ci	unsigned long flags;
92328c2ecf20Sopenharmony_ci	struct srb *srb = NULL;
92338c2ecf20Sopenharmony_ci	int ret = SUCCESS;
92348c2ecf20Sopenharmony_ci	int wait = 0;
92358c2ecf20Sopenharmony_ci	int rval;
92368c2ecf20Sopenharmony_ci
92378c2ecf20Sopenharmony_ci	ql4_printk(KERN_INFO, ha, "scsi%ld:%d:%llu: Abort command issued cmd=%p, cdb=0x%x\n",
92388c2ecf20Sopenharmony_ci		   ha->host_no, id, lun, cmd, cmd->cmnd[0]);
92398c2ecf20Sopenharmony_ci
92408c2ecf20Sopenharmony_ci	rval = qla4xxx_isp_check_reg(ha);
92418c2ecf20Sopenharmony_ci	if (rval != QLA_SUCCESS) {
92428c2ecf20Sopenharmony_ci		ql4_printk(KERN_INFO, ha, "PCI/Register disconnect, exiting.\n");
92438c2ecf20Sopenharmony_ci		return FAILED;
92448c2ecf20Sopenharmony_ci	}
92458c2ecf20Sopenharmony_ci
92468c2ecf20Sopenharmony_ci	spin_lock_irqsave(&ha->hardware_lock, flags);
92478c2ecf20Sopenharmony_ci	srb = (struct srb *) CMD_SP(cmd);
92488c2ecf20Sopenharmony_ci	if (!srb) {
92498c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&ha->hardware_lock, flags);
92508c2ecf20Sopenharmony_ci		ql4_printk(KERN_INFO, ha, "scsi%ld:%d:%llu: Specified command has already completed.\n",
92518c2ecf20Sopenharmony_ci			   ha->host_no, id, lun);
92528c2ecf20Sopenharmony_ci		return SUCCESS;
92538c2ecf20Sopenharmony_ci	}
92548c2ecf20Sopenharmony_ci	kref_get(&srb->srb_ref);
92558c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&ha->hardware_lock, flags);
92568c2ecf20Sopenharmony_ci
92578c2ecf20Sopenharmony_ci	if (qla4xxx_abort_task(ha, srb) != QLA_SUCCESS) {
92588c2ecf20Sopenharmony_ci		DEBUG3(printk("scsi%ld:%d:%llu: Abort_task mbx failed.\n",
92598c2ecf20Sopenharmony_ci		    ha->host_no, id, lun));
92608c2ecf20Sopenharmony_ci		ret = FAILED;
92618c2ecf20Sopenharmony_ci	} else {
92628c2ecf20Sopenharmony_ci		DEBUG3(printk("scsi%ld:%d:%llu: Abort_task mbx success.\n",
92638c2ecf20Sopenharmony_ci		    ha->host_no, id, lun));
92648c2ecf20Sopenharmony_ci		wait = 1;
92658c2ecf20Sopenharmony_ci	}
92668c2ecf20Sopenharmony_ci
92678c2ecf20Sopenharmony_ci	kref_put(&srb->srb_ref, qla4xxx_srb_compl);
92688c2ecf20Sopenharmony_ci
92698c2ecf20Sopenharmony_ci	/* Wait for command to complete */
92708c2ecf20Sopenharmony_ci	if (wait) {
92718c2ecf20Sopenharmony_ci		if (!qla4xxx_eh_wait_on_command(ha, cmd)) {
92728c2ecf20Sopenharmony_ci			DEBUG2(printk("scsi%ld:%d:%llu: Abort handler timed out\n",
92738c2ecf20Sopenharmony_ci			    ha->host_no, id, lun));
92748c2ecf20Sopenharmony_ci			ret = FAILED;
92758c2ecf20Sopenharmony_ci		}
92768c2ecf20Sopenharmony_ci	}
92778c2ecf20Sopenharmony_ci
92788c2ecf20Sopenharmony_ci	ql4_printk(KERN_INFO, ha,
92798c2ecf20Sopenharmony_ci	    "scsi%ld:%d:%llu: Abort command - %s\n",
92808c2ecf20Sopenharmony_ci	    ha->host_no, id, lun, (ret == SUCCESS) ? "succeeded" : "failed");
92818c2ecf20Sopenharmony_ci
92828c2ecf20Sopenharmony_ci	return ret;
92838c2ecf20Sopenharmony_ci}
92848c2ecf20Sopenharmony_ci
92858c2ecf20Sopenharmony_ci/**
92868c2ecf20Sopenharmony_ci * qla4xxx_eh_device_reset - callback for target reset.
92878c2ecf20Sopenharmony_ci * @cmd: Pointer to Linux's SCSI command structure
92888c2ecf20Sopenharmony_ci *
92898c2ecf20Sopenharmony_ci * This routine is called by the Linux OS to reset all luns on the
92908c2ecf20Sopenharmony_ci * specified target.
92918c2ecf20Sopenharmony_ci **/
92928c2ecf20Sopenharmony_cistatic int qla4xxx_eh_device_reset(struct scsi_cmnd *cmd)
92938c2ecf20Sopenharmony_ci{
92948c2ecf20Sopenharmony_ci	struct scsi_qla_host *ha = to_qla_host(cmd->device->host);
92958c2ecf20Sopenharmony_ci	struct ddb_entry *ddb_entry = cmd->device->hostdata;
92968c2ecf20Sopenharmony_ci	int ret = FAILED, stat;
92978c2ecf20Sopenharmony_ci	int rval;
92988c2ecf20Sopenharmony_ci
92998c2ecf20Sopenharmony_ci	if (!ddb_entry)
93008c2ecf20Sopenharmony_ci		return ret;
93018c2ecf20Sopenharmony_ci
93028c2ecf20Sopenharmony_ci	ret = iscsi_block_scsi_eh(cmd);
93038c2ecf20Sopenharmony_ci	if (ret)
93048c2ecf20Sopenharmony_ci		return ret;
93058c2ecf20Sopenharmony_ci	ret = FAILED;
93068c2ecf20Sopenharmony_ci
93078c2ecf20Sopenharmony_ci	ql4_printk(KERN_INFO, ha,
93088c2ecf20Sopenharmony_ci		   "scsi%ld:%d:%d:%llu: DEVICE RESET ISSUED.\n", ha->host_no,
93098c2ecf20Sopenharmony_ci		   cmd->device->channel, cmd->device->id, cmd->device->lun);
93108c2ecf20Sopenharmony_ci
93118c2ecf20Sopenharmony_ci	DEBUG2(printk(KERN_INFO
93128c2ecf20Sopenharmony_ci		      "scsi%ld: DEVICE_RESET cmd=%p jiffies = 0x%lx, to=%x,"
93138c2ecf20Sopenharmony_ci		      "dpc_flags=%lx, status=%x allowed=%d\n", ha->host_no,
93148c2ecf20Sopenharmony_ci		      cmd, jiffies, cmd->request->timeout / HZ,
93158c2ecf20Sopenharmony_ci		      ha->dpc_flags, cmd->result, cmd->allowed));
93168c2ecf20Sopenharmony_ci
93178c2ecf20Sopenharmony_ci	rval = qla4xxx_isp_check_reg(ha);
93188c2ecf20Sopenharmony_ci	if (rval != QLA_SUCCESS) {
93198c2ecf20Sopenharmony_ci		ql4_printk(KERN_INFO, ha, "PCI/Register disconnect, exiting.\n");
93208c2ecf20Sopenharmony_ci		return FAILED;
93218c2ecf20Sopenharmony_ci	}
93228c2ecf20Sopenharmony_ci
93238c2ecf20Sopenharmony_ci	/* FIXME: wait for hba to go online */
93248c2ecf20Sopenharmony_ci	stat = qla4xxx_reset_lun(ha, ddb_entry, cmd->device->lun);
93258c2ecf20Sopenharmony_ci	if (stat != QLA_SUCCESS) {
93268c2ecf20Sopenharmony_ci		ql4_printk(KERN_INFO, ha, "DEVICE RESET FAILED. %d\n", stat);
93278c2ecf20Sopenharmony_ci		goto eh_dev_reset_done;
93288c2ecf20Sopenharmony_ci	}
93298c2ecf20Sopenharmony_ci
93308c2ecf20Sopenharmony_ci	if (qla4xxx_eh_wait_for_commands(ha, scsi_target(cmd->device),
93318c2ecf20Sopenharmony_ci					 cmd->device)) {
93328c2ecf20Sopenharmony_ci		ql4_printk(KERN_INFO, ha,
93338c2ecf20Sopenharmony_ci			   "DEVICE RESET FAILED - waiting for "
93348c2ecf20Sopenharmony_ci			   "commands.\n");
93358c2ecf20Sopenharmony_ci		goto eh_dev_reset_done;
93368c2ecf20Sopenharmony_ci	}
93378c2ecf20Sopenharmony_ci
93388c2ecf20Sopenharmony_ci	/* Send marker. */
93398c2ecf20Sopenharmony_ci	if (qla4xxx_send_marker_iocb(ha, ddb_entry, cmd->device->lun,
93408c2ecf20Sopenharmony_ci		MM_LUN_RESET) != QLA_SUCCESS)
93418c2ecf20Sopenharmony_ci		goto eh_dev_reset_done;
93428c2ecf20Sopenharmony_ci
93438c2ecf20Sopenharmony_ci	ql4_printk(KERN_INFO, ha,
93448c2ecf20Sopenharmony_ci		   "scsi(%ld:%d:%d:%llu): DEVICE RESET SUCCEEDED.\n",
93458c2ecf20Sopenharmony_ci		   ha->host_no, cmd->device->channel, cmd->device->id,
93468c2ecf20Sopenharmony_ci		   cmd->device->lun);
93478c2ecf20Sopenharmony_ci
93488c2ecf20Sopenharmony_ci	ret = SUCCESS;
93498c2ecf20Sopenharmony_ci
93508c2ecf20Sopenharmony_cieh_dev_reset_done:
93518c2ecf20Sopenharmony_ci
93528c2ecf20Sopenharmony_ci	return ret;
93538c2ecf20Sopenharmony_ci}
93548c2ecf20Sopenharmony_ci
93558c2ecf20Sopenharmony_ci/**
93568c2ecf20Sopenharmony_ci * qla4xxx_eh_target_reset - callback for target reset.
93578c2ecf20Sopenharmony_ci * @cmd: Pointer to Linux's SCSI command structure
93588c2ecf20Sopenharmony_ci *
93598c2ecf20Sopenharmony_ci * This routine is called by the Linux OS to reset the target.
93608c2ecf20Sopenharmony_ci **/
93618c2ecf20Sopenharmony_cistatic int qla4xxx_eh_target_reset(struct scsi_cmnd *cmd)
93628c2ecf20Sopenharmony_ci{
93638c2ecf20Sopenharmony_ci	struct scsi_qla_host *ha = to_qla_host(cmd->device->host);
93648c2ecf20Sopenharmony_ci	struct ddb_entry *ddb_entry = cmd->device->hostdata;
93658c2ecf20Sopenharmony_ci	int stat, ret;
93668c2ecf20Sopenharmony_ci	int rval;
93678c2ecf20Sopenharmony_ci
93688c2ecf20Sopenharmony_ci	if (!ddb_entry)
93698c2ecf20Sopenharmony_ci		return FAILED;
93708c2ecf20Sopenharmony_ci
93718c2ecf20Sopenharmony_ci	ret = iscsi_block_scsi_eh(cmd);
93728c2ecf20Sopenharmony_ci	if (ret)
93738c2ecf20Sopenharmony_ci		return ret;
93748c2ecf20Sopenharmony_ci
93758c2ecf20Sopenharmony_ci	starget_printk(KERN_INFO, scsi_target(cmd->device),
93768c2ecf20Sopenharmony_ci		       "WARM TARGET RESET ISSUED.\n");
93778c2ecf20Sopenharmony_ci
93788c2ecf20Sopenharmony_ci	DEBUG2(printk(KERN_INFO
93798c2ecf20Sopenharmony_ci		      "scsi%ld: TARGET_DEVICE_RESET cmd=%p jiffies = 0x%lx, "
93808c2ecf20Sopenharmony_ci		      "to=%x,dpc_flags=%lx, status=%x allowed=%d\n",
93818c2ecf20Sopenharmony_ci		      ha->host_no, cmd, jiffies, cmd->request->timeout / HZ,
93828c2ecf20Sopenharmony_ci		      ha->dpc_flags, cmd->result, cmd->allowed));
93838c2ecf20Sopenharmony_ci
93848c2ecf20Sopenharmony_ci	rval = qla4xxx_isp_check_reg(ha);
93858c2ecf20Sopenharmony_ci	if (rval != QLA_SUCCESS) {
93868c2ecf20Sopenharmony_ci		ql4_printk(KERN_INFO, ha, "PCI/Register disconnect, exiting.\n");
93878c2ecf20Sopenharmony_ci		return FAILED;
93888c2ecf20Sopenharmony_ci	}
93898c2ecf20Sopenharmony_ci
93908c2ecf20Sopenharmony_ci	stat = qla4xxx_reset_target(ha, ddb_entry);
93918c2ecf20Sopenharmony_ci	if (stat != QLA_SUCCESS) {
93928c2ecf20Sopenharmony_ci		starget_printk(KERN_INFO, scsi_target(cmd->device),
93938c2ecf20Sopenharmony_ci			       "WARM TARGET RESET FAILED.\n");
93948c2ecf20Sopenharmony_ci		return FAILED;
93958c2ecf20Sopenharmony_ci	}
93968c2ecf20Sopenharmony_ci
93978c2ecf20Sopenharmony_ci	if (qla4xxx_eh_wait_for_commands(ha, scsi_target(cmd->device),
93988c2ecf20Sopenharmony_ci					 NULL)) {
93998c2ecf20Sopenharmony_ci		starget_printk(KERN_INFO, scsi_target(cmd->device),
94008c2ecf20Sopenharmony_ci			       "WARM TARGET DEVICE RESET FAILED - "
94018c2ecf20Sopenharmony_ci			       "waiting for commands.\n");
94028c2ecf20Sopenharmony_ci		return FAILED;
94038c2ecf20Sopenharmony_ci	}
94048c2ecf20Sopenharmony_ci
94058c2ecf20Sopenharmony_ci	/* Send marker. */
94068c2ecf20Sopenharmony_ci	if (qla4xxx_send_marker_iocb(ha, ddb_entry, cmd->device->lun,
94078c2ecf20Sopenharmony_ci		MM_TGT_WARM_RESET) != QLA_SUCCESS) {
94088c2ecf20Sopenharmony_ci		starget_printk(KERN_INFO, scsi_target(cmd->device),
94098c2ecf20Sopenharmony_ci			       "WARM TARGET DEVICE RESET FAILED - "
94108c2ecf20Sopenharmony_ci			       "marker iocb failed.\n");
94118c2ecf20Sopenharmony_ci		return FAILED;
94128c2ecf20Sopenharmony_ci	}
94138c2ecf20Sopenharmony_ci
94148c2ecf20Sopenharmony_ci	starget_printk(KERN_INFO, scsi_target(cmd->device),
94158c2ecf20Sopenharmony_ci		       "WARM TARGET RESET SUCCEEDED.\n");
94168c2ecf20Sopenharmony_ci	return SUCCESS;
94178c2ecf20Sopenharmony_ci}
94188c2ecf20Sopenharmony_ci
94198c2ecf20Sopenharmony_ci/**
94208c2ecf20Sopenharmony_ci * qla4xxx_is_eh_active - check if error handler is running
94218c2ecf20Sopenharmony_ci * @shost: Pointer to SCSI Host struct
94228c2ecf20Sopenharmony_ci *
94238c2ecf20Sopenharmony_ci * This routine finds that if reset host is called in EH
94248c2ecf20Sopenharmony_ci * scenario or from some application like sg_reset
94258c2ecf20Sopenharmony_ci **/
94268c2ecf20Sopenharmony_cistatic int qla4xxx_is_eh_active(struct Scsi_Host *shost)
94278c2ecf20Sopenharmony_ci{
94288c2ecf20Sopenharmony_ci	if (shost->shost_state == SHOST_RECOVERY)
94298c2ecf20Sopenharmony_ci		return 1;
94308c2ecf20Sopenharmony_ci	return 0;
94318c2ecf20Sopenharmony_ci}
94328c2ecf20Sopenharmony_ci
94338c2ecf20Sopenharmony_ci/**
94348c2ecf20Sopenharmony_ci * qla4xxx_eh_host_reset - kernel callback
94358c2ecf20Sopenharmony_ci * @cmd: Pointer to Linux's SCSI command structure
94368c2ecf20Sopenharmony_ci *
94378c2ecf20Sopenharmony_ci * This routine is invoked by the Linux kernel to perform fatal error
94388c2ecf20Sopenharmony_ci * recovery on the specified adapter.
94398c2ecf20Sopenharmony_ci **/
94408c2ecf20Sopenharmony_cistatic int qla4xxx_eh_host_reset(struct scsi_cmnd *cmd)
94418c2ecf20Sopenharmony_ci{
94428c2ecf20Sopenharmony_ci	int return_status = FAILED;
94438c2ecf20Sopenharmony_ci	struct scsi_qla_host *ha;
94448c2ecf20Sopenharmony_ci	int rval;
94458c2ecf20Sopenharmony_ci
94468c2ecf20Sopenharmony_ci	ha = to_qla_host(cmd->device->host);
94478c2ecf20Sopenharmony_ci
94488c2ecf20Sopenharmony_ci	rval = qla4xxx_isp_check_reg(ha);
94498c2ecf20Sopenharmony_ci	if (rval != QLA_SUCCESS) {
94508c2ecf20Sopenharmony_ci		ql4_printk(KERN_INFO, ha, "PCI/Register disconnect, exiting.\n");
94518c2ecf20Sopenharmony_ci		return FAILED;
94528c2ecf20Sopenharmony_ci	}
94538c2ecf20Sopenharmony_ci
94548c2ecf20Sopenharmony_ci	if ((is_qla8032(ha) || is_qla8042(ha)) && ql4xdontresethba)
94558c2ecf20Sopenharmony_ci		qla4_83xx_set_idc_dontreset(ha);
94568c2ecf20Sopenharmony_ci
94578c2ecf20Sopenharmony_ci	/*
94588c2ecf20Sopenharmony_ci	 * For ISP8324 and ISP8042, if IDC_CTRL DONTRESET_BIT0 is set by other
94598c2ecf20Sopenharmony_ci	 * protocol drivers, we should not set device_state to NEED_RESET
94608c2ecf20Sopenharmony_ci	 */
94618c2ecf20Sopenharmony_ci	if (ql4xdontresethba ||
94628c2ecf20Sopenharmony_ci	    ((is_qla8032(ha) || is_qla8042(ha)) &&
94638c2ecf20Sopenharmony_ci	     qla4_83xx_idc_dontreset(ha))) {
94648c2ecf20Sopenharmony_ci		DEBUG2(printk("scsi%ld: %s: Don't Reset HBA\n",
94658c2ecf20Sopenharmony_ci		     ha->host_no, __func__));
94668c2ecf20Sopenharmony_ci
94678c2ecf20Sopenharmony_ci		/* Clear outstanding srb in queues */
94688c2ecf20Sopenharmony_ci		if (qla4xxx_is_eh_active(cmd->device->host))
94698c2ecf20Sopenharmony_ci			qla4xxx_abort_active_cmds(ha, DID_ABORT << 16);
94708c2ecf20Sopenharmony_ci
94718c2ecf20Sopenharmony_ci		return FAILED;
94728c2ecf20Sopenharmony_ci	}
94738c2ecf20Sopenharmony_ci
94748c2ecf20Sopenharmony_ci	ql4_printk(KERN_INFO, ha,
94758c2ecf20Sopenharmony_ci		   "scsi(%ld:%d:%d:%llu): HOST RESET ISSUED.\n", ha->host_no,
94768c2ecf20Sopenharmony_ci		   cmd->device->channel, cmd->device->id, cmd->device->lun);
94778c2ecf20Sopenharmony_ci
94788c2ecf20Sopenharmony_ci	if (qla4xxx_wait_for_hba_online(ha) != QLA_SUCCESS) {
94798c2ecf20Sopenharmony_ci		DEBUG2(printk("scsi%ld:%d: %s: Unable to reset host.  Adapter "
94808c2ecf20Sopenharmony_ci			      "DEAD.\n", ha->host_no, cmd->device->channel,
94818c2ecf20Sopenharmony_ci			      __func__));
94828c2ecf20Sopenharmony_ci
94838c2ecf20Sopenharmony_ci		return FAILED;
94848c2ecf20Sopenharmony_ci	}
94858c2ecf20Sopenharmony_ci
94868c2ecf20Sopenharmony_ci	if (!test_bit(DPC_RESET_HA, &ha->dpc_flags)) {
94878c2ecf20Sopenharmony_ci		if (is_qla80XX(ha))
94888c2ecf20Sopenharmony_ci			set_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags);
94898c2ecf20Sopenharmony_ci		else
94908c2ecf20Sopenharmony_ci			set_bit(DPC_RESET_HA, &ha->dpc_flags);
94918c2ecf20Sopenharmony_ci	}
94928c2ecf20Sopenharmony_ci
94938c2ecf20Sopenharmony_ci	if (qla4xxx_recover_adapter(ha) == QLA_SUCCESS)
94948c2ecf20Sopenharmony_ci		return_status = SUCCESS;
94958c2ecf20Sopenharmony_ci
94968c2ecf20Sopenharmony_ci	ql4_printk(KERN_INFO, ha, "HOST RESET %s.\n",
94978c2ecf20Sopenharmony_ci		   return_status == FAILED ? "FAILED" : "SUCCEEDED");
94988c2ecf20Sopenharmony_ci
94998c2ecf20Sopenharmony_ci	return return_status;
95008c2ecf20Sopenharmony_ci}
95018c2ecf20Sopenharmony_ci
95028c2ecf20Sopenharmony_cistatic int qla4xxx_context_reset(struct scsi_qla_host *ha)
95038c2ecf20Sopenharmony_ci{
95048c2ecf20Sopenharmony_ci	uint32_t mbox_cmd[MBOX_REG_COUNT];
95058c2ecf20Sopenharmony_ci	uint32_t mbox_sts[MBOX_REG_COUNT];
95068c2ecf20Sopenharmony_ci	struct addr_ctrl_blk_def *acb = NULL;
95078c2ecf20Sopenharmony_ci	uint32_t acb_len = sizeof(struct addr_ctrl_blk_def);
95088c2ecf20Sopenharmony_ci	int rval = QLA_SUCCESS;
95098c2ecf20Sopenharmony_ci	dma_addr_t acb_dma;
95108c2ecf20Sopenharmony_ci
95118c2ecf20Sopenharmony_ci	acb = dma_alloc_coherent(&ha->pdev->dev,
95128c2ecf20Sopenharmony_ci				 sizeof(struct addr_ctrl_blk_def),
95138c2ecf20Sopenharmony_ci				 &acb_dma, GFP_KERNEL);
95148c2ecf20Sopenharmony_ci	if (!acb) {
95158c2ecf20Sopenharmony_ci		ql4_printk(KERN_ERR, ha, "%s: Unable to alloc acb\n",
95168c2ecf20Sopenharmony_ci			   __func__);
95178c2ecf20Sopenharmony_ci		rval = -ENOMEM;
95188c2ecf20Sopenharmony_ci		goto exit_port_reset;
95198c2ecf20Sopenharmony_ci	}
95208c2ecf20Sopenharmony_ci
95218c2ecf20Sopenharmony_ci	memset(acb, 0, acb_len);
95228c2ecf20Sopenharmony_ci
95238c2ecf20Sopenharmony_ci	rval = qla4xxx_get_acb(ha, acb_dma, PRIMARI_ACB, acb_len);
95248c2ecf20Sopenharmony_ci	if (rval != QLA_SUCCESS) {
95258c2ecf20Sopenharmony_ci		rval = -EIO;
95268c2ecf20Sopenharmony_ci		goto exit_free_acb;
95278c2ecf20Sopenharmony_ci	}
95288c2ecf20Sopenharmony_ci
95298c2ecf20Sopenharmony_ci	rval = qla4xxx_disable_acb(ha);
95308c2ecf20Sopenharmony_ci	if (rval != QLA_SUCCESS) {
95318c2ecf20Sopenharmony_ci		rval = -EIO;
95328c2ecf20Sopenharmony_ci		goto exit_free_acb;
95338c2ecf20Sopenharmony_ci	}
95348c2ecf20Sopenharmony_ci
95358c2ecf20Sopenharmony_ci	wait_for_completion_timeout(&ha->disable_acb_comp,
95368c2ecf20Sopenharmony_ci				    DISABLE_ACB_TOV * HZ);
95378c2ecf20Sopenharmony_ci
95388c2ecf20Sopenharmony_ci	rval = qla4xxx_set_acb(ha, &mbox_cmd[0], &mbox_sts[0], acb_dma);
95398c2ecf20Sopenharmony_ci	if (rval != QLA_SUCCESS) {
95408c2ecf20Sopenharmony_ci		rval = -EIO;
95418c2ecf20Sopenharmony_ci		goto exit_free_acb;
95428c2ecf20Sopenharmony_ci	}
95438c2ecf20Sopenharmony_ci
95448c2ecf20Sopenharmony_ciexit_free_acb:
95458c2ecf20Sopenharmony_ci	dma_free_coherent(&ha->pdev->dev, sizeof(struct addr_ctrl_blk_def),
95468c2ecf20Sopenharmony_ci			  acb, acb_dma);
95478c2ecf20Sopenharmony_ciexit_port_reset:
95488c2ecf20Sopenharmony_ci	DEBUG2(ql4_printk(KERN_INFO, ha, "%s %s\n", __func__,
95498c2ecf20Sopenharmony_ci			  rval == QLA_SUCCESS ? "SUCCEEDED" : "FAILED"));
95508c2ecf20Sopenharmony_ci	return rval;
95518c2ecf20Sopenharmony_ci}
95528c2ecf20Sopenharmony_ci
95538c2ecf20Sopenharmony_cistatic int qla4xxx_host_reset(struct Scsi_Host *shost, int reset_type)
95548c2ecf20Sopenharmony_ci{
95558c2ecf20Sopenharmony_ci	struct scsi_qla_host *ha = to_qla_host(shost);
95568c2ecf20Sopenharmony_ci	int rval = QLA_SUCCESS;
95578c2ecf20Sopenharmony_ci	uint32_t idc_ctrl;
95588c2ecf20Sopenharmony_ci
95598c2ecf20Sopenharmony_ci	if (ql4xdontresethba) {
95608c2ecf20Sopenharmony_ci		DEBUG2(ql4_printk(KERN_INFO, ha, "%s: Don't Reset HBA\n",
95618c2ecf20Sopenharmony_ci				  __func__));
95628c2ecf20Sopenharmony_ci		rval = -EPERM;
95638c2ecf20Sopenharmony_ci		goto exit_host_reset;
95648c2ecf20Sopenharmony_ci	}
95658c2ecf20Sopenharmony_ci
95668c2ecf20Sopenharmony_ci	if (test_bit(DPC_RESET_HA, &ha->dpc_flags))
95678c2ecf20Sopenharmony_ci		goto recover_adapter;
95688c2ecf20Sopenharmony_ci
95698c2ecf20Sopenharmony_ci	switch (reset_type) {
95708c2ecf20Sopenharmony_ci	case SCSI_ADAPTER_RESET:
95718c2ecf20Sopenharmony_ci		set_bit(DPC_RESET_HA, &ha->dpc_flags);
95728c2ecf20Sopenharmony_ci		break;
95738c2ecf20Sopenharmony_ci	case SCSI_FIRMWARE_RESET:
95748c2ecf20Sopenharmony_ci		if (!test_bit(DPC_RESET_HA, &ha->dpc_flags)) {
95758c2ecf20Sopenharmony_ci			if (is_qla80XX(ha))
95768c2ecf20Sopenharmony_ci				/* set firmware context reset */
95778c2ecf20Sopenharmony_ci				set_bit(DPC_RESET_HA_FW_CONTEXT,
95788c2ecf20Sopenharmony_ci					&ha->dpc_flags);
95798c2ecf20Sopenharmony_ci			else {
95808c2ecf20Sopenharmony_ci				rval = qla4xxx_context_reset(ha);
95818c2ecf20Sopenharmony_ci				goto exit_host_reset;
95828c2ecf20Sopenharmony_ci			}
95838c2ecf20Sopenharmony_ci		}
95848c2ecf20Sopenharmony_ci		break;
95858c2ecf20Sopenharmony_ci	}
95868c2ecf20Sopenharmony_ci
95878c2ecf20Sopenharmony_cirecover_adapter:
95888c2ecf20Sopenharmony_ci	/* For ISP8324 and ISP8042 set graceful reset bit in IDC_DRV_CTRL if
95898c2ecf20Sopenharmony_ci	 * reset is issued by application */
95908c2ecf20Sopenharmony_ci	if ((is_qla8032(ha) || is_qla8042(ha)) &&
95918c2ecf20Sopenharmony_ci	    test_bit(DPC_RESET_HA, &ha->dpc_flags)) {
95928c2ecf20Sopenharmony_ci		idc_ctrl = qla4_83xx_rd_reg(ha, QLA83XX_IDC_DRV_CTRL);
95938c2ecf20Sopenharmony_ci		qla4_83xx_wr_reg(ha, QLA83XX_IDC_DRV_CTRL,
95948c2ecf20Sopenharmony_ci				 (idc_ctrl | GRACEFUL_RESET_BIT1));
95958c2ecf20Sopenharmony_ci	}
95968c2ecf20Sopenharmony_ci
95978c2ecf20Sopenharmony_ci	rval = qla4xxx_recover_adapter(ha);
95988c2ecf20Sopenharmony_ci	if (rval != QLA_SUCCESS) {
95998c2ecf20Sopenharmony_ci		DEBUG2(ql4_printk(KERN_INFO, ha, "%s: recover adapter fail\n",
96008c2ecf20Sopenharmony_ci				  __func__));
96018c2ecf20Sopenharmony_ci		rval = -EIO;
96028c2ecf20Sopenharmony_ci	}
96038c2ecf20Sopenharmony_ci
96048c2ecf20Sopenharmony_ciexit_host_reset:
96058c2ecf20Sopenharmony_ci	return rval;
96068c2ecf20Sopenharmony_ci}
96078c2ecf20Sopenharmony_ci
96088c2ecf20Sopenharmony_ci/* PCI AER driver recovers from all correctable errors w/o
96098c2ecf20Sopenharmony_ci * driver intervention. For uncorrectable errors PCI AER
96108c2ecf20Sopenharmony_ci * driver calls the following device driver's callbacks
96118c2ecf20Sopenharmony_ci *
96128c2ecf20Sopenharmony_ci * - Fatal Errors - link_reset
96138c2ecf20Sopenharmony_ci * - Non-Fatal Errors - driver's error_detected() which
96148c2ecf20Sopenharmony_ci * returns CAN_RECOVER, NEED_RESET or DISCONNECT.
96158c2ecf20Sopenharmony_ci *
96168c2ecf20Sopenharmony_ci * PCI AER driver calls
96178c2ecf20Sopenharmony_ci * CAN_RECOVER - driver's mmio_enabled(), mmio_enabled()
96188c2ecf20Sopenharmony_ci *               returns RECOVERED or NEED_RESET if fw_hung
96198c2ecf20Sopenharmony_ci * NEED_RESET - driver's slot_reset()
96208c2ecf20Sopenharmony_ci * DISCONNECT - device is dead & cannot recover
96218c2ecf20Sopenharmony_ci * RECOVERED - driver's resume()
96228c2ecf20Sopenharmony_ci */
96238c2ecf20Sopenharmony_cistatic pci_ers_result_t
96248c2ecf20Sopenharmony_ciqla4xxx_pci_error_detected(struct pci_dev *pdev, pci_channel_state_t state)
96258c2ecf20Sopenharmony_ci{
96268c2ecf20Sopenharmony_ci	struct scsi_qla_host *ha = pci_get_drvdata(pdev);
96278c2ecf20Sopenharmony_ci
96288c2ecf20Sopenharmony_ci	ql4_printk(KERN_WARNING, ha, "scsi%ld: %s: error detected:state %x\n",
96298c2ecf20Sopenharmony_ci	    ha->host_no, __func__, state);
96308c2ecf20Sopenharmony_ci
96318c2ecf20Sopenharmony_ci	if (!is_aer_supported(ha))
96328c2ecf20Sopenharmony_ci		return PCI_ERS_RESULT_NONE;
96338c2ecf20Sopenharmony_ci
96348c2ecf20Sopenharmony_ci	switch (state) {
96358c2ecf20Sopenharmony_ci	case pci_channel_io_normal:
96368c2ecf20Sopenharmony_ci		clear_bit(AF_EEH_BUSY, &ha->flags);
96378c2ecf20Sopenharmony_ci		return PCI_ERS_RESULT_CAN_RECOVER;
96388c2ecf20Sopenharmony_ci	case pci_channel_io_frozen:
96398c2ecf20Sopenharmony_ci		set_bit(AF_EEH_BUSY, &ha->flags);
96408c2ecf20Sopenharmony_ci		qla4xxx_mailbox_premature_completion(ha);
96418c2ecf20Sopenharmony_ci		qla4xxx_free_irqs(ha);
96428c2ecf20Sopenharmony_ci		pci_disable_device(pdev);
96438c2ecf20Sopenharmony_ci		/* Return back all IOs */
96448c2ecf20Sopenharmony_ci		qla4xxx_abort_active_cmds(ha, DID_RESET << 16);
96458c2ecf20Sopenharmony_ci		return PCI_ERS_RESULT_NEED_RESET;
96468c2ecf20Sopenharmony_ci	case pci_channel_io_perm_failure:
96478c2ecf20Sopenharmony_ci		set_bit(AF_EEH_BUSY, &ha->flags);
96488c2ecf20Sopenharmony_ci		set_bit(AF_PCI_CHANNEL_IO_PERM_FAILURE, &ha->flags);
96498c2ecf20Sopenharmony_ci		qla4xxx_abort_active_cmds(ha, DID_NO_CONNECT << 16);
96508c2ecf20Sopenharmony_ci		return PCI_ERS_RESULT_DISCONNECT;
96518c2ecf20Sopenharmony_ci	}
96528c2ecf20Sopenharmony_ci	return PCI_ERS_RESULT_NEED_RESET;
96538c2ecf20Sopenharmony_ci}
96548c2ecf20Sopenharmony_ci
96558c2ecf20Sopenharmony_ci/**
96568c2ecf20Sopenharmony_ci * qla4xxx_pci_mmio_enabled() gets called if
96578c2ecf20Sopenharmony_ci * qla4xxx_pci_error_detected() returns PCI_ERS_RESULT_CAN_RECOVER
96588c2ecf20Sopenharmony_ci * and read/write to the device still works.
96598c2ecf20Sopenharmony_ci * @pdev: PCI device pointer
96608c2ecf20Sopenharmony_ci **/
96618c2ecf20Sopenharmony_cistatic pci_ers_result_t
96628c2ecf20Sopenharmony_ciqla4xxx_pci_mmio_enabled(struct pci_dev *pdev)
96638c2ecf20Sopenharmony_ci{
96648c2ecf20Sopenharmony_ci	struct scsi_qla_host *ha = pci_get_drvdata(pdev);
96658c2ecf20Sopenharmony_ci
96668c2ecf20Sopenharmony_ci	if (!is_aer_supported(ha))
96678c2ecf20Sopenharmony_ci		return PCI_ERS_RESULT_NONE;
96688c2ecf20Sopenharmony_ci
96698c2ecf20Sopenharmony_ci	return PCI_ERS_RESULT_RECOVERED;
96708c2ecf20Sopenharmony_ci}
96718c2ecf20Sopenharmony_ci
96728c2ecf20Sopenharmony_cistatic uint32_t qla4_8xxx_error_recovery(struct scsi_qla_host *ha)
96738c2ecf20Sopenharmony_ci{
96748c2ecf20Sopenharmony_ci	uint32_t rval = QLA_ERROR;
96758c2ecf20Sopenharmony_ci	int fn;
96768c2ecf20Sopenharmony_ci	struct pci_dev *other_pdev = NULL;
96778c2ecf20Sopenharmony_ci
96788c2ecf20Sopenharmony_ci	ql4_printk(KERN_WARNING, ha, "scsi%ld: In %s\n", ha->host_no, __func__);
96798c2ecf20Sopenharmony_ci
96808c2ecf20Sopenharmony_ci	set_bit(DPC_RESET_ACTIVE, &ha->dpc_flags);
96818c2ecf20Sopenharmony_ci
96828c2ecf20Sopenharmony_ci	if (test_bit(AF_ONLINE, &ha->flags)) {
96838c2ecf20Sopenharmony_ci		clear_bit(AF_ONLINE, &ha->flags);
96848c2ecf20Sopenharmony_ci		clear_bit(AF_LINK_UP, &ha->flags);
96858c2ecf20Sopenharmony_ci		iscsi_host_for_each_session(ha->host, qla4xxx_fail_session);
96868c2ecf20Sopenharmony_ci		qla4xxx_process_aen(ha, FLUSH_DDB_CHANGED_AENS);
96878c2ecf20Sopenharmony_ci	}
96888c2ecf20Sopenharmony_ci
96898c2ecf20Sopenharmony_ci	fn = PCI_FUNC(ha->pdev->devfn);
96908c2ecf20Sopenharmony_ci	if (is_qla8022(ha)) {
96918c2ecf20Sopenharmony_ci		while (fn > 0) {
96928c2ecf20Sopenharmony_ci			fn--;
96938c2ecf20Sopenharmony_ci			ql4_printk(KERN_INFO, ha, "scsi%ld: %s: Finding PCI device at func %x\n",
96948c2ecf20Sopenharmony_ci				   ha->host_no, __func__, fn);
96958c2ecf20Sopenharmony_ci			/* Get the pci device given the domain, bus,
96968c2ecf20Sopenharmony_ci			 * slot/function number */
96978c2ecf20Sopenharmony_ci			other_pdev = pci_get_domain_bus_and_slot(
96988c2ecf20Sopenharmony_ci					   pci_domain_nr(ha->pdev->bus),
96998c2ecf20Sopenharmony_ci					   ha->pdev->bus->number,
97008c2ecf20Sopenharmony_ci					   PCI_DEVFN(PCI_SLOT(ha->pdev->devfn),
97018c2ecf20Sopenharmony_ci					   fn));
97028c2ecf20Sopenharmony_ci
97038c2ecf20Sopenharmony_ci			if (!other_pdev)
97048c2ecf20Sopenharmony_ci				continue;
97058c2ecf20Sopenharmony_ci
97068c2ecf20Sopenharmony_ci			if (atomic_read(&other_pdev->enable_cnt)) {
97078c2ecf20Sopenharmony_ci				ql4_printk(KERN_INFO, ha, "scsi%ld: %s: Found PCI func in enabled state%x\n",
97088c2ecf20Sopenharmony_ci					   ha->host_no, __func__, fn);
97098c2ecf20Sopenharmony_ci				pci_dev_put(other_pdev);
97108c2ecf20Sopenharmony_ci				break;
97118c2ecf20Sopenharmony_ci			}
97128c2ecf20Sopenharmony_ci			pci_dev_put(other_pdev);
97138c2ecf20Sopenharmony_ci		}
97148c2ecf20Sopenharmony_ci	} else {
97158c2ecf20Sopenharmony_ci		/* this case is meant for ISP83xx/ISP84xx only */
97168c2ecf20Sopenharmony_ci		if (qla4_83xx_can_perform_reset(ha)) {
97178c2ecf20Sopenharmony_ci			/* reset fn as iSCSI is going to perform the reset */
97188c2ecf20Sopenharmony_ci			fn = 0;
97198c2ecf20Sopenharmony_ci		}
97208c2ecf20Sopenharmony_ci	}
97218c2ecf20Sopenharmony_ci
97228c2ecf20Sopenharmony_ci	/* The first function on the card, the reset owner will
97238c2ecf20Sopenharmony_ci	 * start & initialize the firmware. The other functions
97248c2ecf20Sopenharmony_ci	 * on the card will reset the firmware context
97258c2ecf20Sopenharmony_ci	 */
97268c2ecf20Sopenharmony_ci	if (!fn) {
97278c2ecf20Sopenharmony_ci		ql4_printk(KERN_INFO, ha, "scsi%ld: %s: devfn being reset "
97288c2ecf20Sopenharmony_ci		    "0x%x is the owner\n", ha->host_no, __func__,
97298c2ecf20Sopenharmony_ci		    ha->pdev->devfn);
97308c2ecf20Sopenharmony_ci
97318c2ecf20Sopenharmony_ci		ha->isp_ops->idc_lock(ha);
97328c2ecf20Sopenharmony_ci		qla4_8xxx_wr_direct(ha, QLA8XXX_CRB_DEV_STATE,
97338c2ecf20Sopenharmony_ci				    QLA8XXX_DEV_COLD);
97348c2ecf20Sopenharmony_ci		ha->isp_ops->idc_unlock(ha);
97358c2ecf20Sopenharmony_ci
97368c2ecf20Sopenharmony_ci		rval = qla4_8xxx_update_idc_reg(ha);
97378c2ecf20Sopenharmony_ci		if (rval == QLA_ERROR) {
97388c2ecf20Sopenharmony_ci			ql4_printk(KERN_INFO, ha, "scsi%ld: %s: HW State: FAILED\n",
97398c2ecf20Sopenharmony_ci				   ha->host_no, __func__);
97408c2ecf20Sopenharmony_ci			ha->isp_ops->idc_lock(ha);
97418c2ecf20Sopenharmony_ci			qla4_8xxx_wr_direct(ha, QLA8XXX_CRB_DEV_STATE,
97428c2ecf20Sopenharmony_ci					    QLA8XXX_DEV_FAILED);
97438c2ecf20Sopenharmony_ci			ha->isp_ops->idc_unlock(ha);
97448c2ecf20Sopenharmony_ci			goto exit_error_recovery;
97458c2ecf20Sopenharmony_ci		}
97468c2ecf20Sopenharmony_ci
97478c2ecf20Sopenharmony_ci		clear_bit(AF_FW_RECOVERY, &ha->flags);
97488c2ecf20Sopenharmony_ci		rval = qla4xxx_initialize_adapter(ha, RESET_ADAPTER);
97498c2ecf20Sopenharmony_ci
97508c2ecf20Sopenharmony_ci		if (rval != QLA_SUCCESS) {
97518c2ecf20Sopenharmony_ci			ql4_printk(KERN_INFO, ha, "scsi%ld: %s: HW State: "
97528c2ecf20Sopenharmony_ci			    "FAILED\n", ha->host_no, __func__);
97538c2ecf20Sopenharmony_ci			qla4xxx_free_irqs(ha);
97548c2ecf20Sopenharmony_ci			ha->isp_ops->idc_lock(ha);
97558c2ecf20Sopenharmony_ci			qla4_8xxx_clear_drv_active(ha);
97568c2ecf20Sopenharmony_ci			qla4_8xxx_wr_direct(ha, QLA8XXX_CRB_DEV_STATE,
97578c2ecf20Sopenharmony_ci					    QLA8XXX_DEV_FAILED);
97588c2ecf20Sopenharmony_ci			ha->isp_ops->idc_unlock(ha);
97598c2ecf20Sopenharmony_ci		} else {
97608c2ecf20Sopenharmony_ci			ql4_printk(KERN_INFO, ha, "scsi%ld: %s: HW State: "
97618c2ecf20Sopenharmony_ci			    "READY\n", ha->host_no, __func__);
97628c2ecf20Sopenharmony_ci			ha->isp_ops->idc_lock(ha);
97638c2ecf20Sopenharmony_ci			qla4_8xxx_wr_direct(ha, QLA8XXX_CRB_DEV_STATE,
97648c2ecf20Sopenharmony_ci					    QLA8XXX_DEV_READY);
97658c2ecf20Sopenharmony_ci			/* Clear driver state register */
97668c2ecf20Sopenharmony_ci			qla4_8xxx_wr_direct(ha, QLA8XXX_CRB_DRV_STATE, 0);
97678c2ecf20Sopenharmony_ci			qla4_8xxx_set_drv_active(ha);
97688c2ecf20Sopenharmony_ci			ha->isp_ops->idc_unlock(ha);
97698c2ecf20Sopenharmony_ci			ha->isp_ops->enable_intrs(ha);
97708c2ecf20Sopenharmony_ci		}
97718c2ecf20Sopenharmony_ci	} else {
97728c2ecf20Sopenharmony_ci		ql4_printk(KERN_INFO, ha, "scsi%ld: %s: devfn 0x%x is not "
97738c2ecf20Sopenharmony_ci		    "the reset owner\n", ha->host_no, __func__,
97748c2ecf20Sopenharmony_ci		    ha->pdev->devfn);
97758c2ecf20Sopenharmony_ci		if ((qla4_8xxx_rd_direct(ha, QLA8XXX_CRB_DEV_STATE) ==
97768c2ecf20Sopenharmony_ci		     QLA8XXX_DEV_READY)) {
97778c2ecf20Sopenharmony_ci			clear_bit(AF_FW_RECOVERY, &ha->flags);
97788c2ecf20Sopenharmony_ci			rval = qla4xxx_initialize_adapter(ha, RESET_ADAPTER);
97798c2ecf20Sopenharmony_ci			if (rval == QLA_SUCCESS)
97808c2ecf20Sopenharmony_ci				ha->isp_ops->enable_intrs(ha);
97818c2ecf20Sopenharmony_ci			else
97828c2ecf20Sopenharmony_ci				qla4xxx_free_irqs(ha);
97838c2ecf20Sopenharmony_ci
97848c2ecf20Sopenharmony_ci			ha->isp_ops->idc_lock(ha);
97858c2ecf20Sopenharmony_ci			qla4_8xxx_set_drv_active(ha);
97868c2ecf20Sopenharmony_ci			ha->isp_ops->idc_unlock(ha);
97878c2ecf20Sopenharmony_ci		}
97888c2ecf20Sopenharmony_ci	}
97898c2ecf20Sopenharmony_ciexit_error_recovery:
97908c2ecf20Sopenharmony_ci	clear_bit(DPC_RESET_ACTIVE, &ha->dpc_flags);
97918c2ecf20Sopenharmony_ci	return rval;
97928c2ecf20Sopenharmony_ci}
97938c2ecf20Sopenharmony_ci
97948c2ecf20Sopenharmony_cistatic pci_ers_result_t
97958c2ecf20Sopenharmony_ciqla4xxx_pci_slot_reset(struct pci_dev *pdev)
97968c2ecf20Sopenharmony_ci{
97978c2ecf20Sopenharmony_ci	pci_ers_result_t ret = PCI_ERS_RESULT_DISCONNECT;
97988c2ecf20Sopenharmony_ci	struct scsi_qla_host *ha = pci_get_drvdata(pdev);
97998c2ecf20Sopenharmony_ci	int rc;
98008c2ecf20Sopenharmony_ci
98018c2ecf20Sopenharmony_ci	ql4_printk(KERN_WARNING, ha, "scsi%ld: %s: slot_reset\n",
98028c2ecf20Sopenharmony_ci	    ha->host_no, __func__);
98038c2ecf20Sopenharmony_ci
98048c2ecf20Sopenharmony_ci	if (!is_aer_supported(ha))
98058c2ecf20Sopenharmony_ci		return PCI_ERS_RESULT_NONE;
98068c2ecf20Sopenharmony_ci
98078c2ecf20Sopenharmony_ci	/* Restore the saved state of PCIe device -
98088c2ecf20Sopenharmony_ci	 * BAR registers, PCI Config space, PCIX, MSI,
98098c2ecf20Sopenharmony_ci	 * IOV states
98108c2ecf20Sopenharmony_ci	 */
98118c2ecf20Sopenharmony_ci	pci_restore_state(pdev);
98128c2ecf20Sopenharmony_ci
98138c2ecf20Sopenharmony_ci	/* pci_restore_state() clears the saved_state flag of the device
98148c2ecf20Sopenharmony_ci	 * save restored state which resets saved_state flag
98158c2ecf20Sopenharmony_ci	 */
98168c2ecf20Sopenharmony_ci	pci_save_state(pdev);
98178c2ecf20Sopenharmony_ci
98188c2ecf20Sopenharmony_ci	/* Initialize device or resume if in suspended state */
98198c2ecf20Sopenharmony_ci	rc = pci_enable_device(pdev);
98208c2ecf20Sopenharmony_ci	if (rc) {
98218c2ecf20Sopenharmony_ci		ql4_printk(KERN_WARNING, ha, "scsi%ld: %s: Can't re-enable "
98228c2ecf20Sopenharmony_ci		    "device after reset\n", ha->host_no, __func__);
98238c2ecf20Sopenharmony_ci		goto exit_slot_reset;
98248c2ecf20Sopenharmony_ci	}
98258c2ecf20Sopenharmony_ci
98268c2ecf20Sopenharmony_ci	ha->isp_ops->disable_intrs(ha);
98278c2ecf20Sopenharmony_ci
98288c2ecf20Sopenharmony_ci	if (is_qla80XX(ha)) {
98298c2ecf20Sopenharmony_ci		if (qla4_8xxx_error_recovery(ha) == QLA_SUCCESS) {
98308c2ecf20Sopenharmony_ci			ret = PCI_ERS_RESULT_RECOVERED;
98318c2ecf20Sopenharmony_ci			goto exit_slot_reset;
98328c2ecf20Sopenharmony_ci		} else
98338c2ecf20Sopenharmony_ci			goto exit_slot_reset;
98348c2ecf20Sopenharmony_ci	}
98358c2ecf20Sopenharmony_ci
98368c2ecf20Sopenharmony_ciexit_slot_reset:
98378c2ecf20Sopenharmony_ci	ql4_printk(KERN_WARNING, ha, "scsi%ld: %s: Return=%x\n"
98388c2ecf20Sopenharmony_ci	    "device after reset\n", ha->host_no, __func__, ret);
98398c2ecf20Sopenharmony_ci	return ret;
98408c2ecf20Sopenharmony_ci}
98418c2ecf20Sopenharmony_ci
98428c2ecf20Sopenharmony_cistatic void
98438c2ecf20Sopenharmony_ciqla4xxx_pci_resume(struct pci_dev *pdev)
98448c2ecf20Sopenharmony_ci{
98458c2ecf20Sopenharmony_ci	struct scsi_qla_host *ha = pci_get_drvdata(pdev);
98468c2ecf20Sopenharmony_ci	int ret;
98478c2ecf20Sopenharmony_ci
98488c2ecf20Sopenharmony_ci	ql4_printk(KERN_WARNING, ha, "scsi%ld: %s: pci_resume\n",
98498c2ecf20Sopenharmony_ci	    ha->host_no, __func__);
98508c2ecf20Sopenharmony_ci
98518c2ecf20Sopenharmony_ci	ret = qla4xxx_wait_for_hba_online(ha);
98528c2ecf20Sopenharmony_ci	if (ret != QLA_SUCCESS) {
98538c2ecf20Sopenharmony_ci		ql4_printk(KERN_ERR, ha, "scsi%ld: %s: the device failed to "
98548c2ecf20Sopenharmony_ci		    "resume I/O from slot/link_reset\n", ha->host_no,
98558c2ecf20Sopenharmony_ci		     __func__);
98568c2ecf20Sopenharmony_ci	}
98578c2ecf20Sopenharmony_ci
98588c2ecf20Sopenharmony_ci	clear_bit(AF_EEH_BUSY, &ha->flags);
98598c2ecf20Sopenharmony_ci}
98608c2ecf20Sopenharmony_ci
98618c2ecf20Sopenharmony_cistatic const struct pci_error_handlers qla4xxx_err_handler = {
98628c2ecf20Sopenharmony_ci	.error_detected = qla4xxx_pci_error_detected,
98638c2ecf20Sopenharmony_ci	.mmio_enabled = qla4xxx_pci_mmio_enabled,
98648c2ecf20Sopenharmony_ci	.slot_reset = qla4xxx_pci_slot_reset,
98658c2ecf20Sopenharmony_ci	.resume = qla4xxx_pci_resume,
98668c2ecf20Sopenharmony_ci};
98678c2ecf20Sopenharmony_ci
98688c2ecf20Sopenharmony_cistatic struct pci_device_id qla4xxx_pci_tbl[] = {
98698c2ecf20Sopenharmony_ci	{
98708c2ecf20Sopenharmony_ci		.vendor		= PCI_VENDOR_ID_QLOGIC,
98718c2ecf20Sopenharmony_ci		.device		= PCI_DEVICE_ID_QLOGIC_ISP4010,
98728c2ecf20Sopenharmony_ci		.subvendor	= PCI_ANY_ID,
98738c2ecf20Sopenharmony_ci		.subdevice	= PCI_ANY_ID,
98748c2ecf20Sopenharmony_ci	},
98758c2ecf20Sopenharmony_ci	{
98768c2ecf20Sopenharmony_ci		.vendor		= PCI_VENDOR_ID_QLOGIC,
98778c2ecf20Sopenharmony_ci		.device		= PCI_DEVICE_ID_QLOGIC_ISP4022,
98788c2ecf20Sopenharmony_ci		.subvendor	= PCI_ANY_ID,
98798c2ecf20Sopenharmony_ci		.subdevice	= PCI_ANY_ID,
98808c2ecf20Sopenharmony_ci	},
98818c2ecf20Sopenharmony_ci	{
98828c2ecf20Sopenharmony_ci		.vendor		= PCI_VENDOR_ID_QLOGIC,
98838c2ecf20Sopenharmony_ci		.device		= PCI_DEVICE_ID_QLOGIC_ISP4032,
98848c2ecf20Sopenharmony_ci		.subvendor	= PCI_ANY_ID,
98858c2ecf20Sopenharmony_ci		.subdevice	= PCI_ANY_ID,
98868c2ecf20Sopenharmony_ci	},
98878c2ecf20Sopenharmony_ci	{
98888c2ecf20Sopenharmony_ci		.vendor         = PCI_VENDOR_ID_QLOGIC,
98898c2ecf20Sopenharmony_ci		.device         = PCI_DEVICE_ID_QLOGIC_ISP8022,
98908c2ecf20Sopenharmony_ci		.subvendor      = PCI_ANY_ID,
98918c2ecf20Sopenharmony_ci		.subdevice      = PCI_ANY_ID,
98928c2ecf20Sopenharmony_ci	},
98938c2ecf20Sopenharmony_ci	{
98948c2ecf20Sopenharmony_ci		.vendor		= PCI_VENDOR_ID_QLOGIC,
98958c2ecf20Sopenharmony_ci		.device		= PCI_DEVICE_ID_QLOGIC_ISP8324,
98968c2ecf20Sopenharmony_ci		.subvendor	= PCI_ANY_ID,
98978c2ecf20Sopenharmony_ci		.subdevice	= PCI_ANY_ID,
98988c2ecf20Sopenharmony_ci	},
98998c2ecf20Sopenharmony_ci	{
99008c2ecf20Sopenharmony_ci		.vendor		= PCI_VENDOR_ID_QLOGIC,
99018c2ecf20Sopenharmony_ci		.device		= PCI_DEVICE_ID_QLOGIC_ISP8042,
99028c2ecf20Sopenharmony_ci		.subvendor	= PCI_ANY_ID,
99038c2ecf20Sopenharmony_ci		.subdevice	= PCI_ANY_ID,
99048c2ecf20Sopenharmony_ci	},
99058c2ecf20Sopenharmony_ci	{0, 0},
99068c2ecf20Sopenharmony_ci};
99078c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pci, qla4xxx_pci_tbl);
99088c2ecf20Sopenharmony_ci
99098c2ecf20Sopenharmony_cistatic struct pci_driver qla4xxx_pci_driver = {
99108c2ecf20Sopenharmony_ci	.name		= DRIVER_NAME,
99118c2ecf20Sopenharmony_ci	.id_table	= qla4xxx_pci_tbl,
99128c2ecf20Sopenharmony_ci	.probe		= qla4xxx_probe_adapter,
99138c2ecf20Sopenharmony_ci	.remove		= qla4xxx_remove_adapter,
99148c2ecf20Sopenharmony_ci	.err_handler = &qla4xxx_err_handler,
99158c2ecf20Sopenharmony_ci};
99168c2ecf20Sopenharmony_ci
99178c2ecf20Sopenharmony_cistatic int __init qla4xxx_module_init(void)
99188c2ecf20Sopenharmony_ci{
99198c2ecf20Sopenharmony_ci	int ret;
99208c2ecf20Sopenharmony_ci
99218c2ecf20Sopenharmony_ci	if (ql4xqfulltracking)
99228c2ecf20Sopenharmony_ci		qla4xxx_driver_template.track_queue_depth = 1;
99238c2ecf20Sopenharmony_ci
99248c2ecf20Sopenharmony_ci	/* Allocate cache for SRBs. */
99258c2ecf20Sopenharmony_ci	srb_cachep = kmem_cache_create("qla4xxx_srbs", sizeof(struct srb), 0,
99268c2ecf20Sopenharmony_ci				       SLAB_HWCACHE_ALIGN, NULL);
99278c2ecf20Sopenharmony_ci	if (srb_cachep == NULL) {
99288c2ecf20Sopenharmony_ci		printk(KERN_ERR
99298c2ecf20Sopenharmony_ci		       "%s: Unable to allocate SRB cache..."
99308c2ecf20Sopenharmony_ci		       "Failing load!\n", DRIVER_NAME);
99318c2ecf20Sopenharmony_ci		ret = -ENOMEM;
99328c2ecf20Sopenharmony_ci		goto no_srp_cache;
99338c2ecf20Sopenharmony_ci	}
99348c2ecf20Sopenharmony_ci
99358c2ecf20Sopenharmony_ci	/* Derive version string. */
99368c2ecf20Sopenharmony_ci	strcpy(qla4xxx_version_str, QLA4XXX_DRIVER_VERSION);
99378c2ecf20Sopenharmony_ci	if (ql4xextended_error_logging)
99388c2ecf20Sopenharmony_ci		strcat(qla4xxx_version_str, "-debug");
99398c2ecf20Sopenharmony_ci
99408c2ecf20Sopenharmony_ci	qla4xxx_scsi_transport =
99418c2ecf20Sopenharmony_ci		iscsi_register_transport(&qla4xxx_iscsi_transport);
99428c2ecf20Sopenharmony_ci	if (!qla4xxx_scsi_transport){
99438c2ecf20Sopenharmony_ci		ret = -ENODEV;
99448c2ecf20Sopenharmony_ci		goto release_srb_cache;
99458c2ecf20Sopenharmony_ci	}
99468c2ecf20Sopenharmony_ci
99478c2ecf20Sopenharmony_ci	ret = pci_register_driver(&qla4xxx_pci_driver);
99488c2ecf20Sopenharmony_ci	if (ret)
99498c2ecf20Sopenharmony_ci		goto unregister_transport;
99508c2ecf20Sopenharmony_ci
99518c2ecf20Sopenharmony_ci	printk(KERN_INFO "QLogic iSCSI HBA Driver\n");
99528c2ecf20Sopenharmony_ci	return 0;
99538c2ecf20Sopenharmony_ci
99548c2ecf20Sopenharmony_ciunregister_transport:
99558c2ecf20Sopenharmony_ci	iscsi_unregister_transport(&qla4xxx_iscsi_transport);
99568c2ecf20Sopenharmony_cirelease_srb_cache:
99578c2ecf20Sopenharmony_ci	kmem_cache_destroy(srb_cachep);
99588c2ecf20Sopenharmony_cino_srp_cache:
99598c2ecf20Sopenharmony_ci	return ret;
99608c2ecf20Sopenharmony_ci}
99618c2ecf20Sopenharmony_ci
99628c2ecf20Sopenharmony_cistatic void __exit qla4xxx_module_exit(void)
99638c2ecf20Sopenharmony_ci{
99648c2ecf20Sopenharmony_ci	pci_unregister_driver(&qla4xxx_pci_driver);
99658c2ecf20Sopenharmony_ci	iscsi_unregister_transport(&qla4xxx_iscsi_transport);
99668c2ecf20Sopenharmony_ci	kmem_cache_destroy(srb_cachep);
99678c2ecf20Sopenharmony_ci}
99688c2ecf20Sopenharmony_ci
99698c2ecf20Sopenharmony_cimodule_init(qla4xxx_module_init);
99708c2ecf20Sopenharmony_cimodule_exit(qla4xxx_module_exit);
99718c2ecf20Sopenharmony_ci
99728c2ecf20Sopenharmony_ciMODULE_AUTHOR("QLogic Corporation");
99738c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("QLogic iSCSI HBA Driver");
99748c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
99758c2ecf20Sopenharmony_ciMODULE_VERSION(QLA4XXX_DRIVER_VERSION);
9976