xref: /openbmc/linux/drivers/scsi/qla4xxx/ql4_os.c (revision df86f771)
1afaf5a2dSDavid Somayajulu /*
2afaf5a2dSDavid Somayajulu  * QLogic iSCSI HBA Driver
34a4f51e9SVikas Chaudhary  * Copyright (c)  2003-2013 QLogic Corporation
4afaf5a2dSDavid Somayajulu  *
5afaf5a2dSDavid Somayajulu  * See LICENSE.qla4xxx for copyright and licensing details.
6afaf5a2dSDavid Somayajulu  */
7afaf5a2dSDavid Somayajulu #include <linux/moduleparam.h>
85a0e3ad6STejun Heo #include <linux/slab.h>
92a991c21SManish Rangankar #include <linux/blkdev.h>
102a991c21SManish Rangankar #include <linux/iscsi_boot_sysfs.h>
1113483730SMike Christie #include <linux/inet.h>
12afaf5a2dSDavid Somayajulu 
13afaf5a2dSDavid Somayajulu #include <scsi/scsi_tcq.h>
14afaf5a2dSDavid Somayajulu #include <scsi/scsicam.h>
15afaf5a2dSDavid Somayajulu 
16afaf5a2dSDavid Somayajulu #include "ql4_def.h"
17bee4fe8eSDavid C Somayajulu #include "ql4_version.h"
18bee4fe8eSDavid C Somayajulu #include "ql4_glbl.h"
19bee4fe8eSDavid C Somayajulu #include "ql4_dbg.h"
20bee4fe8eSDavid C Somayajulu #include "ql4_inline.h"
216e7b4292SVikas Chaudhary #include "ql4_83xx.h"
22afaf5a2dSDavid Somayajulu 
23afaf5a2dSDavid Somayajulu /*
24afaf5a2dSDavid Somayajulu  * Driver version
25afaf5a2dSDavid Somayajulu  */
2647975477SAdrian Bunk static char qla4xxx_version_str[40];
27afaf5a2dSDavid Somayajulu 
28afaf5a2dSDavid Somayajulu /*
29afaf5a2dSDavid Somayajulu  * SRB allocation cache
30afaf5a2dSDavid Somayajulu  */
31e18b890bSChristoph Lameter static struct kmem_cache *srb_cachep;
32afaf5a2dSDavid Somayajulu 
33afaf5a2dSDavid Somayajulu /*
34afaf5a2dSDavid Somayajulu  * Module parameter information and variables
35afaf5a2dSDavid Somayajulu  */
36a7380a65SVikas Chaudhary static int ql4xdisablesysfsboot = 1;
3713483730SMike Christie module_param(ql4xdisablesysfsboot, int, S_IRUGO | S_IWUSR);
3813483730SMike Christie MODULE_PARM_DESC(ql4xdisablesysfsboot,
39a4e8a715SKaren Higgins 		 " Set to disable exporting boot targets to sysfs.\n"
40a4e8a715SKaren Higgins 		 "\t\t  0 - Export boot targets\n"
41a4e8a715SKaren Higgins 		 "\t\t  1 - Do not export boot targets (Default)");
4213483730SMike Christie 
433573bfb2SVikas Chaudhary int ql4xdontresethba;
44f4f5df23SVikas Chaudhary module_param(ql4xdontresethba, int, S_IRUGO | S_IWUSR);
45afaf5a2dSDavid Somayajulu MODULE_PARM_DESC(ql4xdontresethba,
46a4e8a715SKaren Higgins 		 " Don't reset the HBA for driver recovery.\n"
47a4e8a715SKaren Higgins 		 "\t\t  0 - It will reset HBA (Default)\n"
48a4e8a715SKaren Higgins 		 "\t\t  1 - It will NOT reset HBA");
49afaf5a2dSDavid Somayajulu 
50a4e8a715SKaren Higgins int ql4xextended_error_logging;
51f4f5df23SVikas Chaudhary module_param(ql4xextended_error_logging, int, S_IRUGO | S_IWUSR);
5211010fecSAndrew Vasquez MODULE_PARM_DESC(ql4xextended_error_logging,
53a4e8a715SKaren Higgins 		 " Option to enable extended error logging.\n"
54a4e8a715SKaren Higgins 		 "\t\t  0 - no logging (Default)\n"
55a4e8a715SKaren Higgins 		 "\t\t  2 - debug logging");
56afaf5a2dSDavid Somayajulu 
57f4f5df23SVikas Chaudhary int ql4xenablemsix = 1;
58f4f5df23SVikas Chaudhary module_param(ql4xenablemsix, int, S_IRUGO|S_IWUSR);
59f4f5df23SVikas Chaudhary MODULE_PARM_DESC(ql4xenablemsix,
60f4f5df23SVikas Chaudhary 		 " Set to enable MSI or MSI-X interrupt mechanism.\n"
61a4e8a715SKaren Higgins 		 "\t\t  0 = enable INTx interrupt mechanism.\n"
62a4e8a715SKaren Higgins 		 "\t\t  1 = enable MSI-X interrupt mechanism (Default).\n"
63a4e8a715SKaren Higgins 		 "\t\t  2 = enable MSI interrupt mechanism.");
64477ffb9dSDavid C Somayajulu 
65d510d965SMike Christie #define QL4_DEF_QDEPTH 32
668bb4033dSVikas Chaudhary static int ql4xmaxqdepth = QL4_DEF_QDEPTH;
678bb4033dSVikas Chaudhary module_param(ql4xmaxqdepth, int, S_IRUGO | S_IWUSR);
688bb4033dSVikas Chaudhary MODULE_PARM_DESC(ql4xmaxqdepth,
698bb4033dSVikas Chaudhary 		 " Maximum queue depth to report for target devices.\n"
70a4e8a715SKaren Higgins 		 "\t\t  Default: 32.");
71d510d965SMike Christie 
72f7b4aa63STej Parkash static int ql4xqfulltracking = 1;
73f7b4aa63STej Parkash module_param(ql4xqfulltracking, int, S_IRUGO | S_IWUSR);
74f7b4aa63STej Parkash MODULE_PARM_DESC(ql4xqfulltracking,
75f7b4aa63STej Parkash 		 " Enable or disable dynamic tracking and adjustment of\n"
76f7b4aa63STej Parkash 		 "\t\t scsi device queue depth.\n"
77f7b4aa63STej Parkash 		 "\t\t  0 - Disable.\n"
78f7b4aa63STej Parkash 		 "\t\t  1 - Enable. (Default)");
79f7b4aa63STej Parkash 
803038727cSVikas Chaudhary static int ql4xsess_recovery_tmo = QL4_SESS_RECOVERY_TMO;
813038727cSVikas Chaudhary module_param(ql4xsess_recovery_tmo, int, S_IRUGO);
823038727cSVikas Chaudhary MODULE_PARM_DESC(ql4xsess_recovery_tmo,
833038727cSVikas Chaudhary 		" Target Session Recovery Timeout.\n"
84a4e8a715SKaren Higgins 		"\t\t  Default: 120 sec.");
853038727cSVikas Chaudhary 
86068237c8STej Parkash int ql4xmdcapmask = 0x1F;
87068237c8STej Parkash module_param(ql4xmdcapmask, int, S_IRUGO);
88068237c8STej Parkash MODULE_PARM_DESC(ql4xmdcapmask,
89068237c8STej Parkash 		 " Set the Minidump driver capture mask level.\n"
90068237c8STej Parkash 		 "\t\t  Default is 0x1F.\n"
91068237c8STej Parkash 		 "\t\t  Can be set to 0x3, 0x7, 0xF, 0x1F, 0x3F, 0x7F");
92068237c8STej Parkash 
93068237c8STej Parkash int ql4xenablemd = 1;
94068237c8STej Parkash module_param(ql4xenablemd, int, S_IRUGO | S_IWUSR);
95068237c8STej Parkash MODULE_PARM_DESC(ql4xenablemd,
96068237c8STej Parkash 		 " Set to enable minidump.\n"
97068237c8STej Parkash 		 "\t\t  0 - disable minidump\n"
98068237c8STej Parkash 		 "\t\t  1 - enable minidump (Default)");
99068237c8STej Parkash 
100b3a271a9SManish Rangankar static int qla4xxx_wait_for_hba_online(struct scsi_qla_host *ha);
101afaf5a2dSDavid Somayajulu /*
102afaf5a2dSDavid Somayajulu  * SCSI host template entry points
103afaf5a2dSDavid Somayajulu  */
10447975477SAdrian Bunk static void qla4xxx_config_dma_addressing(struct scsi_qla_host *ha);
105afaf5a2dSDavid Somayajulu 
106afaf5a2dSDavid Somayajulu /*
107afaf5a2dSDavid Somayajulu  * iSCSI template entry points
108afaf5a2dSDavid Somayajulu  */
109fca9f04dSMike Christie static int qla4xxx_session_get_param(struct iscsi_cls_session *cls_sess,
110fca9f04dSMike Christie 				     enum iscsi_param param, char *buf);
111afaf5a2dSDavid Somayajulu static int qla4xxx_conn_get_param(struct iscsi_cls_conn *conn,
112afaf5a2dSDavid Somayajulu 				  enum iscsi_param param, char *buf);
113aa1e93a2SMike Christie static int qla4xxx_host_get_param(struct Scsi_Host *shost,
114aa1e93a2SMike Christie 				  enum iscsi_host_param param, char *buf);
11500c31889SMike Christie static int qla4xxx_iface_set_param(struct Scsi_Host *shost, void *data,
11600c31889SMike Christie 				   uint32_t len);
117ed1086e0SVikas Chaudhary static int qla4xxx_get_iface_param(struct iscsi_iface *iface,
118ed1086e0SVikas Chaudhary 				   enum iscsi_param_type param_type,
119ed1086e0SVikas Chaudhary 				   int param, char *buf);
1205c656af7SMike Christie static enum blk_eh_timer_return qla4xxx_eh_cmd_timed_out(struct scsi_cmnd *sc);
121b3a271a9SManish Rangankar static struct iscsi_endpoint *qla4xxx_ep_connect(struct Scsi_Host *shost,
122b3a271a9SManish Rangankar 						 struct sockaddr *dst_addr,
123b3a271a9SManish Rangankar 						 int non_blocking);
124b3a271a9SManish Rangankar static int qla4xxx_ep_poll(struct iscsi_endpoint *ep, int timeout_ms);
125b3a271a9SManish Rangankar static void qla4xxx_ep_disconnect(struct iscsi_endpoint *ep);
126b3a271a9SManish Rangankar static int qla4xxx_get_ep_param(struct iscsi_endpoint *ep,
127b3a271a9SManish Rangankar 				enum iscsi_param param, char *buf);
128b3a271a9SManish Rangankar static int qla4xxx_conn_start(struct iscsi_cls_conn *conn);
129b3a271a9SManish Rangankar static struct iscsi_cls_conn *
130b3a271a9SManish Rangankar qla4xxx_conn_create(struct iscsi_cls_session *cls_sess, uint32_t conn_idx);
131b3a271a9SManish Rangankar static int qla4xxx_conn_bind(struct iscsi_cls_session *cls_session,
132b3a271a9SManish Rangankar 			     struct iscsi_cls_conn *cls_conn,
133b3a271a9SManish Rangankar 			     uint64_t transport_fd, int is_leading);
134b3a271a9SManish Rangankar static void qla4xxx_conn_destroy(struct iscsi_cls_conn *conn);
135b3a271a9SManish Rangankar static struct iscsi_cls_session *
136b3a271a9SManish Rangankar qla4xxx_session_create(struct iscsi_endpoint *ep, uint16_t cmds_max,
137b3a271a9SManish Rangankar 			uint16_t qdepth, uint32_t initial_cmdsn);
138b3a271a9SManish Rangankar static void qla4xxx_session_destroy(struct iscsi_cls_session *sess);
139b3a271a9SManish Rangankar static void qla4xxx_task_work(struct work_struct *wdata);
140b3a271a9SManish Rangankar static int qla4xxx_alloc_pdu(struct iscsi_task *, uint8_t);
141b3a271a9SManish Rangankar static int qla4xxx_task_xmit(struct iscsi_task *);
142b3a271a9SManish Rangankar static void qla4xxx_task_cleanup(struct iscsi_task *);
143b3a271a9SManish Rangankar static void qla4xxx_fail_session(struct iscsi_cls_session *cls_session);
144b3a271a9SManish Rangankar static void qla4xxx_conn_get_stats(struct iscsi_cls_conn *cls_conn,
145b3a271a9SManish Rangankar 				   struct iscsi_stats *stats);
146c0b9d3f7SVikas Chaudhary static int qla4xxx_send_ping(struct Scsi_Host *shost, uint32_t iface_num,
147c0b9d3f7SVikas Chaudhary 			     uint32_t iface_type, uint32_t payload_size,
148c0b9d3f7SVikas Chaudhary 			     uint32_t pid, struct sockaddr *dst_addr);
149376738afSNilesh Javali static int qla4xxx_get_chap_list(struct Scsi_Host *shost, uint16_t chap_tbl_idx,
150376738afSNilesh Javali 				 uint32_t *num_entries, char *buf);
151376738afSNilesh Javali static int qla4xxx_delete_chap(struct Scsi_Host *shost, uint16_t chap_tbl_idx);
15226ffd7b4SAdheer Chandravanshi static int qla4xxx_set_chap_entry(struct Scsi_Host *shost, void  *data,
15326ffd7b4SAdheer Chandravanshi 				  int len);
154c0b9d3f7SVikas Chaudhary 
155afaf5a2dSDavid Somayajulu /*
156afaf5a2dSDavid Somayajulu  * SCSI host template entry points
157afaf5a2dSDavid Somayajulu  */
158f281233dSJeff Garzik static int qla4xxx_queuecommand(struct Scsi_Host *h, struct scsi_cmnd *cmd);
15909a0f719SVikas Chaudhary static int qla4xxx_eh_abort(struct scsi_cmnd *cmd);
160afaf5a2dSDavid Somayajulu static int qla4xxx_eh_device_reset(struct scsi_cmnd *cmd);
161ce545039SMike Christie static int qla4xxx_eh_target_reset(struct scsi_cmnd *cmd);
162afaf5a2dSDavid Somayajulu static int qla4xxx_eh_host_reset(struct scsi_cmnd *cmd);
163afaf5a2dSDavid Somayajulu static int qla4xxx_slave_alloc(struct scsi_device *device);
164afaf5a2dSDavid Somayajulu static int qla4xxx_slave_configure(struct scsi_device *device);
165afaf5a2dSDavid Somayajulu static void qla4xxx_slave_destroy(struct scsi_device *sdev);
1665e9bcec7SVikas Chaudhary static umode_t qla4_attr_is_visible(int param_type, int param);
16795d31262SVikas Chaudhary static int qla4xxx_host_reset(struct Scsi_Host *shost, int reset_type);
168f7b4aa63STej Parkash static int qla4xxx_change_queue_depth(struct scsi_device *sdev, int qdepth,
169f7b4aa63STej Parkash 				      int reason);
170afaf5a2dSDavid Somayajulu 
1711e9e2be3SAdheer Chandravanshi /*
1721e9e2be3SAdheer Chandravanshi  * iSCSI Flash DDB sysfs entry points
1731e9e2be3SAdheer Chandravanshi  */
1741e9e2be3SAdheer Chandravanshi static int
1751e9e2be3SAdheer Chandravanshi qla4xxx_sysfs_ddb_set_param(struct iscsi_bus_flash_session *fnode_sess,
1761e9e2be3SAdheer Chandravanshi 			    struct iscsi_bus_flash_conn *fnode_conn,
1771e9e2be3SAdheer Chandravanshi 			    void *data, int len);
1781e9e2be3SAdheer Chandravanshi static int
1791e9e2be3SAdheer Chandravanshi qla4xxx_sysfs_ddb_get_param(struct iscsi_bus_flash_session *fnode_sess,
1801e9e2be3SAdheer Chandravanshi 			    int param, char *buf);
1811e9e2be3SAdheer Chandravanshi static int qla4xxx_sysfs_ddb_add(struct Scsi_Host *shost, const char *buf,
1821e9e2be3SAdheer Chandravanshi 				 int len);
1831e9e2be3SAdheer Chandravanshi static int
1841e9e2be3SAdheer Chandravanshi qla4xxx_sysfs_ddb_delete(struct iscsi_bus_flash_session *fnode_sess);
1851e9e2be3SAdheer Chandravanshi static int qla4xxx_sysfs_ddb_login(struct iscsi_bus_flash_session *fnode_sess,
1861e9e2be3SAdheer Chandravanshi 				   struct iscsi_bus_flash_conn *fnode_conn);
1871e9e2be3SAdheer Chandravanshi static int qla4xxx_sysfs_ddb_logout(struct iscsi_bus_flash_session *fnode_sess,
1881e9e2be3SAdheer Chandravanshi 				    struct iscsi_bus_flash_conn *fnode_conn);
1891e9e2be3SAdheer Chandravanshi static int qla4xxx_sysfs_ddb_logout_sid(struct iscsi_cls_session *cls_sess);
1901e9e2be3SAdheer Chandravanshi 
191f4f5df23SVikas Chaudhary static struct qla4_8xxx_legacy_intr_set legacy_intr[] =
192f4f5df23SVikas Chaudhary     QLA82XX_LEGACY_INTR_CONFIG;
193f4f5df23SVikas Chaudhary 
194afaf5a2dSDavid Somayajulu static struct scsi_host_template qla4xxx_driver_template = {
195afaf5a2dSDavid Somayajulu 	.module			= THIS_MODULE,
196afaf5a2dSDavid Somayajulu 	.name			= DRIVER_NAME,
197afaf5a2dSDavid Somayajulu 	.proc_name		= DRIVER_NAME,
198afaf5a2dSDavid Somayajulu 	.queuecommand		= qla4xxx_queuecommand,
199afaf5a2dSDavid Somayajulu 
20009a0f719SVikas Chaudhary 	.eh_abort_handler	= qla4xxx_eh_abort,
201afaf5a2dSDavid Somayajulu 	.eh_device_reset_handler = qla4xxx_eh_device_reset,
202ce545039SMike Christie 	.eh_target_reset_handler = qla4xxx_eh_target_reset,
203afaf5a2dSDavid Somayajulu 	.eh_host_reset_handler	= qla4xxx_eh_host_reset,
2045c656af7SMike Christie 	.eh_timed_out		= qla4xxx_eh_cmd_timed_out,
205afaf5a2dSDavid Somayajulu 
206afaf5a2dSDavid Somayajulu 	.slave_configure	= qla4xxx_slave_configure,
207afaf5a2dSDavid Somayajulu 	.slave_alloc		= qla4xxx_slave_alloc,
208afaf5a2dSDavid Somayajulu 	.slave_destroy		= qla4xxx_slave_destroy,
209f7b4aa63STej Parkash 	.change_queue_depth	= qla4xxx_change_queue_depth,
210afaf5a2dSDavid Somayajulu 
211afaf5a2dSDavid Somayajulu 	.this_id		= -1,
212afaf5a2dSDavid Somayajulu 	.cmd_per_lun		= 3,
213afaf5a2dSDavid Somayajulu 	.use_clustering		= ENABLE_CLUSTERING,
214afaf5a2dSDavid Somayajulu 	.sg_tablesize		= SG_ALL,
215afaf5a2dSDavid Somayajulu 
216afaf5a2dSDavid Somayajulu 	.max_sectors		= 0xFFFF,
2177ad633c0SHarish Zunjarrao 	.shost_attrs		= qla4xxx_host_attrs,
21895d31262SVikas Chaudhary 	.host_reset		= qla4xxx_host_reset,
219a355943cSVikas Chaudhary 	.vendor_id		= SCSI_NL_VID_TYPE_PCI | PCI_VENDOR_ID_QLOGIC,
220afaf5a2dSDavid Somayajulu };
221afaf5a2dSDavid Somayajulu 
222afaf5a2dSDavid Somayajulu static struct iscsi_transport qla4xxx_iscsi_transport = {
223afaf5a2dSDavid Somayajulu 	.owner			= THIS_MODULE,
224afaf5a2dSDavid Somayajulu 	.name			= DRIVER_NAME,
225b3a271a9SManish Rangankar 	.caps			= CAP_TEXT_NEGO |
226b3a271a9SManish Rangankar 				  CAP_DATA_PATH_OFFLOAD | CAP_HDRDGST |
227b3a271a9SManish Rangankar 				  CAP_DATADGST | CAP_LOGIN_OFFLOAD |
228b3a271a9SManish Rangankar 				  CAP_MULTI_R2T,
2295e9bcec7SVikas Chaudhary 	.attr_is_visible	= qla4_attr_is_visible,
230b3a271a9SManish Rangankar 	.create_session         = qla4xxx_session_create,
231b3a271a9SManish Rangankar 	.destroy_session        = qla4xxx_session_destroy,
232b3a271a9SManish Rangankar 	.start_conn             = qla4xxx_conn_start,
233b3a271a9SManish Rangankar 	.create_conn            = qla4xxx_conn_create,
234b3a271a9SManish Rangankar 	.bind_conn              = qla4xxx_conn_bind,
235b3a271a9SManish Rangankar 	.stop_conn              = iscsi_conn_stop,
236b3a271a9SManish Rangankar 	.destroy_conn           = qla4xxx_conn_destroy,
237b3a271a9SManish Rangankar 	.set_param              = iscsi_set_param,
238afaf5a2dSDavid Somayajulu 	.get_conn_param		= qla4xxx_conn_get_param,
239fca9f04dSMike Christie 	.get_session_param	= qla4xxx_session_get_param,
240b3a271a9SManish Rangankar 	.get_ep_param           = qla4xxx_get_ep_param,
241b3a271a9SManish Rangankar 	.ep_connect		= qla4xxx_ep_connect,
242b3a271a9SManish Rangankar 	.ep_poll		= qla4xxx_ep_poll,
243b3a271a9SManish Rangankar 	.ep_disconnect		= qla4xxx_ep_disconnect,
244b3a271a9SManish Rangankar 	.get_stats		= qla4xxx_conn_get_stats,
245b3a271a9SManish Rangankar 	.send_pdu		= iscsi_conn_send_pdu,
246b3a271a9SManish Rangankar 	.xmit_task		= qla4xxx_task_xmit,
247b3a271a9SManish Rangankar 	.cleanup_task		= qla4xxx_task_cleanup,
248b3a271a9SManish Rangankar 	.alloc_pdu		= qla4xxx_alloc_pdu,
249b3a271a9SManish Rangankar 
250aa1e93a2SMike Christie 	.get_host_param		= qla4xxx_host_get_param,
251d00efe3fSMike Christie 	.set_iface_param	= qla4xxx_iface_set_param,
252ed1086e0SVikas Chaudhary 	.get_iface_param	= qla4xxx_get_iface_param,
253a355943cSVikas Chaudhary 	.bsg_request		= qla4xxx_bsg_request,
254c0b9d3f7SVikas Chaudhary 	.send_ping		= qla4xxx_send_ping,
255376738afSNilesh Javali 	.get_chap		= qla4xxx_get_chap_list,
256376738afSNilesh Javali 	.delete_chap		= qla4xxx_delete_chap,
25726ffd7b4SAdheer Chandravanshi 	.set_chap		= qla4xxx_set_chap_entry,
2581e9e2be3SAdheer Chandravanshi 	.get_flashnode_param	= qla4xxx_sysfs_ddb_get_param,
2591e9e2be3SAdheer Chandravanshi 	.set_flashnode_param	= qla4xxx_sysfs_ddb_set_param,
2601e9e2be3SAdheer Chandravanshi 	.new_flashnode		= qla4xxx_sysfs_ddb_add,
2611e9e2be3SAdheer Chandravanshi 	.del_flashnode		= qla4xxx_sysfs_ddb_delete,
2621e9e2be3SAdheer Chandravanshi 	.login_flashnode	= qla4xxx_sysfs_ddb_login,
2631e9e2be3SAdheer Chandravanshi 	.logout_flashnode	= qla4xxx_sysfs_ddb_logout,
2641e9e2be3SAdheer Chandravanshi 	.logout_flashnode_sid	= qla4xxx_sysfs_ddb_logout_sid,
265afaf5a2dSDavid Somayajulu };
266afaf5a2dSDavid Somayajulu 
267afaf5a2dSDavid Somayajulu static struct scsi_transport_template *qla4xxx_scsi_transport;
268afaf5a2dSDavid Somayajulu 
269c0b9d3f7SVikas Chaudhary static int qla4xxx_send_ping(struct Scsi_Host *shost, uint32_t iface_num,
270c0b9d3f7SVikas Chaudhary 			     uint32_t iface_type, uint32_t payload_size,
271c0b9d3f7SVikas Chaudhary 			     uint32_t pid, struct sockaddr *dst_addr)
272c0b9d3f7SVikas Chaudhary {
273c0b9d3f7SVikas Chaudhary 	struct scsi_qla_host *ha = to_qla_host(shost);
274c0b9d3f7SVikas Chaudhary 	struct sockaddr_in *addr;
275c0b9d3f7SVikas Chaudhary 	struct sockaddr_in6 *addr6;
276c0b9d3f7SVikas Chaudhary 	uint32_t options = 0;
277c0b9d3f7SVikas Chaudhary 	uint8_t ipaddr[IPv6_ADDR_LEN];
278c0b9d3f7SVikas Chaudhary 	int rval;
279c0b9d3f7SVikas Chaudhary 
280c0b9d3f7SVikas Chaudhary 	memset(ipaddr, 0, IPv6_ADDR_LEN);
281c0b9d3f7SVikas Chaudhary 	/* IPv4 to IPv4 */
282c0b9d3f7SVikas Chaudhary 	if ((iface_type == ISCSI_IFACE_TYPE_IPV4) &&
283c0b9d3f7SVikas Chaudhary 	    (dst_addr->sa_family == AF_INET)) {
284c0b9d3f7SVikas Chaudhary 		addr = (struct sockaddr_in *)dst_addr;
285c0b9d3f7SVikas Chaudhary 		memcpy(ipaddr, &addr->sin_addr.s_addr, IP_ADDR_LEN);
286c0b9d3f7SVikas Chaudhary 		DEBUG2(ql4_printk(KERN_INFO, ha, "%s: IPv4 Ping src: %pI4 "
287c0b9d3f7SVikas Chaudhary 				  "dest: %pI4\n", __func__,
288c0b9d3f7SVikas Chaudhary 				  &ha->ip_config.ip_address, ipaddr));
289c0b9d3f7SVikas Chaudhary 		rval = qla4xxx_ping_iocb(ha, options, payload_size, pid,
290c0b9d3f7SVikas Chaudhary 					 ipaddr);
291c0b9d3f7SVikas Chaudhary 		if (rval)
292c0b9d3f7SVikas Chaudhary 			rval = -EINVAL;
293c0b9d3f7SVikas Chaudhary 	} else if ((iface_type == ISCSI_IFACE_TYPE_IPV6) &&
294c0b9d3f7SVikas Chaudhary 		   (dst_addr->sa_family == AF_INET6)) {
295c0b9d3f7SVikas Chaudhary 		/* IPv6 to IPv6 */
296c0b9d3f7SVikas Chaudhary 		addr6 = (struct sockaddr_in6 *)dst_addr;
297c0b9d3f7SVikas Chaudhary 		memcpy(ipaddr, &addr6->sin6_addr.in6_u.u6_addr8, IPv6_ADDR_LEN);
298c0b9d3f7SVikas Chaudhary 
299c0b9d3f7SVikas Chaudhary 		options |= PING_IPV6_PROTOCOL_ENABLE;
300c0b9d3f7SVikas Chaudhary 
301c0b9d3f7SVikas Chaudhary 		/* Ping using LinkLocal address */
302c0b9d3f7SVikas Chaudhary 		if ((iface_num == 0) || (iface_num == 1)) {
303c0b9d3f7SVikas Chaudhary 			DEBUG2(ql4_printk(KERN_INFO, ha, "%s: LinkLocal Ping "
304c0b9d3f7SVikas Chaudhary 					  "src: %pI6 dest: %pI6\n", __func__,
305c0b9d3f7SVikas Chaudhary 					  &ha->ip_config.ipv6_link_local_addr,
306c0b9d3f7SVikas Chaudhary 					  ipaddr));
307c0b9d3f7SVikas Chaudhary 			options |= PING_IPV6_LINKLOCAL_ADDR;
308c0b9d3f7SVikas Chaudhary 			rval = qla4xxx_ping_iocb(ha, options, payload_size,
309c0b9d3f7SVikas Chaudhary 						 pid, ipaddr);
310c0b9d3f7SVikas Chaudhary 		} else {
311c0b9d3f7SVikas Chaudhary 			ql4_printk(KERN_WARNING, ha, "%s: iface num = %d "
312c0b9d3f7SVikas Chaudhary 				   "not supported\n", __func__, iface_num);
313c0b9d3f7SVikas Chaudhary 			rval = -ENOSYS;
314c0b9d3f7SVikas Chaudhary 			goto exit_send_ping;
315c0b9d3f7SVikas Chaudhary 		}
316c0b9d3f7SVikas Chaudhary 
317c0b9d3f7SVikas Chaudhary 		/*
318c0b9d3f7SVikas Chaudhary 		 * If ping using LinkLocal address fails, try ping using
319c0b9d3f7SVikas Chaudhary 		 * IPv6 address
320c0b9d3f7SVikas Chaudhary 		 */
321c0b9d3f7SVikas Chaudhary 		if (rval != QLA_SUCCESS) {
322c0b9d3f7SVikas Chaudhary 			options &= ~PING_IPV6_LINKLOCAL_ADDR;
323c0b9d3f7SVikas Chaudhary 			if (iface_num == 0) {
324c0b9d3f7SVikas Chaudhary 				options |= PING_IPV6_ADDR0;
325c0b9d3f7SVikas Chaudhary 				DEBUG2(ql4_printk(KERN_INFO, ha, "%s: IPv6 "
326c0b9d3f7SVikas Chaudhary 						  "Ping src: %pI6 "
327c0b9d3f7SVikas Chaudhary 						  "dest: %pI6\n", __func__,
328c0b9d3f7SVikas Chaudhary 						  &ha->ip_config.ipv6_addr0,
329c0b9d3f7SVikas Chaudhary 						  ipaddr));
330c0b9d3f7SVikas Chaudhary 			} else if (iface_num == 1) {
331c0b9d3f7SVikas Chaudhary 				options |= PING_IPV6_ADDR1;
332c0b9d3f7SVikas Chaudhary 				DEBUG2(ql4_printk(KERN_INFO, ha, "%s: IPv6 "
333c0b9d3f7SVikas Chaudhary 						  "Ping src: %pI6 "
334c0b9d3f7SVikas Chaudhary 						  "dest: %pI6\n", __func__,
335c0b9d3f7SVikas Chaudhary 						  &ha->ip_config.ipv6_addr1,
336c0b9d3f7SVikas Chaudhary 						  ipaddr));
337c0b9d3f7SVikas Chaudhary 			}
338c0b9d3f7SVikas Chaudhary 			rval = qla4xxx_ping_iocb(ha, options, payload_size,
339c0b9d3f7SVikas Chaudhary 						 pid, ipaddr);
340c0b9d3f7SVikas Chaudhary 			if (rval)
341c0b9d3f7SVikas Chaudhary 				rval = -EINVAL;
342c0b9d3f7SVikas Chaudhary 		}
343c0b9d3f7SVikas Chaudhary 	} else
344c0b9d3f7SVikas Chaudhary 		rval = -ENOSYS;
345c0b9d3f7SVikas Chaudhary exit_send_ping:
346c0b9d3f7SVikas Chaudhary 	return rval;
347c0b9d3f7SVikas Chaudhary }
348c0b9d3f7SVikas Chaudhary 
3495e9bcec7SVikas Chaudhary static umode_t qla4_attr_is_visible(int param_type, int param)
3503128c6c7SMike Christie {
3513128c6c7SMike Christie 	switch (param_type) {
352f27fb2efSMike Christie 	case ISCSI_HOST_PARAM:
353f27fb2efSMike Christie 		switch (param) {
354f27fb2efSMike Christie 		case ISCSI_HOST_PARAM_HWADDRESS:
355f27fb2efSMike Christie 		case ISCSI_HOST_PARAM_IPADDRESS:
356f27fb2efSMike Christie 		case ISCSI_HOST_PARAM_INITIATOR_NAME:
3573254dbe9SVikas Chaudhary 		case ISCSI_HOST_PARAM_PORT_STATE:
3583254dbe9SVikas Chaudhary 		case ISCSI_HOST_PARAM_PORT_SPEED:
359f27fb2efSMike Christie 			return S_IRUGO;
360f27fb2efSMike Christie 		default:
361f27fb2efSMike Christie 			return 0;
362f27fb2efSMike Christie 		}
3633128c6c7SMike Christie 	case ISCSI_PARAM:
3643128c6c7SMike Christie 		switch (param) {
365590134faSMike Christie 		case ISCSI_PARAM_PERSISTENT_ADDRESS:
366590134faSMike Christie 		case ISCSI_PARAM_PERSISTENT_PORT:
3673128c6c7SMike Christie 		case ISCSI_PARAM_CONN_ADDRESS:
3683128c6c7SMike Christie 		case ISCSI_PARAM_CONN_PORT:
3691d063c17SMike Christie 		case ISCSI_PARAM_TARGET_NAME:
3701d063c17SMike Christie 		case ISCSI_PARAM_TPGT:
3711d063c17SMike Christie 		case ISCSI_PARAM_TARGET_ALIAS:
372b3a271a9SManish Rangankar 		case ISCSI_PARAM_MAX_BURST:
373b3a271a9SManish Rangankar 		case ISCSI_PARAM_MAX_R2T:
374b3a271a9SManish Rangankar 		case ISCSI_PARAM_FIRST_BURST:
375b3a271a9SManish Rangankar 		case ISCSI_PARAM_MAX_RECV_DLENGTH:
376b3a271a9SManish Rangankar 		case ISCSI_PARAM_MAX_XMIT_DLENGTH:
377de37920bSMike Christie 		case ISCSI_PARAM_IFACE_NAME:
378fca9f04dSMike Christie 		case ISCSI_PARAM_CHAP_OUT_IDX:
379fca9f04dSMike Christie 		case ISCSI_PARAM_CHAP_IN_IDX:
380fca9f04dSMike Christie 		case ISCSI_PARAM_USERNAME:
381fca9f04dSMike Christie 		case ISCSI_PARAM_PASSWORD:
382fca9f04dSMike Christie 		case ISCSI_PARAM_USERNAME_IN:
383fca9f04dSMike Christie 		case ISCSI_PARAM_PASSWORD_IN:
3848cc91d42SAdheer Chandravanshi 		case ISCSI_PARAM_AUTO_SND_TGT_DISABLE:
3858cc91d42SAdheer Chandravanshi 		case ISCSI_PARAM_DISCOVERY_SESS:
3868cc91d42SAdheer Chandravanshi 		case ISCSI_PARAM_PORTAL_TYPE:
3878cc91d42SAdheer Chandravanshi 		case ISCSI_PARAM_CHAP_AUTH_EN:
3888cc91d42SAdheer Chandravanshi 		case ISCSI_PARAM_DISCOVERY_LOGOUT_EN:
3898cc91d42SAdheer Chandravanshi 		case ISCSI_PARAM_BIDI_CHAP_EN:
3908cc91d42SAdheer Chandravanshi 		case ISCSI_PARAM_DISCOVERY_AUTH_OPTIONAL:
3918cc91d42SAdheer Chandravanshi 		case ISCSI_PARAM_DEF_TIME2WAIT:
3928cc91d42SAdheer Chandravanshi 		case ISCSI_PARAM_DEF_TIME2RETAIN:
3938cc91d42SAdheer Chandravanshi 		case ISCSI_PARAM_HDRDGST_EN:
3948cc91d42SAdheer Chandravanshi 		case ISCSI_PARAM_DATADGST_EN:
3958cc91d42SAdheer Chandravanshi 		case ISCSI_PARAM_INITIAL_R2T_EN:
3968cc91d42SAdheer Chandravanshi 		case ISCSI_PARAM_IMM_DATA_EN:
3978cc91d42SAdheer Chandravanshi 		case ISCSI_PARAM_PDU_INORDER_EN:
3988cc91d42SAdheer Chandravanshi 		case ISCSI_PARAM_DATASEQ_INORDER_EN:
3998cc91d42SAdheer Chandravanshi 		case ISCSI_PARAM_MAX_SEGMENT_SIZE:
4008cc91d42SAdheer Chandravanshi 		case ISCSI_PARAM_TCP_TIMESTAMP_STAT:
4018cc91d42SAdheer Chandravanshi 		case ISCSI_PARAM_TCP_WSF_DISABLE:
4028cc91d42SAdheer Chandravanshi 		case ISCSI_PARAM_TCP_NAGLE_DISABLE:
4038cc91d42SAdheer Chandravanshi 		case ISCSI_PARAM_TCP_TIMER_SCALE:
4048cc91d42SAdheer Chandravanshi 		case ISCSI_PARAM_TCP_TIMESTAMP_EN:
4058cc91d42SAdheer Chandravanshi 		case ISCSI_PARAM_TCP_XMIT_WSF:
4068cc91d42SAdheer Chandravanshi 		case ISCSI_PARAM_TCP_RECV_WSF:
4078cc91d42SAdheer Chandravanshi 		case ISCSI_PARAM_IP_FRAGMENT_DISABLE:
4088cc91d42SAdheer Chandravanshi 		case ISCSI_PARAM_IPV4_TOS:
4098cc91d42SAdheer Chandravanshi 		case ISCSI_PARAM_IPV6_TC:
4108cc91d42SAdheer Chandravanshi 		case ISCSI_PARAM_IPV6_FLOW_LABEL:
4118cc91d42SAdheer Chandravanshi 		case ISCSI_PARAM_IS_FW_ASSIGNED_IPV6:
4128cc91d42SAdheer Chandravanshi 		case ISCSI_PARAM_KEEPALIVE_TMO:
4138cc91d42SAdheer Chandravanshi 		case ISCSI_PARAM_LOCAL_PORT:
4148cc91d42SAdheer Chandravanshi 		case ISCSI_PARAM_ISID:
4158cc91d42SAdheer Chandravanshi 		case ISCSI_PARAM_TSID:
4168cc91d42SAdheer Chandravanshi 		case ISCSI_PARAM_DEF_TASKMGMT_TMO:
4178cc91d42SAdheer Chandravanshi 		case ISCSI_PARAM_ERL:
4188cc91d42SAdheer Chandravanshi 		case ISCSI_PARAM_STATSN:
4198cc91d42SAdheer Chandravanshi 		case ISCSI_PARAM_EXP_STATSN:
4208cc91d42SAdheer Chandravanshi 		case ISCSI_PARAM_DISCOVERY_PARENT_IDX:
4218cc91d42SAdheer Chandravanshi 		case ISCSI_PARAM_DISCOVERY_PARENT_TYPE:
4223128c6c7SMike Christie 			return S_IRUGO;
4233128c6c7SMike Christie 		default:
4243128c6c7SMike Christie 			return 0;
4253128c6c7SMike Christie 		}
426b78dbba0SMike Christie 	case ISCSI_NET_PARAM:
427b78dbba0SMike Christie 		switch (param) {
428b78dbba0SMike Christie 		case ISCSI_NET_PARAM_IPV4_ADDR:
429b78dbba0SMike Christie 		case ISCSI_NET_PARAM_IPV4_SUBNET:
430b78dbba0SMike Christie 		case ISCSI_NET_PARAM_IPV4_GW:
431b78dbba0SMike Christie 		case ISCSI_NET_PARAM_IPV4_BOOTPROTO:
432b78dbba0SMike Christie 		case ISCSI_NET_PARAM_IFACE_ENABLE:
433b78dbba0SMike Christie 		case ISCSI_NET_PARAM_IPV6_LINKLOCAL:
434b78dbba0SMike Christie 		case ISCSI_NET_PARAM_IPV6_ADDR:
435b78dbba0SMike Christie 		case ISCSI_NET_PARAM_IPV6_ROUTER:
436b78dbba0SMike Christie 		case ISCSI_NET_PARAM_IPV6_ADDR_AUTOCFG:
437b78dbba0SMike Christie 		case ISCSI_NET_PARAM_IPV6_LINKLOCAL_AUTOCFG:
4386ac73e8cSVikas Chaudhary 		case ISCSI_NET_PARAM_VLAN_ID:
4396ac73e8cSVikas Chaudhary 		case ISCSI_NET_PARAM_VLAN_PRIORITY:
4406ac73e8cSVikas Chaudhary 		case ISCSI_NET_PARAM_VLAN_ENABLED:
441943c157bSVikas Chaudhary 		case ISCSI_NET_PARAM_MTU:
4422ada7fc5SVikas Chaudhary 		case ISCSI_NET_PARAM_PORT:
443f8e93412SHarish Zunjarrao 		case ISCSI_NET_PARAM_IPADDR_STATE:
444f8e93412SHarish Zunjarrao 		case ISCSI_NET_PARAM_IPV6_LINKLOCAL_STATE:
445f8e93412SHarish Zunjarrao 		case ISCSI_NET_PARAM_IPV6_ROUTER_STATE:
446f8e93412SHarish Zunjarrao 		case ISCSI_NET_PARAM_DELAYED_ACK_EN:
447f8e93412SHarish Zunjarrao 		case ISCSI_NET_PARAM_TCP_NAGLE_DISABLE:
448f8e93412SHarish Zunjarrao 		case ISCSI_NET_PARAM_TCP_WSF_DISABLE:
449f8e93412SHarish Zunjarrao 		case ISCSI_NET_PARAM_TCP_WSF:
450f8e93412SHarish Zunjarrao 		case ISCSI_NET_PARAM_TCP_TIMER_SCALE:
451f8e93412SHarish Zunjarrao 		case ISCSI_NET_PARAM_TCP_TIMESTAMP_EN:
452f8e93412SHarish Zunjarrao 		case ISCSI_NET_PARAM_CACHE_ID:
453f8e93412SHarish Zunjarrao 		case ISCSI_NET_PARAM_IPV4_DHCP_DNS_ADDR_EN:
454f8e93412SHarish Zunjarrao 		case ISCSI_NET_PARAM_IPV4_DHCP_SLP_DA_EN:
455f8e93412SHarish Zunjarrao 		case ISCSI_NET_PARAM_IPV4_TOS_EN:
456f8e93412SHarish Zunjarrao 		case ISCSI_NET_PARAM_IPV4_TOS:
457f8e93412SHarish Zunjarrao 		case ISCSI_NET_PARAM_IPV4_GRAT_ARP_EN:
458f8e93412SHarish Zunjarrao 		case ISCSI_NET_PARAM_IPV4_DHCP_ALT_CLIENT_ID_EN:
459f8e93412SHarish Zunjarrao 		case ISCSI_NET_PARAM_IPV4_DHCP_ALT_CLIENT_ID:
460f8e93412SHarish Zunjarrao 		case ISCSI_NET_PARAM_IPV4_DHCP_REQ_VENDOR_ID_EN:
461f8e93412SHarish Zunjarrao 		case ISCSI_NET_PARAM_IPV4_DHCP_USE_VENDOR_ID_EN:
462f8e93412SHarish Zunjarrao 		case ISCSI_NET_PARAM_IPV4_DHCP_VENDOR_ID:
463f8e93412SHarish Zunjarrao 		case ISCSI_NET_PARAM_IPV4_DHCP_LEARN_IQN_EN:
464f8e93412SHarish Zunjarrao 		case ISCSI_NET_PARAM_IPV4_FRAGMENT_DISABLE:
465f8e93412SHarish Zunjarrao 		case ISCSI_NET_PARAM_IPV4_IN_FORWARD_EN:
466f8e93412SHarish Zunjarrao 		case ISCSI_NET_PARAM_REDIRECT_EN:
467f8e93412SHarish Zunjarrao 		case ISCSI_NET_PARAM_IPV4_TTL:
468f8e93412SHarish Zunjarrao 		case ISCSI_NET_PARAM_IPV6_GRAT_NEIGHBOR_ADV_EN:
469f8e93412SHarish Zunjarrao 		case ISCSI_NET_PARAM_IPV6_MLD_EN:
470f8e93412SHarish Zunjarrao 		case ISCSI_NET_PARAM_IPV6_FLOW_LABEL:
471f8e93412SHarish Zunjarrao 		case ISCSI_NET_PARAM_IPV6_TRAFFIC_CLASS:
472f8e93412SHarish Zunjarrao 		case ISCSI_NET_PARAM_IPV6_HOP_LIMIT:
473f8e93412SHarish Zunjarrao 		case ISCSI_NET_PARAM_IPV6_ND_REACHABLE_TMO:
474f8e93412SHarish Zunjarrao 		case ISCSI_NET_PARAM_IPV6_ND_REXMIT_TIME:
475f8e93412SHarish Zunjarrao 		case ISCSI_NET_PARAM_IPV6_ND_STALE_TMO:
476f8e93412SHarish Zunjarrao 		case ISCSI_NET_PARAM_IPV6_DUP_ADDR_DETECT_CNT:
477f8e93412SHarish Zunjarrao 		case ISCSI_NET_PARAM_IPV6_RTR_ADV_LINK_MTU:
478f8e93412SHarish Zunjarrao 			return S_IRUGO;
479f8e93412SHarish Zunjarrao 		default:
480f8e93412SHarish Zunjarrao 			return 0;
481f8e93412SHarish Zunjarrao 		}
482f8e93412SHarish Zunjarrao 	case ISCSI_IFACE_PARAM:
483f8e93412SHarish Zunjarrao 		switch (param) {
484f8e93412SHarish Zunjarrao 		case ISCSI_IFACE_PARAM_DEF_TASKMGMT_TMO:
485f8e93412SHarish Zunjarrao 		case ISCSI_IFACE_PARAM_HDRDGST_EN:
486f8e93412SHarish Zunjarrao 		case ISCSI_IFACE_PARAM_DATADGST_EN:
487f8e93412SHarish Zunjarrao 		case ISCSI_IFACE_PARAM_IMM_DATA_EN:
488f8e93412SHarish Zunjarrao 		case ISCSI_IFACE_PARAM_INITIAL_R2T_EN:
489f8e93412SHarish Zunjarrao 		case ISCSI_IFACE_PARAM_DATASEQ_INORDER_EN:
490f8e93412SHarish Zunjarrao 		case ISCSI_IFACE_PARAM_PDU_INORDER_EN:
491f8e93412SHarish Zunjarrao 		case ISCSI_IFACE_PARAM_ERL:
492f8e93412SHarish Zunjarrao 		case ISCSI_IFACE_PARAM_MAX_RECV_DLENGTH:
493f8e93412SHarish Zunjarrao 		case ISCSI_IFACE_PARAM_FIRST_BURST:
494f8e93412SHarish Zunjarrao 		case ISCSI_IFACE_PARAM_MAX_R2T:
495f8e93412SHarish Zunjarrao 		case ISCSI_IFACE_PARAM_MAX_BURST:
496f8e93412SHarish Zunjarrao 		case ISCSI_IFACE_PARAM_CHAP_AUTH_EN:
497f8e93412SHarish Zunjarrao 		case ISCSI_IFACE_PARAM_BIDI_CHAP_EN:
498f8e93412SHarish Zunjarrao 		case ISCSI_IFACE_PARAM_DISCOVERY_AUTH_OPTIONAL:
499f8e93412SHarish Zunjarrao 		case ISCSI_IFACE_PARAM_DISCOVERY_LOGOUT_EN:
500f8e93412SHarish Zunjarrao 		case ISCSI_IFACE_PARAM_STRICT_LOGIN_COMP_EN:
501f8e93412SHarish Zunjarrao 		case ISCSI_IFACE_PARAM_INITIATOR_NAME:
502b78dbba0SMike Christie 			return S_IRUGO;
503b78dbba0SMike Christie 		default:
504b78dbba0SMike Christie 			return 0;
505b78dbba0SMike Christie 		}
5061e9e2be3SAdheer Chandravanshi 	case ISCSI_FLASHNODE_PARAM:
5071e9e2be3SAdheer Chandravanshi 		switch (param) {
5081e9e2be3SAdheer Chandravanshi 		case ISCSI_FLASHNODE_IS_FW_ASSIGNED_IPV6:
5091e9e2be3SAdheer Chandravanshi 		case ISCSI_FLASHNODE_PORTAL_TYPE:
5101e9e2be3SAdheer Chandravanshi 		case ISCSI_FLASHNODE_AUTO_SND_TGT_DISABLE:
5111e9e2be3SAdheer Chandravanshi 		case ISCSI_FLASHNODE_DISCOVERY_SESS:
5121e9e2be3SAdheer Chandravanshi 		case ISCSI_FLASHNODE_ENTRY_EN:
5131e9e2be3SAdheer Chandravanshi 		case ISCSI_FLASHNODE_HDR_DGST_EN:
5141e9e2be3SAdheer Chandravanshi 		case ISCSI_FLASHNODE_DATA_DGST_EN:
5151e9e2be3SAdheer Chandravanshi 		case ISCSI_FLASHNODE_IMM_DATA_EN:
5161e9e2be3SAdheer Chandravanshi 		case ISCSI_FLASHNODE_INITIAL_R2T_EN:
5171e9e2be3SAdheer Chandravanshi 		case ISCSI_FLASHNODE_DATASEQ_INORDER:
5181e9e2be3SAdheer Chandravanshi 		case ISCSI_FLASHNODE_PDU_INORDER:
5191e9e2be3SAdheer Chandravanshi 		case ISCSI_FLASHNODE_CHAP_AUTH_EN:
5201e9e2be3SAdheer Chandravanshi 		case ISCSI_FLASHNODE_SNACK_REQ_EN:
5211e9e2be3SAdheer Chandravanshi 		case ISCSI_FLASHNODE_DISCOVERY_LOGOUT_EN:
5221e9e2be3SAdheer Chandravanshi 		case ISCSI_FLASHNODE_BIDI_CHAP_EN:
5231e9e2be3SAdheer Chandravanshi 		case ISCSI_FLASHNODE_DISCOVERY_AUTH_OPTIONAL:
5241e9e2be3SAdheer Chandravanshi 		case ISCSI_FLASHNODE_ERL:
5251e9e2be3SAdheer Chandravanshi 		case ISCSI_FLASHNODE_TCP_TIMESTAMP_STAT:
5261e9e2be3SAdheer Chandravanshi 		case ISCSI_FLASHNODE_TCP_NAGLE_DISABLE:
5271e9e2be3SAdheer Chandravanshi 		case ISCSI_FLASHNODE_TCP_WSF_DISABLE:
5281e9e2be3SAdheer Chandravanshi 		case ISCSI_FLASHNODE_TCP_TIMER_SCALE:
5291e9e2be3SAdheer Chandravanshi 		case ISCSI_FLASHNODE_TCP_TIMESTAMP_EN:
5301e9e2be3SAdheer Chandravanshi 		case ISCSI_FLASHNODE_IP_FRAG_DISABLE:
5311e9e2be3SAdheer Chandravanshi 		case ISCSI_FLASHNODE_MAX_RECV_DLENGTH:
5321e9e2be3SAdheer Chandravanshi 		case ISCSI_FLASHNODE_MAX_XMIT_DLENGTH:
5331e9e2be3SAdheer Chandravanshi 		case ISCSI_FLASHNODE_FIRST_BURST:
5341e9e2be3SAdheer Chandravanshi 		case ISCSI_FLASHNODE_DEF_TIME2WAIT:
5351e9e2be3SAdheer Chandravanshi 		case ISCSI_FLASHNODE_DEF_TIME2RETAIN:
5361e9e2be3SAdheer Chandravanshi 		case ISCSI_FLASHNODE_MAX_R2T:
5371e9e2be3SAdheer Chandravanshi 		case ISCSI_FLASHNODE_KEEPALIVE_TMO:
5381e9e2be3SAdheer Chandravanshi 		case ISCSI_FLASHNODE_ISID:
5391e9e2be3SAdheer Chandravanshi 		case ISCSI_FLASHNODE_TSID:
5401e9e2be3SAdheer Chandravanshi 		case ISCSI_FLASHNODE_PORT:
5411e9e2be3SAdheer Chandravanshi 		case ISCSI_FLASHNODE_MAX_BURST:
5421e9e2be3SAdheer Chandravanshi 		case ISCSI_FLASHNODE_DEF_TASKMGMT_TMO:
5431e9e2be3SAdheer Chandravanshi 		case ISCSI_FLASHNODE_IPADDR:
5441e9e2be3SAdheer Chandravanshi 		case ISCSI_FLASHNODE_ALIAS:
5451e9e2be3SAdheer Chandravanshi 		case ISCSI_FLASHNODE_REDIRECT_IPADDR:
5461e9e2be3SAdheer Chandravanshi 		case ISCSI_FLASHNODE_MAX_SEGMENT_SIZE:
5471e9e2be3SAdheer Chandravanshi 		case ISCSI_FLASHNODE_LOCAL_PORT:
5481e9e2be3SAdheer Chandravanshi 		case ISCSI_FLASHNODE_IPV4_TOS:
5491e9e2be3SAdheer Chandravanshi 		case ISCSI_FLASHNODE_IPV6_TC:
5501e9e2be3SAdheer Chandravanshi 		case ISCSI_FLASHNODE_IPV6_FLOW_LABEL:
5511e9e2be3SAdheer Chandravanshi 		case ISCSI_FLASHNODE_NAME:
5521e9e2be3SAdheer Chandravanshi 		case ISCSI_FLASHNODE_TPGT:
5531e9e2be3SAdheer Chandravanshi 		case ISCSI_FLASHNODE_LINK_LOCAL_IPV6:
5541e9e2be3SAdheer Chandravanshi 		case ISCSI_FLASHNODE_DISCOVERY_PARENT_IDX:
5551e9e2be3SAdheer Chandravanshi 		case ISCSI_FLASHNODE_DISCOVERY_PARENT_TYPE:
5561e9e2be3SAdheer Chandravanshi 		case ISCSI_FLASHNODE_TCP_XMIT_WSF:
5571e9e2be3SAdheer Chandravanshi 		case ISCSI_FLASHNODE_TCP_RECV_WSF:
5581e9e2be3SAdheer Chandravanshi 		case ISCSI_FLASHNODE_CHAP_OUT_IDX:
5591e9e2be3SAdheer Chandravanshi 		case ISCSI_FLASHNODE_USERNAME:
5601e9e2be3SAdheer Chandravanshi 		case ISCSI_FLASHNODE_PASSWORD:
5611e9e2be3SAdheer Chandravanshi 		case ISCSI_FLASHNODE_STATSN:
5621e9e2be3SAdheer Chandravanshi 		case ISCSI_FLASHNODE_EXP_STATSN:
5631e9e2be3SAdheer Chandravanshi 		case ISCSI_FLASHNODE_IS_BOOT_TGT:
5641e9e2be3SAdheer Chandravanshi 			return S_IRUGO;
5651e9e2be3SAdheer Chandravanshi 		default:
5661e9e2be3SAdheer Chandravanshi 			return 0;
5671e9e2be3SAdheer Chandravanshi 		}
5683128c6c7SMike Christie 	}
5693128c6c7SMike Christie 
5703128c6c7SMike Christie 	return 0;
5713128c6c7SMike Christie }
5723128c6c7SMike Christie 
57326ffd7b4SAdheer Chandravanshi static int qla4xxx_get_chap_by_index(struct scsi_qla_host *ha,
57426ffd7b4SAdheer Chandravanshi 				     int16_t chap_index,
57526ffd7b4SAdheer Chandravanshi 				     struct ql4_chap_table **chap_entry)
57626ffd7b4SAdheer Chandravanshi {
57726ffd7b4SAdheer Chandravanshi 	int rval = QLA_ERROR;
57826ffd7b4SAdheer Chandravanshi 	int max_chap_entries;
57926ffd7b4SAdheer Chandravanshi 
58026ffd7b4SAdheer Chandravanshi 	if (!ha->chap_list) {
58126ffd7b4SAdheer Chandravanshi 		ql4_printk(KERN_ERR, ha, "CHAP table cache is empty!\n");
58226ffd7b4SAdheer Chandravanshi 		rval = QLA_ERROR;
58326ffd7b4SAdheer Chandravanshi 		goto exit_get_chap;
58426ffd7b4SAdheer Chandravanshi 	}
58526ffd7b4SAdheer Chandravanshi 
58626ffd7b4SAdheer Chandravanshi 	if (is_qla80XX(ha))
58726ffd7b4SAdheer Chandravanshi 		max_chap_entries = (ha->hw.flt_chap_size / 2) /
58826ffd7b4SAdheer Chandravanshi 				   sizeof(struct ql4_chap_table);
58926ffd7b4SAdheer Chandravanshi 	else
59026ffd7b4SAdheer Chandravanshi 		max_chap_entries = MAX_CHAP_ENTRIES_40XX;
59126ffd7b4SAdheer Chandravanshi 
59226ffd7b4SAdheer Chandravanshi 	if (chap_index > max_chap_entries) {
59326ffd7b4SAdheer Chandravanshi 		ql4_printk(KERN_ERR, ha, "Invalid Chap index\n");
59426ffd7b4SAdheer Chandravanshi 		rval = QLA_ERROR;
59526ffd7b4SAdheer Chandravanshi 		goto exit_get_chap;
59626ffd7b4SAdheer Chandravanshi 	}
59726ffd7b4SAdheer Chandravanshi 
59826ffd7b4SAdheer Chandravanshi 	*chap_entry = (struct ql4_chap_table *)ha->chap_list + chap_index;
59926ffd7b4SAdheer Chandravanshi 	if ((*chap_entry)->cookie !=
60026ffd7b4SAdheer Chandravanshi 	     __constant_cpu_to_le16(CHAP_VALID_COOKIE)) {
60126ffd7b4SAdheer Chandravanshi 		rval = QLA_ERROR;
60226ffd7b4SAdheer Chandravanshi 		*chap_entry = NULL;
60326ffd7b4SAdheer Chandravanshi 	} else {
60426ffd7b4SAdheer Chandravanshi 		rval = QLA_SUCCESS;
60526ffd7b4SAdheer Chandravanshi 	}
60626ffd7b4SAdheer Chandravanshi 
60726ffd7b4SAdheer Chandravanshi exit_get_chap:
60826ffd7b4SAdheer Chandravanshi 	return rval;
60926ffd7b4SAdheer Chandravanshi }
61026ffd7b4SAdheer Chandravanshi 
61126ffd7b4SAdheer Chandravanshi /**
61226ffd7b4SAdheer Chandravanshi  * qla4xxx_find_free_chap_index - Find the first free chap index
61326ffd7b4SAdheer Chandravanshi  * @ha: pointer to adapter structure
61426ffd7b4SAdheer Chandravanshi  * @chap_index: CHAP index to be returned
61526ffd7b4SAdheer Chandravanshi  *
61626ffd7b4SAdheer Chandravanshi  * Find the first free chap index available in the chap table
61726ffd7b4SAdheer Chandravanshi  *
61826ffd7b4SAdheer Chandravanshi  * Note: Caller should acquire the chap lock before getting here.
61926ffd7b4SAdheer Chandravanshi  **/
62026ffd7b4SAdheer Chandravanshi static int qla4xxx_find_free_chap_index(struct scsi_qla_host *ha,
62126ffd7b4SAdheer Chandravanshi 					uint16_t *chap_index)
62226ffd7b4SAdheer Chandravanshi {
62326ffd7b4SAdheer Chandravanshi 	int i, rval;
62426ffd7b4SAdheer Chandravanshi 	int free_index = -1;
62526ffd7b4SAdheer Chandravanshi 	int max_chap_entries = 0;
62626ffd7b4SAdheer Chandravanshi 	struct ql4_chap_table *chap_table;
62726ffd7b4SAdheer Chandravanshi 
62826ffd7b4SAdheer Chandravanshi 	if (is_qla80XX(ha))
62926ffd7b4SAdheer Chandravanshi 		max_chap_entries = (ha->hw.flt_chap_size / 2) /
63026ffd7b4SAdheer Chandravanshi 						sizeof(struct ql4_chap_table);
63126ffd7b4SAdheer Chandravanshi 	else
63226ffd7b4SAdheer Chandravanshi 		max_chap_entries = MAX_CHAP_ENTRIES_40XX;
63326ffd7b4SAdheer Chandravanshi 
63426ffd7b4SAdheer Chandravanshi 	if (!ha->chap_list) {
63526ffd7b4SAdheer Chandravanshi 		ql4_printk(KERN_ERR, ha, "CHAP table cache is empty!\n");
63626ffd7b4SAdheer Chandravanshi 		rval = QLA_ERROR;
63726ffd7b4SAdheer Chandravanshi 		goto exit_find_chap;
63826ffd7b4SAdheer Chandravanshi 	}
63926ffd7b4SAdheer Chandravanshi 
64026ffd7b4SAdheer Chandravanshi 	for (i = 0; i < max_chap_entries; i++) {
64126ffd7b4SAdheer Chandravanshi 		chap_table = (struct ql4_chap_table *)ha->chap_list + i;
64226ffd7b4SAdheer Chandravanshi 
64326ffd7b4SAdheer Chandravanshi 		if ((chap_table->cookie !=
64426ffd7b4SAdheer Chandravanshi 		    __constant_cpu_to_le16(CHAP_VALID_COOKIE)) &&
64526ffd7b4SAdheer Chandravanshi 		   (i > MAX_RESRV_CHAP_IDX)) {
64626ffd7b4SAdheer Chandravanshi 				free_index = i;
64726ffd7b4SAdheer Chandravanshi 				break;
64826ffd7b4SAdheer Chandravanshi 		}
64926ffd7b4SAdheer Chandravanshi 	}
65026ffd7b4SAdheer Chandravanshi 
65126ffd7b4SAdheer Chandravanshi 	if (free_index != -1) {
65226ffd7b4SAdheer Chandravanshi 		*chap_index = free_index;
65326ffd7b4SAdheer Chandravanshi 		rval = QLA_SUCCESS;
65426ffd7b4SAdheer Chandravanshi 	} else {
65526ffd7b4SAdheer Chandravanshi 		rval = QLA_ERROR;
65626ffd7b4SAdheer Chandravanshi 	}
65726ffd7b4SAdheer Chandravanshi 
65826ffd7b4SAdheer Chandravanshi exit_find_chap:
65926ffd7b4SAdheer Chandravanshi 	return rval;
66026ffd7b4SAdheer Chandravanshi }
66126ffd7b4SAdheer Chandravanshi 
662376738afSNilesh Javali static int qla4xxx_get_chap_list(struct Scsi_Host *shost, uint16_t chap_tbl_idx,
663376738afSNilesh Javali 				  uint32_t *num_entries, char *buf)
664376738afSNilesh Javali {
665376738afSNilesh Javali 	struct scsi_qla_host *ha = to_qla_host(shost);
666376738afSNilesh Javali 	struct ql4_chap_table *chap_table;
667376738afSNilesh Javali 	struct iscsi_chap_rec *chap_rec;
668376738afSNilesh Javali 	int max_chap_entries = 0;
669376738afSNilesh Javali 	int valid_chap_entries = 0;
670376738afSNilesh Javali 	int ret = 0, i;
671376738afSNilesh Javali 
672d11b0ca3SVikas Chaudhary 	if (is_qla80XX(ha))
673376738afSNilesh Javali 		max_chap_entries = (ha->hw.flt_chap_size / 2) /
674376738afSNilesh Javali 					sizeof(struct ql4_chap_table);
675376738afSNilesh Javali 	else
676376738afSNilesh Javali 		max_chap_entries = MAX_CHAP_ENTRIES_40XX;
677376738afSNilesh Javali 
678376738afSNilesh Javali 	ql4_printk(KERN_INFO, ha, "%s: num_entries = %d, CHAP idx = %d\n",
679376738afSNilesh Javali 			__func__, *num_entries, chap_tbl_idx);
680376738afSNilesh Javali 
681376738afSNilesh Javali 	if (!buf) {
682376738afSNilesh Javali 		ret = -ENOMEM;
683376738afSNilesh Javali 		goto exit_get_chap_list;
684376738afSNilesh Javali 	}
685376738afSNilesh Javali 
686376738afSNilesh Javali 	chap_rec = (struct iscsi_chap_rec *) buf;
687376738afSNilesh Javali 	mutex_lock(&ha->chap_sem);
688376738afSNilesh Javali 	for (i = chap_tbl_idx; i < max_chap_entries; i++) {
689376738afSNilesh Javali 		chap_table = (struct ql4_chap_table *)ha->chap_list + i;
690376738afSNilesh Javali 		if (chap_table->cookie !=
691376738afSNilesh Javali 		    __constant_cpu_to_le16(CHAP_VALID_COOKIE))
692376738afSNilesh Javali 			continue;
693376738afSNilesh Javali 
694376738afSNilesh Javali 		chap_rec->chap_tbl_idx = i;
695376738afSNilesh Javali 		strncpy(chap_rec->username, chap_table->name,
696376738afSNilesh Javali 			ISCSI_CHAP_AUTH_NAME_MAX_LEN);
697376738afSNilesh Javali 		strncpy(chap_rec->password, chap_table->secret,
698376738afSNilesh Javali 			QL4_CHAP_MAX_SECRET_LEN);
699376738afSNilesh Javali 		chap_rec->password_length = chap_table->secret_len;
700376738afSNilesh Javali 
701376738afSNilesh Javali 		if (chap_table->flags & BIT_7) /* local */
702376738afSNilesh Javali 			chap_rec->chap_type = CHAP_TYPE_OUT;
703376738afSNilesh Javali 
704376738afSNilesh Javali 		if (chap_table->flags & BIT_6) /* peer */
705376738afSNilesh Javali 			chap_rec->chap_type = CHAP_TYPE_IN;
706376738afSNilesh Javali 
707376738afSNilesh Javali 		chap_rec++;
708376738afSNilesh Javali 
709376738afSNilesh Javali 		valid_chap_entries++;
710376738afSNilesh Javali 		if (valid_chap_entries == *num_entries)
711376738afSNilesh Javali 			break;
712376738afSNilesh Javali 		else
713376738afSNilesh Javali 			continue;
714376738afSNilesh Javali 	}
715376738afSNilesh Javali 	mutex_unlock(&ha->chap_sem);
716376738afSNilesh Javali 
717376738afSNilesh Javali exit_get_chap_list:
718376738afSNilesh Javali 	ql4_printk(KERN_INFO, ha, "%s: Valid CHAP Entries = %d\n",
719376738afSNilesh Javali 			__func__,  valid_chap_entries);
720376738afSNilesh Javali 	*num_entries = valid_chap_entries;
721376738afSNilesh Javali 	return ret;
722376738afSNilesh Javali }
723376738afSNilesh Javali 
724376738afSNilesh Javali static int __qla4xxx_is_chap_active(struct device *dev, void *data)
725376738afSNilesh Javali {
726376738afSNilesh Javali 	int ret = 0;
727376738afSNilesh Javali 	uint16_t *chap_tbl_idx = (uint16_t *) data;
728376738afSNilesh Javali 	struct iscsi_cls_session *cls_session;
729376738afSNilesh Javali 	struct iscsi_session *sess;
730376738afSNilesh Javali 	struct ddb_entry *ddb_entry;
731376738afSNilesh Javali 
732376738afSNilesh Javali 	if (!iscsi_is_session_dev(dev))
733376738afSNilesh Javali 		goto exit_is_chap_active;
734376738afSNilesh Javali 
735376738afSNilesh Javali 	cls_session = iscsi_dev_to_session(dev);
736376738afSNilesh Javali 	sess = cls_session->dd_data;
737376738afSNilesh Javali 	ddb_entry = sess->dd_data;
738376738afSNilesh Javali 
739376738afSNilesh Javali 	if (iscsi_session_chkready(cls_session))
740376738afSNilesh Javali 		goto exit_is_chap_active;
741376738afSNilesh Javali 
742376738afSNilesh Javali 	if (ddb_entry->chap_tbl_idx == *chap_tbl_idx)
743376738afSNilesh Javali 		ret = 1;
744376738afSNilesh Javali 
745376738afSNilesh Javali exit_is_chap_active:
746376738afSNilesh Javali 	return ret;
747376738afSNilesh Javali }
748376738afSNilesh Javali 
749376738afSNilesh Javali static int qla4xxx_is_chap_active(struct Scsi_Host *shost,
750376738afSNilesh Javali 				  uint16_t chap_tbl_idx)
751376738afSNilesh Javali {
752376738afSNilesh Javali 	int ret = 0;
753376738afSNilesh Javali 
754376738afSNilesh Javali 	ret = device_for_each_child(&shost->shost_gendev, &chap_tbl_idx,
755376738afSNilesh Javali 				    __qla4xxx_is_chap_active);
756376738afSNilesh Javali 
757376738afSNilesh Javali 	return ret;
758376738afSNilesh Javali }
759376738afSNilesh Javali 
760376738afSNilesh Javali static int qla4xxx_delete_chap(struct Scsi_Host *shost, uint16_t chap_tbl_idx)
761376738afSNilesh Javali {
762376738afSNilesh Javali 	struct scsi_qla_host *ha = to_qla_host(shost);
763376738afSNilesh Javali 	struct ql4_chap_table *chap_table;
764376738afSNilesh Javali 	dma_addr_t chap_dma;
765376738afSNilesh Javali 	int max_chap_entries = 0;
766376738afSNilesh Javali 	uint32_t offset = 0;
767376738afSNilesh Javali 	uint32_t chap_size;
768376738afSNilesh Javali 	int ret = 0;
769376738afSNilesh Javali 
770376738afSNilesh Javali 	chap_table = dma_pool_alloc(ha->chap_dma_pool, GFP_KERNEL, &chap_dma);
771376738afSNilesh Javali 	if (chap_table == NULL)
772376738afSNilesh Javali 		return -ENOMEM;
773376738afSNilesh Javali 
774376738afSNilesh Javali 	memset(chap_table, 0, sizeof(struct ql4_chap_table));
775376738afSNilesh Javali 
776d11b0ca3SVikas Chaudhary 	if (is_qla80XX(ha))
777376738afSNilesh Javali 		max_chap_entries = (ha->hw.flt_chap_size / 2) /
778376738afSNilesh Javali 				   sizeof(struct ql4_chap_table);
779376738afSNilesh Javali 	else
780376738afSNilesh Javali 		max_chap_entries = MAX_CHAP_ENTRIES_40XX;
781376738afSNilesh Javali 
782376738afSNilesh Javali 	if (chap_tbl_idx > max_chap_entries) {
783376738afSNilesh Javali 		ret = -EINVAL;
784376738afSNilesh Javali 		goto exit_delete_chap;
785376738afSNilesh Javali 	}
786376738afSNilesh Javali 
787376738afSNilesh Javali 	/* Check if chap index is in use.
788376738afSNilesh Javali 	 * If chap is in use don't delet chap entry */
789376738afSNilesh Javali 	ret = qla4xxx_is_chap_active(shost, chap_tbl_idx);
790376738afSNilesh Javali 	if (ret) {
791376738afSNilesh Javali 		ql4_printk(KERN_INFO, ha, "CHAP entry %d is in use, cannot "
792376738afSNilesh Javali 			   "delete from flash\n", chap_tbl_idx);
793376738afSNilesh Javali 		ret = -EBUSY;
794376738afSNilesh Javali 		goto exit_delete_chap;
795376738afSNilesh Javali 	}
796376738afSNilesh Javali 
797376738afSNilesh Javali 	chap_size = sizeof(struct ql4_chap_table);
798376738afSNilesh Javali 	if (is_qla40XX(ha))
799376738afSNilesh Javali 		offset = FLASH_CHAP_OFFSET | (chap_tbl_idx * chap_size);
800376738afSNilesh Javali 	else {
801376738afSNilesh Javali 		offset = FLASH_RAW_ACCESS_ADDR + (ha->hw.flt_region_chap << 2);
802376738afSNilesh Javali 		/* flt_chap_size is CHAP table size for both ports
803376738afSNilesh Javali 		 * so divide it by 2 to calculate the offset for second port
804376738afSNilesh Javali 		 */
805376738afSNilesh Javali 		if (ha->port_num == 1)
806376738afSNilesh Javali 			offset += (ha->hw.flt_chap_size / 2);
807376738afSNilesh Javali 		offset += (chap_tbl_idx * chap_size);
808376738afSNilesh Javali 	}
809376738afSNilesh Javali 
810376738afSNilesh Javali 	ret = qla4xxx_get_flash(ha, chap_dma, offset, chap_size);
811376738afSNilesh Javali 	if (ret != QLA_SUCCESS) {
812376738afSNilesh Javali 		ret = -EINVAL;
813376738afSNilesh Javali 		goto exit_delete_chap;
814376738afSNilesh Javali 	}
815376738afSNilesh Javali 
816376738afSNilesh Javali 	DEBUG2(ql4_printk(KERN_INFO, ha, "Chap Cookie: x%x\n",
817376738afSNilesh Javali 			  __le16_to_cpu(chap_table->cookie)));
818376738afSNilesh Javali 
819376738afSNilesh Javali 	if (__le16_to_cpu(chap_table->cookie) != CHAP_VALID_COOKIE) {
820376738afSNilesh Javali 		ql4_printk(KERN_ERR, ha, "No valid chap entry found\n");
821376738afSNilesh Javali 		goto exit_delete_chap;
822376738afSNilesh Javali 	}
823376738afSNilesh Javali 
824376738afSNilesh Javali 	chap_table->cookie = __constant_cpu_to_le16(0xFFFF);
825376738afSNilesh Javali 
826376738afSNilesh Javali 	offset = FLASH_CHAP_OFFSET |
827376738afSNilesh Javali 			(chap_tbl_idx * sizeof(struct ql4_chap_table));
828376738afSNilesh Javali 	ret = qla4xxx_set_flash(ha, chap_dma, offset, chap_size,
829376738afSNilesh Javali 				FLASH_OPT_RMW_COMMIT);
830376738afSNilesh Javali 	if (ret == QLA_SUCCESS && ha->chap_list) {
831376738afSNilesh Javali 		mutex_lock(&ha->chap_sem);
832376738afSNilesh Javali 		/* Update ha chap_list cache */
833376738afSNilesh Javali 		memcpy((struct ql4_chap_table *)ha->chap_list + chap_tbl_idx,
834376738afSNilesh Javali 			chap_table, sizeof(struct ql4_chap_table));
835376738afSNilesh Javali 		mutex_unlock(&ha->chap_sem);
836376738afSNilesh Javali 	}
837376738afSNilesh Javali 	if (ret != QLA_SUCCESS)
838376738afSNilesh Javali 		ret =  -EINVAL;
839376738afSNilesh Javali 
840376738afSNilesh Javali exit_delete_chap:
841376738afSNilesh Javali 	dma_pool_free(ha->chap_dma_pool, chap_table, chap_dma);
842376738afSNilesh Javali 	return ret;
843376738afSNilesh Javali }
844376738afSNilesh Javali 
84526ffd7b4SAdheer Chandravanshi /**
84626ffd7b4SAdheer Chandravanshi  * qla4xxx_set_chap_entry - Make chap entry with given information
84726ffd7b4SAdheer Chandravanshi  * @shost: pointer to host
84826ffd7b4SAdheer Chandravanshi  * @data: chap info - credentials, index and type to make chap entry
84926ffd7b4SAdheer Chandravanshi  * @len: length of data
85026ffd7b4SAdheer Chandravanshi  *
85126ffd7b4SAdheer Chandravanshi  * Add or update chap entry with the given information
85226ffd7b4SAdheer Chandravanshi  **/
85326ffd7b4SAdheer Chandravanshi static int qla4xxx_set_chap_entry(struct Scsi_Host *shost, void *data, int len)
85426ffd7b4SAdheer Chandravanshi {
85526ffd7b4SAdheer Chandravanshi 	struct scsi_qla_host *ha = to_qla_host(shost);
85626ffd7b4SAdheer Chandravanshi 	struct iscsi_chap_rec chap_rec;
85726ffd7b4SAdheer Chandravanshi 	struct ql4_chap_table *chap_entry = NULL;
85826ffd7b4SAdheer Chandravanshi 	struct iscsi_param_info *param_info;
85926ffd7b4SAdheer Chandravanshi 	struct nlattr *attr;
86026ffd7b4SAdheer Chandravanshi 	int max_chap_entries = 0;
86126ffd7b4SAdheer Chandravanshi 	int type;
86226ffd7b4SAdheer Chandravanshi 	int rem = len;
86326ffd7b4SAdheer Chandravanshi 	int rc = 0;
8643c60cfd7SDan Carpenter 	int size;
86526ffd7b4SAdheer Chandravanshi 
86626ffd7b4SAdheer Chandravanshi 	memset(&chap_rec, 0, sizeof(chap_rec));
86726ffd7b4SAdheer Chandravanshi 
86826ffd7b4SAdheer Chandravanshi 	nla_for_each_attr(attr, data, len, rem) {
86926ffd7b4SAdheer Chandravanshi 		param_info = nla_data(attr);
87026ffd7b4SAdheer Chandravanshi 
87126ffd7b4SAdheer Chandravanshi 		switch (param_info->param) {
87226ffd7b4SAdheer Chandravanshi 		case ISCSI_CHAP_PARAM_INDEX:
87326ffd7b4SAdheer Chandravanshi 			chap_rec.chap_tbl_idx = *(uint16_t *)param_info->value;
87426ffd7b4SAdheer Chandravanshi 			break;
87526ffd7b4SAdheer Chandravanshi 		case ISCSI_CHAP_PARAM_CHAP_TYPE:
87626ffd7b4SAdheer Chandravanshi 			chap_rec.chap_type = param_info->value[0];
87726ffd7b4SAdheer Chandravanshi 			break;
87826ffd7b4SAdheer Chandravanshi 		case ISCSI_CHAP_PARAM_USERNAME:
8793c60cfd7SDan Carpenter 			size = min_t(size_t, sizeof(chap_rec.username),
88026ffd7b4SAdheer Chandravanshi 				     param_info->len);
8813c60cfd7SDan Carpenter 			memcpy(chap_rec.username, param_info->value, size);
88226ffd7b4SAdheer Chandravanshi 			break;
88326ffd7b4SAdheer Chandravanshi 		case ISCSI_CHAP_PARAM_PASSWORD:
8843c60cfd7SDan Carpenter 			size = min_t(size_t, sizeof(chap_rec.password),
88526ffd7b4SAdheer Chandravanshi 				     param_info->len);
8863c60cfd7SDan Carpenter 			memcpy(chap_rec.password, param_info->value, size);
88726ffd7b4SAdheer Chandravanshi 			break;
88826ffd7b4SAdheer Chandravanshi 		case ISCSI_CHAP_PARAM_PASSWORD_LEN:
88926ffd7b4SAdheer Chandravanshi 			chap_rec.password_length = param_info->value[0];
89026ffd7b4SAdheer Chandravanshi 			break;
89126ffd7b4SAdheer Chandravanshi 		default:
89226ffd7b4SAdheer Chandravanshi 			ql4_printk(KERN_ERR, ha,
89326ffd7b4SAdheer Chandravanshi 				   "%s: No such sysfs attribute\n", __func__);
89426ffd7b4SAdheer Chandravanshi 			rc = -ENOSYS;
89526ffd7b4SAdheer Chandravanshi 			goto exit_set_chap;
89626ffd7b4SAdheer Chandravanshi 		};
89726ffd7b4SAdheer Chandravanshi 	}
89826ffd7b4SAdheer Chandravanshi 
89926ffd7b4SAdheer Chandravanshi 	if (chap_rec.chap_type == CHAP_TYPE_IN)
90026ffd7b4SAdheer Chandravanshi 		type = BIDI_CHAP;
90126ffd7b4SAdheer Chandravanshi 	else
90226ffd7b4SAdheer Chandravanshi 		type = LOCAL_CHAP;
90326ffd7b4SAdheer Chandravanshi 
90426ffd7b4SAdheer Chandravanshi 	if (is_qla80XX(ha))
90526ffd7b4SAdheer Chandravanshi 		max_chap_entries = (ha->hw.flt_chap_size / 2) /
90626ffd7b4SAdheer Chandravanshi 				   sizeof(struct ql4_chap_table);
90726ffd7b4SAdheer Chandravanshi 	else
90826ffd7b4SAdheer Chandravanshi 		max_chap_entries = MAX_CHAP_ENTRIES_40XX;
90926ffd7b4SAdheer Chandravanshi 
91026ffd7b4SAdheer Chandravanshi 	mutex_lock(&ha->chap_sem);
91126ffd7b4SAdheer Chandravanshi 	if (chap_rec.chap_tbl_idx < max_chap_entries) {
91226ffd7b4SAdheer Chandravanshi 		rc = qla4xxx_get_chap_by_index(ha, chap_rec.chap_tbl_idx,
91326ffd7b4SAdheer Chandravanshi 					       &chap_entry);
91426ffd7b4SAdheer Chandravanshi 		if (!rc) {
91526ffd7b4SAdheer Chandravanshi 			if (!(type == qla4xxx_get_chap_type(chap_entry))) {
91626ffd7b4SAdheer Chandravanshi 				ql4_printk(KERN_INFO, ha,
91726ffd7b4SAdheer Chandravanshi 					   "Type mismatch for CHAP entry %d\n",
91826ffd7b4SAdheer Chandravanshi 					   chap_rec.chap_tbl_idx);
91926ffd7b4SAdheer Chandravanshi 				rc = -EINVAL;
92026ffd7b4SAdheer Chandravanshi 				goto exit_unlock_chap;
92126ffd7b4SAdheer Chandravanshi 			}
92226ffd7b4SAdheer Chandravanshi 
92326ffd7b4SAdheer Chandravanshi 			/* If chap index is in use then don't modify it */
92426ffd7b4SAdheer Chandravanshi 			rc = qla4xxx_is_chap_active(shost,
92526ffd7b4SAdheer Chandravanshi 						    chap_rec.chap_tbl_idx);
92626ffd7b4SAdheer Chandravanshi 			if (rc) {
92726ffd7b4SAdheer Chandravanshi 				ql4_printk(KERN_INFO, ha,
92826ffd7b4SAdheer Chandravanshi 					   "CHAP entry %d is in use\n",
92926ffd7b4SAdheer Chandravanshi 					   chap_rec.chap_tbl_idx);
93026ffd7b4SAdheer Chandravanshi 				rc = -EBUSY;
93126ffd7b4SAdheer Chandravanshi 				goto exit_unlock_chap;
93226ffd7b4SAdheer Chandravanshi 			}
93326ffd7b4SAdheer Chandravanshi 		}
93426ffd7b4SAdheer Chandravanshi 	} else {
93526ffd7b4SAdheer Chandravanshi 		rc = qla4xxx_find_free_chap_index(ha, &chap_rec.chap_tbl_idx);
93626ffd7b4SAdheer Chandravanshi 		if (rc) {
93726ffd7b4SAdheer Chandravanshi 			ql4_printk(KERN_INFO, ha, "CHAP entry not available\n");
93826ffd7b4SAdheer Chandravanshi 			rc = -EBUSY;
93926ffd7b4SAdheer Chandravanshi 			goto exit_unlock_chap;
94026ffd7b4SAdheer Chandravanshi 		}
94126ffd7b4SAdheer Chandravanshi 	}
94226ffd7b4SAdheer Chandravanshi 
94326ffd7b4SAdheer Chandravanshi 	rc = qla4xxx_set_chap(ha, chap_rec.username, chap_rec.password,
94426ffd7b4SAdheer Chandravanshi 			      chap_rec.chap_tbl_idx, type);
94526ffd7b4SAdheer Chandravanshi 
94626ffd7b4SAdheer Chandravanshi exit_unlock_chap:
94726ffd7b4SAdheer Chandravanshi 	mutex_unlock(&ha->chap_sem);
94826ffd7b4SAdheer Chandravanshi 
94926ffd7b4SAdheer Chandravanshi exit_set_chap:
95026ffd7b4SAdheer Chandravanshi 	return rc;
95126ffd7b4SAdheer Chandravanshi }
95226ffd7b4SAdheer Chandravanshi 
953ed1086e0SVikas Chaudhary static int qla4xxx_get_iface_param(struct iscsi_iface *iface,
954ed1086e0SVikas Chaudhary 				   enum iscsi_param_type param_type,
955ed1086e0SVikas Chaudhary 				   int param, char *buf)
956ed1086e0SVikas Chaudhary {
957ed1086e0SVikas Chaudhary 	struct Scsi_Host *shost = iscsi_iface_to_shost(iface);
958ed1086e0SVikas Chaudhary 	struct scsi_qla_host *ha = to_qla_host(shost);
959f8e93412SHarish Zunjarrao 	int ival;
960f8e93412SHarish Zunjarrao 	char *pval = NULL;
961ed1086e0SVikas Chaudhary 	int len = -ENOSYS;
962ed1086e0SVikas Chaudhary 
963f8e93412SHarish Zunjarrao 	if (param_type == ISCSI_NET_PARAM) {
964ed1086e0SVikas Chaudhary 		switch (param) {
965ed1086e0SVikas Chaudhary 		case ISCSI_NET_PARAM_IPV4_ADDR:
966ed1086e0SVikas Chaudhary 			len = sprintf(buf, "%pI4\n", &ha->ip_config.ip_address);
967ed1086e0SVikas Chaudhary 			break;
968ed1086e0SVikas Chaudhary 		case ISCSI_NET_PARAM_IPV4_SUBNET:
969f8e93412SHarish Zunjarrao 			len = sprintf(buf, "%pI4\n",
970f8e93412SHarish Zunjarrao 				      &ha->ip_config.subnet_mask);
971ed1086e0SVikas Chaudhary 			break;
972ed1086e0SVikas Chaudhary 		case ISCSI_NET_PARAM_IPV4_GW:
973ed1086e0SVikas Chaudhary 			len = sprintf(buf, "%pI4\n", &ha->ip_config.gateway);
974ed1086e0SVikas Chaudhary 			break;
975ed1086e0SVikas Chaudhary 		case ISCSI_NET_PARAM_IFACE_ENABLE:
976f8e93412SHarish Zunjarrao 			if (iface->iface_type == ISCSI_IFACE_TYPE_IPV4) {
977f8e93412SHarish Zunjarrao 				OP_STATE(ha->ip_config.ipv4_options,
978f8e93412SHarish Zunjarrao 					 IPOPT_IPV4_PROTOCOL_ENABLE, pval);
979f8e93412SHarish Zunjarrao 			} else {
980f8e93412SHarish Zunjarrao 				OP_STATE(ha->ip_config.ipv6_options,
981f8e93412SHarish Zunjarrao 					 IPV6_OPT_IPV6_PROTOCOL_ENABLE, pval);
982f8e93412SHarish Zunjarrao 			}
983f8e93412SHarish Zunjarrao 
984f8e93412SHarish Zunjarrao 			len = sprintf(buf, "%s\n", pval);
985ed1086e0SVikas Chaudhary 			break;
986ed1086e0SVikas Chaudhary 		case ISCSI_NET_PARAM_IPV4_BOOTPROTO:
987ed1086e0SVikas Chaudhary 			len = sprintf(buf, "%s\n",
988f8e93412SHarish Zunjarrao 				      (ha->ip_config.tcp_options &
989f8e93412SHarish Zunjarrao 				       TCPOPT_DHCP_ENABLE) ?
990ed1086e0SVikas Chaudhary 				      "dhcp" : "static");
991ed1086e0SVikas Chaudhary 			break;
992ed1086e0SVikas Chaudhary 		case ISCSI_NET_PARAM_IPV6_ADDR:
993ed1086e0SVikas Chaudhary 			if (iface->iface_num == 0)
994f8e93412SHarish Zunjarrao 				len = sprintf(buf, "%pI6\n",
995f8e93412SHarish Zunjarrao 					      &ha->ip_config.ipv6_addr0);
996ed1086e0SVikas Chaudhary 			if (iface->iface_num == 1)
997f8e93412SHarish Zunjarrao 				len = sprintf(buf, "%pI6\n",
998f8e93412SHarish Zunjarrao 					      &ha->ip_config.ipv6_addr1);
999ed1086e0SVikas Chaudhary 			break;
1000ed1086e0SVikas Chaudhary 		case ISCSI_NET_PARAM_IPV6_LINKLOCAL:
1001ed1086e0SVikas Chaudhary 			len = sprintf(buf, "%pI6\n",
1002ed1086e0SVikas Chaudhary 				      &ha->ip_config.ipv6_link_local_addr);
1003ed1086e0SVikas Chaudhary 			break;
1004ed1086e0SVikas Chaudhary 		case ISCSI_NET_PARAM_IPV6_ROUTER:
1005ed1086e0SVikas Chaudhary 			len = sprintf(buf, "%pI6\n",
1006ed1086e0SVikas Chaudhary 				      &ha->ip_config.ipv6_default_router_addr);
1007ed1086e0SVikas Chaudhary 			break;
1008ed1086e0SVikas Chaudhary 		case ISCSI_NET_PARAM_IPV6_ADDR_AUTOCFG:
1009f8e93412SHarish Zunjarrao 			pval = (ha->ip_config.ipv6_addl_options &
1010ed1086e0SVikas Chaudhary 				IPV6_ADDOPT_NEIGHBOR_DISCOVERY_ADDR_ENABLE) ?
1011f8e93412SHarish Zunjarrao 				"nd" : "static";
1012f8e93412SHarish Zunjarrao 
1013f8e93412SHarish Zunjarrao 			len = sprintf(buf, "%s\n", pval);
1014ed1086e0SVikas Chaudhary 			break;
1015ed1086e0SVikas Chaudhary 		case ISCSI_NET_PARAM_IPV6_LINKLOCAL_AUTOCFG:
1016f8e93412SHarish Zunjarrao 			pval = (ha->ip_config.ipv6_addl_options &
1017ed1086e0SVikas Chaudhary 				IPV6_ADDOPT_AUTOCONFIG_LINK_LOCAL_ADDR) ?
1018f8e93412SHarish Zunjarrao 				"auto" : "static";
1019f8e93412SHarish Zunjarrao 
1020f8e93412SHarish Zunjarrao 			len = sprintf(buf, "%s\n", pval);
1021ed1086e0SVikas Chaudhary 			break;
10226ac73e8cSVikas Chaudhary 		case ISCSI_NET_PARAM_VLAN_ID:
10236ac73e8cSVikas Chaudhary 			if (iface->iface_type == ISCSI_IFACE_TYPE_IPV4)
1024f8e93412SHarish Zunjarrao 				ival = ha->ip_config.ipv4_vlan_tag &
1025f8e93412SHarish Zunjarrao 				       ISCSI_MAX_VLAN_ID;
1026f8e93412SHarish Zunjarrao 			else
1027f8e93412SHarish Zunjarrao 				ival = ha->ip_config.ipv6_vlan_tag &
1028f8e93412SHarish Zunjarrao 				       ISCSI_MAX_VLAN_ID;
1029f8e93412SHarish Zunjarrao 
1030f8e93412SHarish Zunjarrao 			len = sprintf(buf, "%d\n", ival);
10316ac73e8cSVikas Chaudhary 			break;
10326ac73e8cSVikas Chaudhary 		case ISCSI_NET_PARAM_VLAN_PRIORITY:
10336ac73e8cSVikas Chaudhary 			if (iface->iface_type == ISCSI_IFACE_TYPE_IPV4)
1034f8e93412SHarish Zunjarrao 				ival = (ha->ip_config.ipv4_vlan_tag >> 13) &
1035f8e93412SHarish Zunjarrao 				       ISCSI_MAX_VLAN_PRIORITY;
1036f8e93412SHarish Zunjarrao 			else
1037f8e93412SHarish Zunjarrao 				ival = (ha->ip_config.ipv6_vlan_tag >> 13) &
1038f8e93412SHarish Zunjarrao 				       ISCSI_MAX_VLAN_PRIORITY;
1039f8e93412SHarish Zunjarrao 
1040f8e93412SHarish Zunjarrao 			len = sprintf(buf, "%d\n", ival);
10416ac73e8cSVikas Chaudhary 			break;
10426ac73e8cSVikas Chaudhary 		case ISCSI_NET_PARAM_VLAN_ENABLED:
1043f8e93412SHarish Zunjarrao 			if (iface->iface_type == ISCSI_IFACE_TYPE_IPV4) {
1044f8e93412SHarish Zunjarrao 				OP_STATE(ha->ip_config.ipv4_options,
1045f8e93412SHarish Zunjarrao 					 IPOPT_VLAN_TAGGING_ENABLE, pval);
1046f8e93412SHarish Zunjarrao 			} else {
1047f8e93412SHarish Zunjarrao 				OP_STATE(ha->ip_config.ipv6_options,
1048f8e93412SHarish Zunjarrao 					 IPV6_OPT_VLAN_TAGGING_ENABLE, pval);
1049f8e93412SHarish Zunjarrao 			}
1050f8e93412SHarish Zunjarrao 			len = sprintf(buf, "%s\n", pval);
10516ac73e8cSVikas Chaudhary 			break;
1052943c157bSVikas Chaudhary 		case ISCSI_NET_PARAM_MTU:
1053943c157bSVikas Chaudhary 			len = sprintf(buf, "%d\n", ha->ip_config.eth_mtu_size);
1054943c157bSVikas Chaudhary 			break;
10552ada7fc5SVikas Chaudhary 		case ISCSI_NET_PARAM_PORT:
10562ada7fc5SVikas Chaudhary 			if (iface->iface_type == ISCSI_IFACE_TYPE_IPV4)
1057f8e93412SHarish Zunjarrao 				len = sprintf(buf, "%d\n",
1058f8e93412SHarish Zunjarrao 					      ha->ip_config.ipv4_port);
1059f8e93412SHarish Zunjarrao 			else
1060f8e93412SHarish Zunjarrao 				len = sprintf(buf, "%d\n",
1061f8e93412SHarish Zunjarrao 					      ha->ip_config.ipv6_port);
1062f8e93412SHarish Zunjarrao 			break;
1063f8e93412SHarish Zunjarrao 		case ISCSI_NET_PARAM_IPADDR_STATE:
1064f8e93412SHarish Zunjarrao 			if (iface->iface_type == ISCSI_IFACE_TYPE_IPV4) {
1065f8e93412SHarish Zunjarrao 				pval = iscsi_get_ipaddress_state_name(
1066f8e93412SHarish Zunjarrao 						ha->ip_config.ipv4_addr_state);
1067f8e93412SHarish Zunjarrao 			} else {
1068f8e93412SHarish Zunjarrao 				if (iface->iface_num == 0)
1069f8e93412SHarish Zunjarrao 					pval = iscsi_get_ipaddress_state_name(
1070f8e93412SHarish Zunjarrao 						ha->ip_config.ipv6_addr0_state);
1071f8e93412SHarish Zunjarrao 				else if (iface->iface_num == 1)
1072f8e93412SHarish Zunjarrao 					pval = iscsi_get_ipaddress_state_name(
1073f8e93412SHarish Zunjarrao 						ha->ip_config.ipv6_addr1_state);
1074f8e93412SHarish Zunjarrao 			}
1075f8e93412SHarish Zunjarrao 
1076f8e93412SHarish Zunjarrao 			len = sprintf(buf, "%s\n", pval);
1077f8e93412SHarish Zunjarrao 			break;
1078f8e93412SHarish Zunjarrao 		case ISCSI_NET_PARAM_IPV6_LINKLOCAL_STATE:
1079f8e93412SHarish Zunjarrao 			pval = iscsi_get_ipaddress_state_name(
1080f8e93412SHarish Zunjarrao 					ha->ip_config.ipv6_link_local_state);
1081f8e93412SHarish Zunjarrao 			len = sprintf(buf, "%s\n", pval);
1082f8e93412SHarish Zunjarrao 			break;
1083f8e93412SHarish Zunjarrao 		case ISCSI_NET_PARAM_IPV6_ROUTER_STATE:
1084f8e93412SHarish Zunjarrao 			pval = iscsi_get_router_state_name(
1085f8e93412SHarish Zunjarrao 				      ha->ip_config.ipv6_default_router_state);
1086f8e93412SHarish Zunjarrao 			len = sprintf(buf, "%s\n", pval);
1087f8e93412SHarish Zunjarrao 			break;
1088f8e93412SHarish Zunjarrao 		case ISCSI_NET_PARAM_DELAYED_ACK_EN:
1089f8e93412SHarish Zunjarrao 			if (iface->iface_type == ISCSI_IFACE_TYPE_IPV4) {
1090f8e93412SHarish Zunjarrao 				OP_STATE(~ha->ip_config.tcp_options,
1091f8e93412SHarish Zunjarrao 					 TCPOPT_DELAYED_ACK_DISABLE, pval);
1092f8e93412SHarish Zunjarrao 			} else {
1093f8e93412SHarish Zunjarrao 				OP_STATE(~ha->ip_config.ipv6_tcp_options,
1094f8e93412SHarish Zunjarrao 					 IPV6_TCPOPT_DELAYED_ACK_DISABLE, pval);
1095f8e93412SHarish Zunjarrao 			}
1096f8e93412SHarish Zunjarrao 			len = sprintf(buf, "%s\n", pval);
1097f8e93412SHarish Zunjarrao 			break;
1098f8e93412SHarish Zunjarrao 		case ISCSI_NET_PARAM_TCP_NAGLE_DISABLE:
1099f8e93412SHarish Zunjarrao 			if (iface->iface_type == ISCSI_IFACE_TYPE_IPV4) {
1100f8e93412SHarish Zunjarrao 				OP_STATE(~ha->ip_config.tcp_options,
1101f8e93412SHarish Zunjarrao 					 TCPOPT_NAGLE_ALGO_DISABLE, pval);
1102f8e93412SHarish Zunjarrao 			} else {
1103f8e93412SHarish Zunjarrao 				OP_STATE(~ha->ip_config.ipv6_tcp_options,
1104f8e93412SHarish Zunjarrao 					 IPV6_TCPOPT_NAGLE_ALGO_DISABLE, pval);
1105f8e93412SHarish Zunjarrao 			}
1106f8e93412SHarish Zunjarrao 			len = sprintf(buf, "%s\n", pval);
1107f8e93412SHarish Zunjarrao 			break;
1108f8e93412SHarish Zunjarrao 		case ISCSI_NET_PARAM_TCP_WSF_DISABLE:
1109f8e93412SHarish Zunjarrao 			if (iface->iface_type == ISCSI_IFACE_TYPE_IPV4) {
1110f8e93412SHarish Zunjarrao 				OP_STATE(~ha->ip_config.tcp_options,
1111f8e93412SHarish Zunjarrao 					 TCPOPT_WINDOW_SCALE_DISABLE, pval);
1112f8e93412SHarish Zunjarrao 			} else {
1113f8e93412SHarish Zunjarrao 				OP_STATE(~ha->ip_config.ipv6_tcp_options,
1114f8e93412SHarish Zunjarrao 					 IPV6_TCPOPT_WINDOW_SCALE_DISABLE,
1115f8e93412SHarish Zunjarrao 					 pval);
1116f8e93412SHarish Zunjarrao 			}
1117f8e93412SHarish Zunjarrao 			len = sprintf(buf, "%s\n", pval);
1118f8e93412SHarish Zunjarrao 			break;
1119f8e93412SHarish Zunjarrao 		case ISCSI_NET_PARAM_TCP_WSF:
1120f8e93412SHarish Zunjarrao 			if (iface->iface_type == ISCSI_IFACE_TYPE_IPV4)
1121f8e93412SHarish Zunjarrao 				len = sprintf(buf, "%d\n",
1122f8e93412SHarish Zunjarrao 					      ha->ip_config.tcp_wsf);
1123f8e93412SHarish Zunjarrao 			else
1124f8e93412SHarish Zunjarrao 				len = sprintf(buf, "%d\n",
1125f8e93412SHarish Zunjarrao 					      ha->ip_config.ipv6_tcp_wsf);
1126f8e93412SHarish Zunjarrao 			break;
1127f8e93412SHarish Zunjarrao 		case ISCSI_NET_PARAM_TCP_TIMER_SCALE:
1128f8e93412SHarish Zunjarrao 			if (iface->iface_type == ISCSI_IFACE_TYPE_IPV4)
1129f8e93412SHarish Zunjarrao 				ival = (ha->ip_config.tcp_options &
1130f8e93412SHarish Zunjarrao 					TCPOPT_TIMER_SCALE) >> 1;
1131f8e93412SHarish Zunjarrao 			else
1132f8e93412SHarish Zunjarrao 				ival = (ha->ip_config.ipv6_tcp_options &
1133f8e93412SHarish Zunjarrao 					IPV6_TCPOPT_TIMER_SCALE) >> 1;
1134f8e93412SHarish Zunjarrao 
1135f8e93412SHarish Zunjarrao 			len = sprintf(buf, "%d\n", ival);
1136f8e93412SHarish Zunjarrao 			break;
1137f8e93412SHarish Zunjarrao 		case ISCSI_NET_PARAM_TCP_TIMESTAMP_EN:
1138f8e93412SHarish Zunjarrao 			if (iface->iface_type == ISCSI_IFACE_TYPE_IPV4) {
1139f8e93412SHarish Zunjarrao 				OP_STATE(ha->ip_config.tcp_options,
1140f8e93412SHarish Zunjarrao 					 TCPOPT_TIMESTAMP_ENABLE, pval);
1141f8e93412SHarish Zunjarrao 			} else {
1142f8e93412SHarish Zunjarrao 				OP_STATE(ha->ip_config.ipv6_tcp_options,
1143f8e93412SHarish Zunjarrao 					 IPV6_TCPOPT_TIMESTAMP_EN, pval);
1144f8e93412SHarish Zunjarrao 			}
1145f8e93412SHarish Zunjarrao 			len = sprintf(buf, "%s\n", pval);
1146f8e93412SHarish Zunjarrao 			break;
1147f8e93412SHarish Zunjarrao 		case ISCSI_NET_PARAM_CACHE_ID:
1148f8e93412SHarish Zunjarrao 			if (iface->iface_type == ISCSI_IFACE_TYPE_IPV4)
1149f8e93412SHarish Zunjarrao 				len = sprintf(buf, "%d\n",
1150f8e93412SHarish Zunjarrao 					      ha->ip_config.ipv4_cache_id);
1151f8e93412SHarish Zunjarrao 			else
1152f8e93412SHarish Zunjarrao 				len = sprintf(buf, "%d\n",
1153f8e93412SHarish Zunjarrao 					      ha->ip_config.ipv6_cache_id);
1154f8e93412SHarish Zunjarrao 			break;
1155f8e93412SHarish Zunjarrao 		case ISCSI_NET_PARAM_IPV4_DHCP_DNS_ADDR_EN:
1156f8e93412SHarish Zunjarrao 			OP_STATE(ha->ip_config.tcp_options,
1157f8e93412SHarish Zunjarrao 				 TCPOPT_DNS_SERVER_IP_EN, pval);
1158f8e93412SHarish Zunjarrao 
1159f8e93412SHarish Zunjarrao 			len = sprintf(buf, "%s\n", pval);
1160f8e93412SHarish Zunjarrao 			break;
1161f8e93412SHarish Zunjarrao 		case ISCSI_NET_PARAM_IPV4_DHCP_SLP_DA_EN:
1162f8e93412SHarish Zunjarrao 			OP_STATE(ha->ip_config.tcp_options,
1163f8e93412SHarish Zunjarrao 				 TCPOPT_SLP_DA_INFO_EN, pval);
1164f8e93412SHarish Zunjarrao 
1165f8e93412SHarish Zunjarrao 			len = sprintf(buf, "%s\n", pval);
1166f8e93412SHarish Zunjarrao 			break;
1167f8e93412SHarish Zunjarrao 		case ISCSI_NET_PARAM_IPV4_TOS_EN:
1168f8e93412SHarish Zunjarrao 			OP_STATE(ha->ip_config.ipv4_options,
1169f8e93412SHarish Zunjarrao 				 IPOPT_IPV4_TOS_EN, pval);
1170f8e93412SHarish Zunjarrao 
1171f8e93412SHarish Zunjarrao 			len = sprintf(buf, "%s\n", pval);
1172f8e93412SHarish Zunjarrao 			break;
1173f8e93412SHarish Zunjarrao 		case ISCSI_NET_PARAM_IPV4_TOS:
1174f8e93412SHarish Zunjarrao 			len = sprintf(buf, "%d\n", ha->ip_config.ipv4_tos);
1175f8e93412SHarish Zunjarrao 			break;
1176f8e93412SHarish Zunjarrao 		case ISCSI_NET_PARAM_IPV4_GRAT_ARP_EN:
1177f8e93412SHarish Zunjarrao 			OP_STATE(ha->ip_config.ipv4_options,
1178f8e93412SHarish Zunjarrao 				 IPOPT_GRAT_ARP_EN, pval);
1179f8e93412SHarish Zunjarrao 
1180f8e93412SHarish Zunjarrao 			len = sprintf(buf, "%s\n", pval);
1181f8e93412SHarish Zunjarrao 			break;
1182f8e93412SHarish Zunjarrao 		case ISCSI_NET_PARAM_IPV4_DHCP_ALT_CLIENT_ID_EN:
1183f8e93412SHarish Zunjarrao 			OP_STATE(ha->ip_config.ipv4_options, IPOPT_ALT_CID_EN,
1184f8e93412SHarish Zunjarrao 				 pval);
1185f8e93412SHarish Zunjarrao 
1186f8e93412SHarish Zunjarrao 			len = sprintf(buf, "%s\n", pval);
1187f8e93412SHarish Zunjarrao 			break;
1188f8e93412SHarish Zunjarrao 		case ISCSI_NET_PARAM_IPV4_DHCP_ALT_CLIENT_ID:
1189f8e93412SHarish Zunjarrao 			pval = (ha->ip_config.ipv4_alt_cid_len) ?
1190f8e93412SHarish Zunjarrao 			       (char *)ha->ip_config.ipv4_alt_cid : "";
1191f8e93412SHarish Zunjarrao 
1192f8e93412SHarish Zunjarrao 			len = sprintf(buf, "%s\n", pval);
1193f8e93412SHarish Zunjarrao 			break;
1194f8e93412SHarish Zunjarrao 		case ISCSI_NET_PARAM_IPV4_DHCP_REQ_VENDOR_ID_EN:
1195f8e93412SHarish Zunjarrao 			OP_STATE(ha->ip_config.ipv4_options,
1196f8e93412SHarish Zunjarrao 				 IPOPT_REQ_VID_EN, pval);
1197f8e93412SHarish Zunjarrao 
1198f8e93412SHarish Zunjarrao 			len = sprintf(buf, "%s\n", pval);
1199f8e93412SHarish Zunjarrao 			break;
1200f8e93412SHarish Zunjarrao 		case ISCSI_NET_PARAM_IPV4_DHCP_USE_VENDOR_ID_EN:
1201f8e93412SHarish Zunjarrao 			OP_STATE(ha->ip_config.ipv4_options,
1202f8e93412SHarish Zunjarrao 				 IPOPT_USE_VID_EN, pval);
1203f8e93412SHarish Zunjarrao 
1204f8e93412SHarish Zunjarrao 			len = sprintf(buf, "%s\n", pval);
1205f8e93412SHarish Zunjarrao 			break;
1206f8e93412SHarish Zunjarrao 		case ISCSI_NET_PARAM_IPV4_DHCP_VENDOR_ID:
1207f8e93412SHarish Zunjarrao 			pval = (ha->ip_config.ipv4_vid_len) ?
1208f8e93412SHarish Zunjarrao 			       (char *)ha->ip_config.ipv4_vid : "";
1209f8e93412SHarish Zunjarrao 
1210f8e93412SHarish Zunjarrao 			len = sprintf(buf, "%s\n", pval);
1211f8e93412SHarish Zunjarrao 			break;
1212f8e93412SHarish Zunjarrao 		case ISCSI_NET_PARAM_IPV4_DHCP_LEARN_IQN_EN:
1213f8e93412SHarish Zunjarrao 			OP_STATE(ha->ip_config.ipv4_options,
1214f8e93412SHarish Zunjarrao 				 IPOPT_LEARN_IQN_EN, pval);
1215f8e93412SHarish Zunjarrao 
1216f8e93412SHarish Zunjarrao 			len = sprintf(buf, "%s\n", pval);
1217f8e93412SHarish Zunjarrao 			break;
1218f8e93412SHarish Zunjarrao 		case ISCSI_NET_PARAM_IPV4_FRAGMENT_DISABLE:
1219f8e93412SHarish Zunjarrao 			OP_STATE(~ha->ip_config.ipv4_options,
1220f8e93412SHarish Zunjarrao 				 IPOPT_FRAGMENTATION_DISABLE, pval);
1221f8e93412SHarish Zunjarrao 
1222f8e93412SHarish Zunjarrao 			len = sprintf(buf, "%s\n", pval);
1223f8e93412SHarish Zunjarrao 			break;
1224f8e93412SHarish Zunjarrao 		case ISCSI_NET_PARAM_IPV4_IN_FORWARD_EN:
1225f8e93412SHarish Zunjarrao 			OP_STATE(ha->ip_config.ipv4_options,
1226f8e93412SHarish Zunjarrao 				 IPOPT_IN_FORWARD_EN, pval);
1227f8e93412SHarish Zunjarrao 
1228f8e93412SHarish Zunjarrao 			len = sprintf(buf, "%s\n", pval);
1229f8e93412SHarish Zunjarrao 			break;
1230f8e93412SHarish Zunjarrao 		case ISCSI_NET_PARAM_REDIRECT_EN:
1231f8e93412SHarish Zunjarrao 			if (iface->iface_type == ISCSI_IFACE_TYPE_IPV4) {
1232f8e93412SHarish Zunjarrao 				OP_STATE(ha->ip_config.ipv4_options,
1233f8e93412SHarish Zunjarrao 					 IPOPT_ARP_REDIRECT_EN, pval);
1234f8e93412SHarish Zunjarrao 			} else {
1235f8e93412SHarish Zunjarrao 				OP_STATE(ha->ip_config.ipv6_options,
1236f8e93412SHarish Zunjarrao 					 IPV6_OPT_REDIRECT_EN, pval);
1237f8e93412SHarish Zunjarrao 			}
1238f8e93412SHarish Zunjarrao 			len = sprintf(buf, "%s\n", pval);
1239f8e93412SHarish Zunjarrao 			break;
1240f8e93412SHarish Zunjarrao 		case ISCSI_NET_PARAM_IPV4_TTL:
1241f8e93412SHarish Zunjarrao 			len = sprintf(buf, "%d\n", ha->ip_config.ipv4_ttl);
1242f8e93412SHarish Zunjarrao 			break;
1243f8e93412SHarish Zunjarrao 		case ISCSI_NET_PARAM_IPV6_GRAT_NEIGHBOR_ADV_EN:
1244f8e93412SHarish Zunjarrao 			OP_STATE(ha->ip_config.ipv6_options,
1245f8e93412SHarish Zunjarrao 				 IPV6_OPT_GRAT_NEIGHBOR_ADV_EN, pval);
1246f8e93412SHarish Zunjarrao 
1247f8e93412SHarish Zunjarrao 			len = sprintf(buf, "%s\n", pval);
1248f8e93412SHarish Zunjarrao 			break;
1249f8e93412SHarish Zunjarrao 		case ISCSI_NET_PARAM_IPV6_MLD_EN:
1250f8e93412SHarish Zunjarrao 			OP_STATE(ha->ip_config.ipv6_addl_options,
1251f8e93412SHarish Zunjarrao 				 IPV6_ADDOPT_MLD_EN, pval);
1252f8e93412SHarish Zunjarrao 
1253f8e93412SHarish Zunjarrao 			len = sprintf(buf, "%s\n", pval);
1254f8e93412SHarish Zunjarrao 			break;
1255f8e93412SHarish Zunjarrao 		case ISCSI_NET_PARAM_IPV6_FLOW_LABEL:
1256f8e93412SHarish Zunjarrao 			len = sprintf(buf, "%u\n", ha->ip_config.ipv6_flow_lbl);
1257f8e93412SHarish Zunjarrao 			break;
1258f8e93412SHarish Zunjarrao 		case ISCSI_NET_PARAM_IPV6_TRAFFIC_CLASS:
1259f8e93412SHarish Zunjarrao 			len = sprintf(buf, "%d\n",
1260f8e93412SHarish Zunjarrao 				      ha->ip_config.ipv6_traffic_class);
1261f8e93412SHarish Zunjarrao 			break;
1262f8e93412SHarish Zunjarrao 		case ISCSI_NET_PARAM_IPV6_HOP_LIMIT:
1263f8e93412SHarish Zunjarrao 			len = sprintf(buf, "%d\n",
1264f8e93412SHarish Zunjarrao 				      ha->ip_config.ipv6_hop_limit);
1265f8e93412SHarish Zunjarrao 			break;
1266f8e93412SHarish Zunjarrao 		case ISCSI_NET_PARAM_IPV6_ND_REACHABLE_TMO:
1267f8e93412SHarish Zunjarrao 			len = sprintf(buf, "%d\n",
1268f8e93412SHarish Zunjarrao 				      ha->ip_config.ipv6_nd_reach_time);
1269f8e93412SHarish Zunjarrao 			break;
1270f8e93412SHarish Zunjarrao 		case ISCSI_NET_PARAM_IPV6_ND_REXMIT_TIME:
1271f8e93412SHarish Zunjarrao 			len = sprintf(buf, "%d\n",
1272f8e93412SHarish Zunjarrao 				      ha->ip_config.ipv6_nd_rexmit_timer);
1273f8e93412SHarish Zunjarrao 			break;
1274f8e93412SHarish Zunjarrao 		case ISCSI_NET_PARAM_IPV6_ND_STALE_TMO:
1275f8e93412SHarish Zunjarrao 			len = sprintf(buf, "%d\n",
1276f8e93412SHarish Zunjarrao 				      ha->ip_config.ipv6_nd_stale_timeout);
1277f8e93412SHarish Zunjarrao 			break;
1278f8e93412SHarish Zunjarrao 		case ISCSI_NET_PARAM_IPV6_DUP_ADDR_DETECT_CNT:
1279f8e93412SHarish Zunjarrao 			len = sprintf(buf, "%d\n",
1280f8e93412SHarish Zunjarrao 				      ha->ip_config.ipv6_dup_addr_detect_count);
1281f8e93412SHarish Zunjarrao 			break;
1282f8e93412SHarish Zunjarrao 		case ISCSI_NET_PARAM_IPV6_RTR_ADV_LINK_MTU:
1283f8e93412SHarish Zunjarrao 			len = sprintf(buf, "%d\n",
1284f8e93412SHarish Zunjarrao 				      ha->ip_config.ipv6_gw_advrt_mtu);
12852ada7fc5SVikas Chaudhary 			break;
1286ed1086e0SVikas Chaudhary 		default:
1287ed1086e0SVikas Chaudhary 			len = -ENOSYS;
1288ed1086e0SVikas Chaudhary 		}
1289f8e93412SHarish Zunjarrao 	} else if (param_type == ISCSI_IFACE_PARAM) {
1290f8e93412SHarish Zunjarrao 		switch (param) {
1291f8e93412SHarish Zunjarrao 		case ISCSI_IFACE_PARAM_DEF_TASKMGMT_TMO:
1292f8e93412SHarish Zunjarrao 			len = sprintf(buf, "%d\n", ha->ip_config.def_timeout);
1293f8e93412SHarish Zunjarrao 			break;
1294f8e93412SHarish Zunjarrao 		case ISCSI_IFACE_PARAM_HDRDGST_EN:
1295f8e93412SHarish Zunjarrao 			OP_STATE(ha->ip_config.iscsi_options,
1296f8e93412SHarish Zunjarrao 				 ISCSIOPTS_HEADER_DIGEST_EN, pval);
1297f8e93412SHarish Zunjarrao 
1298f8e93412SHarish Zunjarrao 			len = sprintf(buf, "%s\n", pval);
1299f8e93412SHarish Zunjarrao 			break;
1300f8e93412SHarish Zunjarrao 		case ISCSI_IFACE_PARAM_DATADGST_EN:
1301f8e93412SHarish Zunjarrao 			OP_STATE(ha->ip_config.iscsi_options,
1302f8e93412SHarish Zunjarrao 				 ISCSIOPTS_DATA_DIGEST_EN, pval);
1303f8e93412SHarish Zunjarrao 
1304f8e93412SHarish Zunjarrao 			len = sprintf(buf, "%s\n", pval);
1305f8e93412SHarish Zunjarrao 			break;
1306f8e93412SHarish Zunjarrao 		case ISCSI_IFACE_PARAM_IMM_DATA_EN:
1307f8e93412SHarish Zunjarrao 			OP_STATE(ha->ip_config.iscsi_options,
1308f8e93412SHarish Zunjarrao 				 ISCSIOPTS_IMMEDIATE_DATA_EN, pval);
1309f8e93412SHarish Zunjarrao 
1310f8e93412SHarish Zunjarrao 			len = sprintf(buf, "%s\n", pval);
1311f8e93412SHarish Zunjarrao 			break;
1312f8e93412SHarish Zunjarrao 		case ISCSI_IFACE_PARAM_INITIAL_R2T_EN:
1313f8e93412SHarish Zunjarrao 			OP_STATE(ha->ip_config.iscsi_options,
1314f8e93412SHarish Zunjarrao 				 ISCSIOPTS_INITIAL_R2T_EN, pval);
1315f8e93412SHarish Zunjarrao 
1316f8e93412SHarish Zunjarrao 			len = sprintf(buf, "%s\n", pval);
1317f8e93412SHarish Zunjarrao 			break;
1318f8e93412SHarish Zunjarrao 		case ISCSI_IFACE_PARAM_DATASEQ_INORDER_EN:
1319f8e93412SHarish Zunjarrao 			OP_STATE(ha->ip_config.iscsi_options,
1320f8e93412SHarish Zunjarrao 				 ISCSIOPTS_DATA_SEQ_INORDER_EN, pval);
1321f8e93412SHarish Zunjarrao 
1322f8e93412SHarish Zunjarrao 			len = sprintf(buf, "%s\n", pval);
1323f8e93412SHarish Zunjarrao 			break;
1324f8e93412SHarish Zunjarrao 		case ISCSI_IFACE_PARAM_PDU_INORDER_EN:
1325f8e93412SHarish Zunjarrao 			OP_STATE(ha->ip_config.iscsi_options,
1326f8e93412SHarish Zunjarrao 				 ISCSIOPTS_DATA_PDU_INORDER_EN, pval);
1327f8e93412SHarish Zunjarrao 
1328f8e93412SHarish Zunjarrao 			len = sprintf(buf, "%s\n", pval);
1329f8e93412SHarish Zunjarrao 			break;
1330f8e93412SHarish Zunjarrao 		case ISCSI_IFACE_PARAM_ERL:
1331f8e93412SHarish Zunjarrao 			len = sprintf(buf, "%d\n",
1332f8e93412SHarish Zunjarrao 				      (ha->ip_config.iscsi_options &
1333f8e93412SHarish Zunjarrao 				       ISCSIOPTS_ERL));
1334f8e93412SHarish Zunjarrao 			break;
1335f8e93412SHarish Zunjarrao 		case ISCSI_IFACE_PARAM_MAX_RECV_DLENGTH:
1336f8e93412SHarish Zunjarrao 			len = sprintf(buf, "%u\n",
1337f8e93412SHarish Zunjarrao 				      ha->ip_config.iscsi_max_pdu_size *
1338f8e93412SHarish Zunjarrao 				      BYTE_UNITS);
1339f8e93412SHarish Zunjarrao 			break;
1340f8e93412SHarish Zunjarrao 		case ISCSI_IFACE_PARAM_FIRST_BURST:
1341f8e93412SHarish Zunjarrao 			len = sprintf(buf, "%u\n",
1342f8e93412SHarish Zunjarrao 				      ha->ip_config.iscsi_first_burst_len *
1343f8e93412SHarish Zunjarrao 				      BYTE_UNITS);
1344f8e93412SHarish Zunjarrao 			break;
1345f8e93412SHarish Zunjarrao 		case ISCSI_IFACE_PARAM_MAX_R2T:
1346f8e93412SHarish Zunjarrao 			len = sprintf(buf, "%d\n",
1347f8e93412SHarish Zunjarrao 				      ha->ip_config.iscsi_max_outstnd_r2t);
1348f8e93412SHarish Zunjarrao 			break;
1349f8e93412SHarish Zunjarrao 		case ISCSI_IFACE_PARAM_MAX_BURST:
1350f8e93412SHarish Zunjarrao 			len = sprintf(buf, "%u\n",
1351f8e93412SHarish Zunjarrao 				      ha->ip_config.iscsi_max_burst_len *
1352f8e93412SHarish Zunjarrao 				      BYTE_UNITS);
1353f8e93412SHarish Zunjarrao 			break;
1354f8e93412SHarish Zunjarrao 		case ISCSI_IFACE_PARAM_CHAP_AUTH_EN:
1355f8e93412SHarish Zunjarrao 			OP_STATE(ha->ip_config.iscsi_options,
1356f8e93412SHarish Zunjarrao 				 ISCSIOPTS_CHAP_AUTH_EN, pval);
1357f8e93412SHarish Zunjarrao 
1358f8e93412SHarish Zunjarrao 			len = sprintf(buf, "%s\n", pval);
1359f8e93412SHarish Zunjarrao 			break;
1360f8e93412SHarish Zunjarrao 		case ISCSI_IFACE_PARAM_BIDI_CHAP_EN:
1361f8e93412SHarish Zunjarrao 			OP_STATE(ha->ip_config.iscsi_options,
1362f8e93412SHarish Zunjarrao 				 ISCSIOPTS_BIDI_CHAP_EN, pval);
1363f8e93412SHarish Zunjarrao 
1364f8e93412SHarish Zunjarrao 			len = sprintf(buf, "%s\n", pval);
1365f8e93412SHarish Zunjarrao 			break;
1366f8e93412SHarish Zunjarrao 		case ISCSI_IFACE_PARAM_DISCOVERY_AUTH_OPTIONAL:
1367f8e93412SHarish Zunjarrao 			OP_STATE(ha->ip_config.iscsi_options,
1368f8e93412SHarish Zunjarrao 				 ISCSIOPTS_DISCOVERY_AUTH_EN, pval);
1369f8e93412SHarish Zunjarrao 
1370f8e93412SHarish Zunjarrao 			len = sprintf(buf, "%s\n", pval);
1371f8e93412SHarish Zunjarrao 			break;
1372f8e93412SHarish Zunjarrao 		case ISCSI_IFACE_PARAM_DISCOVERY_LOGOUT_EN:
1373f8e93412SHarish Zunjarrao 			OP_STATE(ha->ip_config.iscsi_options,
1374f8e93412SHarish Zunjarrao 				 ISCSIOPTS_DISCOVERY_LOGOUT_EN, pval);
1375f8e93412SHarish Zunjarrao 
1376f8e93412SHarish Zunjarrao 			len = sprintf(buf, "%s\n", pval);
1377f8e93412SHarish Zunjarrao 			break;
1378f8e93412SHarish Zunjarrao 		case ISCSI_IFACE_PARAM_STRICT_LOGIN_COMP_EN:
1379f8e93412SHarish Zunjarrao 			OP_STATE(ha->ip_config.iscsi_options,
1380f8e93412SHarish Zunjarrao 				 ISCSIOPTS_STRICT_LOGIN_COMP_EN, pval);
1381f8e93412SHarish Zunjarrao 
1382f8e93412SHarish Zunjarrao 			len = sprintf(buf, "%s\n", pval);
1383f8e93412SHarish Zunjarrao 			break;
1384f8e93412SHarish Zunjarrao 		case ISCSI_IFACE_PARAM_INITIATOR_NAME:
1385f8e93412SHarish Zunjarrao 			len = sprintf(buf, "%s\n", ha->ip_config.iscsi_name);
1386f8e93412SHarish Zunjarrao 			break;
1387f8e93412SHarish Zunjarrao 		default:
1388f8e93412SHarish Zunjarrao 			len = -ENOSYS;
1389f8e93412SHarish Zunjarrao 		}
1390f8e93412SHarish Zunjarrao 	}
1391ed1086e0SVikas Chaudhary 
1392ed1086e0SVikas Chaudhary 	return len;
1393ed1086e0SVikas Chaudhary }
1394ed1086e0SVikas Chaudhary 
1395b3a271a9SManish Rangankar static struct iscsi_endpoint *
1396b3a271a9SManish Rangankar qla4xxx_ep_connect(struct Scsi_Host *shost, struct sockaddr *dst_addr,
1397b3a271a9SManish Rangankar 		   int non_blocking)
1398b3a271a9SManish Rangankar {
1399b3a271a9SManish Rangankar 	int ret;
1400b3a271a9SManish Rangankar 	struct iscsi_endpoint *ep;
1401b3a271a9SManish Rangankar 	struct qla_endpoint *qla_ep;
1402b3a271a9SManish Rangankar 	struct scsi_qla_host *ha;
1403b3a271a9SManish Rangankar 	struct sockaddr_in *addr;
1404b3a271a9SManish Rangankar 	struct sockaddr_in6 *addr6;
1405b3a271a9SManish Rangankar 
1406b3a271a9SManish Rangankar 	DEBUG2(printk(KERN_INFO "Func: %s\n", __func__));
1407b3a271a9SManish Rangankar 	if (!shost) {
1408b3a271a9SManish Rangankar 		ret = -ENXIO;
1409b3a271a9SManish Rangankar 		printk(KERN_ERR "%s: shost is NULL\n",
1410b3a271a9SManish Rangankar 		       __func__);
1411b3a271a9SManish Rangankar 		return ERR_PTR(ret);
1412b3a271a9SManish Rangankar 	}
1413b3a271a9SManish Rangankar 
1414b3a271a9SManish Rangankar 	ha = iscsi_host_priv(shost);
1415b3a271a9SManish Rangankar 
1416b3a271a9SManish Rangankar 	ep = iscsi_create_endpoint(sizeof(struct qla_endpoint));
1417b3a271a9SManish Rangankar 	if (!ep) {
1418b3a271a9SManish Rangankar 		ret = -ENOMEM;
1419b3a271a9SManish Rangankar 		return ERR_PTR(ret);
1420b3a271a9SManish Rangankar 	}
1421b3a271a9SManish Rangankar 
1422b3a271a9SManish Rangankar 	qla_ep = ep->dd_data;
1423b3a271a9SManish Rangankar 	memset(qla_ep, 0, sizeof(struct qla_endpoint));
1424b3a271a9SManish Rangankar 	if (dst_addr->sa_family == AF_INET) {
1425b3a271a9SManish Rangankar 		memcpy(&qla_ep->dst_addr, dst_addr, sizeof(struct sockaddr_in));
1426b3a271a9SManish Rangankar 		addr = (struct sockaddr_in *)&qla_ep->dst_addr;
1427b3a271a9SManish Rangankar 		DEBUG2(ql4_printk(KERN_INFO, ha, "%s: %pI4\n", __func__,
1428b3a271a9SManish Rangankar 				  (char *)&addr->sin_addr));
1429b3a271a9SManish Rangankar 	} else if (dst_addr->sa_family == AF_INET6) {
1430b3a271a9SManish Rangankar 		memcpy(&qla_ep->dst_addr, dst_addr,
1431b3a271a9SManish Rangankar 		       sizeof(struct sockaddr_in6));
1432b3a271a9SManish Rangankar 		addr6 = (struct sockaddr_in6 *)&qla_ep->dst_addr;
1433b3a271a9SManish Rangankar 		DEBUG2(ql4_printk(KERN_INFO, ha, "%s: %pI6\n", __func__,
1434b3a271a9SManish Rangankar 				  (char *)&addr6->sin6_addr));
1435b3a271a9SManish Rangankar 	}
1436b3a271a9SManish Rangankar 
1437b3a271a9SManish Rangankar 	qla_ep->host = shost;
1438b3a271a9SManish Rangankar 
1439b3a271a9SManish Rangankar 	return ep;
1440b3a271a9SManish Rangankar }
1441b3a271a9SManish Rangankar 
1442b3a271a9SManish Rangankar static int qla4xxx_ep_poll(struct iscsi_endpoint *ep, int timeout_ms)
1443b3a271a9SManish Rangankar {
1444b3a271a9SManish Rangankar 	struct qla_endpoint *qla_ep;
1445b3a271a9SManish Rangankar 	struct scsi_qla_host *ha;
1446b3a271a9SManish Rangankar 	int ret = 0;
1447b3a271a9SManish Rangankar 
1448b3a271a9SManish Rangankar 	DEBUG2(printk(KERN_INFO "Func: %s\n", __func__));
1449b3a271a9SManish Rangankar 	qla_ep = ep->dd_data;
1450b3a271a9SManish Rangankar 	ha = to_qla_host(qla_ep->host);
1451b3a271a9SManish Rangankar 
145213483730SMike Christie 	if (adapter_up(ha) && !test_bit(AF_BUILD_DDB_LIST, &ha->flags))
1453b3a271a9SManish Rangankar 		ret = 1;
1454b3a271a9SManish Rangankar 
1455b3a271a9SManish Rangankar 	return ret;
1456b3a271a9SManish Rangankar }
1457b3a271a9SManish Rangankar 
1458b3a271a9SManish Rangankar static void qla4xxx_ep_disconnect(struct iscsi_endpoint *ep)
1459b3a271a9SManish Rangankar {
1460b3a271a9SManish Rangankar 	DEBUG2(printk(KERN_INFO "Func: %s\n", __func__));
1461b3a271a9SManish Rangankar 	iscsi_destroy_endpoint(ep);
1462b3a271a9SManish Rangankar }
1463b3a271a9SManish Rangankar 
1464b3a271a9SManish Rangankar static int qla4xxx_get_ep_param(struct iscsi_endpoint *ep,
1465b3a271a9SManish Rangankar 				enum iscsi_param param,
1466b3a271a9SManish Rangankar 				char *buf)
1467b3a271a9SManish Rangankar {
1468b3a271a9SManish Rangankar 	struct qla_endpoint *qla_ep = ep->dd_data;
1469b3a271a9SManish Rangankar 	struct sockaddr *dst_addr;
1470b3a271a9SManish Rangankar 
1471b3a271a9SManish Rangankar 	DEBUG2(printk(KERN_INFO "Func: %s\n", __func__));
1472b3a271a9SManish Rangankar 
1473b3a271a9SManish Rangankar 	switch (param) {
1474b3a271a9SManish Rangankar 	case ISCSI_PARAM_CONN_PORT:
1475b3a271a9SManish Rangankar 	case ISCSI_PARAM_CONN_ADDRESS:
1476b3a271a9SManish Rangankar 		if (!qla_ep)
1477b3a271a9SManish Rangankar 			return -ENOTCONN;
1478b3a271a9SManish Rangankar 
1479b3a271a9SManish Rangankar 		dst_addr = (struct sockaddr *)&qla_ep->dst_addr;
1480b3a271a9SManish Rangankar 		if (!dst_addr)
1481b3a271a9SManish Rangankar 			return -ENOTCONN;
1482b3a271a9SManish Rangankar 
1483b3a271a9SManish Rangankar 		return iscsi_conn_get_addr_param((struct sockaddr_storage *)
1484b3a271a9SManish Rangankar 						 &qla_ep->dst_addr, param, buf);
1485b3a271a9SManish Rangankar 	default:
1486b3a271a9SManish Rangankar 		return -ENOSYS;
1487b3a271a9SManish Rangankar 	}
1488b3a271a9SManish Rangankar }
1489b3a271a9SManish Rangankar 
1490b3a271a9SManish Rangankar static void qla4xxx_conn_get_stats(struct iscsi_cls_conn *cls_conn,
1491b3a271a9SManish Rangankar 				   struct iscsi_stats *stats)
1492b3a271a9SManish Rangankar {
1493b3a271a9SManish Rangankar 	struct iscsi_session *sess;
1494b3a271a9SManish Rangankar 	struct iscsi_cls_session *cls_sess;
1495b3a271a9SManish Rangankar 	struct ddb_entry *ddb_entry;
1496b3a271a9SManish Rangankar 	struct scsi_qla_host *ha;
1497b3a271a9SManish Rangankar 	struct ql_iscsi_stats *ql_iscsi_stats;
1498b3a271a9SManish Rangankar 	int stats_size;
1499b3a271a9SManish Rangankar 	int ret;
1500b3a271a9SManish Rangankar 	dma_addr_t iscsi_stats_dma;
1501b3a271a9SManish Rangankar 
1502b3a271a9SManish Rangankar 	DEBUG2(printk(KERN_INFO "Func: %s\n", __func__));
1503b3a271a9SManish Rangankar 
1504b3a271a9SManish Rangankar 	cls_sess = iscsi_conn_to_session(cls_conn);
1505b3a271a9SManish Rangankar 	sess = cls_sess->dd_data;
1506b3a271a9SManish Rangankar 	ddb_entry = sess->dd_data;
1507b3a271a9SManish Rangankar 	ha = ddb_entry->ha;
1508b3a271a9SManish Rangankar 
1509b3a271a9SManish Rangankar 	stats_size = PAGE_ALIGN(sizeof(struct ql_iscsi_stats));
1510b3a271a9SManish Rangankar 	/* Allocate memory */
1511b3a271a9SManish Rangankar 	ql_iscsi_stats = dma_alloc_coherent(&ha->pdev->dev, stats_size,
1512b3a271a9SManish Rangankar 					    &iscsi_stats_dma, GFP_KERNEL);
1513b3a271a9SManish Rangankar 	if (!ql_iscsi_stats) {
1514b3a271a9SManish Rangankar 		ql4_printk(KERN_ERR, ha,
1515b3a271a9SManish Rangankar 			   "Unable to allocate memory for iscsi stats\n");
1516b3a271a9SManish Rangankar 		goto exit_get_stats;
1517b3a271a9SManish Rangankar 	}
1518b3a271a9SManish Rangankar 
1519b3a271a9SManish Rangankar 	ret =  qla4xxx_get_mgmt_data(ha, ddb_entry->fw_ddb_index, stats_size,
1520b3a271a9SManish Rangankar 				     iscsi_stats_dma);
1521b3a271a9SManish Rangankar 	if (ret != QLA_SUCCESS) {
1522b3a271a9SManish Rangankar 		ql4_printk(KERN_ERR, ha,
152359e13d48SMasanari Iida 			   "Unable to retrieve iscsi stats\n");
1524b3a271a9SManish Rangankar 		goto free_stats;
1525b3a271a9SManish Rangankar 	}
1526b3a271a9SManish Rangankar 
1527b3a271a9SManish Rangankar 	/* octets */
1528b3a271a9SManish Rangankar 	stats->txdata_octets = le64_to_cpu(ql_iscsi_stats->tx_data_octets);
1529b3a271a9SManish Rangankar 	stats->rxdata_octets = le64_to_cpu(ql_iscsi_stats->rx_data_octets);
1530b3a271a9SManish Rangankar 	/* xmit pdus */
1531b3a271a9SManish Rangankar 	stats->noptx_pdus = le32_to_cpu(ql_iscsi_stats->tx_nopout_pdus);
1532b3a271a9SManish Rangankar 	stats->scsicmd_pdus = le32_to_cpu(ql_iscsi_stats->tx_scsi_cmd_pdus);
1533b3a271a9SManish Rangankar 	stats->tmfcmd_pdus = le32_to_cpu(ql_iscsi_stats->tx_tmf_cmd_pdus);
1534b3a271a9SManish Rangankar 	stats->login_pdus = le32_to_cpu(ql_iscsi_stats->tx_login_cmd_pdus);
1535b3a271a9SManish Rangankar 	stats->text_pdus = le32_to_cpu(ql_iscsi_stats->tx_text_cmd_pdus);
1536b3a271a9SManish Rangankar 	stats->dataout_pdus = le32_to_cpu(ql_iscsi_stats->tx_scsi_write_pdus);
1537b3a271a9SManish Rangankar 	stats->logout_pdus = le32_to_cpu(ql_iscsi_stats->tx_logout_cmd_pdus);
1538b3a271a9SManish Rangankar 	stats->snack_pdus = le32_to_cpu(ql_iscsi_stats->tx_snack_req_pdus);
1539b3a271a9SManish Rangankar 	/* recv pdus */
1540b3a271a9SManish Rangankar 	stats->noprx_pdus = le32_to_cpu(ql_iscsi_stats->rx_nopin_pdus);
1541b3a271a9SManish Rangankar 	stats->scsirsp_pdus = le32_to_cpu(ql_iscsi_stats->rx_scsi_resp_pdus);
1542b3a271a9SManish Rangankar 	stats->tmfrsp_pdus = le32_to_cpu(ql_iscsi_stats->rx_tmf_resp_pdus);
1543b3a271a9SManish Rangankar 	stats->textrsp_pdus = le32_to_cpu(ql_iscsi_stats->rx_text_resp_pdus);
1544b3a271a9SManish Rangankar 	stats->datain_pdus = le32_to_cpu(ql_iscsi_stats->rx_scsi_read_pdus);
1545b3a271a9SManish Rangankar 	stats->logoutrsp_pdus =
1546b3a271a9SManish Rangankar 			le32_to_cpu(ql_iscsi_stats->rx_logout_resp_pdus);
1547b3a271a9SManish Rangankar 	stats->r2t_pdus = le32_to_cpu(ql_iscsi_stats->rx_r2t_pdus);
1548b3a271a9SManish Rangankar 	stats->async_pdus = le32_to_cpu(ql_iscsi_stats->rx_async_pdus);
1549b3a271a9SManish Rangankar 	stats->rjt_pdus = le32_to_cpu(ql_iscsi_stats->rx_reject_pdus);
1550b3a271a9SManish Rangankar 
1551b3a271a9SManish Rangankar free_stats:
1552b3a271a9SManish Rangankar 	dma_free_coherent(&ha->pdev->dev, stats_size, ql_iscsi_stats,
1553b3a271a9SManish Rangankar 			  iscsi_stats_dma);
1554b3a271a9SManish Rangankar exit_get_stats:
1555b3a271a9SManish Rangankar 	return;
1556b3a271a9SManish Rangankar }
1557b3a271a9SManish Rangankar 
15585c656af7SMike Christie static enum blk_eh_timer_return qla4xxx_eh_cmd_timed_out(struct scsi_cmnd *sc)
15595c656af7SMike Christie {
15605c656af7SMike Christie 	struct iscsi_cls_session *session;
1561b3a271a9SManish Rangankar 	struct iscsi_session *sess;
1562b3a271a9SManish Rangankar 	unsigned long flags;
1563b3a271a9SManish Rangankar 	enum blk_eh_timer_return ret = BLK_EH_NOT_HANDLED;
15645c656af7SMike Christie 
15655c656af7SMike Christie 	session = starget_to_session(scsi_target(sc->device));
1566b3a271a9SManish Rangankar 	sess = session->dd_data;
15675c656af7SMike Christie 
1568b3a271a9SManish Rangankar 	spin_lock_irqsave(&session->lock, flags);
1569b3a271a9SManish Rangankar 	if (session->state == ISCSI_SESSION_FAILED)
1570b3a271a9SManish Rangankar 		ret = BLK_EH_RESET_TIMER;
1571b3a271a9SManish Rangankar 	spin_unlock_irqrestore(&session->lock, flags);
15725c656af7SMike Christie 
1573b3a271a9SManish Rangankar 	return ret;
1574568d303bSMike Christie }
1575afaf5a2dSDavid Somayajulu 
15763254dbe9SVikas Chaudhary static void qla4xxx_set_port_speed(struct Scsi_Host *shost)
15773254dbe9SVikas Chaudhary {
15783254dbe9SVikas Chaudhary 	struct scsi_qla_host *ha = to_qla_host(shost);
1579e16d166eSVikas Chaudhary 	struct iscsi_cls_host *ihost = shost->shost_data;
15803254dbe9SVikas Chaudhary 	uint32_t speed = ISCSI_PORT_SPEED_UNKNOWN;
15813254dbe9SVikas Chaudhary 
15823254dbe9SVikas Chaudhary 	qla4xxx_get_firmware_state(ha);
15833254dbe9SVikas Chaudhary 
15843254dbe9SVikas Chaudhary 	switch (ha->addl_fw_state & 0x0F00) {
15853254dbe9SVikas Chaudhary 	case FW_ADDSTATE_LINK_SPEED_10MBPS:
15863254dbe9SVikas Chaudhary 		speed = ISCSI_PORT_SPEED_10MBPS;
15873254dbe9SVikas Chaudhary 		break;
15883254dbe9SVikas Chaudhary 	case FW_ADDSTATE_LINK_SPEED_100MBPS:
15893254dbe9SVikas Chaudhary 		speed = ISCSI_PORT_SPEED_100MBPS;
15903254dbe9SVikas Chaudhary 		break;
15913254dbe9SVikas Chaudhary 	case FW_ADDSTATE_LINK_SPEED_1GBPS:
15923254dbe9SVikas Chaudhary 		speed = ISCSI_PORT_SPEED_1GBPS;
15933254dbe9SVikas Chaudhary 		break;
15943254dbe9SVikas Chaudhary 	case FW_ADDSTATE_LINK_SPEED_10GBPS:
15953254dbe9SVikas Chaudhary 		speed = ISCSI_PORT_SPEED_10GBPS;
15963254dbe9SVikas Chaudhary 		break;
15973254dbe9SVikas Chaudhary 	}
15983254dbe9SVikas Chaudhary 	ihost->port_speed = speed;
15993254dbe9SVikas Chaudhary }
16003254dbe9SVikas Chaudhary 
16013254dbe9SVikas Chaudhary static void qla4xxx_set_port_state(struct Scsi_Host *shost)
16023254dbe9SVikas Chaudhary {
16033254dbe9SVikas Chaudhary 	struct scsi_qla_host *ha = to_qla_host(shost);
1604e16d166eSVikas Chaudhary 	struct iscsi_cls_host *ihost = shost->shost_data;
16053254dbe9SVikas Chaudhary 	uint32_t state = ISCSI_PORT_STATE_DOWN;
16063254dbe9SVikas Chaudhary 
16073254dbe9SVikas Chaudhary 	if (test_bit(AF_LINK_UP, &ha->flags))
16083254dbe9SVikas Chaudhary 		state = ISCSI_PORT_STATE_UP;
16093254dbe9SVikas Chaudhary 
16103254dbe9SVikas Chaudhary 	ihost->port_state = state;
16113254dbe9SVikas Chaudhary }
16123254dbe9SVikas Chaudhary 
1613aa1e93a2SMike Christie static int qla4xxx_host_get_param(struct Scsi_Host *shost,
1614aa1e93a2SMike Christie 				  enum iscsi_host_param param, char *buf)
1615aa1e93a2SMike Christie {
1616aa1e93a2SMike Christie 	struct scsi_qla_host *ha = to_qla_host(shost);
1617aa1e93a2SMike Christie 	int len;
1618aa1e93a2SMike Christie 
1619aa1e93a2SMike Christie 	switch (param) {
1620aa1e93a2SMike Christie 	case ISCSI_HOST_PARAM_HWADDRESS:
16217ffc49a6SMichael Chan 		len = sysfs_format_mac(buf, ha->my_mac, MAC_ADDR_LEN);
1622aa1e93a2SMike Christie 		break;
162322236961SMike Christie 	case ISCSI_HOST_PARAM_IPADDRESS:
16242bab08fcSVikas Chaudhary 		len = sprintf(buf, "%pI4\n", &ha->ip_config.ip_address);
162522236961SMike Christie 		break;
16268ad5781aSMike Christie 	case ISCSI_HOST_PARAM_INITIATOR_NAME:
162722236961SMike Christie 		len = sprintf(buf, "%s\n", ha->name_string);
16288ad5781aSMike Christie 		break;
16293254dbe9SVikas Chaudhary 	case ISCSI_HOST_PARAM_PORT_STATE:
16303254dbe9SVikas Chaudhary 		qla4xxx_set_port_state(shost);
16313254dbe9SVikas Chaudhary 		len = sprintf(buf, "%s\n", iscsi_get_port_state_name(shost));
16323254dbe9SVikas Chaudhary 		break;
16333254dbe9SVikas Chaudhary 	case ISCSI_HOST_PARAM_PORT_SPEED:
16343254dbe9SVikas Chaudhary 		qla4xxx_set_port_speed(shost);
16353254dbe9SVikas Chaudhary 		len = sprintf(buf, "%s\n", iscsi_get_port_speed_name(shost));
16363254dbe9SVikas Chaudhary 		break;
1637aa1e93a2SMike Christie 	default:
1638aa1e93a2SMike Christie 		return -ENOSYS;
1639aa1e93a2SMike Christie 	}
1640aa1e93a2SMike Christie 
1641aa1e93a2SMike Christie 	return len;
1642aa1e93a2SMike Christie }
1643aa1e93a2SMike Christie 
1644ed1086e0SVikas Chaudhary static void qla4xxx_create_ipv4_iface(struct scsi_qla_host *ha)
1645ed1086e0SVikas Chaudhary {
1646ed1086e0SVikas Chaudhary 	if (ha->iface_ipv4)
1647ed1086e0SVikas Chaudhary 		return;
1648ed1086e0SVikas Chaudhary 
1649ed1086e0SVikas Chaudhary 	/* IPv4 */
1650ed1086e0SVikas Chaudhary 	ha->iface_ipv4 = iscsi_create_iface(ha->host,
1651ed1086e0SVikas Chaudhary 					    &qla4xxx_iscsi_transport,
1652ed1086e0SVikas Chaudhary 					    ISCSI_IFACE_TYPE_IPV4, 0, 0);
1653ed1086e0SVikas Chaudhary 	if (!ha->iface_ipv4)
1654ed1086e0SVikas Chaudhary 		ql4_printk(KERN_ERR, ha, "Could not create IPv4 iSCSI "
1655ed1086e0SVikas Chaudhary 			   "iface0.\n");
1656ed1086e0SVikas Chaudhary }
1657ed1086e0SVikas Chaudhary 
1658ed1086e0SVikas Chaudhary static void qla4xxx_create_ipv6_iface(struct scsi_qla_host *ha)
1659ed1086e0SVikas Chaudhary {
1660ed1086e0SVikas Chaudhary 	if (!ha->iface_ipv6_0)
1661ed1086e0SVikas Chaudhary 		/* IPv6 iface-0 */
1662ed1086e0SVikas Chaudhary 		ha->iface_ipv6_0 = iscsi_create_iface(ha->host,
1663ed1086e0SVikas Chaudhary 						      &qla4xxx_iscsi_transport,
1664ed1086e0SVikas Chaudhary 						      ISCSI_IFACE_TYPE_IPV6, 0,
1665ed1086e0SVikas Chaudhary 						      0);
1666ed1086e0SVikas Chaudhary 	if (!ha->iface_ipv6_0)
1667ed1086e0SVikas Chaudhary 		ql4_printk(KERN_ERR, ha, "Could not create IPv6 iSCSI "
1668ed1086e0SVikas Chaudhary 			   "iface0.\n");
1669ed1086e0SVikas Chaudhary 
1670ed1086e0SVikas Chaudhary 	if (!ha->iface_ipv6_1)
1671ed1086e0SVikas Chaudhary 		/* IPv6 iface-1 */
1672ed1086e0SVikas Chaudhary 		ha->iface_ipv6_1 = iscsi_create_iface(ha->host,
1673ed1086e0SVikas Chaudhary 						      &qla4xxx_iscsi_transport,
1674ed1086e0SVikas Chaudhary 						      ISCSI_IFACE_TYPE_IPV6, 1,
1675ed1086e0SVikas Chaudhary 						      0);
1676ed1086e0SVikas Chaudhary 	if (!ha->iface_ipv6_1)
1677ed1086e0SVikas Chaudhary 		ql4_printk(KERN_ERR, ha, "Could not create IPv6 iSCSI "
1678ed1086e0SVikas Chaudhary 			   "iface1.\n");
1679ed1086e0SVikas Chaudhary }
1680ed1086e0SVikas Chaudhary 
1681ed1086e0SVikas Chaudhary static void qla4xxx_create_ifaces(struct scsi_qla_host *ha)
1682ed1086e0SVikas Chaudhary {
1683ed1086e0SVikas Chaudhary 	if (ha->ip_config.ipv4_options & IPOPT_IPV4_PROTOCOL_ENABLE)
1684ed1086e0SVikas Chaudhary 		qla4xxx_create_ipv4_iface(ha);
1685ed1086e0SVikas Chaudhary 
1686ed1086e0SVikas Chaudhary 	if (ha->ip_config.ipv6_options & IPV6_OPT_IPV6_PROTOCOL_ENABLE)
1687ed1086e0SVikas Chaudhary 		qla4xxx_create_ipv6_iface(ha);
1688ed1086e0SVikas Chaudhary }
1689ed1086e0SVikas Chaudhary 
1690ed1086e0SVikas Chaudhary static void qla4xxx_destroy_ipv4_iface(struct scsi_qla_host *ha)
1691ed1086e0SVikas Chaudhary {
1692ed1086e0SVikas Chaudhary 	if (ha->iface_ipv4) {
1693ed1086e0SVikas Chaudhary 		iscsi_destroy_iface(ha->iface_ipv4);
1694ed1086e0SVikas Chaudhary 		ha->iface_ipv4 = NULL;
1695ed1086e0SVikas Chaudhary 	}
1696ed1086e0SVikas Chaudhary }
1697ed1086e0SVikas Chaudhary 
1698ed1086e0SVikas Chaudhary static void qla4xxx_destroy_ipv6_iface(struct scsi_qla_host *ha)
1699ed1086e0SVikas Chaudhary {
1700ed1086e0SVikas Chaudhary 	if (ha->iface_ipv6_0) {
1701ed1086e0SVikas Chaudhary 		iscsi_destroy_iface(ha->iface_ipv6_0);
1702ed1086e0SVikas Chaudhary 		ha->iface_ipv6_0 = NULL;
1703ed1086e0SVikas Chaudhary 	}
1704ed1086e0SVikas Chaudhary 	if (ha->iface_ipv6_1) {
1705ed1086e0SVikas Chaudhary 		iscsi_destroy_iface(ha->iface_ipv6_1);
1706ed1086e0SVikas Chaudhary 		ha->iface_ipv6_1 = NULL;
1707ed1086e0SVikas Chaudhary 	}
1708ed1086e0SVikas Chaudhary }
1709ed1086e0SVikas Chaudhary 
1710ed1086e0SVikas Chaudhary static void qla4xxx_destroy_ifaces(struct scsi_qla_host *ha)
1711ed1086e0SVikas Chaudhary {
1712ed1086e0SVikas Chaudhary 	qla4xxx_destroy_ipv4_iface(ha);
1713ed1086e0SVikas Chaudhary 	qla4xxx_destroy_ipv6_iface(ha);
1714ed1086e0SVikas Chaudhary }
1715ed1086e0SVikas Chaudhary 
1716d00efe3fSMike Christie static void qla4xxx_set_ipv6(struct scsi_qla_host *ha,
1717d00efe3fSMike Christie 			     struct iscsi_iface_param_info *iface_param,
1718d00efe3fSMike Christie 			     struct addr_ctrl_blk *init_fw_cb)
1719d00efe3fSMike Christie {
1720d00efe3fSMike Christie 	/*
1721d00efe3fSMike Christie 	 * iface_num 0 is valid for IPv6 Addr, linklocal, router, autocfg.
1722d00efe3fSMike Christie 	 * iface_num 1 is valid only for IPv6 Addr.
1723d00efe3fSMike Christie 	 */
1724d00efe3fSMike Christie 	switch (iface_param->param) {
1725d00efe3fSMike Christie 	case ISCSI_NET_PARAM_IPV6_ADDR:
1726d00efe3fSMike Christie 		if (iface_param->iface_num & 0x1)
1727d00efe3fSMike Christie 			/* IPv6 Addr 1 */
1728d00efe3fSMike Christie 			memcpy(init_fw_cb->ipv6_addr1, iface_param->value,
1729d00efe3fSMike Christie 			       sizeof(init_fw_cb->ipv6_addr1));
1730d00efe3fSMike Christie 		else
1731d00efe3fSMike Christie 			/* IPv6 Addr 0 */
1732d00efe3fSMike Christie 			memcpy(init_fw_cb->ipv6_addr0, iface_param->value,
1733d00efe3fSMike Christie 			       sizeof(init_fw_cb->ipv6_addr0));
1734d00efe3fSMike Christie 		break;
1735d00efe3fSMike Christie 	case ISCSI_NET_PARAM_IPV6_LINKLOCAL:
1736d00efe3fSMike Christie 		if (iface_param->iface_num & 0x1)
1737d00efe3fSMike Christie 			break;
1738d00efe3fSMike Christie 		memcpy(init_fw_cb->ipv6_if_id, &iface_param->value[8],
1739d00efe3fSMike Christie 		       sizeof(init_fw_cb->ipv6_if_id));
1740d00efe3fSMike Christie 		break;
1741d00efe3fSMike Christie 	case ISCSI_NET_PARAM_IPV6_ROUTER:
1742d00efe3fSMike Christie 		if (iface_param->iface_num & 0x1)
1743d00efe3fSMike Christie 			break;
1744d00efe3fSMike Christie 		memcpy(init_fw_cb->ipv6_dflt_rtr_addr, iface_param->value,
1745d00efe3fSMike Christie 		       sizeof(init_fw_cb->ipv6_dflt_rtr_addr));
1746d00efe3fSMike Christie 		break;
1747d00efe3fSMike Christie 	case ISCSI_NET_PARAM_IPV6_ADDR_AUTOCFG:
1748d00efe3fSMike Christie 		/* Autocfg applies to even interface */
1749d00efe3fSMike Christie 		if (iface_param->iface_num & 0x1)
1750d00efe3fSMike Christie 			break;
1751d00efe3fSMike Christie 
1752d00efe3fSMike Christie 		if (iface_param->value[0] == ISCSI_IPV6_AUTOCFG_DISABLE)
1753d00efe3fSMike Christie 			init_fw_cb->ipv6_addtl_opts &=
1754d00efe3fSMike Christie 				cpu_to_le16(
1755d00efe3fSMike Christie 				  ~IPV6_ADDOPT_NEIGHBOR_DISCOVERY_ADDR_ENABLE);
1756d00efe3fSMike Christie 		else if (iface_param->value[0] == ISCSI_IPV6_AUTOCFG_ND_ENABLE)
1757d00efe3fSMike Christie 			init_fw_cb->ipv6_addtl_opts |=
1758d00efe3fSMike Christie 				cpu_to_le16(
1759d00efe3fSMike Christie 				  IPV6_ADDOPT_NEIGHBOR_DISCOVERY_ADDR_ENABLE);
1760d00efe3fSMike Christie 		else
1761f8e93412SHarish Zunjarrao 			ql4_printk(KERN_ERR, ha,
1762f8e93412SHarish Zunjarrao 				   "Invalid autocfg setting for IPv6 addr\n");
1763d00efe3fSMike Christie 		break;
1764d00efe3fSMike Christie 	case ISCSI_NET_PARAM_IPV6_LINKLOCAL_AUTOCFG:
1765d00efe3fSMike Christie 		/* Autocfg applies to even interface */
1766d00efe3fSMike Christie 		if (iface_param->iface_num & 0x1)
1767d00efe3fSMike Christie 			break;
1768d00efe3fSMike Christie 
1769d00efe3fSMike Christie 		if (iface_param->value[0] ==
1770d00efe3fSMike Christie 		    ISCSI_IPV6_LINKLOCAL_AUTOCFG_ENABLE)
1771d00efe3fSMike Christie 			init_fw_cb->ipv6_addtl_opts |= cpu_to_le16(
1772d00efe3fSMike Christie 					IPV6_ADDOPT_AUTOCONFIG_LINK_LOCAL_ADDR);
1773d00efe3fSMike Christie 		else if (iface_param->value[0] ==
1774d00efe3fSMike Christie 			 ISCSI_IPV6_LINKLOCAL_AUTOCFG_DISABLE)
1775d00efe3fSMike Christie 			init_fw_cb->ipv6_addtl_opts &= cpu_to_le16(
1776d00efe3fSMike Christie 				       ~IPV6_ADDOPT_AUTOCONFIG_LINK_LOCAL_ADDR);
1777d00efe3fSMike Christie 		else
1778f8e93412SHarish Zunjarrao 			ql4_printk(KERN_ERR, ha,
1779f8e93412SHarish Zunjarrao 				   "Invalid autocfg setting for IPv6 linklocal addr\n");
1780d00efe3fSMike Christie 		break;
1781d00efe3fSMike Christie 	case ISCSI_NET_PARAM_IPV6_ROUTER_AUTOCFG:
1782d00efe3fSMike Christie 		/* Autocfg applies to even interface */
1783d00efe3fSMike Christie 		if (iface_param->iface_num & 0x1)
1784d00efe3fSMike Christie 			break;
1785d00efe3fSMike Christie 
1786d00efe3fSMike Christie 		if (iface_param->value[0] == ISCSI_IPV6_ROUTER_AUTOCFG_ENABLE)
1787d00efe3fSMike Christie 			memset(init_fw_cb->ipv6_dflt_rtr_addr, 0,
1788d00efe3fSMike Christie 			       sizeof(init_fw_cb->ipv6_dflt_rtr_addr));
1789d00efe3fSMike Christie 		break;
1790d00efe3fSMike Christie 	case ISCSI_NET_PARAM_IFACE_ENABLE:
1791ed1086e0SVikas Chaudhary 		if (iface_param->value[0] == ISCSI_IFACE_ENABLE) {
1792d00efe3fSMike Christie 			init_fw_cb->ipv6_opts |=
1793d00efe3fSMike Christie 				cpu_to_le16(IPV6_OPT_IPV6_PROTOCOL_ENABLE);
1794ed1086e0SVikas Chaudhary 			qla4xxx_create_ipv6_iface(ha);
1795ed1086e0SVikas Chaudhary 		} else {
1796d00efe3fSMike Christie 			init_fw_cb->ipv6_opts &=
1797d00efe3fSMike Christie 				cpu_to_le16(~IPV6_OPT_IPV6_PROTOCOL_ENABLE &
1798d00efe3fSMike Christie 					    0xFFFF);
1799ed1086e0SVikas Chaudhary 			qla4xxx_destroy_ipv6_iface(ha);
1800ed1086e0SVikas Chaudhary 		}
1801d00efe3fSMike Christie 		break;
18022d63673bSMike Christie 	case ISCSI_NET_PARAM_VLAN_TAG:
1803d00efe3fSMike Christie 		if (iface_param->len != sizeof(init_fw_cb->ipv6_vlan_tag))
1804d00efe3fSMike Christie 			break;
18056ac73e8cSVikas Chaudhary 		init_fw_cb->ipv6_vlan_tag =
18066ac73e8cSVikas Chaudhary 				cpu_to_be16(*(uint16_t *)iface_param->value);
18076ac73e8cSVikas Chaudhary 		break;
18086ac73e8cSVikas Chaudhary 	case ISCSI_NET_PARAM_VLAN_ENABLED:
18096ac73e8cSVikas Chaudhary 		if (iface_param->value[0] == ISCSI_VLAN_ENABLE)
18106ac73e8cSVikas Chaudhary 			init_fw_cb->ipv6_opts |=
18116ac73e8cSVikas Chaudhary 				cpu_to_le16(IPV6_OPT_VLAN_TAGGING_ENABLE);
18126ac73e8cSVikas Chaudhary 		else
18136ac73e8cSVikas Chaudhary 			init_fw_cb->ipv6_opts &=
18146ac73e8cSVikas Chaudhary 				cpu_to_le16(~IPV6_OPT_VLAN_TAGGING_ENABLE);
1815d00efe3fSMike Christie 		break;
1816943c157bSVikas Chaudhary 	case ISCSI_NET_PARAM_MTU:
1817943c157bSVikas Chaudhary 		init_fw_cb->eth_mtu_size =
1818943c157bSVikas Chaudhary 				cpu_to_le16(*(uint16_t *)iface_param->value);
1819943c157bSVikas Chaudhary 		break;
18202ada7fc5SVikas Chaudhary 	case ISCSI_NET_PARAM_PORT:
18212ada7fc5SVikas Chaudhary 		/* Autocfg applies to even interface */
18222ada7fc5SVikas Chaudhary 		if (iface_param->iface_num & 0x1)
18232ada7fc5SVikas Chaudhary 			break;
18242ada7fc5SVikas Chaudhary 
18252ada7fc5SVikas Chaudhary 		init_fw_cb->ipv6_port =
18262ada7fc5SVikas Chaudhary 				cpu_to_le16(*(uint16_t *)iface_param->value);
18272ada7fc5SVikas Chaudhary 		break;
1828f8e93412SHarish Zunjarrao 	case ISCSI_NET_PARAM_DELAYED_ACK_EN:
1829f8e93412SHarish Zunjarrao 		if (iface_param->iface_num & 0x1)
1830f8e93412SHarish Zunjarrao 			break;
1831f8e93412SHarish Zunjarrao 		if (iface_param->value[0] == ISCSI_NET_PARAM_DISABLE)
1832f8e93412SHarish Zunjarrao 			init_fw_cb->ipv6_tcp_opts |=
1833f8e93412SHarish Zunjarrao 				cpu_to_le16(IPV6_TCPOPT_DELAYED_ACK_DISABLE);
1834f8e93412SHarish Zunjarrao 		else
1835f8e93412SHarish Zunjarrao 			init_fw_cb->ipv6_tcp_opts &=
1836f8e93412SHarish Zunjarrao 				cpu_to_le16(~IPV6_TCPOPT_DELAYED_ACK_DISABLE);
1837f8e93412SHarish Zunjarrao 		break;
1838f8e93412SHarish Zunjarrao 	case ISCSI_NET_PARAM_TCP_NAGLE_DISABLE:
1839f8e93412SHarish Zunjarrao 		if (iface_param->iface_num & 0x1)
1840f8e93412SHarish Zunjarrao 			break;
1841f8e93412SHarish Zunjarrao 		if (iface_param->value[0] == ISCSI_NET_PARAM_DISABLE)
1842f8e93412SHarish Zunjarrao 			init_fw_cb->ipv6_tcp_opts |=
1843f8e93412SHarish Zunjarrao 				cpu_to_le16(IPV6_TCPOPT_NAGLE_ALGO_DISABLE);
1844f8e93412SHarish Zunjarrao 		else
1845f8e93412SHarish Zunjarrao 			init_fw_cb->ipv6_tcp_opts &=
1846f8e93412SHarish Zunjarrao 				cpu_to_le16(~IPV6_TCPOPT_NAGLE_ALGO_DISABLE);
1847f8e93412SHarish Zunjarrao 		break;
1848f8e93412SHarish Zunjarrao 	case ISCSI_NET_PARAM_TCP_WSF_DISABLE:
1849f8e93412SHarish Zunjarrao 		if (iface_param->iface_num & 0x1)
1850f8e93412SHarish Zunjarrao 			break;
1851f8e93412SHarish Zunjarrao 		if (iface_param->value[0] == ISCSI_NET_PARAM_DISABLE)
1852f8e93412SHarish Zunjarrao 			init_fw_cb->ipv6_tcp_opts |=
1853f8e93412SHarish Zunjarrao 				cpu_to_le16(IPV6_TCPOPT_WINDOW_SCALE_DISABLE);
1854f8e93412SHarish Zunjarrao 		else
1855f8e93412SHarish Zunjarrao 			init_fw_cb->ipv6_tcp_opts &=
1856f8e93412SHarish Zunjarrao 				cpu_to_le16(~IPV6_TCPOPT_WINDOW_SCALE_DISABLE);
1857f8e93412SHarish Zunjarrao 		break;
1858f8e93412SHarish Zunjarrao 	case ISCSI_NET_PARAM_TCP_WSF:
1859f8e93412SHarish Zunjarrao 		if (iface_param->iface_num & 0x1)
1860f8e93412SHarish Zunjarrao 			break;
1861f8e93412SHarish Zunjarrao 		init_fw_cb->ipv6_tcp_wsf = iface_param->value[0];
1862f8e93412SHarish Zunjarrao 		break;
1863f8e93412SHarish Zunjarrao 	case ISCSI_NET_PARAM_TCP_TIMER_SCALE:
1864f8e93412SHarish Zunjarrao 		if (iface_param->iface_num & 0x1)
1865f8e93412SHarish Zunjarrao 			break;
1866f8e93412SHarish Zunjarrao 		init_fw_cb->ipv6_tcp_opts &=
1867f8e93412SHarish Zunjarrao 					cpu_to_le16(~IPV6_TCPOPT_TIMER_SCALE);
1868f8e93412SHarish Zunjarrao 		init_fw_cb->ipv6_tcp_opts |=
1869f8e93412SHarish Zunjarrao 				cpu_to_le16((iface_param->value[0] << 1) &
1870f8e93412SHarish Zunjarrao 					    IPV6_TCPOPT_TIMER_SCALE);
1871f8e93412SHarish Zunjarrao 		break;
1872f8e93412SHarish Zunjarrao 	case ISCSI_NET_PARAM_TCP_TIMESTAMP_EN:
1873f8e93412SHarish Zunjarrao 		if (iface_param->iface_num & 0x1)
1874f8e93412SHarish Zunjarrao 			break;
1875f8e93412SHarish Zunjarrao 		if (iface_param->value[0] == ISCSI_NET_PARAM_ENABLE)
1876f8e93412SHarish Zunjarrao 			init_fw_cb->ipv6_tcp_opts |=
1877f8e93412SHarish Zunjarrao 				cpu_to_le16(IPV6_TCPOPT_TIMESTAMP_EN);
1878f8e93412SHarish Zunjarrao 		else
1879f8e93412SHarish Zunjarrao 			init_fw_cb->ipv6_tcp_opts &=
1880f8e93412SHarish Zunjarrao 				cpu_to_le16(~IPV6_TCPOPT_TIMESTAMP_EN);
1881f8e93412SHarish Zunjarrao 		break;
1882f8e93412SHarish Zunjarrao 	case ISCSI_NET_PARAM_IPV6_GRAT_NEIGHBOR_ADV_EN:
1883f8e93412SHarish Zunjarrao 		if (iface_param->iface_num & 0x1)
1884f8e93412SHarish Zunjarrao 			break;
1885f8e93412SHarish Zunjarrao 		if (iface_param->value[0] == ISCSI_NET_PARAM_ENABLE)
1886f8e93412SHarish Zunjarrao 			init_fw_cb->ipv6_opts |=
1887f8e93412SHarish Zunjarrao 				cpu_to_le16(IPV6_OPT_GRAT_NEIGHBOR_ADV_EN);
1888f8e93412SHarish Zunjarrao 		else
1889f8e93412SHarish Zunjarrao 			init_fw_cb->ipv6_opts &=
1890f8e93412SHarish Zunjarrao 				cpu_to_le16(~IPV6_OPT_GRAT_NEIGHBOR_ADV_EN);
1891f8e93412SHarish Zunjarrao 		break;
1892f8e93412SHarish Zunjarrao 	case ISCSI_NET_PARAM_REDIRECT_EN:
1893f8e93412SHarish Zunjarrao 		if (iface_param->iface_num & 0x1)
1894f8e93412SHarish Zunjarrao 			break;
1895f8e93412SHarish Zunjarrao 		if (iface_param->value[0] == ISCSI_NET_PARAM_ENABLE)
1896f8e93412SHarish Zunjarrao 			init_fw_cb->ipv6_opts |=
1897f8e93412SHarish Zunjarrao 				cpu_to_le16(IPV6_OPT_REDIRECT_EN);
1898f8e93412SHarish Zunjarrao 		else
1899f8e93412SHarish Zunjarrao 			init_fw_cb->ipv6_opts &=
1900f8e93412SHarish Zunjarrao 				cpu_to_le16(~IPV6_OPT_REDIRECT_EN);
1901f8e93412SHarish Zunjarrao 		break;
1902f8e93412SHarish Zunjarrao 	case ISCSI_NET_PARAM_IPV6_MLD_EN:
1903f8e93412SHarish Zunjarrao 		if (iface_param->iface_num & 0x1)
1904f8e93412SHarish Zunjarrao 			break;
1905f8e93412SHarish Zunjarrao 		if (iface_param->value[0] == ISCSI_NET_PARAM_ENABLE)
1906f8e93412SHarish Zunjarrao 			init_fw_cb->ipv6_addtl_opts |=
1907f8e93412SHarish Zunjarrao 				cpu_to_le16(IPV6_ADDOPT_MLD_EN);
1908f8e93412SHarish Zunjarrao 		else
1909f8e93412SHarish Zunjarrao 			init_fw_cb->ipv6_addtl_opts &=
1910f8e93412SHarish Zunjarrao 				cpu_to_le16(~IPV6_ADDOPT_MLD_EN);
1911f8e93412SHarish Zunjarrao 		break;
1912f8e93412SHarish Zunjarrao 	case ISCSI_NET_PARAM_IPV6_FLOW_LABEL:
1913f8e93412SHarish Zunjarrao 		if (iface_param->iface_num & 0x1)
1914f8e93412SHarish Zunjarrao 			break;
1915f8e93412SHarish Zunjarrao 		init_fw_cb->ipv6_flow_lbl =
1916f8e93412SHarish Zunjarrao 				cpu_to_le16(*(uint16_t *)iface_param->value);
1917f8e93412SHarish Zunjarrao 		break;
1918f8e93412SHarish Zunjarrao 	case ISCSI_NET_PARAM_IPV6_TRAFFIC_CLASS:
1919f8e93412SHarish Zunjarrao 		if (iface_param->iface_num & 0x1)
1920f8e93412SHarish Zunjarrao 			break;
1921f8e93412SHarish Zunjarrao 		init_fw_cb->ipv6_traffic_class = iface_param->value[0];
1922f8e93412SHarish Zunjarrao 		break;
1923f8e93412SHarish Zunjarrao 	case ISCSI_NET_PARAM_IPV6_HOP_LIMIT:
1924f8e93412SHarish Zunjarrao 		if (iface_param->iface_num & 0x1)
1925f8e93412SHarish Zunjarrao 			break;
1926f8e93412SHarish Zunjarrao 		init_fw_cb->ipv6_hop_limit = iface_param->value[0];
1927f8e93412SHarish Zunjarrao 		break;
1928f8e93412SHarish Zunjarrao 	case ISCSI_NET_PARAM_IPV6_ND_REACHABLE_TMO:
1929f8e93412SHarish Zunjarrao 		if (iface_param->iface_num & 0x1)
1930f8e93412SHarish Zunjarrao 			break;
1931f8e93412SHarish Zunjarrao 		init_fw_cb->ipv6_nd_reach_time =
1932f8e93412SHarish Zunjarrao 				cpu_to_le32(*(uint32_t *)iface_param->value);
1933f8e93412SHarish Zunjarrao 		break;
1934f8e93412SHarish Zunjarrao 	case ISCSI_NET_PARAM_IPV6_ND_REXMIT_TIME:
1935f8e93412SHarish Zunjarrao 		if (iface_param->iface_num & 0x1)
1936f8e93412SHarish Zunjarrao 			break;
1937f8e93412SHarish Zunjarrao 		init_fw_cb->ipv6_nd_rexmit_timer =
1938f8e93412SHarish Zunjarrao 				cpu_to_le32(*(uint32_t *)iface_param->value);
1939f8e93412SHarish Zunjarrao 		break;
1940f8e93412SHarish Zunjarrao 	case ISCSI_NET_PARAM_IPV6_ND_STALE_TMO:
1941f8e93412SHarish Zunjarrao 		if (iface_param->iface_num & 0x1)
1942f8e93412SHarish Zunjarrao 			break;
1943f8e93412SHarish Zunjarrao 		init_fw_cb->ipv6_nd_stale_timeout =
1944f8e93412SHarish Zunjarrao 				cpu_to_le32(*(uint32_t *)iface_param->value);
1945f8e93412SHarish Zunjarrao 		break;
1946f8e93412SHarish Zunjarrao 	case ISCSI_NET_PARAM_IPV6_DUP_ADDR_DETECT_CNT:
1947f8e93412SHarish Zunjarrao 		if (iface_param->iface_num & 0x1)
1948f8e93412SHarish Zunjarrao 			break;
1949f8e93412SHarish Zunjarrao 		init_fw_cb->ipv6_dup_addr_detect_count = iface_param->value[0];
1950f8e93412SHarish Zunjarrao 		break;
1951f8e93412SHarish Zunjarrao 	case ISCSI_NET_PARAM_IPV6_RTR_ADV_LINK_MTU:
1952f8e93412SHarish Zunjarrao 		if (iface_param->iface_num & 0x1)
1953f8e93412SHarish Zunjarrao 			break;
1954f8e93412SHarish Zunjarrao 		init_fw_cb->ipv6_gw_advrt_mtu =
1955f8e93412SHarish Zunjarrao 				cpu_to_le32(*(uint32_t *)iface_param->value);
1956f8e93412SHarish Zunjarrao 		break;
1957d00efe3fSMike Christie 	default:
1958d00efe3fSMike Christie 		ql4_printk(KERN_ERR, ha, "Unknown IPv6 param = %d\n",
1959d00efe3fSMike Christie 			   iface_param->param);
1960d00efe3fSMike Christie 		break;
1961d00efe3fSMike Christie 	}
1962d00efe3fSMike Christie }
1963d00efe3fSMike Christie 
1964d00efe3fSMike Christie static void qla4xxx_set_ipv4(struct scsi_qla_host *ha,
1965d00efe3fSMike Christie 			     struct iscsi_iface_param_info *iface_param,
1966d00efe3fSMike Christie 			     struct addr_ctrl_blk *init_fw_cb)
1967d00efe3fSMike Christie {
1968d00efe3fSMike Christie 	switch (iface_param->param) {
1969d00efe3fSMike Christie 	case ISCSI_NET_PARAM_IPV4_ADDR:
1970d00efe3fSMike Christie 		memcpy(init_fw_cb->ipv4_addr, iface_param->value,
1971d00efe3fSMike Christie 		       sizeof(init_fw_cb->ipv4_addr));
1972d00efe3fSMike Christie 		break;
1973d00efe3fSMike Christie 	case ISCSI_NET_PARAM_IPV4_SUBNET:
1974d00efe3fSMike Christie 		memcpy(init_fw_cb->ipv4_subnet,	iface_param->value,
1975d00efe3fSMike Christie 		       sizeof(init_fw_cb->ipv4_subnet));
1976d00efe3fSMike Christie 		break;
1977d00efe3fSMike Christie 	case ISCSI_NET_PARAM_IPV4_GW:
1978d00efe3fSMike Christie 		memcpy(init_fw_cb->ipv4_gw_addr, iface_param->value,
1979d00efe3fSMike Christie 		       sizeof(init_fw_cb->ipv4_gw_addr));
1980d00efe3fSMike Christie 		break;
1981d00efe3fSMike Christie 	case ISCSI_NET_PARAM_IPV4_BOOTPROTO:
1982d00efe3fSMike Christie 		if (iface_param->value[0] == ISCSI_BOOTPROTO_DHCP)
1983d00efe3fSMike Christie 			init_fw_cb->ipv4_tcp_opts |=
1984d00efe3fSMike Christie 					cpu_to_le16(TCPOPT_DHCP_ENABLE);
1985d00efe3fSMike Christie 		else if (iface_param->value[0] == ISCSI_BOOTPROTO_STATIC)
1986d00efe3fSMike Christie 			init_fw_cb->ipv4_tcp_opts &=
1987d00efe3fSMike Christie 					cpu_to_le16(~TCPOPT_DHCP_ENABLE);
1988d00efe3fSMike Christie 		else
1989d00efe3fSMike Christie 			ql4_printk(KERN_ERR, ha, "Invalid IPv4 bootproto\n");
1990d00efe3fSMike Christie 		break;
1991d00efe3fSMike Christie 	case ISCSI_NET_PARAM_IFACE_ENABLE:
1992ed1086e0SVikas Chaudhary 		if (iface_param->value[0] == ISCSI_IFACE_ENABLE) {
1993d00efe3fSMike Christie 			init_fw_cb->ipv4_ip_opts |=
19942bab08fcSVikas Chaudhary 				cpu_to_le16(IPOPT_IPV4_PROTOCOL_ENABLE);
1995ed1086e0SVikas Chaudhary 			qla4xxx_create_ipv4_iface(ha);
1996ed1086e0SVikas Chaudhary 		} else {
1997d00efe3fSMike Christie 			init_fw_cb->ipv4_ip_opts &=
19982bab08fcSVikas Chaudhary 				cpu_to_le16(~IPOPT_IPV4_PROTOCOL_ENABLE &
1999d00efe3fSMike Christie 					    0xFFFF);
2000ed1086e0SVikas Chaudhary 			qla4xxx_destroy_ipv4_iface(ha);
2001ed1086e0SVikas Chaudhary 		}
2002d00efe3fSMike Christie 		break;
20032d63673bSMike Christie 	case ISCSI_NET_PARAM_VLAN_TAG:
2004d00efe3fSMike Christie 		if (iface_param->len != sizeof(init_fw_cb->ipv4_vlan_tag))
2005d00efe3fSMike Christie 			break;
20066ac73e8cSVikas Chaudhary 		init_fw_cb->ipv4_vlan_tag =
20076ac73e8cSVikas Chaudhary 				cpu_to_be16(*(uint16_t *)iface_param->value);
20086ac73e8cSVikas Chaudhary 		break;
20096ac73e8cSVikas Chaudhary 	case ISCSI_NET_PARAM_VLAN_ENABLED:
20106ac73e8cSVikas Chaudhary 		if (iface_param->value[0] == ISCSI_VLAN_ENABLE)
20116ac73e8cSVikas Chaudhary 			init_fw_cb->ipv4_ip_opts |=
20126ac73e8cSVikas Chaudhary 					cpu_to_le16(IPOPT_VLAN_TAGGING_ENABLE);
20136ac73e8cSVikas Chaudhary 		else
20146ac73e8cSVikas Chaudhary 			init_fw_cb->ipv4_ip_opts &=
20156ac73e8cSVikas Chaudhary 					cpu_to_le16(~IPOPT_VLAN_TAGGING_ENABLE);
2016d00efe3fSMike Christie 		break;
2017943c157bSVikas Chaudhary 	case ISCSI_NET_PARAM_MTU:
2018943c157bSVikas Chaudhary 		init_fw_cb->eth_mtu_size =
2019943c157bSVikas Chaudhary 				cpu_to_le16(*(uint16_t *)iface_param->value);
2020943c157bSVikas Chaudhary 		break;
20212ada7fc5SVikas Chaudhary 	case ISCSI_NET_PARAM_PORT:
20222ada7fc5SVikas Chaudhary 		init_fw_cb->ipv4_port =
20232ada7fc5SVikas Chaudhary 				cpu_to_le16(*(uint16_t *)iface_param->value);
20242ada7fc5SVikas Chaudhary 		break;
2025f8e93412SHarish Zunjarrao 	case ISCSI_NET_PARAM_DELAYED_ACK_EN:
2026f8e93412SHarish Zunjarrao 		if (iface_param->iface_num & 0x1)
2027f8e93412SHarish Zunjarrao 			break;
2028f8e93412SHarish Zunjarrao 		if (iface_param->value[0] == ISCSI_NET_PARAM_DISABLE)
2029f8e93412SHarish Zunjarrao 			init_fw_cb->ipv4_tcp_opts |=
2030f8e93412SHarish Zunjarrao 				cpu_to_le16(TCPOPT_DELAYED_ACK_DISABLE);
2031f8e93412SHarish Zunjarrao 		else
2032f8e93412SHarish Zunjarrao 			init_fw_cb->ipv4_tcp_opts &=
2033f8e93412SHarish Zunjarrao 				cpu_to_le16(~TCPOPT_DELAYED_ACK_DISABLE);
2034f8e93412SHarish Zunjarrao 		break;
2035f8e93412SHarish Zunjarrao 	case ISCSI_NET_PARAM_TCP_NAGLE_DISABLE:
2036f8e93412SHarish Zunjarrao 		if (iface_param->iface_num & 0x1)
2037f8e93412SHarish Zunjarrao 			break;
2038f8e93412SHarish Zunjarrao 		if (iface_param->value[0] == ISCSI_NET_PARAM_DISABLE)
2039f8e93412SHarish Zunjarrao 			init_fw_cb->ipv4_tcp_opts |=
2040f8e93412SHarish Zunjarrao 				cpu_to_le16(TCPOPT_NAGLE_ALGO_DISABLE);
2041f8e93412SHarish Zunjarrao 		else
2042f8e93412SHarish Zunjarrao 			init_fw_cb->ipv4_tcp_opts &=
2043f8e93412SHarish Zunjarrao 				cpu_to_le16(~TCPOPT_NAGLE_ALGO_DISABLE);
2044f8e93412SHarish Zunjarrao 		break;
2045f8e93412SHarish Zunjarrao 	case ISCSI_NET_PARAM_TCP_WSF_DISABLE:
2046f8e93412SHarish Zunjarrao 		if (iface_param->iface_num & 0x1)
2047f8e93412SHarish Zunjarrao 			break;
2048f8e93412SHarish Zunjarrao 		if (iface_param->value[0] == ISCSI_NET_PARAM_DISABLE)
2049f8e93412SHarish Zunjarrao 			init_fw_cb->ipv4_tcp_opts |=
2050f8e93412SHarish Zunjarrao 				cpu_to_le16(TCPOPT_WINDOW_SCALE_DISABLE);
2051f8e93412SHarish Zunjarrao 		else
2052f8e93412SHarish Zunjarrao 			init_fw_cb->ipv4_tcp_opts &=
2053f8e93412SHarish Zunjarrao 				cpu_to_le16(~TCPOPT_WINDOW_SCALE_DISABLE);
2054f8e93412SHarish Zunjarrao 		break;
2055f8e93412SHarish Zunjarrao 	case ISCSI_NET_PARAM_TCP_WSF:
2056f8e93412SHarish Zunjarrao 		if (iface_param->iface_num & 0x1)
2057f8e93412SHarish Zunjarrao 			break;
2058f8e93412SHarish Zunjarrao 		init_fw_cb->ipv4_tcp_wsf = iface_param->value[0];
2059f8e93412SHarish Zunjarrao 		break;
2060f8e93412SHarish Zunjarrao 	case ISCSI_NET_PARAM_TCP_TIMER_SCALE:
2061f8e93412SHarish Zunjarrao 		if (iface_param->iface_num & 0x1)
2062f8e93412SHarish Zunjarrao 			break;
2063f8e93412SHarish Zunjarrao 		init_fw_cb->ipv4_tcp_opts &= cpu_to_le16(~TCPOPT_TIMER_SCALE);
2064f8e93412SHarish Zunjarrao 		init_fw_cb->ipv4_tcp_opts |=
2065f8e93412SHarish Zunjarrao 				cpu_to_le16((iface_param->value[0] << 1) &
2066f8e93412SHarish Zunjarrao 					    TCPOPT_TIMER_SCALE);
2067f8e93412SHarish Zunjarrao 		break;
2068f8e93412SHarish Zunjarrao 	case ISCSI_NET_PARAM_TCP_TIMESTAMP_EN:
2069f8e93412SHarish Zunjarrao 		if (iface_param->iface_num & 0x1)
2070f8e93412SHarish Zunjarrao 			break;
2071f8e93412SHarish Zunjarrao 		if (iface_param->value[0] == ISCSI_NET_PARAM_ENABLE)
2072f8e93412SHarish Zunjarrao 			init_fw_cb->ipv4_tcp_opts |=
2073f8e93412SHarish Zunjarrao 				cpu_to_le16(TCPOPT_TIMESTAMP_ENABLE);
2074f8e93412SHarish Zunjarrao 		else
2075f8e93412SHarish Zunjarrao 			init_fw_cb->ipv4_tcp_opts &=
2076f8e93412SHarish Zunjarrao 				cpu_to_le16(~TCPOPT_TIMESTAMP_ENABLE);
2077f8e93412SHarish Zunjarrao 		break;
2078f8e93412SHarish Zunjarrao 	case ISCSI_NET_PARAM_IPV4_DHCP_DNS_ADDR_EN:
2079f8e93412SHarish Zunjarrao 		if (iface_param->iface_num & 0x1)
2080f8e93412SHarish Zunjarrao 			break;
2081f8e93412SHarish Zunjarrao 		if (iface_param->value[0] == ISCSI_NET_PARAM_ENABLE)
2082f8e93412SHarish Zunjarrao 			init_fw_cb->ipv4_tcp_opts |=
2083f8e93412SHarish Zunjarrao 				cpu_to_le16(TCPOPT_DNS_SERVER_IP_EN);
2084f8e93412SHarish Zunjarrao 		else
2085f8e93412SHarish Zunjarrao 			init_fw_cb->ipv4_tcp_opts &=
2086f8e93412SHarish Zunjarrao 				cpu_to_le16(~TCPOPT_DNS_SERVER_IP_EN);
2087f8e93412SHarish Zunjarrao 		break;
2088f8e93412SHarish Zunjarrao 	case ISCSI_NET_PARAM_IPV4_DHCP_SLP_DA_EN:
2089f8e93412SHarish Zunjarrao 		if (iface_param->iface_num & 0x1)
2090f8e93412SHarish Zunjarrao 			break;
2091f8e93412SHarish Zunjarrao 		if (iface_param->value[0] == ISCSI_NET_PARAM_ENABLE)
2092f8e93412SHarish Zunjarrao 			init_fw_cb->ipv4_tcp_opts |=
2093f8e93412SHarish Zunjarrao 				cpu_to_le16(TCPOPT_SLP_DA_INFO_EN);
2094f8e93412SHarish Zunjarrao 		else
2095f8e93412SHarish Zunjarrao 			init_fw_cb->ipv4_tcp_opts &=
2096f8e93412SHarish Zunjarrao 				cpu_to_le16(~TCPOPT_SLP_DA_INFO_EN);
2097f8e93412SHarish Zunjarrao 		break;
2098f8e93412SHarish Zunjarrao 	case ISCSI_NET_PARAM_IPV4_TOS_EN:
2099f8e93412SHarish Zunjarrao 		if (iface_param->iface_num & 0x1)
2100f8e93412SHarish Zunjarrao 			break;
2101f8e93412SHarish Zunjarrao 		if (iface_param->value[0] == ISCSI_NET_PARAM_ENABLE)
2102f8e93412SHarish Zunjarrao 			init_fw_cb->ipv4_ip_opts |=
2103f8e93412SHarish Zunjarrao 				cpu_to_le16(IPOPT_IPV4_TOS_EN);
2104f8e93412SHarish Zunjarrao 		else
2105f8e93412SHarish Zunjarrao 			init_fw_cb->ipv4_ip_opts &=
2106f8e93412SHarish Zunjarrao 				cpu_to_le16(~IPOPT_IPV4_TOS_EN);
2107f8e93412SHarish Zunjarrao 		break;
2108f8e93412SHarish Zunjarrao 	case ISCSI_NET_PARAM_IPV4_TOS:
2109f8e93412SHarish Zunjarrao 		if (iface_param->iface_num & 0x1)
2110f8e93412SHarish Zunjarrao 			break;
2111f8e93412SHarish Zunjarrao 		init_fw_cb->ipv4_tos = iface_param->value[0];
2112f8e93412SHarish Zunjarrao 		break;
2113f8e93412SHarish Zunjarrao 	case ISCSI_NET_PARAM_IPV4_GRAT_ARP_EN:
2114f8e93412SHarish Zunjarrao 		if (iface_param->iface_num & 0x1)
2115f8e93412SHarish Zunjarrao 			break;
2116f8e93412SHarish Zunjarrao 		if (iface_param->value[0] == ISCSI_NET_PARAM_ENABLE)
2117f8e93412SHarish Zunjarrao 			init_fw_cb->ipv4_ip_opts |=
2118f8e93412SHarish Zunjarrao 					cpu_to_le16(IPOPT_GRAT_ARP_EN);
2119f8e93412SHarish Zunjarrao 		else
2120f8e93412SHarish Zunjarrao 			init_fw_cb->ipv4_ip_opts &=
2121f8e93412SHarish Zunjarrao 					cpu_to_le16(~IPOPT_GRAT_ARP_EN);
2122f8e93412SHarish Zunjarrao 		break;
2123f8e93412SHarish Zunjarrao 	case ISCSI_NET_PARAM_IPV4_DHCP_ALT_CLIENT_ID_EN:
2124f8e93412SHarish Zunjarrao 		if (iface_param->iface_num & 0x1)
2125f8e93412SHarish Zunjarrao 			break;
2126f8e93412SHarish Zunjarrao 		if (iface_param->value[0] == ISCSI_NET_PARAM_ENABLE)
2127f8e93412SHarish Zunjarrao 			init_fw_cb->ipv4_ip_opts |=
2128f8e93412SHarish Zunjarrao 				cpu_to_le16(IPOPT_ALT_CID_EN);
2129f8e93412SHarish Zunjarrao 		else
2130f8e93412SHarish Zunjarrao 			init_fw_cb->ipv4_ip_opts &=
2131f8e93412SHarish Zunjarrao 				cpu_to_le16(~IPOPT_ALT_CID_EN);
2132f8e93412SHarish Zunjarrao 		break;
2133f8e93412SHarish Zunjarrao 	case ISCSI_NET_PARAM_IPV4_DHCP_ALT_CLIENT_ID:
2134f8e93412SHarish Zunjarrao 		if (iface_param->iface_num & 0x1)
2135f8e93412SHarish Zunjarrao 			break;
2136f8e93412SHarish Zunjarrao 		memcpy(init_fw_cb->ipv4_dhcp_alt_cid, iface_param->value,
2137f8e93412SHarish Zunjarrao 		       (sizeof(init_fw_cb->ipv4_dhcp_alt_cid) - 1));
2138f8e93412SHarish Zunjarrao 		init_fw_cb->ipv4_dhcp_alt_cid_len =
2139f8e93412SHarish Zunjarrao 					strlen(init_fw_cb->ipv4_dhcp_alt_cid);
2140f8e93412SHarish Zunjarrao 		break;
2141f8e93412SHarish Zunjarrao 	case ISCSI_NET_PARAM_IPV4_DHCP_REQ_VENDOR_ID_EN:
2142f8e93412SHarish Zunjarrao 		if (iface_param->iface_num & 0x1)
2143f8e93412SHarish Zunjarrao 			break;
2144f8e93412SHarish Zunjarrao 		if (iface_param->value[0] == ISCSI_NET_PARAM_ENABLE)
2145f8e93412SHarish Zunjarrao 			init_fw_cb->ipv4_ip_opts |=
2146f8e93412SHarish Zunjarrao 					cpu_to_le16(IPOPT_REQ_VID_EN);
2147f8e93412SHarish Zunjarrao 		else
2148f8e93412SHarish Zunjarrao 			init_fw_cb->ipv4_ip_opts &=
2149f8e93412SHarish Zunjarrao 					cpu_to_le16(~IPOPT_REQ_VID_EN);
2150f8e93412SHarish Zunjarrao 		break;
2151f8e93412SHarish Zunjarrao 	case ISCSI_NET_PARAM_IPV4_DHCP_USE_VENDOR_ID_EN:
2152f8e93412SHarish Zunjarrao 		if (iface_param->iface_num & 0x1)
2153f8e93412SHarish Zunjarrao 			break;
2154f8e93412SHarish Zunjarrao 		if (iface_param->value[0] == ISCSI_NET_PARAM_ENABLE)
2155f8e93412SHarish Zunjarrao 			init_fw_cb->ipv4_ip_opts |=
2156f8e93412SHarish Zunjarrao 					cpu_to_le16(IPOPT_USE_VID_EN);
2157f8e93412SHarish Zunjarrao 		else
2158f8e93412SHarish Zunjarrao 			init_fw_cb->ipv4_ip_opts &=
2159f8e93412SHarish Zunjarrao 					cpu_to_le16(~IPOPT_USE_VID_EN);
2160f8e93412SHarish Zunjarrao 		break;
2161f8e93412SHarish Zunjarrao 	case ISCSI_NET_PARAM_IPV4_DHCP_VENDOR_ID:
2162f8e93412SHarish Zunjarrao 		if (iface_param->iface_num & 0x1)
2163f8e93412SHarish Zunjarrao 			break;
2164f8e93412SHarish Zunjarrao 		memcpy(init_fw_cb->ipv4_dhcp_vid, iface_param->value,
2165f8e93412SHarish Zunjarrao 		       (sizeof(init_fw_cb->ipv4_dhcp_vid) - 1));
2166f8e93412SHarish Zunjarrao 		init_fw_cb->ipv4_dhcp_vid_len =
2167f8e93412SHarish Zunjarrao 					strlen(init_fw_cb->ipv4_dhcp_vid);
2168f8e93412SHarish Zunjarrao 		break;
2169f8e93412SHarish Zunjarrao 	case ISCSI_NET_PARAM_IPV4_DHCP_LEARN_IQN_EN:
2170f8e93412SHarish Zunjarrao 		if (iface_param->iface_num & 0x1)
2171f8e93412SHarish Zunjarrao 			break;
2172f8e93412SHarish Zunjarrao 		if (iface_param->value[0] == ISCSI_NET_PARAM_ENABLE)
2173f8e93412SHarish Zunjarrao 			init_fw_cb->ipv4_ip_opts |=
2174f8e93412SHarish Zunjarrao 					cpu_to_le16(IPOPT_LEARN_IQN_EN);
2175f8e93412SHarish Zunjarrao 		else
2176f8e93412SHarish Zunjarrao 			init_fw_cb->ipv4_ip_opts &=
2177f8e93412SHarish Zunjarrao 					cpu_to_le16(~IPOPT_LEARN_IQN_EN);
2178f8e93412SHarish Zunjarrao 		break;
2179f8e93412SHarish Zunjarrao 	case ISCSI_NET_PARAM_IPV4_FRAGMENT_DISABLE:
2180f8e93412SHarish Zunjarrao 		if (iface_param->iface_num & 0x1)
2181f8e93412SHarish Zunjarrao 			break;
2182f8e93412SHarish Zunjarrao 		if (iface_param->value[0] == ISCSI_NET_PARAM_DISABLE)
2183f8e93412SHarish Zunjarrao 			init_fw_cb->ipv4_ip_opts |=
2184f8e93412SHarish Zunjarrao 				cpu_to_le16(IPOPT_FRAGMENTATION_DISABLE);
2185f8e93412SHarish Zunjarrao 		else
2186f8e93412SHarish Zunjarrao 			init_fw_cb->ipv4_ip_opts &=
2187f8e93412SHarish Zunjarrao 				cpu_to_le16(~IPOPT_FRAGMENTATION_DISABLE);
2188f8e93412SHarish Zunjarrao 		break;
2189f8e93412SHarish Zunjarrao 	case ISCSI_NET_PARAM_IPV4_IN_FORWARD_EN:
2190f8e93412SHarish Zunjarrao 		if (iface_param->iface_num & 0x1)
2191f8e93412SHarish Zunjarrao 			break;
2192f8e93412SHarish Zunjarrao 		if (iface_param->value[0] == ISCSI_NET_PARAM_ENABLE)
2193f8e93412SHarish Zunjarrao 			init_fw_cb->ipv4_ip_opts |=
2194f8e93412SHarish Zunjarrao 				cpu_to_le16(IPOPT_IN_FORWARD_EN);
2195f8e93412SHarish Zunjarrao 		else
2196f8e93412SHarish Zunjarrao 			init_fw_cb->ipv4_ip_opts &=
2197f8e93412SHarish Zunjarrao 				cpu_to_le16(~IPOPT_IN_FORWARD_EN);
2198f8e93412SHarish Zunjarrao 		break;
2199f8e93412SHarish Zunjarrao 	case ISCSI_NET_PARAM_REDIRECT_EN:
2200f8e93412SHarish Zunjarrao 		if (iface_param->iface_num & 0x1)
2201f8e93412SHarish Zunjarrao 			break;
2202f8e93412SHarish Zunjarrao 		if (iface_param->value[0] == ISCSI_NET_PARAM_ENABLE)
2203f8e93412SHarish Zunjarrao 			init_fw_cb->ipv4_ip_opts |=
2204f8e93412SHarish Zunjarrao 				cpu_to_le16(IPOPT_ARP_REDIRECT_EN);
2205f8e93412SHarish Zunjarrao 		else
2206f8e93412SHarish Zunjarrao 			init_fw_cb->ipv4_ip_opts &=
2207f8e93412SHarish Zunjarrao 				cpu_to_le16(~IPOPT_ARP_REDIRECT_EN);
2208f8e93412SHarish Zunjarrao 		break;
2209f8e93412SHarish Zunjarrao 	case ISCSI_NET_PARAM_IPV4_TTL:
2210f8e93412SHarish Zunjarrao 		if (iface_param->iface_num & 0x1)
2211f8e93412SHarish Zunjarrao 			break;
2212f8e93412SHarish Zunjarrao 		init_fw_cb->ipv4_ttl = iface_param->value[0];
2213f8e93412SHarish Zunjarrao 		break;
2214d00efe3fSMike Christie 	default:
2215d00efe3fSMike Christie 		ql4_printk(KERN_ERR, ha, "Unknown IPv4 param = %d\n",
2216d00efe3fSMike Christie 			   iface_param->param);
2217d00efe3fSMike Christie 		break;
2218d00efe3fSMike Christie 	}
2219d00efe3fSMike Christie }
2220d00efe3fSMike Christie 
2221f8e93412SHarish Zunjarrao static void qla4xxx_set_iscsi_param(struct scsi_qla_host *ha,
2222f8e93412SHarish Zunjarrao 				    struct iscsi_iface_param_info *iface_param,
2223f8e93412SHarish Zunjarrao 				    struct addr_ctrl_blk *init_fw_cb)
2224f8e93412SHarish Zunjarrao {
2225f8e93412SHarish Zunjarrao 	switch (iface_param->param) {
2226f8e93412SHarish Zunjarrao 	case ISCSI_IFACE_PARAM_DEF_TASKMGMT_TMO:
2227f8e93412SHarish Zunjarrao 		if (iface_param->iface_num & 0x1)
2228f8e93412SHarish Zunjarrao 			break;
2229f8e93412SHarish Zunjarrao 		init_fw_cb->def_timeout =
2230f8e93412SHarish Zunjarrao 				cpu_to_le16(*(uint16_t *)iface_param->value);
2231f8e93412SHarish Zunjarrao 		break;
2232f8e93412SHarish Zunjarrao 	case ISCSI_IFACE_PARAM_HDRDGST_EN:
2233f8e93412SHarish Zunjarrao 		if (iface_param->iface_num & 0x1)
2234f8e93412SHarish Zunjarrao 			break;
2235f8e93412SHarish Zunjarrao 		if (iface_param->value[0] == ISCSI_NET_PARAM_ENABLE)
2236f8e93412SHarish Zunjarrao 			init_fw_cb->iscsi_opts |=
2237f8e93412SHarish Zunjarrao 				cpu_to_le16(ISCSIOPTS_HEADER_DIGEST_EN);
2238f8e93412SHarish Zunjarrao 		else
2239f8e93412SHarish Zunjarrao 			init_fw_cb->iscsi_opts &=
2240f8e93412SHarish Zunjarrao 				cpu_to_le16(~ISCSIOPTS_HEADER_DIGEST_EN);
2241f8e93412SHarish Zunjarrao 		break;
2242f8e93412SHarish Zunjarrao 	case ISCSI_IFACE_PARAM_DATADGST_EN:
2243f8e93412SHarish Zunjarrao 		if (iface_param->iface_num & 0x1)
2244f8e93412SHarish Zunjarrao 			break;
2245f8e93412SHarish Zunjarrao 		if (iface_param->value[0] == ISCSI_NET_PARAM_ENABLE)
2246f8e93412SHarish Zunjarrao 			init_fw_cb->iscsi_opts |=
2247f8e93412SHarish Zunjarrao 				cpu_to_le16(ISCSIOPTS_DATA_DIGEST_EN);
2248f8e93412SHarish Zunjarrao 		else
2249f8e93412SHarish Zunjarrao 			init_fw_cb->iscsi_opts &=
2250f8e93412SHarish Zunjarrao 				cpu_to_le16(~ISCSIOPTS_DATA_DIGEST_EN);
2251f8e93412SHarish Zunjarrao 		break;
2252f8e93412SHarish Zunjarrao 	case ISCSI_IFACE_PARAM_IMM_DATA_EN:
2253f8e93412SHarish Zunjarrao 		if (iface_param->iface_num & 0x1)
2254f8e93412SHarish Zunjarrao 			break;
2255f8e93412SHarish Zunjarrao 		if (iface_param->value[0] == ISCSI_NET_PARAM_ENABLE)
2256f8e93412SHarish Zunjarrao 			init_fw_cb->iscsi_opts |=
2257f8e93412SHarish Zunjarrao 				cpu_to_le16(ISCSIOPTS_IMMEDIATE_DATA_EN);
2258f8e93412SHarish Zunjarrao 		else
2259f8e93412SHarish Zunjarrao 			init_fw_cb->iscsi_opts &=
2260f8e93412SHarish Zunjarrao 				cpu_to_le16(~ISCSIOPTS_IMMEDIATE_DATA_EN);
2261f8e93412SHarish Zunjarrao 		break;
2262f8e93412SHarish Zunjarrao 	case ISCSI_IFACE_PARAM_INITIAL_R2T_EN:
2263f8e93412SHarish Zunjarrao 		if (iface_param->iface_num & 0x1)
2264f8e93412SHarish Zunjarrao 			break;
2265f8e93412SHarish Zunjarrao 		if (iface_param->value[0] == ISCSI_NET_PARAM_ENABLE)
2266f8e93412SHarish Zunjarrao 			init_fw_cb->iscsi_opts |=
2267f8e93412SHarish Zunjarrao 				cpu_to_le16(ISCSIOPTS_INITIAL_R2T_EN);
2268f8e93412SHarish Zunjarrao 		else
2269f8e93412SHarish Zunjarrao 			init_fw_cb->iscsi_opts &=
2270f8e93412SHarish Zunjarrao 				cpu_to_le16(~ISCSIOPTS_INITIAL_R2T_EN);
2271f8e93412SHarish Zunjarrao 		break;
2272f8e93412SHarish Zunjarrao 	case ISCSI_IFACE_PARAM_DATASEQ_INORDER_EN:
2273f8e93412SHarish Zunjarrao 		if (iface_param->iface_num & 0x1)
2274f8e93412SHarish Zunjarrao 			break;
2275f8e93412SHarish Zunjarrao 		if (iface_param->value[0] == ISCSI_NET_PARAM_ENABLE)
2276f8e93412SHarish Zunjarrao 			init_fw_cb->iscsi_opts |=
2277f8e93412SHarish Zunjarrao 				cpu_to_le16(ISCSIOPTS_DATA_SEQ_INORDER_EN);
2278f8e93412SHarish Zunjarrao 		else
2279f8e93412SHarish Zunjarrao 			init_fw_cb->iscsi_opts &=
2280f8e93412SHarish Zunjarrao 				cpu_to_le16(~ISCSIOPTS_DATA_SEQ_INORDER_EN);
2281f8e93412SHarish Zunjarrao 		break;
2282f8e93412SHarish Zunjarrao 	case ISCSI_IFACE_PARAM_PDU_INORDER_EN:
2283f8e93412SHarish Zunjarrao 		if (iface_param->iface_num & 0x1)
2284f8e93412SHarish Zunjarrao 			break;
2285f8e93412SHarish Zunjarrao 		if (iface_param->value[0] == ISCSI_NET_PARAM_ENABLE)
2286f8e93412SHarish Zunjarrao 			init_fw_cb->iscsi_opts |=
2287f8e93412SHarish Zunjarrao 				cpu_to_le16(ISCSIOPTS_DATA_PDU_INORDER_EN);
2288f8e93412SHarish Zunjarrao 		else
2289f8e93412SHarish Zunjarrao 			init_fw_cb->iscsi_opts &=
2290f8e93412SHarish Zunjarrao 				cpu_to_le16(~ISCSIOPTS_DATA_PDU_INORDER_EN);
2291f8e93412SHarish Zunjarrao 		break;
2292f8e93412SHarish Zunjarrao 	case ISCSI_IFACE_PARAM_ERL:
2293f8e93412SHarish Zunjarrao 		if (iface_param->iface_num & 0x1)
2294f8e93412SHarish Zunjarrao 			break;
2295f8e93412SHarish Zunjarrao 		init_fw_cb->iscsi_opts &= cpu_to_le16(~ISCSIOPTS_ERL);
2296f8e93412SHarish Zunjarrao 		init_fw_cb->iscsi_opts |= cpu_to_le16(iface_param->value[0] &
2297f8e93412SHarish Zunjarrao 						      ISCSIOPTS_ERL);
2298f8e93412SHarish Zunjarrao 		break;
2299f8e93412SHarish Zunjarrao 	case ISCSI_IFACE_PARAM_MAX_RECV_DLENGTH:
2300f8e93412SHarish Zunjarrao 		if (iface_param->iface_num & 0x1)
2301f8e93412SHarish Zunjarrao 			break;
2302f8e93412SHarish Zunjarrao 		init_fw_cb->iscsi_max_pdu_size =
2303f8e93412SHarish Zunjarrao 				cpu_to_le32(*(uint32_t *)iface_param->value) /
2304f8e93412SHarish Zunjarrao 				BYTE_UNITS;
2305f8e93412SHarish Zunjarrao 		break;
2306f8e93412SHarish Zunjarrao 	case ISCSI_IFACE_PARAM_FIRST_BURST:
2307f8e93412SHarish Zunjarrao 		if (iface_param->iface_num & 0x1)
2308f8e93412SHarish Zunjarrao 			break;
2309f8e93412SHarish Zunjarrao 		init_fw_cb->iscsi_fburst_len =
2310f8e93412SHarish Zunjarrao 				cpu_to_le32(*(uint32_t *)iface_param->value) /
2311f8e93412SHarish Zunjarrao 				BYTE_UNITS;
2312f8e93412SHarish Zunjarrao 		break;
2313f8e93412SHarish Zunjarrao 	case ISCSI_IFACE_PARAM_MAX_R2T:
2314f8e93412SHarish Zunjarrao 		if (iface_param->iface_num & 0x1)
2315f8e93412SHarish Zunjarrao 			break;
2316f8e93412SHarish Zunjarrao 		init_fw_cb->iscsi_max_outstnd_r2t =
2317f8e93412SHarish Zunjarrao 				cpu_to_le16(*(uint16_t *)iface_param->value);
2318f8e93412SHarish Zunjarrao 		break;
2319f8e93412SHarish Zunjarrao 	case ISCSI_IFACE_PARAM_MAX_BURST:
2320f8e93412SHarish Zunjarrao 		if (iface_param->iface_num & 0x1)
2321f8e93412SHarish Zunjarrao 			break;
2322f8e93412SHarish Zunjarrao 		init_fw_cb->iscsi_max_burst_len =
2323f8e93412SHarish Zunjarrao 				cpu_to_le32(*(uint32_t *)iface_param->value) /
2324f8e93412SHarish Zunjarrao 				BYTE_UNITS;
2325f8e93412SHarish Zunjarrao 		break;
2326f8e93412SHarish Zunjarrao 	case ISCSI_IFACE_PARAM_CHAP_AUTH_EN:
2327f8e93412SHarish Zunjarrao 		if (iface_param->iface_num & 0x1)
2328f8e93412SHarish Zunjarrao 			break;
2329f8e93412SHarish Zunjarrao 		if (iface_param->value[0] == ISCSI_NET_PARAM_ENABLE)
2330f8e93412SHarish Zunjarrao 			init_fw_cb->iscsi_opts |=
2331f8e93412SHarish Zunjarrao 				cpu_to_le16(ISCSIOPTS_CHAP_AUTH_EN);
2332f8e93412SHarish Zunjarrao 		else
2333f8e93412SHarish Zunjarrao 			init_fw_cb->iscsi_opts &=
2334f8e93412SHarish Zunjarrao 				cpu_to_le16(~ISCSIOPTS_CHAP_AUTH_EN);
2335f8e93412SHarish Zunjarrao 		break;
2336f8e93412SHarish Zunjarrao 	case ISCSI_IFACE_PARAM_BIDI_CHAP_EN:
2337f8e93412SHarish Zunjarrao 		if (iface_param->iface_num & 0x1)
2338f8e93412SHarish Zunjarrao 			break;
2339f8e93412SHarish Zunjarrao 		if (iface_param->value[0] == ISCSI_NET_PARAM_ENABLE)
2340f8e93412SHarish Zunjarrao 			init_fw_cb->iscsi_opts |=
2341f8e93412SHarish Zunjarrao 				cpu_to_le16(ISCSIOPTS_BIDI_CHAP_EN);
2342f8e93412SHarish Zunjarrao 		else
2343f8e93412SHarish Zunjarrao 			init_fw_cb->iscsi_opts &=
2344f8e93412SHarish Zunjarrao 				cpu_to_le16(~ISCSIOPTS_BIDI_CHAP_EN);
2345f8e93412SHarish Zunjarrao 		break;
2346f8e93412SHarish Zunjarrao 	case ISCSI_IFACE_PARAM_DISCOVERY_AUTH_OPTIONAL:
2347f8e93412SHarish Zunjarrao 		if (iface_param->iface_num & 0x1)
2348f8e93412SHarish Zunjarrao 			break;
2349f8e93412SHarish Zunjarrao 		if (iface_param->value[0] == ISCSI_NET_PARAM_ENABLE)
2350f8e93412SHarish Zunjarrao 			init_fw_cb->iscsi_opts |=
2351f8e93412SHarish Zunjarrao 				cpu_to_le16(ISCSIOPTS_DISCOVERY_AUTH_EN);
2352f8e93412SHarish Zunjarrao 		else
2353f8e93412SHarish Zunjarrao 			init_fw_cb->iscsi_opts &=
2354f8e93412SHarish Zunjarrao 				cpu_to_le16(~ISCSIOPTS_DISCOVERY_AUTH_EN);
2355f8e93412SHarish Zunjarrao 		break;
2356f8e93412SHarish Zunjarrao 	case ISCSI_IFACE_PARAM_DISCOVERY_LOGOUT_EN:
2357f8e93412SHarish Zunjarrao 		if (iface_param->iface_num & 0x1)
2358f8e93412SHarish Zunjarrao 			break;
2359f8e93412SHarish Zunjarrao 		if (iface_param->value[0] == ISCSI_NET_PARAM_ENABLE)
2360f8e93412SHarish Zunjarrao 			init_fw_cb->iscsi_opts |=
2361f8e93412SHarish Zunjarrao 				cpu_to_le16(ISCSIOPTS_DISCOVERY_LOGOUT_EN);
2362f8e93412SHarish Zunjarrao 		else
2363f8e93412SHarish Zunjarrao 			init_fw_cb->iscsi_opts &=
2364f8e93412SHarish Zunjarrao 				cpu_to_le16(~ISCSIOPTS_DISCOVERY_LOGOUT_EN);
2365f8e93412SHarish Zunjarrao 		break;
2366f8e93412SHarish Zunjarrao 	case ISCSI_IFACE_PARAM_STRICT_LOGIN_COMP_EN:
2367f8e93412SHarish Zunjarrao 		if (iface_param->iface_num & 0x1)
2368f8e93412SHarish Zunjarrao 			break;
2369f8e93412SHarish Zunjarrao 		if (iface_param->value[0] == ISCSI_NET_PARAM_ENABLE)
2370f8e93412SHarish Zunjarrao 			init_fw_cb->iscsi_opts |=
2371f8e93412SHarish Zunjarrao 				cpu_to_le16(ISCSIOPTS_STRICT_LOGIN_COMP_EN);
2372f8e93412SHarish Zunjarrao 		else
2373f8e93412SHarish Zunjarrao 			init_fw_cb->iscsi_opts &=
2374f8e93412SHarish Zunjarrao 				cpu_to_le16(~ISCSIOPTS_STRICT_LOGIN_COMP_EN);
2375f8e93412SHarish Zunjarrao 		break;
2376f8e93412SHarish Zunjarrao 	default:
2377f8e93412SHarish Zunjarrao 		ql4_printk(KERN_ERR, ha, "Unknown iscsi param = %d\n",
2378f8e93412SHarish Zunjarrao 			   iface_param->param);
2379f8e93412SHarish Zunjarrao 		break;
2380f8e93412SHarish Zunjarrao 	}
2381f8e93412SHarish Zunjarrao }
2382f8e93412SHarish Zunjarrao 
2383d00efe3fSMike Christie static void
2384d00efe3fSMike Christie qla4xxx_initcb_to_acb(struct addr_ctrl_blk *init_fw_cb)
2385d00efe3fSMike Christie {
2386d00efe3fSMike Christie 	struct addr_ctrl_blk_def *acb;
2387d00efe3fSMike Christie 	acb = (struct addr_ctrl_blk_def *)init_fw_cb;
2388d00efe3fSMike Christie 	memset(acb->reserved1, 0, sizeof(acb->reserved1));
2389d00efe3fSMike Christie 	memset(acb->reserved2, 0, sizeof(acb->reserved2));
2390d00efe3fSMike Christie 	memset(acb->reserved3, 0, sizeof(acb->reserved3));
2391d00efe3fSMike Christie 	memset(acb->reserved4, 0, sizeof(acb->reserved4));
2392d00efe3fSMike Christie 	memset(acb->reserved5, 0, sizeof(acb->reserved5));
2393d00efe3fSMike Christie 	memset(acb->reserved6, 0, sizeof(acb->reserved6));
2394d00efe3fSMike Christie 	memset(acb->reserved7, 0, sizeof(acb->reserved7));
2395d00efe3fSMike Christie 	memset(acb->reserved8, 0, sizeof(acb->reserved8));
2396d00efe3fSMike Christie 	memset(acb->reserved9, 0, sizeof(acb->reserved9));
2397d00efe3fSMike Christie 	memset(acb->reserved10, 0, sizeof(acb->reserved10));
2398d00efe3fSMike Christie 	memset(acb->reserved11, 0, sizeof(acb->reserved11));
2399d00efe3fSMike Christie 	memset(acb->reserved12, 0, sizeof(acb->reserved12));
2400d00efe3fSMike Christie 	memset(acb->reserved13, 0, sizeof(acb->reserved13));
2401d00efe3fSMike Christie 	memset(acb->reserved14, 0, sizeof(acb->reserved14));
2402d00efe3fSMike Christie 	memset(acb->reserved15, 0, sizeof(acb->reserved15));
2403d00efe3fSMike Christie }
2404d00efe3fSMike Christie 
2405d00efe3fSMike Christie static int
240600c31889SMike Christie qla4xxx_iface_set_param(struct Scsi_Host *shost, void *data, uint32_t len)
2407d00efe3fSMike Christie {
2408d00efe3fSMike Christie 	struct scsi_qla_host *ha = to_qla_host(shost);
2409d00efe3fSMike Christie 	int rval = 0;
2410d00efe3fSMike Christie 	struct iscsi_iface_param_info *iface_param = NULL;
2411d00efe3fSMike Christie 	struct addr_ctrl_blk *init_fw_cb = NULL;
2412d00efe3fSMike Christie 	dma_addr_t init_fw_cb_dma;
2413d00efe3fSMike Christie 	uint32_t mbox_cmd[MBOX_REG_COUNT];
2414d00efe3fSMike Christie 	uint32_t mbox_sts[MBOX_REG_COUNT];
241500c31889SMike Christie 	uint32_t rem = len;
241600c31889SMike Christie 	struct nlattr *attr;
2417d00efe3fSMike Christie 
2418d00efe3fSMike Christie 	init_fw_cb = dma_alloc_coherent(&ha->pdev->dev,
2419d00efe3fSMike Christie 					sizeof(struct addr_ctrl_blk),
2420d00efe3fSMike Christie 					&init_fw_cb_dma, GFP_KERNEL);
2421d00efe3fSMike Christie 	if (!init_fw_cb) {
2422d00efe3fSMike Christie 		ql4_printk(KERN_ERR, ha, "%s: Unable to alloc init_cb\n",
2423d00efe3fSMike Christie 			   __func__);
2424d00efe3fSMike Christie 		return -ENOMEM;
2425d00efe3fSMike Christie 	}
2426d00efe3fSMike Christie 
2427d00efe3fSMike Christie 	memset(init_fw_cb, 0, sizeof(struct addr_ctrl_blk));
2428d00efe3fSMike Christie 	memset(&mbox_cmd, 0, sizeof(mbox_cmd));
2429d00efe3fSMike Christie 	memset(&mbox_sts, 0, sizeof(mbox_sts));
2430d00efe3fSMike Christie 
2431d00efe3fSMike Christie 	if (qla4xxx_get_ifcb(ha, &mbox_cmd[0], &mbox_sts[0], init_fw_cb_dma)) {
2432d00efe3fSMike Christie 		ql4_printk(KERN_ERR, ha, "%s: get ifcb failed\n", __func__);
2433d00efe3fSMike Christie 		rval = -EIO;
2434d00efe3fSMike Christie 		goto exit_init_fw_cb;
2435d00efe3fSMike Christie 	}
2436d00efe3fSMike Christie 
243700c31889SMike Christie 	nla_for_each_attr(attr, data, len, rem) {
243800c31889SMike Christie 		iface_param = nla_data(attr);
2439d00efe3fSMike Christie 
2440f8e93412SHarish Zunjarrao 		if (iface_param->param_type == ISCSI_NET_PARAM) {
2441d00efe3fSMike Christie 			switch (iface_param->iface_type) {
2442d00efe3fSMike Christie 			case ISCSI_IFACE_TYPE_IPV4:
2443d00efe3fSMike Christie 				switch (iface_param->iface_num) {
2444d00efe3fSMike Christie 				case 0:
2445f8e93412SHarish Zunjarrao 					qla4xxx_set_ipv4(ha, iface_param,
2446f8e93412SHarish Zunjarrao 							 init_fw_cb);
2447d00efe3fSMike Christie 					break;
2448d00efe3fSMike Christie 				default:
2449d00efe3fSMike Christie 				/* Cannot have more than one IPv4 interface */
2450f8e93412SHarish Zunjarrao 					ql4_printk(KERN_ERR, ha,
2451f8e93412SHarish Zunjarrao 						   "Invalid IPv4 iface number = %d\n",
2452d00efe3fSMike Christie 						   iface_param->iface_num);
2453d00efe3fSMike Christie 					break;
2454d00efe3fSMike Christie 				}
2455d00efe3fSMike Christie 				break;
2456d00efe3fSMike Christie 			case ISCSI_IFACE_TYPE_IPV6:
2457d00efe3fSMike Christie 				switch (iface_param->iface_num) {
2458d00efe3fSMike Christie 				case 0:
2459d00efe3fSMike Christie 				case 1:
2460f8e93412SHarish Zunjarrao 					qla4xxx_set_ipv6(ha, iface_param,
2461f8e93412SHarish Zunjarrao 							 init_fw_cb);
2462d00efe3fSMike Christie 					break;
2463d00efe3fSMike Christie 				default:
2464d00efe3fSMike Christie 				/* Cannot have more than two IPv6 interface */
2465f8e93412SHarish Zunjarrao 					ql4_printk(KERN_ERR, ha,
2466f8e93412SHarish Zunjarrao 						   "Invalid IPv6 iface number = %d\n",
2467d00efe3fSMike Christie 						   iface_param->iface_num);
2468d00efe3fSMike Christie 					break;
2469d00efe3fSMike Christie 				}
2470d00efe3fSMike Christie 				break;
2471d00efe3fSMike Christie 			default:
2472f8e93412SHarish Zunjarrao 				ql4_printk(KERN_ERR, ha,
2473f8e93412SHarish Zunjarrao 					   "Invalid iface type\n");
2474d00efe3fSMike Christie 				break;
2475d00efe3fSMike Christie 			}
2476f8e93412SHarish Zunjarrao 		} else if (iface_param->param_type == ISCSI_IFACE_PARAM) {
2477f8e93412SHarish Zunjarrao 				qla4xxx_set_iscsi_param(ha, iface_param,
2478f8e93412SHarish Zunjarrao 							init_fw_cb);
2479f8e93412SHarish Zunjarrao 		} else {
2480f8e93412SHarish Zunjarrao 			continue;
2481f8e93412SHarish Zunjarrao 		}
2482d00efe3fSMike Christie 	}
2483d00efe3fSMike Christie 
2484d00efe3fSMike Christie 	init_fw_cb->cookie = cpu_to_le32(0x11BEAD5A);
2485d00efe3fSMike Christie 
2486d00efe3fSMike Christie 	rval = qla4xxx_set_flash(ha, init_fw_cb_dma, FLASH_SEGMENT_IFCB,
2487d00efe3fSMike Christie 				 sizeof(struct addr_ctrl_blk),
2488d00efe3fSMike Christie 				 FLASH_OPT_RMW_COMMIT);
2489d00efe3fSMike Christie 	if (rval != QLA_SUCCESS) {
2490d00efe3fSMike Christie 		ql4_printk(KERN_ERR, ha, "%s: set flash mbx failed\n",
2491d00efe3fSMike Christie 			   __func__);
2492d00efe3fSMike Christie 		rval = -EIO;
2493d00efe3fSMike Christie 		goto exit_init_fw_cb;
2494d00efe3fSMike Christie 	}
2495d00efe3fSMike Christie 
2496ce505f9dSVikas Chaudhary 	rval = qla4xxx_disable_acb(ha);
2497ce505f9dSVikas Chaudhary 	if (rval != QLA_SUCCESS) {
2498ce505f9dSVikas Chaudhary 		ql4_printk(KERN_ERR, ha, "%s: disable acb mbx failed\n",
2499ce505f9dSVikas Chaudhary 			   __func__);
2500ce505f9dSVikas Chaudhary 		rval = -EIO;
2501ce505f9dSVikas Chaudhary 		goto exit_init_fw_cb;
2502ce505f9dSVikas Chaudhary 	}
2503ce505f9dSVikas Chaudhary 
2504ce505f9dSVikas Chaudhary 	wait_for_completion_timeout(&ha->disable_acb_comp,
2505ce505f9dSVikas Chaudhary 				    DISABLE_ACB_TOV * HZ);
2506d00efe3fSMike Christie 
2507d00efe3fSMike Christie 	qla4xxx_initcb_to_acb(init_fw_cb);
2508d00efe3fSMike Christie 
2509d00efe3fSMike Christie 	rval = qla4xxx_set_acb(ha, &mbox_cmd[0], &mbox_sts[0], init_fw_cb_dma);
2510d00efe3fSMike Christie 	if (rval != QLA_SUCCESS) {
2511d00efe3fSMike Christie 		ql4_printk(KERN_ERR, ha, "%s: set acb mbx failed\n",
2512d00efe3fSMike Christie 			   __func__);
2513d00efe3fSMike Christie 		rval = -EIO;
2514d00efe3fSMike Christie 		goto exit_init_fw_cb;
2515d00efe3fSMike Christie 	}
2516d00efe3fSMike Christie 
2517d00efe3fSMike Christie 	memset(init_fw_cb, 0, sizeof(struct addr_ctrl_blk));
2518d00efe3fSMike Christie 	qla4xxx_update_local_ifcb(ha, &mbox_cmd[0], &mbox_sts[0], init_fw_cb,
2519d00efe3fSMike Christie 				  init_fw_cb_dma);
2520d00efe3fSMike Christie 
2521d00efe3fSMike Christie exit_init_fw_cb:
2522d00efe3fSMike Christie 	dma_free_coherent(&ha->pdev->dev, sizeof(struct addr_ctrl_blk),
2523d00efe3fSMike Christie 			  init_fw_cb, init_fw_cb_dma);
2524d00efe3fSMike Christie 
2525d00efe3fSMike Christie 	return rval;
2526d00efe3fSMike Christie }
2527d00efe3fSMike Christie 
2528fca9f04dSMike Christie static int qla4xxx_session_get_param(struct iscsi_cls_session *cls_sess,
2529fca9f04dSMike Christie 				     enum iscsi_param param, char *buf)
2530fca9f04dSMike Christie {
2531fca9f04dSMike Christie 	struct iscsi_session *sess = cls_sess->dd_data;
2532fca9f04dSMike Christie 	struct ddb_entry *ddb_entry = sess->dd_data;
2533fca9f04dSMike Christie 	struct scsi_qla_host *ha = ddb_entry->ha;
253497c2730cSAdheer Chandravanshi 	struct iscsi_cls_conn *cls_conn = ddb_entry->conn;
253597c2730cSAdheer Chandravanshi 	struct ql4_chap_table chap_tbl;
2536fca9f04dSMike Christie 	int rval, len;
2537fca9f04dSMike Christie 	uint16_t idx;
2538fca9f04dSMike Christie 
253997c2730cSAdheer Chandravanshi 	memset(&chap_tbl, 0, sizeof(chap_tbl));
2540fca9f04dSMike Christie 	switch (param) {
2541fca9f04dSMike Christie 	case ISCSI_PARAM_CHAP_IN_IDX:
2542fca9f04dSMike Christie 		rval = qla4xxx_get_chap_index(ha, sess->username_in,
2543fca9f04dSMike Christie 					      sess->password_in, BIDI_CHAP,
2544fca9f04dSMike Christie 					      &idx);
2545fca9f04dSMike Christie 		if (rval)
2546c7a5e0d0SManish Rangankar 			len = sprintf(buf, "\n");
2547c7a5e0d0SManish Rangankar 		else
2548fca9f04dSMike Christie 			len = sprintf(buf, "%hu\n", idx);
2549fca9f04dSMike Christie 		break;
2550fca9f04dSMike Christie 	case ISCSI_PARAM_CHAP_OUT_IDX:
255197c2730cSAdheer Chandravanshi 		if (ddb_entry->ddb_type == FLASH_DDB) {
255297c2730cSAdheer Chandravanshi 			if (ddb_entry->chap_tbl_idx != INVALID_ENTRY) {
255397c2730cSAdheer Chandravanshi 				idx = ddb_entry->chap_tbl_idx;
255497c2730cSAdheer Chandravanshi 				rval = QLA_SUCCESS;
255597c2730cSAdheer Chandravanshi 			} else {
255697c2730cSAdheer Chandravanshi 				rval = QLA_ERROR;
255797c2730cSAdheer Chandravanshi 			}
255897c2730cSAdheer Chandravanshi 		} else {
2559fca9f04dSMike Christie 			rval = qla4xxx_get_chap_index(ha, sess->username,
256097c2730cSAdheer Chandravanshi 						      sess->password,
256197c2730cSAdheer Chandravanshi 						      LOCAL_CHAP, &idx);
256297c2730cSAdheer Chandravanshi 		}
2563fca9f04dSMike Christie 		if (rval)
2564c7a5e0d0SManish Rangankar 			len = sprintf(buf, "\n");
2565c7a5e0d0SManish Rangankar 		else
2566fca9f04dSMike Christie 			len = sprintf(buf, "%hu\n", idx);
2567fca9f04dSMike Christie 		break;
256897c2730cSAdheer Chandravanshi 	case ISCSI_PARAM_USERNAME:
256997c2730cSAdheer Chandravanshi 	case ISCSI_PARAM_PASSWORD:
257097c2730cSAdheer Chandravanshi 		/* First, populate session username and password for FLASH DDB,
257197c2730cSAdheer Chandravanshi 		 * if not already done. This happens when session login fails
257297c2730cSAdheer Chandravanshi 		 * for a FLASH DDB.
257397c2730cSAdheer Chandravanshi 		 */
257497c2730cSAdheer Chandravanshi 		if (ddb_entry->ddb_type == FLASH_DDB &&
257597c2730cSAdheer Chandravanshi 		    ddb_entry->chap_tbl_idx != INVALID_ENTRY &&
257697c2730cSAdheer Chandravanshi 		    !sess->username && !sess->password) {
257797c2730cSAdheer Chandravanshi 			idx = ddb_entry->chap_tbl_idx;
257897c2730cSAdheer Chandravanshi 			rval = qla4xxx_get_uni_chap_at_index(ha, chap_tbl.name,
257997c2730cSAdheer Chandravanshi 							    chap_tbl.secret,
258097c2730cSAdheer Chandravanshi 							    idx);
258197c2730cSAdheer Chandravanshi 			if (!rval) {
258297c2730cSAdheer Chandravanshi 				iscsi_set_param(cls_conn, ISCSI_PARAM_USERNAME,
258397c2730cSAdheer Chandravanshi 						(char *)chap_tbl.name,
258497c2730cSAdheer Chandravanshi 						strlen((char *)chap_tbl.name));
258597c2730cSAdheer Chandravanshi 				iscsi_set_param(cls_conn, ISCSI_PARAM_PASSWORD,
258697c2730cSAdheer Chandravanshi 						(char *)chap_tbl.secret,
258797c2730cSAdheer Chandravanshi 						chap_tbl.secret_len);
258897c2730cSAdheer Chandravanshi 			}
258997c2730cSAdheer Chandravanshi 		}
259097c2730cSAdheer Chandravanshi 		/* allow fall-through */
2591fca9f04dSMike Christie 	default:
2592fca9f04dSMike Christie 		return iscsi_session_get_param(cls_sess, param, buf);
2593fca9f04dSMike Christie 	}
2594fca9f04dSMike Christie 
2595fca9f04dSMike Christie 	return len;
2596fca9f04dSMike Christie }
2597fca9f04dSMike Christie 
2598b3a271a9SManish Rangankar static int qla4xxx_conn_get_param(struct iscsi_cls_conn *cls_conn,
2599afaf5a2dSDavid Somayajulu 				  enum iscsi_param param, char *buf)
2600afaf5a2dSDavid Somayajulu {
2601b3a271a9SManish Rangankar 	struct iscsi_conn *conn;
2602b3a271a9SManish Rangankar 	struct qla_conn *qla_conn;
2603b3a271a9SManish Rangankar 	struct sockaddr *dst_addr;
2604b3a271a9SManish Rangankar 	int len = 0;
2605afaf5a2dSDavid Somayajulu 
2606b3a271a9SManish Rangankar 	conn = cls_conn->dd_data;
2607b3a271a9SManish Rangankar 	qla_conn = conn->dd_data;
2608d46bdeb1SManish Rangankar 	dst_addr = (struct sockaddr *)&qla_conn->qla_ep->dst_addr;
2609afaf5a2dSDavid Somayajulu 
2610afaf5a2dSDavid Somayajulu 	switch (param) {
2611afaf5a2dSDavid Somayajulu 	case ISCSI_PARAM_CONN_PORT:
2612afaf5a2dSDavid Somayajulu 	case ISCSI_PARAM_CONN_ADDRESS:
2613b3a271a9SManish Rangankar 		return iscsi_conn_get_addr_param((struct sockaddr_storage *)
2614b3a271a9SManish Rangankar 						 dst_addr, param, buf);
2615afaf5a2dSDavid Somayajulu 	default:
2616b3a271a9SManish Rangankar 		return iscsi_conn_get_param(cls_conn, param, buf);
2617afaf5a2dSDavid Somayajulu 	}
2618afaf5a2dSDavid Somayajulu 
2619afaf5a2dSDavid Somayajulu 	return len;
2620b3a271a9SManish Rangankar 
2621afaf5a2dSDavid Somayajulu }
2622afaf5a2dSDavid Somayajulu 
262313483730SMike Christie int qla4xxx_get_ddb_index(struct scsi_qla_host *ha, uint16_t *ddb_index)
262413483730SMike Christie {
262513483730SMike Christie 	uint32_t mbx_sts = 0;
262613483730SMike Christie 	uint16_t tmp_ddb_index;
262713483730SMike Christie 	int ret;
262813483730SMike Christie 
262913483730SMike Christie get_ddb_index:
263013483730SMike Christie 	tmp_ddb_index = find_first_zero_bit(ha->ddb_idx_map, MAX_DDB_ENTRIES);
263113483730SMike Christie 
263213483730SMike Christie 	if (tmp_ddb_index >= MAX_DDB_ENTRIES) {
263313483730SMike Christie 		DEBUG2(ql4_printk(KERN_INFO, ha,
263413483730SMike Christie 				  "Free DDB index not available\n"));
263513483730SMike Christie 		ret = QLA_ERROR;
263613483730SMike Christie 		goto exit_get_ddb_index;
263713483730SMike Christie 	}
263813483730SMike Christie 
263913483730SMike Christie 	if (test_and_set_bit(tmp_ddb_index, ha->ddb_idx_map))
264013483730SMike Christie 		goto get_ddb_index;
264113483730SMike Christie 
264213483730SMike Christie 	DEBUG2(ql4_printk(KERN_INFO, ha,
264313483730SMike Christie 			  "Found a free DDB index at %d\n", tmp_ddb_index));
264413483730SMike Christie 	ret = qla4xxx_req_ddb_entry(ha, tmp_ddb_index, &mbx_sts);
264513483730SMike Christie 	if (ret == QLA_ERROR) {
264613483730SMike Christie 		if (mbx_sts == MBOX_STS_COMMAND_ERROR) {
264713483730SMike Christie 			ql4_printk(KERN_INFO, ha,
264813483730SMike Christie 				   "DDB index = %d not available trying next\n",
264913483730SMike Christie 				   tmp_ddb_index);
265013483730SMike Christie 			goto get_ddb_index;
265113483730SMike Christie 		}
265213483730SMike Christie 		DEBUG2(ql4_printk(KERN_INFO, ha,
265313483730SMike Christie 				  "Free FW DDB not available\n"));
265413483730SMike Christie 	}
265513483730SMike Christie 
265613483730SMike Christie 	*ddb_index = tmp_ddb_index;
265713483730SMike Christie 
265813483730SMike Christie exit_get_ddb_index:
265913483730SMike Christie 	return ret;
266013483730SMike Christie }
266113483730SMike Christie 
266213483730SMike Christie static int qla4xxx_match_ipaddress(struct scsi_qla_host *ha,
266313483730SMike Christie 				   struct ddb_entry *ddb_entry,
266413483730SMike Christie 				   char *existing_ipaddr,
266513483730SMike Christie 				   char *user_ipaddr)
266613483730SMike Christie {
266713483730SMike Christie 	uint8_t dst_ipaddr[IPv6_ADDR_LEN];
266813483730SMike Christie 	char formatted_ipaddr[DDB_IPADDR_LEN];
266913483730SMike Christie 	int status = QLA_SUCCESS, ret = 0;
267013483730SMike Christie 
267113483730SMike Christie 	if (ddb_entry->fw_ddb_entry.options & DDB_OPT_IPV6_DEVICE) {
267213483730SMike Christie 		ret = in6_pton(user_ipaddr, strlen(user_ipaddr), dst_ipaddr,
267313483730SMike Christie 			       '\0', NULL);
267413483730SMike Christie 		if (ret == 0) {
267513483730SMike Christie 			status = QLA_ERROR;
267613483730SMike Christie 			goto out_match;
267713483730SMike Christie 		}
267813483730SMike Christie 		ret = sprintf(formatted_ipaddr, "%pI6", dst_ipaddr);
267913483730SMike Christie 	} else {
268013483730SMike Christie 		ret = in4_pton(user_ipaddr, strlen(user_ipaddr), dst_ipaddr,
268113483730SMike Christie 			       '\0', NULL);
268213483730SMike Christie 		if (ret == 0) {
268313483730SMike Christie 			status = QLA_ERROR;
268413483730SMike Christie 			goto out_match;
268513483730SMike Christie 		}
268613483730SMike Christie 		ret = sprintf(formatted_ipaddr, "%pI4", dst_ipaddr);
268713483730SMike Christie 	}
268813483730SMike Christie 
268913483730SMike Christie 	if (strcmp(existing_ipaddr, formatted_ipaddr))
269013483730SMike Christie 		status = QLA_ERROR;
269113483730SMike Christie 
269213483730SMike Christie out_match:
269313483730SMike Christie 	return status;
269413483730SMike Christie }
269513483730SMike Christie 
269613483730SMike Christie static int qla4xxx_match_fwdb_session(struct scsi_qla_host *ha,
269713483730SMike Christie 				      struct iscsi_cls_conn *cls_conn)
269813483730SMike Christie {
269913483730SMike Christie 	int idx = 0, max_ddbs, rval;
270013483730SMike Christie 	struct iscsi_cls_session *cls_sess = iscsi_conn_to_session(cls_conn);
270113483730SMike Christie 	struct iscsi_session *sess, *existing_sess;
270213483730SMike Christie 	struct iscsi_conn *conn, *existing_conn;
270313483730SMike Christie 	struct ddb_entry *ddb_entry;
270413483730SMike Christie 
270513483730SMike Christie 	sess = cls_sess->dd_data;
270613483730SMike Christie 	conn = cls_conn->dd_data;
270713483730SMike Christie 
270813483730SMike Christie 	if (sess->targetname == NULL ||
270913483730SMike Christie 	    conn->persistent_address == NULL ||
271013483730SMike Christie 	    conn->persistent_port == 0)
271113483730SMike Christie 		return QLA_ERROR;
271213483730SMike Christie 
271313483730SMike Christie 	max_ddbs =  is_qla40XX(ha) ? MAX_DEV_DB_ENTRIES_40XX :
271413483730SMike Christie 				     MAX_DEV_DB_ENTRIES;
271513483730SMike Christie 
271613483730SMike Christie 	for (idx = 0; idx < max_ddbs; idx++) {
271713483730SMike Christie 		ddb_entry = qla4xxx_lookup_ddb_by_fw_index(ha, idx);
271813483730SMike Christie 		if (ddb_entry == NULL)
271913483730SMike Christie 			continue;
272013483730SMike Christie 
272113483730SMike Christie 		if (ddb_entry->ddb_type != FLASH_DDB)
272213483730SMike Christie 			continue;
272313483730SMike Christie 
272413483730SMike Christie 		existing_sess = ddb_entry->sess->dd_data;
272513483730SMike Christie 		existing_conn = ddb_entry->conn->dd_data;
272613483730SMike Christie 
272713483730SMike Christie 		if (existing_sess->targetname == NULL ||
272813483730SMike Christie 		    existing_conn->persistent_address == NULL ||
272913483730SMike Christie 		    existing_conn->persistent_port == 0)
273013483730SMike Christie 			continue;
273113483730SMike Christie 
273213483730SMike Christie 		DEBUG2(ql4_printk(KERN_INFO, ha,
273313483730SMike Christie 				  "IQN = %s User IQN = %s\n",
273413483730SMike Christie 				  existing_sess->targetname,
273513483730SMike Christie 				  sess->targetname));
273613483730SMike Christie 
273713483730SMike Christie 		DEBUG2(ql4_printk(KERN_INFO, ha,
273813483730SMike Christie 				  "IP = %s User IP = %s\n",
273913483730SMike Christie 				  existing_conn->persistent_address,
274013483730SMike Christie 				  conn->persistent_address));
274113483730SMike Christie 
274213483730SMike Christie 		DEBUG2(ql4_printk(KERN_INFO, ha,
274313483730SMike Christie 				  "Port = %d User Port = %d\n",
274413483730SMike Christie 				  existing_conn->persistent_port,
274513483730SMike Christie 				  conn->persistent_port));
274613483730SMike Christie 
274713483730SMike Christie 		if (strcmp(existing_sess->targetname, sess->targetname))
274813483730SMike Christie 			continue;
274913483730SMike Christie 		rval = qla4xxx_match_ipaddress(ha, ddb_entry,
275013483730SMike Christie 					existing_conn->persistent_address,
275113483730SMike Christie 					conn->persistent_address);
275213483730SMike Christie 		if (rval == QLA_ERROR)
275313483730SMike Christie 			continue;
275413483730SMike Christie 		if (existing_conn->persistent_port != conn->persistent_port)
275513483730SMike Christie 			continue;
275613483730SMike Christie 		break;
275713483730SMike Christie 	}
275813483730SMike Christie 
275913483730SMike Christie 	if (idx == max_ddbs)
276013483730SMike Christie 		return QLA_ERROR;
276113483730SMike Christie 
276213483730SMike Christie 	DEBUG2(ql4_printk(KERN_INFO, ha,
276313483730SMike Christie 			  "Match found in fwdb sessions\n"));
276413483730SMike Christie 	return QLA_SUCCESS;
276513483730SMike Christie }
276613483730SMike Christie 
2767b3a271a9SManish Rangankar static struct iscsi_cls_session *
2768b3a271a9SManish Rangankar qla4xxx_session_create(struct iscsi_endpoint *ep,
2769b3a271a9SManish Rangankar 			uint16_t cmds_max, uint16_t qdepth,
2770b3a271a9SManish Rangankar 			uint32_t initial_cmdsn)
2771b3a271a9SManish Rangankar {
2772b3a271a9SManish Rangankar 	struct iscsi_cls_session *cls_sess;
2773b3a271a9SManish Rangankar 	struct scsi_qla_host *ha;
2774b3a271a9SManish Rangankar 	struct qla_endpoint *qla_ep;
2775b3a271a9SManish Rangankar 	struct ddb_entry *ddb_entry;
277613483730SMike Christie 	uint16_t ddb_index;
2777b3a271a9SManish Rangankar 	struct iscsi_session *sess;
2778b3a271a9SManish Rangankar 	struct sockaddr *dst_addr;
2779b3a271a9SManish Rangankar 	int ret;
2780b3a271a9SManish Rangankar 
2781b3a271a9SManish Rangankar 	DEBUG2(printk(KERN_INFO "Func: %s\n", __func__));
2782b3a271a9SManish Rangankar 	if (!ep) {
2783b3a271a9SManish Rangankar 		printk(KERN_ERR "qla4xxx: missing ep.\n");
2784b3a271a9SManish Rangankar 		return NULL;
2785b3a271a9SManish Rangankar 	}
2786b3a271a9SManish Rangankar 
2787b3a271a9SManish Rangankar 	qla_ep = ep->dd_data;
2788b3a271a9SManish Rangankar 	dst_addr = (struct sockaddr *)&qla_ep->dst_addr;
2789b3a271a9SManish Rangankar 	ha = to_qla_host(qla_ep->host);
2790736cf369SManish Rangankar 
279113483730SMike Christie 	ret = qla4xxx_get_ddb_index(ha, &ddb_index);
279213483730SMike Christie 	if (ret == QLA_ERROR)
2793b3a271a9SManish Rangankar 		return NULL;
2794b3a271a9SManish Rangankar 
2795b3a271a9SManish Rangankar 	cls_sess = iscsi_session_setup(&qla4xxx_iscsi_transport, qla_ep->host,
2796b3a271a9SManish Rangankar 				       cmds_max, sizeof(struct ddb_entry),
2797b3a271a9SManish Rangankar 				       sizeof(struct ql4_task_data),
2798b3a271a9SManish Rangankar 				       initial_cmdsn, ddb_index);
2799b3a271a9SManish Rangankar 	if (!cls_sess)
2800b3a271a9SManish Rangankar 		return NULL;
2801b3a271a9SManish Rangankar 
2802b3a271a9SManish Rangankar 	sess = cls_sess->dd_data;
2803b3a271a9SManish Rangankar 	ddb_entry = sess->dd_data;
2804b3a271a9SManish Rangankar 	ddb_entry->fw_ddb_index = ddb_index;
2805b3a271a9SManish Rangankar 	ddb_entry->fw_ddb_device_state = DDB_DS_NO_CONNECTION_ACTIVE;
2806b3a271a9SManish Rangankar 	ddb_entry->ha = ha;
2807b3a271a9SManish Rangankar 	ddb_entry->sess = cls_sess;
280813483730SMike Christie 	ddb_entry->unblock_sess = qla4xxx_unblock_ddb;
280913483730SMike Christie 	ddb_entry->ddb_change = qla4xxx_ddb_change;
2810b3a271a9SManish Rangankar 	cls_sess->recovery_tmo = ql4xsess_recovery_tmo;
2811b3a271a9SManish Rangankar 	ha->fw_ddb_index_map[ddb_entry->fw_ddb_index] = ddb_entry;
2812b3a271a9SManish Rangankar 	ha->tot_ddbs++;
2813b3a271a9SManish Rangankar 
2814b3a271a9SManish Rangankar 	return cls_sess;
2815b3a271a9SManish Rangankar }
2816b3a271a9SManish Rangankar 
2817b3a271a9SManish Rangankar static void qla4xxx_session_destroy(struct iscsi_cls_session *cls_sess)
2818b3a271a9SManish Rangankar {
2819b3a271a9SManish Rangankar 	struct iscsi_session *sess;
2820b3a271a9SManish Rangankar 	struct ddb_entry *ddb_entry;
2821b3a271a9SManish Rangankar 	struct scsi_qla_host *ha;
282290599b62SManish Rangankar 	unsigned long flags, wtime;
282390599b62SManish Rangankar 	struct dev_db_entry *fw_ddb_entry = NULL;
282490599b62SManish Rangankar 	dma_addr_t fw_ddb_entry_dma;
282590599b62SManish Rangankar 	uint32_t ddb_state;
282690599b62SManish Rangankar 	int ret;
2827b3a271a9SManish Rangankar 
2828b3a271a9SManish Rangankar 	DEBUG2(printk(KERN_INFO "Func: %s\n", __func__));
2829b3a271a9SManish Rangankar 	sess = cls_sess->dd_data;
2830b3a271a9SManish Rangankar 	ddb_entry = sess->dd_data;
2831b3a271a9SManish Rangankar 	ha = ddb_entry->ha;
2832b3a271a9SManish Rangankar 
283390599b62SManish Rangankar 	fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
283490599b62SManish Rangankar 					  &fw_ddb_entry_dma, GFP_KERNEL);
283590599b62SManish Rangankar 	if (!fw_ddb_entry) {
283690599b62SManish Rangankar 		ql4_printk(KERN_ERR, ha,
283790599b62SManish Rangankar 			   "%s: Unable to allocate dma buffer\n", __func__);
283890599b62SManish Rangankar 		goto destroy_session;
283990599b62SManish Rangankar 	}
284090599b62SManish Rangankar 
284190599b62SManish Rangankar 	wtime = jiffies + (HZ * LOGOUT_TOV);
284290599b62SManish Rangankar 	do {
284390599b62SManish Rangankar 		ret = qla4xxx_get_fwddb_entry(ha, ddb_entry->fw_ddb_index,
284490599b62SManish Rangankar 					      fw_ddb_entry, fw_ddb_entry_dma,
284590599b62SManish Rangankar 					      NULL, NULL, &ddb_state, NULL,
284690599b62SManish Rangankar 					      NULL, NULL);
284790599b62SManish Rangankar 		if (ret == QLA_ERROR)
284890599b62SManish Rangankar 			goto destroy_session;
284990599b62SManish Rangankar 
285090599b62SManish Rangankar 		if ((ddb_state == DDB_DS_NO_CONNECTION_ACTIVE) ||
285190599b62SManish Rangankar 		    (ddb_state == DDB_DS_SESSION_FAILED))
285290599b62SManish Rangankar 			goto destroy_session;
285390599b62SManish Rangankar 
285490599b62SManish Rangankar 		schedule_timeout_uninterruptible(HZ);
285590599b62SManish Rangankar 	} while ((time_after(wtime, jiffies)));
285690599b62SManish Rangankar 
285790599b62SManish Rangankar destroy_session:
2858736cf369SManish Rangankar 	qla4xxx_clear_ddb_entry(ha, ddb_entry->fw_ddb_index);
2859736cf369SManish Rangankar 
2860b3a271a9SManish Rangankar 	spin_lock_irqsave(&ha->hardware_lock, flags);
2861b3a271a9SManish Rangankar 	qla4xxx_free_ddb(ha, ddb_entry);
2862b3a271a9SManish Rangankar 	spin_unlock_irqrestore(&ha->hardware_lock, flags);
286390599b62SManish Rangankar 
2864b3a271a9SManish Rangankar 	iscsi_session_teardown(cls_sess);
286590599b62SManish Rangankar 
286690599b62SManish Rangankar 	if (fw_ddb_entry)
286790599b62SManish Rangankar 		dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
286890599b62SManish Rangankar 				  fw_ddb_entry, fw_ddb_entry_dma);
2869b3a271a9SManish Rangankar }
2870b3a271a9SManish Rangankar 
2871b3a271a9SManish Rangankar static struct iscsi_cls_conn *
2872b3a271a9SManish Rangankar qla4xxx_conn_create(struct iscsi_cls_session *cls_sess, uint32_t conn_idx)
2873b3a271a9SManish Rangankar {
2874b3a271a9SManish Rangankar 	struct iscsi_cls_conn *cls_conn;
2875b3a271a9SManish Rangankar 	struct iscsi_session *sess;
2876b3a271a9SManish Rangankar 	struct ddb_entry *ddb_entry;
2877b3a271a9SManish Rangankar 
2878b3a271a9SManish Rangankar 	DEBUG2(printk(KERN_INFO "Func: %s\n", __func__));
2879b3a271a9SManish Rangankar 	cls_conn = iscsi_conn_setup(cls_sess, sizeof(struct qla_conn),
2880b3a271a9SManish Rangankar 				    conn_idx);
2881ff1d0319SMike Christie 	if (!cls_conn)
2882ff1d0319SMike Christie 		return NULL;
2883ff1d0319SMike Christie 
2884b3a271a9SManish Rangankar 	sess = cls_sess->dd_data;
2885b3a271a9SManish Rangankar 	ddb_entry = sess->dd_data;
2886b3a271a9SManish Rangankar 	ddb_entry->conn = cls_conn;
2887b3a271a9SManish Rangankar 
2888b3a271a9SManish Rangankar 	return cls_conn;
2889b3a271a9SManish Rangankar }
2890b3a271a9SManish Rangankar 
2891b3a271a9SManish Rangankar static int qla4xxx_conn_bind(struct iscsi_cls_session *cls_session,
2892b3a271a9SManish Rangankar 			     struct iscsi_cls_conn *cls_conn,
2893b3a271a9SManish Rangankar 			     uint64_t transport_fd, int is_leading)
2894b3a271a9SManish Rangankar {
2895b3a271a9SManish Rangankar 	struct iscsi_conn *conn;
2896b3a271a9SManish Rangankar 	struct qla_conn *qla_conn;
2897b3a271a9SManish Rangankar 	struct iscsi_endpoint *ep;
2898b3a271a9SManish Rangankar 
2899b3a271a9SManish Rangankar 	DEBUG2(printk(KERN_INFO "Func: %s\n", __func__));
2900b3a271a9SManish Rangankar 
2901b3a271a9SManish Rangankar 	if (iscsi_conn_bind(cls_session, cls_conn, is_leading))
2902b3a271a9SManish Rangankar 		return -EINVAL;
2903b3a271a9SManish Rangankar 	ep = iscsi_lookup_endpoint(transport_fd);
2904b3a271a9SManish Rangankar 	conn = cls_conn->dd_data;
2905b3a271a9SManish Rangankar 	qla_conn = conn->dd_data;
2906b3a271a9SManish Rangankar 	qla_conn->qla_ep = ep->dd_data;
2907b3a271a9SManish Rangankar 	return 0;
2908b3a271a9SManish Rangankar }
2909b3a271a9SManish Rangankar 
2910b3a271a9SManish Rangankar static int qla4xxx_conn_start(struct iscsi_cls_conn *cls_conn)
2911b3a271a9SManish Rangankar {
2912b3a271a9SManish Rangankar 	struct iscsi_cls_session *cls_sess = iscsi_conn_to_session(cls_conn);
2913b3a271a9SManish Rangankar 	struct iscsi_session *sess;
2914b3a271a9SManish Rangankar 	struct ddb_entry *ddb_entry;
2915b3a271a9SManish Rangankar 	struct scsi_qla_host *ha;
291613483730SMike Christie 	struct dev_db_entry *fw_ddb_entry = NULL;
2917b3a271a9SManish Rangankar 	dma_addr_t fw_ddb_entry_dma;
2918b3a271a9SManish Rangankar 	uint32_t mbx_sts = 0;
2919b3a271a9SManish Rangankar 	int ret = 0;
2920b3a271a9SManish Rangankar 	int status = QLA_SUCCESS;
2921b3a271a9SManish Rangankar 
2922b3a271a9SManish Rangankar 	DEBUG2(printk(KERN_INFO "Func: %s\n", __func__));
2923b3a271a9SManish Rangankar 	sess = cls_sess->dd_data;
2924b3a271a9SManish Rangankar 	ddb_entry = sess->dd_data;
2925b3a271a9SManish Rangankar 	ha = ddb_entry->ha;
2926b3a271a9SManish Rangankar 
292713483730SMike Christie 	/* Check if we have  matching FW DDB, if yes then do not
292813483730SMike Christie 	 * login to this target. This could cause target to logout previous
292913483730SMike Christie 	 * connection
293013483730SMike Christie 	 */
293113483730SMike Christie 	ret = qla4xxx_match_fwdb_session(ha, cls_conn);
293213483730SMike Christie 	if (ret == QLA_SUCCESS) {
293313483730SMike Christie 		ql4_printk(KERN_INFO, ha,
293413483730SMike Christie 			   "Session already exist in FW.\n");
293513483730SMike Christie 		ret = -EEXIST;
293613483730SMike Christie 		goto exit_conn_start;
293713483730SMike Christie 	}
293813483730SMike Christie 
2939b3a271a9SManish Rangankar 	fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
2940b3a271a9SManish Rangankar 					  &fw_ddb_entry_dma, GFP_KERNEL);
2941b3a271a9SManish Rangankar 	if (!fw_ddb_entry) {
2942b3a271a9SManish Rangankar 		ql4_printk(KERN_ERR, ha,
2943b3a271a9SManish Rangankar 			   "%s: Unable to allocate dma buffer\n", __func__);
294413483730SMike Christie 		ret = -ENOMEM;
294513483730SMike Christie 		goto exit_conn_start;
2946b3a271a9SManish Rangankar 	}
2947b3a271a9SManish Rangankar 
2948b3a271a9SManish Rangankar 	ret = qla4xxx_set_param_ddbentry(ha, ddb_entry, cls_conn, &mbx_sts);
2949b3a271a9SManish Rangankar 	if (ret) {
2950b3a271a9SManish Rangankar 		/* If iscsid is stopped and started then no need to do
2951b3a271a9SManish Rangankar 		* set param again since ddb state will be already
2952b3a271a9SManish Rangankar 		* active and FW does not allow set ddb to an
2953b3a271a9SManish Rangankar 		* active session.
2954b3a271a9SManish Rangankar 		*/
2955b3a271a9SManish Rangankar 		if (mbx_sts)
2956b3a271a9SManish Rangankar 			if (ddb_entry->fw_ddb_device_state ==
2957f922da79SManish Rangankar 						DDB_DS_SESSION_ACTIVE) {
295813483730SMike Christie 				ddb_entry->unblock_sess(ddb_entry->sess);
2959b3a271a9SManish Rangankar 				goto exit_set_param;
2960f922da79SManish Rangankar 			}
2961b3a271a9SManish Rangankar 
2962b3a271a9SManish Rangankar 		ql4_printk(KERN_ERR, ha, "%s: Failed set param for index[%d]\n",
2963b3a271a9SManish Rangankar 			   __func__, ddb_entry->fw_ddb_index);
2964b3a271a9SManish Rangankar 		goto exit_conn_start;
2965b3a271a9SManish Rangankar 	}
2966b3a271a9SManish Rangankar 
2967b3a271a9SManish Rangankar 	status = qla4xxx_conn_open(ha, ddb_entry->fw_ddb_index);
2968b3a271a9SManish Rangankar 	if (status == QLA_ERROR) {
29690e7e8501SManish Rangankar 		ql4_printk(KERN_ERR, ha, "%s: Login failed: %s\n", __func__,
29700e7e8501SManish Rangankar 			   sess->targetname);
2971b3a271a9SManish Rangankar 		ret = -EINVAL;
2972b3a271a9SManish Rangankar 		goto exit_conn_start;
2973b3a271a9SManish Rangankar 	}
2974b3a271a9SManish Rangankar 
297598270ab4SManish Rangankar 	if (ddb_entry->fw_ddb_device_state == DDB_DS_NO_CONNECTION_ACTIVE)
2976b3a271a9SManish Rangankar 		ddb_entry->fw_ddb_device_state = DDB_DS_LOGIN_IN_PROCESS;
2977b3a271a9SManish Rangankar 
297898270ab4SManish Rangankar 	DEBUG2(printk(KERN_INFO "%s: DDB state [%d]\n", __func__,
297998270ab4SManish Rangankar 		      ddb_entry->fw_ddb_device_state));
298098270ab4SManish Rangankar 
2981b3a271a9SManish Rangankar exit_set_param:
2982b3a271a9SManish Rangankar 	ret = 0;
2983b3a271a9SManish Rangankar 
2984b3a271a9SManish Rangankar exit_conn_start:
298513483730SMike Christie 	if (fw_ddb_entry)
2986b3a271a9SManish Rangankar 		dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
2987b3a271a9SManish Rangankar 				  fw_ddb_entry, fw_ddb_entry_dma);
2988b3a271a9SManish Rangankar 	return ret;
2989b3a271a9SManish Rangankar }
2990b3a271a9SManish Rangankar 
2991b3a271a9SManish Rangankar static void qla4xxx_conn_destroy(struct iscsi_cls_conn *cls_conn)
2992b3a271a9SManish Rangankar {
2993b3a271a9SManish Rangankar 	struct iscsi_cls_session *cls_sess = iscsi_conn_to_session(cls_conn);
2994b3a271a9SManish Rangankar 	struct iscsi_session *sess;
2995b3a271a9SManish Rangankar 	struct scsi_qla_host *ha;
2996b3a271a9SManish Rangankar 	struct ddb_entry *ddb_entry;
2997b3a271a9SManish Rangankar 	int options;
2998b3a271a9SManish Rangankar 
2999b3a271a9SManish Rangankar 	DEBUG2(printk(KERN_INFO "Func: %s\n", __func__));
3000b3a271a9SManish Rangankar 	sess = cls_sess->dd_data;
3001b3a271a9SManish Rangankar 	ddb_entry = sess->dd_data;
3002b3a271a9SManish Rangankar 	ha = ddb_entry->ha;
3003b3a271a9SManish Rangankar 
3004b3a271a9SManish Rangankar 	options = LOGOUT_OPTION_CLOSE_SESSION;
3005b3a271a9SManish Rangankar 	if (qla4xxx_session_logout_ddb(ha, ddb_entry, options) == QLA_ERROR)
3006b3a271a9SManish Rangankar 		ql4_printk(KERN_ERR, ha, "%s: Logout failed\n", __func__);
3007b3a271a9SManish Rangankar }
3008b3a271a9SManish Rangankar 
3009b3a271a9SManish Rangankar static void qla4xxx_task_work(struct work_struct *wdata)
3010b3a271a9SManish Rangankar {
3011b3a271a9SManish Rangankar 	struct ql4_task_data *task_data;
3012b3a271a9SManish Rangankar 	struct scsi_qla_host *ha;
3013b3a271a9SManish Rangankar 	struct passthru_status *sts;
3014b3a271a9SManish Rangankar 	struct iscsi_task *task;
3015b3a271a9SManish Rangankar 	struct iscsi_hdr *hdr;
3016b3a271a9SManish Rangankar 	uint8_t *data;
3017b3a271a9SManish Rangankar 	uint32_t data_len;
3018b3a271a9SManish Rangankar 	struct iscsi_conn *conn;
3019b3a271a9SManish Rangankar 	int hdr_len;
3020b3a271a9SManish Rangankar 	itt_t itt;
3021b3a271a9SManish Rangankar 
3022b3a271a9SManish Rangankar 	task_data = container_of(wdata, struct ql4_task_data, task_work);
3023b3a271a9SManish Rangankar 	ha = task_data->ha;
3024b3a271a9SManish Rangankar 	task = task_data->task;
3025b3a271a9SManish Rangankar 	sts = &task_data->sts;
3026b3a271a9SManish Rangankar 	hdr_len = sizeof(struct iscsi_hdr);
3027b3a271a9SManish Rangankar 
3028b3a271a9SManish Rangankar 	DEBUG3(printk(KERN_INFO "Status returned\n"));
3029b3a271a9SManish Rangankar 	DEBUG3(qla4xxx_dump_buffer(sts, 64));
3030b3a271a9SManish Rangankar 	DEBUG3(printk(KERN_INFO "Response buffer"));
3031b3a271a9SManish Rangankar 	DEBUG3(qla4xxx_dump_buffer(task_data->resp_buffer, 64));
3032b3a271a9SManish Rangankar 
3033b3a271a9SManish Rangankar 	conn = task->conn;
3034b3a271a9SManish Rangankar 
3035b3a271a9SManish Rangankar 	switch (sts->completionStatus) {
3036b3a271a9SManish Rangankar 	case PASSTHRU_STATUS_COMPLETE:
3037b3a271a9SManish Rangankar 		hdr = (struct iscsi_hdr *)task_data->resp_buffer;
3038b3a271a9SManish Rangankar 		/* Assign back the itt in hdr, until we use the PREASSIGN_TAG */
3039b3a271a9SManish Rangankar 		itt = sts->handle;
3040b3a271a9SManish Rangankar 		hdr->itt = itt;
3041b3a271a9SManish Rangankar 		data = task_data->resp_buffer + hdr_len;
3042b3a271a9SManish Rangankar 		data_len = task_data->resp_len - hdr_len;
3043b3a271a9SManish Rangankar 		iscsi_complete_pdu(conn, hdr, data, data_len);
3044b3a271a9SManish Rangankar 		break;
3045b3a271a9SManish Rangankar 	default:
3046b3a271a9SManish Rangankar 		ql4_printk(KERN_ERR, ha, "Passthru failed status = 0x%x\n",
3047b3a271a9SManish Rangankar 			   sts->completionStatus);
3048b3a271a9SManish Rangankar 		break;
3049b3a271a9SManish Rangankar 	}
3050b3a271a9SManish Rangankar 	return;
3051b3a271a9SManish Rangankar }
3052b3a271a9SManish Rangankar 
3053b3a271a9SManish Rangankar static int qla4xxx_alloc_pdu(struct iscsi_task *task, uint8_t opcode)
3054b3a271a9SManish Rangankar {
3055b3a271a9SManish Rangankar 	struct ql4_task_data *task_data;
3056b3a271a9SManish Rangankar 	struct iscsi_session *sess;
3057b3a271a9SManish Rangankar 	struct ddb_entry *ddb_entry;
3058b3a271a9SManish Rangankar 	struct scsi_qla_host *ha;
3059b3a271a9SManish Rangankar 	int hdr_len;
3060b3a271a9SManish Rangankar 
3061b3a271a9SManish Rangankar 	sess = task->conn->session;
3062b3a271a9SManish Rangankar 	ddb_entry = sess->dd_data;
3063b3a271a9SManish Rangankar 	ha = ddb_entry->ha;
3064b3a271a9SManish Rangankar 	task_data = task->dd_data;
3065b3a271a9SManish Rangankar 	memset(task_data, 0, sizeof(struct ql4_task_data));
3066b3a271a9SManish Rangankar 
3067b3a271a9SManish Rangankar 	if (task->sc) {
3068b3a271a9SManish Rangankar 		ql4_printk(KERN_INFO, ha,
3069b3a271a9SManish Rangankar 			   "%s: SCSI Commands not implemented\n", __func__);
3070b3a271a9SManish Rangankar 		return -EINVAL;
3071b3a271a9SManish Rangankar 	}
3072b3a271a9SManish Rangankar 
3073b3a271a9SManish Rangankar 	hdr_len = sizeof(struct iscsi_hdr);
3074b3a271a9SManish Rangankar 	task_data->ha = ha;
3075b3a271a9SManish Rangankar 	task_data->task = task;
3076b3a271a9SManish Rangankar 
3077b3a271a9SManish Rangankar 	if (task->data_count) {
3078b3a271a9SManish Rangankar 		task_data->data_dma = dma_map_single(&ha->pdev->dev, task->data,
3079b3a271a9SManish Rangankar 						     task->data_count,
3080b3a271a9SManish Rangankar 						     PCI_DMA_TODEVICE);
3081b3a271a9SManish Rangankar 	}
3082b3a271a9SManish Rangankar 
3083b3a271a9SManish Rangankar 	DEBUG2(ql4_printk(KERN_INFO, ha, "%s: MaxRecvLen %u, iscsi hrd %d\n",
3084b3a271a9SManish Rangankar 		      __func__, task->conn->max_recv_dlength, hdr_len));
3085b3a271a9SManish Rangankar 
308669ca216eSManish Rangankar 	task_data->resp_len = task->conn->max_recv_dlength + hdr_len;
3087b3a271a9SManish Rangankar 	task_data->resp_buffer = dma_alloc_coherent(&ha->pdev->dev,
3088b3a271a9SManish Rangankar 						    task_data->resp_len,
3089b3a271a9SManish Rangankar 						    &task_data->resp_dma,
3090b3a271a9SManish Rangankar 						    GFP_ATOMIC);
3091b3a271a9SManish Rangankar 	if (!task_data->resp_buffer)
3092b3a271a9SManish Rangankar 		goto exit_alloc_pdu;
3093b3a271a9SManish Rangankar 
309469ca216eSManish Rangankar 	task_data->req_len = task->data_count + hdr_len;
3095b3a271a9SManish Rangankar 	task_data->req_buffer = dma_alloc_coherent(&ha->pdev->dev,
309669ca216eSManish Rangankar 						   task_data->req_len,
3097b3a271a9SManish Rangankar 						   &task_data->req_dma,
3098b3a271a9SManish Rangankar 						   GFP_ATOMIC);
3099b3a271a9SManish Rangankar 	if (!task_data->req_buffer)
3100b3a271a9SManish Rangankar 		goto exit_alloc_pdu;
3101b3a271a9SManish Rangankar 
3102b3a271a9SManish Rangankar 	task->hdr = task_data->req_buffer;
3103b3a271a9SManish Rangankar 
3104b3a271a9SManish Rangankar 	INIT_WORK(&task_data->task_work, qla4xxx_task_work);
3105b3a271a9SManish Rangankar 
3106b3a271a9SManish Rangankar 	return 0;
3107b3a271a9SManish Rangankar 
3108b3a271a9SManish Rangankar exit_alloc_pdu:
3109b3a271a9SManish Rangankar 	if (task_data->resp_buffer)
3110b3a271a9SManish Rangankar 		dma_free_coherent(&ha->pdev->dev, task_data->resp_len,
3111b3a271a9SManish Rangankar 				  task_data->resp_buffer, task_data->resp_dma);
3112b3a271a9SManish Rangankar 
3113b3a271a9SManish Rangankar 	if (task_data->req_buffer)
311469ca216eSManish Rangankar 		dma_free_coherent(&ha->pdev->dev, task_data->req_len,
3115b3a271a9SManish Rangankar 				  task_data->req_buffer, task_data->req_dma);
3116b3a271a9SManish Rangankar 	return -ENOMEM;
3117b3a271a9SManish Rangankar }
3118b3a271a9SManish Rangankar 
3119b3a271a9SManish Rangankar static void qla4xxx_task_cleanup(struct iscsi_task *task)
3120b3a271a9SManish Rangankar {
3121b3a271a9SManish Rangankar 	struct ql4_task_data *task_data;
3122b3a271a9SManish Rangankar 	struct iscsi_session *sess;
3123b3a271a9SManish Rangankar 	struct ddb_entry *ddb_entry;
3124b3a271a9SManish Rangankar 	struct scsi_qla_host *ha;
3125b3a271a9SManish Rangankar 	int hdr_len;
3126b3a271a9SManish Rangankar 
3127b3a271a9SManish Rangankar 	hdr_len = sizeof(struct iscsi_hdr);
3128b3a271a9SManish Rangankar 	sess = task->conn->session;
3129b3a271a9SManish Rangankar 	ddb_entry = sess->dd_data;
3130b3a271a9SManish Rangankar 	ha = ddb_entry->ha;
3131b3a271a9SManish Rangankar 	task_data = task->dd_data;
3132b3a271a9SManish Rangankar 
3133b3a271a9SManish Rangankar 	if (task->data_count) {
3134b3a271a9SManish Rangankar 		dma_unmap_single(&ha->pdev->dev, task_data->data_dma,
3135b3a271a9SManish Rangankar 				 task->data_count, PCI_DMA_TODEVICE);
3136b3a271a9SManish Rangankar 	}
3137b3a271a9SManish Rangankar 
3138b3a271a9SManish Rangankar 	DEBUG2(ql4_printk(KERN_INFO, ha, "%s: MaxRecvLen %u, iscsi hrd %d\n",
3139b3a271a9SManish Rangankar 		      __func__, task->conn->max_recv_dlength, hdr_len));
3140b3a271a9SManish Rangankar 
3141b3a271a9SManish Rangankar 	dma_free_coherent(&ha->pdev->dev, task_data->resp_len,
3142b3a271a9SManish Rangankar 			  task_data->resp_buffer, task_data->resp_dma);
314369ca216eSManish Rangankar 	dma_free_coherent(&ha->pdev->dev, task_data->req_len,
3144b3a271a9SManish Rangankar 			  task_data->req_buffer, task_data->req_dma);
3145b3a271a9SManish Rangankar 	return;
3146b3a271a9SManish Rangankar }
3147b3a271a9SManish Rangankar 
3148b3a271a9SManish Rangankar static int qla4xxx_task_xmit(struct iscsi_task *task)
3149b3a271a9SManish Rangankar {
3150b3a271a9SManish Rangankar 	struct scsi_cmnd *sc = task->sc;
3151b3a271a9SManish Rangankar 	struct iscsi_session *sess = task->conn->session;
3152b3a271a9SManish Rangankar 	struct ddb_entry *ddb_entry = sess->dd_data;
3153b3a271a9SManish Rangankar 	struct scsi_qla_host *ha = ddb_entry->ha;
3154b3a271a9SManish Rangankar 
3155b3a271a9SManish Rangankar 	if (!sc)
3156b3a271a9SManish Rangankar 		return qla4xxx_send_passthru0(task);
3157b3a271a9SManish Rangankar 
3158b3a271a9SManish Rangankar 	ql4_printk(KERN_INFO, ha, "%s: scsi cmd xmit not implemented\n",
3159b3a271a9SManish Rangankar 		   __func__);
3160b3a271a9SManish Rangankar 	return -ENOSYS;
3161b3a271a9SManish Rangankar }
3162b3a271a9SManish Rangankar 
31631e9e2be3SAdheer Chandravanshi static int qla4xxx_copy_from_fwddb_param(struct iscsi_bus_flash_session *sess,
31641e9e2be3SAdheer Chandravanshi 					 struct iscsi_bus_flash_conn *conn,
31651e9e2be3SAdheer Chandravanshi 					 struct dev_db_entry *fw_ddb_entry)
31661e9e2be3SAdheer Chandravanshi {
31671e9e2be3SAdheer Chandravanshi 	unsigned long options = 0;
31681e9e2be3SAdheer Chandravanshi 	int rc = 0;
31691e9e2be3SAdheer Chandravanshi 
31701e9e2be3SAdheer Chandravanshi 	options = le16_to_cpu(fw_ddb_entry->options);
31711e9e2be3SAdheer Chandravanshi 	conn->is_fw_assigned_ipv6 = test_bit(OPT_IS_FW_ASSIGNED_IPV6, &options);
31721e9e2be3SAdheer Chandravanshi 	if (test_bit(OPT_IPV6_DEVICE, &options)) {
3173c962c18bSAdheer Chandravanshi 		rc = iscsi_switch_str_param(&sess->portal_type,
3174c962c18bSAdheer Chandravanshi 					    PORTAL_TYPE_IPV6);
31751e9e2be3SAdheer Chandravanshi 		if (rc)
31761e9e2be3SAdheer Chandravanshi 			goto exit_copy;
31771e9e2be3SAdheer Chandravanshi 	} else {
3178c962c18bSAdheer Chandravanshi 		rc = iscsi_switch_str_param(&sess->portal_type,
3179c962c18bSAdheer Chandravanshi 					    PORTAL_TYPE_IPV4);
31801e9e2be3SAdheer Chandravanshi 		if (rc)
31811e9e2be3SAdheer Chandravanshi 			goto exit_copy;
31821e9e2be3SAdheer Chandravanshi 	}
31831e9e2be3SAdheer Chandravanshi 
31841e9e2be3SAdheer Chandravanshi 	sess->auto_snd_tgt_disable = test_bit(OPT_AUTO_SENDTGTS_DISABLE,
31851e9e2be3SAdheer Chandravanshi 					      &options);
31861e9e2be3SAdheer Chandravanshi 	sess->discovery_sess = test_bit(OPT_DISC_SESSION, &options);
31871e9e2be3SAdheer Chandravanshi 	sess->entry_state = test_bit(OPT_ENTRY_STATE, &options);
31881e9e2be3SAdheer Chandravanshi 
31891e9e2be3SAdheer Chandravanshi 	options = le16_to_cpu(fw_ddb_entry->iscsi_options);
31901e9e2be3SAdheer Chandravanshi 	conn->hdrdgst_en = test_bit(ISCSIOPT_HEADER_DIGEST_EN, &options);
31911e9e2be3SAdheer Chandravanshi 	conn->datadgst_en = test_bit(ISCSIOPT_DATA_DIGEST_EN, &options);
31921e9e2be3SAdheer Chandravanshi 	sess->imm_data_en = test_bit(ISCSIOPT_IMMEDIATE_DATA_EN, &options);
31931e9e2be3SAdheer Chandravanshi 	sess->initial_r2t_en = test_bit(ISCSIOPT_INITIAL_R2T_EN, &options);
31941e9e2be3SAdheer Chandravanshi 	sess->dataseq_inorder_en = test_bit(ISCSIOPT_DATA_SEQ_IN_ORDER,
31951e9e2be3SAdheer Chandravanshi 					    &options);
31961e9e2be3SAdheer Chandravanshi 	sess->pdu_inorder_en = test_bit(ISCSIOPT_DATA_PDU_IN_ORDER, &options);
31971e9e2be3SAdheer Chandravanshi 	sess->chap_auth_en = test_bit(ISCSIOPT_CHAP_AUTH_EN, &options);
31981e9e2be3SAdheer Chandravanshi 	conn->snack_req_en = test_bit(ISCSIOPT_SNACK_REQ_EN, &options);
31991e9e2be3SAdheer Chandravanshi 	sess->discovery_logout_en = test_bit(ISCSIOPT_DISCOVERY_LOGOUT_EN,
32001e9e2be3SAdheer Chandravanshi 					     &options);
32011e9e2be3SAdheer Chandravanshi 	sess->bidi_chap_en = test_bit(ISCSIOPT_BIDI_CHAP_EN, &options);
32021e9e2be3SAdheer Chandravanshi 	sess->discovery_auth_optional =
32031e9e2be3SAdheer Chandravanshi 			test_bit(ISCSIOPT_DISCOVERY_AUTH_OPTIONAL, &options);
32041e9e2be3SAdheer Chandravanshi 	if (test_bit(ISCSIOPT_ERL1, &options))
32051e9e2be3SAdheer Chandravanshi 		sess->erl |= BIT_1;
32061e9e2be3SAdheer Chandravanshi 	if (test_bit(ISCSIOPT_ERL0, &options))
32071e9e2be3SAdheer Chandravanshi 		sess->erl |= BIT_0;
32081e9e2be3SAdheer Chandravanshi 
32091e9e2be3SAdheer Chandravanshi 	options = le16_to_cpu(fw_ddb_entry->tcp_options);
32101e9e2be3SAdheer Chandravanshi 	conn->tcp_timestamp_stat = test_bit(TCPOPT_TIMESTAMP_STAT, &options);
32111e9e2be3SAdheer Chandravanshi 	conn->tcp_nagle_disable = test_bit(TCPOPT_NAGLE_DISABLE, &options);
32121e9e2be3SAdheer Chandravanshi 	conn->tcp_wsf_disable = test_bit(TCPOPT_WSF_DISABLE, &options);
32131e9e2be3SAdheer Chandravanshi 	if (test_bit(TCPOPT_TIMER_SCALE3, &options))
32141e9e2be3SAdheer Chandravanshi 		conn->tcp_timer_scale |= BIT_3;
32151e9e2be3SAdheer Chandravanshi 	if (test_bit(TCPOPT_TIMER_SCALE2, &options))
32161e9e2be3SAdheer Chandravanshi 		conn->tcp_timer_scale |= BIT_2;
32171e9e2be3SAdheer Chandravanshi 	if (test_bit(TCPOPT_TIMER_SCALE1, &options))
32181e9e2be3SAdheer Chandravanshi 		conn->tcp_timer_scale |= BIT_1;
32191e9e2be3SAdheer Chandravanshi 
32201e9e2be3SAdheer Chandravanshi 	conn->tcp_timer_scale >>= 1;
32211e9e2be3SAdheer Chandravanshi 	conn->tcp_timestamp_en = test_bit(TCPOPT_TIMESTAMP_EN, &options);
32221e9e2be3SAdheer Chandravanshi 
32231e9e2be3SAdheer Chandravanshi 	options = le16_to_cpu(fw_ddb_entry->ip_options);
32241e9e2be3SAdheer Chandravanshi 	conn->fragment_disable = test_bit(IPOPT_FRAGMENT_DISABLE, &options);
32251e9e2be3SAdheer Chandravanshi 
32261e9e2be3SAdheer Chandravanshi 	conn->max_recv_dlength = BYTE_UNITS *
32271e9e2be3SAdheer Chandravanshi 			  le16_to_cpu(fw_ddb_entry->iscsi_max_rcv_data_seg_len);
32281e9e2be3SAdheer Chandravanshi 	conn->max_xmit_dlength = BYTE_UNITS *
32291e9e2be3SAdheer Chandravanshi 			  le16_to_cpu(fw_ddb_entry->iscsi_max_snd_data_seg_len);
32301e9e2be3SAdheer Chandravanshi 	sess->first_burst = BYTE_UNITS *
32311e9e2be3SAdheer Chandravanshi 			       le16_to_cpu(fw_ddb_entry->iscsi_first_burst_len);
32321e9e2be3SAdheer Chandravanshi 	sess->max_burst = BYTE_UNITS *
32331e9e2be3SAdheer Chandravanshi 				 le16_to_cpu(fw_ddb_entry->iscsi_max_burst_len);
32341e9e2be3SAdheer Chandravanshi 	sess->max_r2t = le16_to_cpu(fw_ddb_entry->iscsi_max_outsnd_r2t);
32351e9e2be3SAdheer Chandravanshi 	sess->time2wait = le16_to_cpu(fw_ddb_entry->iscsi_def_time2wait);
32361e9e2be3SAdheer Chandravanshi 	sess->time2retain = le16_to_cpu(fw_ddb_entry->iscsi_def_time2retain);
32371e9e2be3SAdheer Chandravanshi 	sess->tpgt = le32_to_cpu(fw_ddb_entry->tgt_portal_grp);
32381e9e2be3SAdheer Chandravanshi 	conn->max_segment_size = le16_to_cpu(fw_ddb_entry->mss);
32391e9e2be3SAdheer Chandravanshi 	conn->tcp_xmit_wsf = fw_ddb_entry->tcp_xmt_wsf;
32401e9e2be3SAdheer Chandravanshi 	conn->tcp_recv_wsf = fw_ddb_entry->tcp_rcv_wsf;
32411e9e2be3SAdheer Chandravanshi 	conn->ipv6_flow_label = le16_to_cpu(fw_ddb_entry->ipv6_flow_lbl);
32421e9e2be3SAdheer Chandravanshi 	conn->keepalive_timeout = le16_to_cpu(fw_ddb_entry->ka_timeout);
32431e9e2be3SAdheer Chandravanshi 	conn->local_port = le16_to_cpu(fw_ddb_entry->lcl_port);
32441e9e2be3SAdheer Chandravanshi 	conn->statsn = le32_to_cpu(fw_ddb_entry->stat_sn);
32451e9e2be3SAdheer Chandravanshi 	conn->exp_statsn = le32_to_cpu(fw_ddb_entry->exp_stat_sn);
32461e9e2be3SAdheer Chandravanshi 	sess->discovery_parent_idx = le16_to_cpu(fw_ddb_entry->ddb_link);
32471e9e2be3SAdheer Chandravanshi 	sess->discovery_parent_type = le16_to_cpu(fw_ddb_entry->ddb_link);
32481e9e2be3SAdheer Chandravanshi 	sess->chap_out_idx = le16_to_cpu(fw_ddb_entry->chap_tbl_idx);
32491e9e2be3SAdheer Chandravanshi 	sess->tsid = le16_to_cpu(fw_ddb_entry->tsid);
32501e9e2be3SAdheer Chandravanshi 
32511e9e2be3SAdheer Chandravanshi 	sess->default_taskmgmt_timeout =
32521e9e2be3SAdheer Chandravanshi 				le16_to_cpu(fw_ddb_entry->def_timeout);
32531e9e2be3SAdheer Chandravanshi 	conn->port = le16_to_cpu(fw_ddb_entry->port);
32541e9e2be3SAdheer Chandravanshi 
32551e9e2be3SAdheer Chandravanshi 	options = le16_to_cpu(fw_ddb_entry->options);
32561e9e2be3SAdheer Chandravanshi 	conn->ipaddress = kzalloc(IPv6_ADDR_LEN, GFP_KERNEL);
32571e9e2be3SAdheer Chandravanshi 	if (!conn->ipaddress) {
32581e9e2be3SAdheer Chandravanshi 		rc = -ENOMEM;
32591e9e2be3SAdheer Chandravanshi 		goto exit_copy;
32601e9e2be3SAdheer Chandravanshi 	}
32611e9e2be3SAdheer Chandravanshi 
32621e9e2be3SAdheer Chandravanshi 	conn->redirect_ipaddr = kzalloc(IPv6_ADDR_LEN, GFP_KERNEL);
32631e9e2be3SAdheer Chandravanshi 	if (!conn->redirect_ipaddr) {
32641e9e2be3SAdheer Chandravanshi 		rc = -ENOMEM;
32651e9e2be3SAdheer Chandravanshi 		goto exit_copy;
32661e9e2be3SAdheer Chandravanshi 	}
32671e9e2be3SAdheer Chandravanshi 
32681e9e2be3SAdheer Chandravanshi 	memcpy(conn->ipaddress, fw_ddb_entry->ip_addr, IPv6_ADDR_LEN);
32691e9e2be3SAdheer Chandravanshi 	memcpy(conn->redirect_ipaddr, fw_ddb_entry->tgt_addr, IPv6_ADDR_LEN);
32701e9e2be3SAdheer Chandravanshi 
32711e9e2be3SAdheer Chandravanshi 	if (test_bit(OPT_IPV6_DEVICE, &options)) {
32721e9e2be3SAdheer Chandravanshi 		conn->ipv6_traffic_class = fw_ddb_entry->ipv4_tos;
32731e9e2be3SAdheer Chandravanshi 
32741e9e2be3SAdheer Chandravanshi 		conn->link_local_ipv6_addr = kzalloc(IPv6_ADDR_LEN, GFP_KERNEL);
32751e9e2be3SAdheer Chandravanshi 		if (!conn->link_local_ipv6_addr) {
32761e9e2be3SAdheer Chandravanshi 			rc = -ENOMEM;
32771e9e2be3SAdheer Chandravanshi 			goto exit_copy;
32781e9e2be3SAdheer Chandravanshi 		}
32791e9e2be3SAdheer Chandravanshi 
32801e9e2be3SAdheer Chandravanshi 		memcpy(conn->link_local_ipv6_addr,
32811e9e2be3SAdheer Chandravanshi 		       fw_ddb_entry->link_local_ipv6_addr, IPv6_ADDR_LEN);
32821e9e2be3SAdheer Chandravanshi 	} else {
32831e9e2be3SAdheer Chandravanshi 		conn->ipv4_tos = fw_ddb_entry->ipv4_tos;
32841e9e2be3SAdheer Chandravanshi 	}
32851e9e2be3SAdheer Chandravanshi 
32861e9e2be3SAdheer Chandravanshi 	if (fw_ddb_entry->iscsi_name[0]) {
32871e9e2be3SAdheer Chandravanshi 		rc = iscsi_switch_str_param(&sess->targetname,
32881e9e2be3SAdheer Chandravanshi 					    (char *)fw_ddb_entry->iscsi_name);
32891e9e2be3SAdheer Chandravanshi 		if (rc)
32901e9e2be3SAdheer Chandravanshi 			goto exit_copy;
32911e9e2be3SAdheer Chandravanshi 	}
32921e9e2be3SAdheer Chandravanshi 
32931e9e2be3SAdheer Chandravanshi 	if (fw_ddb_entry->iscsi_alias[0]) {
32941e9e2be3SAdheer Chandravanshi 		rc = iscsi_switch_str_param(&sess->targetalias,
32951e9e2be3SAdheer Chandravanshi 					    (char *)fw_ddb_entry->iscsi_alias);
32961e9e2be3SAdheer Chandravanshi 		if (rc)
32971e9e2be3SAdheer Chandravanshi 			goto exit_copy;
32981e9e2be3SAdheer Chandravanshi 	}
32991e9e2be3SAdheer Chandravanshi 
33001e9e2be3SAdheer Chandravanshi 	COPY_ISID(sess->isid, fw_ddb_entry->isid);
33011e9e2be3SAdheer Chandravanshi 
33021e9e2be3SAdheer Chandravanshi exit_copy:
33031e9e2be3SAdheer Chandravanshi 	return rc;
33041e9e2be3SAdheer Chandravanshi }
33051e9e2be3SAdheer Chandravanshi 
33061e9e2be3SAdheer Chandravanshi static int qla4xxx_copy_to_fwddb_param(struct iscsi_bus_flash_session *sess,
33071e9e2be3SAdheer Chandravanshi 				       struct iscsi_bus_flash_conn *conn,
33081e9e2be3SAdheer Chandravanshi 				       struct dev_db_entry *fw_ddb_entry)
33091e9e2be3SAdheer Chandravanshi {
33101e9e2be3SAdheer Chandravanshi 	uint16_t options;
33111e9e2be3SAdheer Chandravanshi 	int rc = 0;
33121e9e2be3SAdheer Chandravanshi 
33131e9e2be3SAdheer Chandravanshi 	options = le16_to_cpu(fw_ddb_entry->options);
33141e9e2be3SAdheer Chandravanshi 	SET_BITVAL(conn->is_fw_assigned_ipv6,  options, BIT_11);
3315c962c18bSAdheer Chandravanshi 	if (!strncmp(sess->portal_type, PORTAL_TYPE_IPV6, 4))
33161e9e2be3SAdheer Chandravanshi 		options |= BIT_8;
33171e9e2be3SAdheer Chandravanshi 	else
33181e9e2be3SAdheer Chandravanshi 		options &= ~BIT_8;
33191e9e2be3SAdheer Chandravanshi 
33201e9e2be3SAdheer Chandravanshi 	SET_BITVAL(sess->auto_snd_tgt_disable, options, BIT_6);
33211e9e2be3SAdheer Chandravanshi 	SET_BITVAL(sess->discovery_sess, options, BIT_4);
33221e9e2be3SAdheer Chandravanshi 	SET_BITVAL(sess->entry_state, options, BIT_3);
33231e9e2be3SAdheer Chandravanshi 	fw_ddb_entry->options = cpu_to_le16(options);
33241e9e2be3SAdheer Chandravanshi 
33251e9e2be3SAdheer Chandravanshi 	options = le16_to_cpu(fw_ddb_entry->iscsi_options);
33261e9e2be3SAdheer Chandravanshi 	SET_BITVAL(conn->hdrdgst_en, options, BIT_13);
33271e9e2be3SAdheer Chandravanshi 	SET_BITVAL(conn->datadgst_en, options, BIT_12);
33281e9e2be3SAdheer Chandravanshi 	SET_BITVAL(sess->imm_data_en, options, BIT_11);
33291e9e2be3SAdheer Chandravanshi 	SET_BITVAL(sess->initial_r2t_en, options, BIT_10);
33301e9e2be3SAdheer Chandravanshi 	SET_BITVAL(sess->dataseq_inorder_en, options, BIT_9);
33311e9e2be3SAdheer Chandravanshi 	SET_BITVAL(sess->pdu_inorder_en, options, BIT_8);
33321e9e2be3SAdheer Chandravanshi 	SET_BITVAL(sess->chap_auth_en, options, BIT_7);
33331e9e2be3SAdheer Chandravanshi 	SET_BITVAL(conn->snack_req_en, options, BIT_6);
33341e9e2be3SAdheer Chandravanshi 	SET_BITVAL(sess->discovery_logout_en, options, BIT_5);
33351e9e2be3SAdheer Chandravanshi 	SET_BITVAL(sess->bidi_chap_en, options, BIT_4);
33361e9e2be3SAdheer Chandravanshi 	SET_BITVAL(sess->discovery_auth_optional, options, BIT_3);
33371e9e2be3SAdheer Chandravanshi 	SET_BITVAL(sess->erl & BIT_1, options, BIT_1);
33381e9e2be3SAdheer Chandravanshi 	SET_BITVAL(sess->erl & BIT_0, options, BIT_0);
33391e9e2be3SAdheer Chandravanshi 	fw_ddb_entry->iscsi_options = cpu_to_le16(options);
33401e9e2be3SAdheer Chandravanshi 
33411e9e2be3SAdheer Chandravanshi 	options = le16_to_cpu(fw_ddb_entry->tcp_options);
33421e9e2be3SAdheer Chandravanshi 	SET_BITVAL(conn->tcp_timestamp_stat, options, BIT_6);
33431e9e2be3SAdheer Chandravanshi 	SET_BITVAL(conn->tcp_nagle_disable, options, BIT_5);
33441e9e2be3SAdheer Chandravanshi 	SET_BITVAL(conn->tcp_wsf_disable, options, BIT_4);
33451e9e2be3SAdheer Chandravanshi 	SET_BITVAL(conn->tcp_timer_scale & BIT_2, options, BIT_3);
33461e9e2be3SAdheer Chandravanshi 	SET_BITVAL(conn->tcp_timer_scale & BIT_1, options, BIT_2);
33471e9e2be3SAdheer Chandravanshi 	SET_BITVAL(conn->tcp_timer_scale & BIT_0, options, BIT_1);
33481e9e2be3SAdheer Chandravanshi 	SET_BITVAL(conn->tcp_timestamp_en, options, BIT_0);
33491e9e2be3SAdheer Chandravanshi 	fw_ddb_entry->tcp_options = cpu_to_le16(options);
33501e9e2be3SAdheer Chandravanshi 
33511e9e2be3SAdheer Chandravanshi 	options = le16_to_cpu(fw_ddb_entry->ip_options);
33521e9e2be3SAdheer Chandravanshi 	SET_BITVAL(conn->fragment_disable, options, BIT_4);
33531e9e2be3SAdheer Chandravanshi 	fw_ddb_entry->ip_options = cpu_to_le16(options);
33541e9e2be3SAdheer Chandravanshi 
33551e9e2be3SAdheer Chandravanshi 	fw_ddb_entry->iscsi_max_outsnd_r2t = cpu_to_le16(sess->max_r2t);
33561e9e2be3SAdheer Chandravanshi 	fw_ddb_entry->iscsi_max_rcv_data_seg_len =
33571e9e2be3SAdheer Chandravanshi 			       cpu_to_le16(conn->max_recv_dlength / BYTE_UNITS);
33581e9e2be3SAdheer Chandravanshi 	fw_ddb_entry->iscsi_max_snd_data_seg_len =
33591e9e2be3SAdheer Chandravanshi 			       cpu_to_le16(conn->max_xmit_dlength / BYTE_UNITS);
33601e9e2be3SAdheer Chandravanshi 	fw_ddb_entry->iscsi_first_burst_len =
33611e9e2be3SAdheer Chandravanshi 				cpu_to_le16(sess->first_burst / BYTE_UNITS);
33621e9e2be3SAdheer Chandravanshi 	fw_ddb_entry->iscsi_max_burst_len = cpu_to_le16(sess->max_burst /
33631e9e2be3SAdheer Chandravanshi 					    BYTE_UNITS);
33641e9e2be3SAdheer Chandravanshi 	fw_ddb_entry->iscsi_def_time2wait = cpu_to_le16(sess->time2wait);
33651e9e2be3SAdheer Chandravanshi 	fw_ddb_entry->iscsi_def_time2retain = cpu_to_le16(sess->time2retain);
33661e9e2be3SAdheer Chandravanshi 	fw_ddb_entry->tgt_portal_grp = cpu_to_le16(sess->tpgt);
33671e9e2be3SAdheer Chandravanshi 	fw_ddb_entry->mss = cpu_to_le16(conn->max_segment_size);
3368fbcd4836SAdheer Chandravanshi 	fw_ddb_entry->tcp_xmt_wsf = (uint8_t) cpu_to_le32(conn->tcp_xmit_wsf);
3369fbcd4836SAdheer Chandravanshi 	fw_ddb_entry->tcp_rcv_wsf = (uint8_t) cpu_to_le32(conn->tcp_recv_wsf);
33701e9e2be3SAdheer Chandravanshi 	fw_ddb_entry->ipv6_flow_lbl = cpu_to_le16(conn->ipv6_flow_label);
33711e9e2be3SAdheer Chandravanshi 	fw_ddb_entry->ka_timeout = cpu_to_le16(conn->keepalive_timeout);
33721e9e2be3SAdheer Chandravanshi 	fw_ddb_entry->lcl_port = cpu_to_le16(conn->local_port);
3373fbcd4836SAdheer Chandravanshi 	fw_ddb_entry->stat_sn = cpu_to_le32(conn->statsn);
3374fbcd4836SAdheer Chandravanshi 	fw_ddb_entry->exp_stat_sn = cpu_to_le32(conn->exp_statsn);
337565560166SAdheer Chandravanshi 	fw_ddb_entry->ddb_link = cpu_to_le16(sess->discovery_parent_idx);
33761e9e2be3SAdheer Chandravanshi 	fw_ddb_entry->chap_tbl_idx = cpu_to_le16(sess->chap_out_idx);
33771e9e2be3SAdheer Chandravanshi 	fw_ddb_entry->tsid = cpu_to_le16(sess->tsid);
33781e9e2be3SAdheer Chandravanshi 	fw_ddb_entry->port = cpu_to_le16(conn->port);
33791e9e2be3SAdheer Chandravanshi 	fw_ddb_entry->def_timeout =
33801e9e2be3SAdheer Chandravanshi 				cpu_to_le16(sess->default_taskmgmt_timeout);
33811e9e2be3SAdheer Chandravanshi 
338284595802SAdheer Chandravanshi 	if (!strncmp(sess->portal_type, PORTAL_TYPE_IPV6, 4))
338384595802SAdheer Chandravanshi 		fw_ddb_entry->ipv4_tos = conn->ipv6_traffic_class;
338484595802SAdheer Chandravanshi 	else
338584595802SAdheer Chandravanshi 		fw_ddb_entry->ipv4_tos = conn->ipv4_tos;
338684595802SAdheer Chandravanshi 
33871e9e2be3SAdheer Chandravanshi 	if (conn->ipaddress)
33881e9e2be3SAdheer Chandravanshi 		memcpy(fw_ddb_entry->ip_addr, conn->ipaddress,
33891e9e2be3SAdheer Chandravanshi 		       sizeof(fw_ddb_entry->ip_addr));
33901e9e2be3SAdheer Chandravanshi 
33911e9e2be3SAdheer Chandravanshi 	if (conn->redirect_ipaddr)
33921e9e2be3SAdheer Chandravanshi 		memcpy(fw_ddb_entry->tgt_addr, conn->redirect_ipaddr,
33931e9e2be3SAdheer Chandravanshi 		       sizeof(fw_ddb_entry->tgt_addr));
33941e9e2be3SAdheer Chandravanshi 
33951e9e2be3SAdheer Chandravanshi 	if (conn->link_local_ipv6_addr)
33961e9e2be3SAdheer Chandravanshi 		memcpy(fw_ddb_entry->link_local_ipv6_addr,
33971e9e2be3SAdheer Chandravanshi 		       conn->link_local_ipv6_addr,
33981e9e2be3SAdheer Chandravanshi 		       sizeof(fw_ddb_entry->link_local_ipv6_addr));
33991e9e2be3SAdheer Chandravanshi 
34001e9e2be3SAdheer Chandravanshi 	if (sess->targetname)
34011e9e2be3SAdheer Chandravanshi 		memcpy(fw_ddb_entry->iscsi_name, sess->targetname,
34021e9e2be3SAdheer Chandravanshi 		       sizeof(fw_ddb_entry->iscsi_name));
34031e9e2be3SAdheer Chandravanshi 
34041e9e2be3SAdheer Chandravanshi 	if (sess->targetalias)
34051e9e2be3SAdheer Chandravanshi 		memcpy(fw_ddb_entry->iscsi_alias, sess->targetalias,
34061e9e2be3SAdheer Chandravanshi 		       sizeof(fw_ddb_entry->iscsi_alias));
34071e9e2be3SAdheer Chandravanshi 
34081e9e2be3SAdheer Chandravanshi 	COPY_ISID(fw_ddb_entry->isid, sess->isid);
34091e9e2be3SAdheer Chandravanshi 
34101e9e2be3SAdheer Chandravanshi 	return rc;
34111e9e2be3SAdheer Chandravanshi }
34121e9e2be3SAdheer Chandravanshi 
34138cc91d42SAdheer Chandravanshi static void qla4xxx_copy_to_sess_conn_params(struct iscsi_conn *conn,
34148cc91d42SAdheer Chandravanshi 					     struct iscsi_session *sess,
34158cc91d42SAdheer Chandravanshi 					     struct dev_db_entry *fw_ddb_entry)
34168cc91d42SAdheer Chandravanshi {
34178cc91d42SAdheer Chandravanshi 	unsigned long options = 0;
34188cc91d42SAdheer Chandravanshi 	uint16_t ddb_link;
34198cc91d42SAdheer Chandravanshi 	uint16_t disc_parent;
34208cc91d42SAdheer Chandravanshi 
34218cc91d42SAdheer Chandravanshi 	options = le16_to_cpu(fw_ddb_entry->options);
34228cc91d42SAdheer Chandravanshi 	conn->is_fw_assigned_ipv6 = test_bit(OPT_IS_FW_ASSIGNED_IPV6, &options);
34238cc91d42SAdheer Chandravanshi 	sess->auto_snd_tgt_disable = test_bit(OPT_AUTO_SENDTGTS_DISABLE,
34248cc91d42SAdheer Chandravanshi 					      &options);
34258cc91d42SAdheer Chandravanshi 	sess->discovery_sess = test_bit(OPT_DISC_SESSION, &options);
34268cc91d42SAdheer Chandravanshi 
34278cc91d42SAdheer Chandravanshi 	options = le16_to_cpu(fw_ddb_entry->iscsi_options);
34288cc91d42SAdheer Chandravanshi 	conn->hdrdgst_en = test_bit(ISCSIOPT_HEADER_DIGEST_EN, &options);
34298cc91d42SAdheer Chandravanshi 	conn->datadgst_en = test_bit(ISCSIOPT_DATA_DIGEST_EN, &options);
34308cc91d42SAdheer Chandravanshi 	sess->imm_data_en = test_bit(ISCSIOPT_IMMEDIATE_DATA_EN, &options);
34318cc91d42SAdheer Chandravanshi 	sess->initial_r2t_en = test_bit(ISCSIOPT_INITIAL_R2T_EN, &options);
34328cc91d42SAdheer Chandravanshi 	sess->dataseq_inorder_en = test_bit(ISCSIOPT_DATA_SEQ_IN_ORDER,
34338cc91d42SAdheer Chandravanshi 					    &options);
34348cc91d42SAdheer Chandravanshi 	sess->pdu_inorder_en = test_bit(ISCSIOPT_DATA_PDU_IN_ORDER, &options);
34358cc91d42SAdheer Chandravanshi 	sess->chap_auth_en = test_bit(ISCSIOPT_CHAP_AUTH_EN, &options);
34368cc91d42SAdheer Chandravanshi 	sess->discovery_logout_en = test_bit(ISCSIOPT_DISCOVERY_LOGOUT_EN,
34378cc91d42SAdheer Chandravanshi 					     &options);
34388cc91d42SAdheer Chandravanshi 	sess->bidi_chap_en = test_bit(ISCSIOPT_BIDI_CHAP_EN, &options);
34398cc91d42SAdheer Chandravanshi 	sess->discovery_auth_optional =
34408cc91d42SAdheer Chandravanshi 			test_bit(ISCSIOPT_DISCOVERY_AUTH_OPTIONAL, &options);
34418cc91d42SAdheer Chandravanshi 	if (test_bit(ISCSIOPT_ERL1, &options))
34428cc91d42SAdheer Chandravanshi 		sess->erl |= BIT_1;
34438cc91d42SAdheer Chandravanshi 	if (test_bit(ISCSIOPT_ERL0, &options))
34448cc91d42SAdheer Chandravanshi 		sess->erl |= BIT_0;
34458cc91d42SAdheer Chandravanshi 
34468cc91d42SAdheer Chandravanshi 	options = le16_to_cpu(fw_ddb_entry->tcp_options);
34478cc91d42SAdheer Chandravanshi 	conn->tcp_timestamp_stat = test_bit(TCPOPT_TIMESTAMP_STAT, &options);
34488cc91d42SAdheer Chandravanshi 	conn->tcp_nagle_disable = test_bit(TCPOPT_NAGLE_DISABLE, &options);
34498cc91d42SAdheer Chandravanshi 	conn->tcp_wsf_disable = test_bit(TCPOPT_WSF_DISABLE, &options);
34508cc91d42SAdheer Chandravanshi 	if (test_bit(TCPOPT_TIMER_SCALE3, &options))
34518cc91d42SAdheer Chandravanshi 		conn->tcp_timer_scale |= BIT_3;
34528cc91d42SAdheer Chandravanshi 	if (test_bit(TCPOPT_TIMER_SCALE2, &options))
34538cc91d42SAdheer Chandravanshi 		conn->tcp_timer_scale |= BIT_2;
34548cc91d42SAdheer Chandravanshi 	if (test_bit(TCPOPT_TIMER_SCALE1, &options))
34558cc91d42SAdheer Chandravanshi 		conn->tcp_timer_scale |= BIT_1;
34568cc91d42SAdheer Chandravanshi 
34578cc91d42SAdheer Chandravanshi 	conn->tcp_timer_scale >>= 1;
34588cc91d42SAdheer Chandravanshi 	conn->tcp_timestamp_en = test_bit(TCPOPT_TIMESTAMP_EN, &options);
34598cc91d42SAdheer Chandravanshi 
34608cc91d42SAdheer Chandravanshi 	options = le16_to_cpu(fw_ddb_entry->ip_options);
34618cc91d42SAdheer Chandravanshi 	conn->fragment_disable = test_bit(IPOPT_FRAGMENT_DISABLE, &options);
34628cc91d42SAdheer Chandravanshi 
34638cc91d42SAdheer Chandravanshi 	conn->max_recv_dlength = BYTE_UNITS *
34648cc91d42SAdheer Chandravanshi 			  le16_to_cpu(fw_ddb_entry->iscsi_max_rcv_data_seg_len);
34658cc91d42SAdheer Chandravanshi 	conn->max_xmit_dlength = BYTE_UNITS *
34668cc91d42SAdheer Chandravanshi 			  le16_to_cpu(fw_ddb_entry->iscsi_max_snd_data_seg_len);
34678cc91d42SAdheer Chandravanshi 	sess->max_r2t = le16_to_cpu(fw_ddb_entry->iscsi_max_outsnd_r2t);
34688cc91d42SAdheer Chandravanshi 	sess->first_burst = BYTE_UNITS *
34698cc91d42SAdheer Chandravanshi 			       le16_to_cpu(fw_ddb_entry->iscsi_first_burst_len);
34708cc91d42SAdheer Chandravanshi 	sess->max_burst = BYTE_UNITS *
34718cc91d42SAdheer Chandravanshi 				 le16_to_cpu(fw_ddb_entry->iscsi_max_burst_len);
34728cc91d42SAdheer Chandravanshi 	sess->time2wait = le16_to_cpu(fw_ddb_entry->iscsi_def_time2wait);
34738cc91d42SAdheer Chandravanshi 	sess->time2retain = le16_to_cpu(fw_ddb_entry->iscsi_def_time2retain);
34748cc91d42SAdheer Chandravanshi 	sess->tpgt = le32_to_cpu(fw_ddb_entry->tgt_portal_grp);
34758cc91d42SAdheer Chandravanshi 	conn->max_segment_size = le16_to_cpu(fw_ddb_entry->mss);
34768cc91d42SAdheer Chandravanshi 	conn->tcp_xmit_wsf = fw_ddb_entry->tcp_xmt_wsf;
34778cc91d42SAdheer Chandravanshi 	conn->tcp_recv_wsf = fw_ddb_entry->tcp_rcv_wsf;
34788cc91d42SAdheer Chandravanshi 	conn->ipv4_tos = fw_ddb_entry->ipv4_tos;
34798cc91d42SAdheer Chandravanshi 	conn->keepalive_tmo = le16_to_cpu(fw_ddb_entry->ka_timeout);
34808cc91d42SAdheer Chandravanshi 	conn->local_port = le16_to_cpu(fw_ddb_entry->lcl_port);
34818cc91d42SAdheer Chandravanshi 	conn->statsn = le32_to_cpu(fw_ddb_entry->stat_sn);
34828cc91d42SAdheer Chandravanshi 	conn->exp_statsn = le32_to_cpu(fw_ddb_entry->exp_stat_sn);
34838cc91d42SAdheer Chandravanshi 	sess->tsid = le16_to_cpu(fw_ddb_entry->tsid);
34848cc91d42SAdheer Chandravanshi 	COPY_ISID(sess->isid, fw_ddb_entry->isid);
34858cc91d42SAdheer Chandravanshi 
34868cc91d42SAdheer Chandravanshi 	ddb_link = le16_to_cpu(fw_ddb_entry->ddb_link);
34878cc91d42SAdheer Chandravanshi 	if (ddb_link == DDB_ISNS)
34888cc91d42SAdheer Chandravanshi 		disc_parent = ISCSI_DISC_PARENT_ISNS;
34898cc91d42SAdheer Chandravanshi 	else if (ddb_link == DDB_NO_LINK)
34908cc91d42SAdheer Chandravanshi 		disc_parent = ISCSI_DISC_PARENT_UNKNOWN;
34918cc91d42SAdheer Chandravanshi 	else if (ddb_link < MAX_DDB_ENTRIES)
34928cc91d42SAdheer Chandravanshi 		disc_parent = ISCSI_DISC_PARENT_SENDTGT;
34938cc91d42SAdheer Chandravanshi 	else
34948cc91d42SAdheer Chandravanshi 		disc_parent = ISCSI_DISC_PARENT_UNKNOWN;
34958cc91d42SAdheer Chandravanshi 
34968cc91d42SAdheer Chandravanshi 	iscsi_set_param(conn->cls_conn, ISCSI_PARAM_DISCOVERY_PARENT_TYPE,
34978cc91d42SAdheer Chandravanshi 			iscsi_get_discovery_parent_name(disc_parent), 0);
34988cc91d42SAdheer Chandravanshi 
34998cc91d42SAdheer Chandravanshi 	iscsi_set_param(conn->cls_conn, ISCSI_PARAM_TARGET_ALIAS,
35008cc91d42SAdheer Chandravanshi 			(char *)fw_ddb_entry->iscsi_alias, 0);
35018cc91d42SAdheer Chandravanshi }
35028cc91d42SAdheer Chandravanshi 
350313483730SMike Christie static void qla4xxx_copy_fwddb_param(struct scsi_qla_host *ha,
350413483730SMike Christie 				     struct dev_db_entry *fw_ddb_entry,
350513483730SMike Christie 				     struct iscsi_cls_session *cls_sess,
350613483730SMike Christie 				     struct iscsi_cls_conn *cls_conn)
350713483730SMike Christie {
350813483730SMike Christie 	int buflen = 0;
350913483730SMike Christie 	struct iscsi_session *sess;
3510376738afSNilesh Javali 	struct ddb_entry *ddb_entry;
3511946ac571SAdheer Chandravanshi 	struct ql4_chap_table chap_tbl;
351213483730SMike Christie 	struct iscsi_conn *conn;
351313483730SMike Christie 	char ip_addr[DDB_IPADDR_LEN];
351413483730SMike Christie 	uint16_t options = 0;
351513483730SMike Christie 
351613483730SMike Christie 	sess = cls_sess->dd_data;
3517376738afSNilesh Javali 	ddb_entry = sess->dd_data;
351813483730SMike Christie 	conn = cls_conn->dd_data;
3519946ac571SAdheer Chandravanshi 	memset(&chap_tbl, 0, sizeof(chap_tbl));
352013483730SMike Christie 
3521376738afSNilesh Javali 	ddb_entry->chap_tbl_idx = le16_to_cpu(fw_ddb_entry->chap_tbl_idx);
3522376738afSNilesh Javali 
35238cc91d42SAdheer Chandravanshi 	qla4xxx_copy_to_sess_conn_params(conn, sess, fw_ddb_entry);
352413483730SMike Christie 
35258cc91d42SAdheer Chandravanshi 	sess->def_taskmgmt_tmo = le16_to_cpu(fw_ddb_entry->def_timeout);
352613483730SMike Christie 	conn->persistent_port = le16_to_cpu(fw_ddb_entry->port);
352713483730SMike Christie 
35288cc91d42SAdheer Chandravanshi 	memset(ip_addr, 0, sizeof(ip_addr));
352913483730SMike Christie 	options = le16_to_cpu(fw_ddb_entry->options);
35308cc91d42SAdheer Chandravanshi 	if (options & DDB_OPT_IPV6_DEVICE) {
35318cc91d42SAdheer Chandravanshi 		iscsi_set_param(cls_conn, ISCSI_PARAM_PORTAL_TYPE, "ipv6", 4);
353213483730SMike Christie 
35338cc91d42SAdheer Chandravanshi 		memset(ip_addr, 0, sizeof(ip_addr));
35348cc91d42SAdheer Chandravanshi 		sprintf(ip_addr, "%pI6", fw_ddb_entry->ip_addr);
35358cc91d42SAdheer Chandravanshi 	} else {
35368cc91d42SAdheer Chandravanshi 		iscsi_set_param(cls_conn, ISCSI_PARAM_PORTAL_TYPE, "ipv4", 4);
35378cc91d42SAdheer Chandravanshi 		sprintf(ip_addr, "%pI4", fw_ddb_entry->ip_addr);
35388cc91d42SAdheer Chandravanshi 	}
35398cc91d42SAdheer Chandravanshi 
35408cc91d42SAdheer Chandravanshi 	iscsi_set_param(cls_conn, ISCSI_PARAM_PERSISTENT_ADDRESS,
35418cc91d42SAdheer Chandravanshi 			(char *)ip_addr, buflen);
354213483730SMike Christie 	iscsi_set_param(cls_conn, ISCSI_PARAM_TARGET_NAME,
354313483730SMike Christie 			(char *)fw_ddb_entry->iscsi_name, buflen);
354413483730SMike Christie 	iscsi_set_param(cls_conn, ISCSI_PARAM_INITIATOR_NAME,
354513483730SMike Christie 			(char *)ha->name_string, buflen);
3546946ac571SAdheer Chandravanshi 
3547946ac571SAdheer Chandravanshi 	if (ddb_entry->chap_tbl_idx != INVALID_ENTRY) {
3548946ac571SAdheer Chandravanshi 		if (!qla4xxx_get_uni_chap_at_index(ha, chap_tbl.name,
3549946ac571SAdheer Chandravanshi 						   chap_tbl.secret,
3550946ac571SAdheer Chandravanshi 						   ddb_entry->chap_tbl_idx)) {
3551946ac571SAdheer Chandravanshi 			iscsi_set_param(cls_conn, ISCSI_PARAM_USERNAME,
3552946ac571SAdheer Chandravanshi 					(char *)chap_tbl.name,
3553946ac571SAdheer Chandravanshi 					strlen((char *)chap_tbl.name));
3554946ac571SAdheer Chandravanshi 			iscsi_set_param(cls_conn, ISCSI_PARAM_PASSWORD,
3555946ac571SAdheer Chandravanshi 					(char *)chap_tbl.secret,
3556946ac571SAdheer Chandravanshi 					chap_tbl.secret_len);
3557946ac571SAdheer Chandravanshi 		}
3558946ac571SAdheer Chandravanshi 	}
355913483730SMike Christie }
356013483730SMike Christie 
356113483730SMike Christie void qla4xxx_update_session_conn_fwddb_param(struct scsi_qla_host *ha,
356213483730SMike Christie 					     struct ddb_entry *ddb_entry)
356313483730SMike Christie {
356413483730SMike Christie 	struct iscsi_cls_session *cls_sess;
356513483730SMike Christie 	struct iscsi_cls_conn *cls_conn;
356613483730SMike Christie 	uint32_t ddb_state;
356713483730SMike Christie 	dma_addr_t fw_ddb_entry_dma;
356813483730SMike Christie 	struct dev_db_entry *fw_ddb_entry;
356913483730SMike Christie 
357013483730SMike Christie 	fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
357113483730SMike Christie 					  &fw_ddb_entry_dma, GFP_KERNEL);
357213483730SMike Christie 	if (!fw_ddb_entry) {
357313483730SMike Christie 		ql4_printk(KERN_ERR, ha,
357413483730SMike Christie 			   "%s: Unable to allocate dma buffer\n", __func__);
357513483730SMike Christie 		goto exit_session_conn_fwddb_param;
357613483730SMike Christie 	}
357713483730SMike Christie 
357813483730SMike Christie 	if (qla4xxx_get_fwddb_entry(ha, ddb_entry->fw_ddb_index, fw_ddb_entry,
357913483730SMike Christie 				    fw_ddb_entry_dma, NULL, NULL, &ddb_state,
358013483730SMike Christie 				    NULL, NULL, NULL) == QLA_ERROR) {
358113483730SMike Christie 		DEBUG2(ql4_printk(KERN_ERR, ha, "scsi%ld: %s: failed "
358213483730SMike Christie 				  "get_ddb_entry for fw_ddb_index %d\n",
358313483730SMike Christie 				  ha->host_no, __func__,
358413483730SMike Christie 				  ddb_entry->fw_ddb_index));
358513483730SMike Christie 		goto exit_session_conn_fwddb_param;
358613483730SMike Christie 	}
358713483730SMike Christie 
358813483730SMike Christie 	cls_sess = ddb_entry->sess;
358913483730SMike Christie 
359013483730SMike Christie 	cls_conn = ddb_entry->conn;
359113483730SMike Christie 
359213483730SMike Christie 	/* Update params */
359313483730SMike Christie 	qla4xxx_copy_fwddb_param(ha, fw_ddb_entry, cls_sess, cls_conn);
359413483730SMike Christie 
359513483730SMike Christie exit_session_conn_fwddb_param:
359613483730SMike Christie 	if (fw_ddb_entry)
359713483730SMike Christie 		dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
359813483730SMike Christie 				  fw_ddb_entry, fw_ddb_entry_dma);
359913483730SMike Christie }
360013483730SMike Christie 
3601b3a271a9SManish Rangankar void qla4xxx_update_session_conn_param(struct scsi_qla_host *ha,
3602b3a271a9SManish Rangankar 				       struct ddb_entry *ddb_entry)
3603b3a271a9SManish Rangankar {
3604b3a271a9SManish Rangankar 	struct iscsi_cls_session *cls_sess;
3605b3a271a9SManish Rangankar 	struct iscsi_cls_conn *cls_conn;
3606b3a271a9SManish Rangankar 	struct iscsi_session *sess;
3607b3a271a9SManish Rangankar 	struct iscsi_conn *conn;
3608b3a271a9SManish Rangankar 	uint32_t ddb_state;
3609b3a271a9SManish Rangankar 	dma_addr_t fw_ddb_entry_dma;
3610b3a271a9SManish Rangankar 	struct dev_db_entry *fw_ddb_entry;
3611b3a271a9SManish Rangankar 
3612b3a271a9SManish Rangankar 	fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
3613b3a271a9SManish Rangankar 					  &fw_ddb_entry_dma, GFP_KERNEL);
3614b3a271a9SManish Rangankar 	if (!fw_ddb_entry) {
3615b3a271a9SManish Rangankar 		ql4_printk(KERN_ERR, ha,
3616b3a271a9SManish Rangankar 			   "%s: Unable to allocate dma buffer\n", __func__);
361713483730SMike Christie 		goto exit_session_conn_param;
3618b3a271a9SManish Rangankar 	}
3619b3a271a9SManish Rangankar 
3620b3a271a9SManish Rangankar 	if (qla4xxx_get_fwddb_entry(ha, ddb_entry->fw_ddb_index, fw_ddb_entry,
3621b3a271a9SManish Rangankar 				    fw_ddb_entry_dma, NULL, NULL, &ddb_state,
3622b3a271a9SManish Rangankar 				    NULL, NULL, NULL) == QLA_ERROR) {
3623b3a271a9SManish Rangankar 		DEBUG2(ql4_printk(KERN_ERR, ha, "scsi%ld: %s: failed "
3624b3a271a9SManish Rangankar 				  "get_ddb_entry for fw_ddb_index %d\n",
3625b3a271a9SManish Rangankar 				  ha->host_no, __func__,
3626b3a271a9SManish Rangankar 				  ddb_entry->fw_ddb_index));
362713483730SMike Christie 		goto exit_session_conn_param;
3628b3a271a9SManish Rangankar 	}
3629b3a271a9SManish Rangankar 
3630b3a271a9SManish Rangankar 	cls_sess = ddb_entry->sess;
3631b3a271a9SManish Rangankar 	sess = cls_sess->dd_data;
3632b3a271a9SManish Rangankar 
3633b3a271a9SManish Rangankar 	cls_conn = ddb_entry->conn;
3634b3a271a9SManish Rangankar 	conn = cls_conn->dd_data;
3635b3a271a9SManish Rangankar 
363613483730SMike Christie 	/* Update timers after login */
363713483730SMike Christie 	ddb_entry->default_relogin_timeout =
3638c28eaacaSNilesh Javali 		(le16_to_cpu(fw_ddb_entry->def_timeout) > LOGIN_TOV) &&
3639c28eaacaSNilesh Javali 		 (le16_to_cpu(fw_ddb_entry->def_timeout) < LOGIN_TOV * 10) ?
3640c28eaacaSNilesh Javali 		 le16_to_cpu(fw_ddb_entry->def_timeout) : LOGIN_TOV;
364113483730SMike Christie 	ddb_entry->default_time2wait =
364213483730SMike Christie 				le16_to_cpu(fw_ddb_entry->iscsi_def_time2wait);
364313483730SMike Christie 
3644b3a271a9SManish Rangankar 	/* Update params */
3645376738afSNilesh Javali 	ddb_entry->chap_tbl_idx = le16_to_cpu(fw_ddb_entry->chap_tbl_idx);
36468cc91d42SAdheer Chandravanshi 	qla4xxx_copy_to_sess_conn_params(conn, sess, fw_ddb_entry);
3647b3a271a9SManish Rangankar 
3648b3a271a9SManish Rangankar 	memcpy(sess->initiatorname, ha->name_string,
3649b3a271a9SManish Rangankar 	       min(sizeof(ha->name_string), sizeof(sess->initiatorname)));
365013483730SMike Christie 
365113483730SMike Christie exit_session_conn_param:
365213483730SMike Christie 	if (fw_ddb_entry)
365313483730SMike Christie 		dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
365413483730SMike Christie 				  fw_ddb_entry, fw_ddb_entry_dma);
3655b3a271a9SManish Rangankar }
3656b3a271a9SManish Rangankar 
3657afaf5a2dSDavid Somayajulu /*
3658afaf5a2dSDavid Somayajulu  * Timer routines
3659afaf5a2dSDavid Somayajulu  */
3660afaf5a2dSDavid Somayajulu 
3661afaf5a2dSDavid Somayajulu static void qla4xxx_start_timer(struct scsi_qla_host *ha, void *func,
3662afaf5a2dSDavid Somayajulu 				unsigned long interval)
3663afaf5a2dSDavid Somayajulu {
3664afaf5a2dSDavid Somayajulu 	DEBUG(printk("scsi: %s: Starting timer thread for adapter %d\n",
3665afaf5a2dSDavid Somayajulu 		     __func__, ha->host->host_no));
3666afaf5a2dSDavid Somayajulu 	init_timer(&ha->timer);
3667afaf5a2dSDavid Somayajulu 	ha->timer.expires = jiffies + interval * HZ;
3668afaf5a2dSDavid Somayajulu 	ha->timer.data = (unsigned long)ha;
3669afaf5a2dSDavid Somayajulu 	ha->timer.function = (void (*)(unsigned long))func;
3670afaf5a2dSDavid Somayajulu 	add_timer(&ha->timer);
3671afaf5a2dSDavid Somayajulu 	ha->timer_active = 1;
3672afaf5a2dSDavid Somayajulu }
3673afaf5a2dSDavid Somayajulu 
3674afaf5a2dSDavid Somayajulu static void qla4xxx_stop_timer(struct scsi_qla_host *ha)
3675afaf5a2dSDavid Somayajulu {
3676afaf5a2dSDavid Somayajulu 	del_timer_sync(&ha->timer);
3677afaf5a2dSDavid Somayajulu 	ha->timer_active = 0;
3678afaf5a2dSDavid Somayajulu }
3679afaf5a2dSDavid Somayajulu 
3680afaf5a2dSDavid Somayajulu /***
3681b3a271a9SManish Rangankar  * qla4xxx_mark_device_missing - blocks the session
3682b3a271a9SManish Rangankar  * @cls_session: Pointer to the session to be blocked
3683afaf5a2dSDavid Somayajulu  * @ddb_entry: Pointer to device database entry
3684afaf5a2dSDavid Somayajulu  *
3685f4f5df23SVikas Chaudhary  * This routine marks a device missing and close connection.
3686afaf5a2dSDavid Somayajulu  **/
3687b3a271a9SManish Rangankar void qla4xxx_mark_device_missing(struct iscsi_cls_session *cls_session)
3688afaf5a2dSDavid Somayajulu {
3689b3a271a9SManish Rangankar 	iscsi_block_session(cls_session);
3690afaf5a2dSDavid Somayajulu }
3691afaf5a2dSDavid Somayajulu 
3692f4f5df23SVikas Chaudhary /**
3693f4f5df23SVikas Chaudhary  * qla4xxx_mark_all_devices_missing - mark all devices as missing.
3694f4f5df23SVikas Chaudhary  * @ha: Pointer to host adapter structure.
3695f4f5df23SVikas Chaudhary  *
3696f4f5df23SVikas Chaudhary  * This routine marks a device missing and resets the relogin retry count.
3697f4f5df23SVikas Chaudhary  **/
3698f4f5df23SVikas Chaudhary void qla4xxx_mark_all_devices_missing(struct scsi_qla_host *ha)
3699f4f5df23SVikas Chaudhary {
3700b3a271a9SManish Rangankar 	iscsi_host_for_each_session(ha->host, qla4xxx_mark_device_missing);
3701f4f5df23SVikas Chaudhary }
3702f4f5df23SVikas Chaudhary 
3703afaf5a2dSDavid Somayajulu static struct srb* qla4xxx_get_new_srb(struct scsi_qla_host *ha,
3704afaf5a2dSDavid Somayajulu 				       struct ddb_entry *ddb_entry,
37058f0722caSVikas Chaudhary 				       struct scsi_cmnd *cmd)
3706afaf5a2dSDavid Somayajulu {
3707afaf5a2dSDavid Somayajulu 	struct srb *srb;
3708afaf5a2dSDavid Somayajulu 
3709afaf5a2dSDavid Somayajulu 	srb = mempool_alloc(ha->srb_mempool, GFP_ATOMIC);
3710afaf5a2dSDavid Somayajulu 	if (!srb)
3711afaf5a2dSDavid Somayajulu 		return srb;
3712afaf5a2dSDavid Somayajulu 
371309a0f719SVikas Chaudhary 	kref_init(&srb->srb_ref);
3714afaf5a2dSDavid Somayajulu 	srb->ha = ha;
3715afaf5a2dSDavid Somayajulu 	srb->ddb = ddb_entry;
3716afaf5a2dSDavid Somayajulu 	srb->cmd = cmd;
3717afaf5a2dSDavid Somayajulu 	srb->flags = 0;
37185369887aSVikas Chaudhary 	CMD_SP(cmd) = (void *)srb;
3719afaf5a2dSDavid Somayajulu 
3720afaf5a2dSDavid Somayajulu 	return srb;
3721afaf5a2dSDavid Somayajulu }
3722afaf5a2dSDavid Somayajulu 
3723afaf5a2dSDavid Somayajulu static void qla4xxx_srb_free_dma(struct scsi_qla_host *ha, struct srb *srb)
3724afaf5a2dSDavid Somayajulu {
3725afaf5a2dSDavid Somayajulu 	struct scsi_cmnd *cmd = srb->cmd;
3726afaf5a2dSDavid Somayajulu 
3727afaf5a2dSDavid Somayajulu 	if (srb->flags & SRB_DMA_VALID) {
37285f7186c8SFUJITA Tomonori 		scsi_dma_unmap(cmd);
3729afaf5a2dSDavid Somayajulu 		srb->flags &= ~SRB_DMA_VALID;
3730afaf5a2dSDavid Somayajulu 	}
37315369887aSVikas Chaudhary 	CMD_SP(cmd) = NULL;
3732afaf5a2dSDavid Somayajulu }
3733afaf5a2dSDavid Somayajulu 
373409a0f719SVikas Chaudhary void qla4xxx_srb_compl(struct kref *ref)
3735afaf5a2dSDavid Somayajulu {
373609a0f719SVikas Chaudhary 	struct srb *srb = container_of(ref, struct srb, srb_ref);
3737afaf5a2dSDavid Somayajulu 	struct scsi_cmnd *cmd = srb->cmd;
373809a0f719SVikas Chaudhary 	struct scsi_qla_host *ha = srb->ha;
3739afaf5a2dSDavid Somayajulu 
3740afaf5a2dSDavid Somayajulu 	qla4xxx_srb_free_dma(ha, srb);
3741afaf5a2dSDavid Somayajulu 
3742afaf5a2dSDavid Somayajulu 	mempool_free(srb, ha->srb_mempool);
3743afaf5a2dSDavid Somayajulu 
3744afaf5a2dSDavid Somayajulu 	cmd->scsi_done(cmd);
3745afaf5a2dSDavid Somayajulu }
3746afaf5a2dSDavid Somayajulu 
3747afaf5a2dSDavid Somayajulu /**
3748afaf5a2dSDavid Somayajulu  * qla4xxx_queuecommand - scsi layer issues scsi command to driver.
37498f0722caSVikas Chaudhary  * @host: scsi host
3750afaf5a2dSDavid Somayajulu  * @cmd: Pointer to Linux's SCSI command structure
3751afaf5a2dSDavid Somayajulu  *
3752afaf5a2dSDavid Somayajulu  * Remarks:
3753afaf5a2dSDavid Somayajulu  * This routine is invoked by Linux to send a SCSI command to the driver.
3754afaf5a2dSDavid Somayajulu  * The mid-level driver tries to ensure that queuecommand never gets
3755afaf5a2dSDavid Somayajulu  * invoked concurrently with itself or the interrupt handler (although
3756afaf5a2dSDavid Somayajulu  * the interrupt handler may call this routine as part of request-
3757afaf5a2dSDavid Somayajulu  * completion handling).   Unfortunely, it sometimes calls the scheduler
3758afaf5a2dSDavid Somayajulu  * in interrupt context which is a big NO! NO!.
3759afaf5a2dSDavid Somayajulu  **/
37608f0722caSVikas Chaudhary static int qla4xxx_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd)
3761afaf5a2dSDavid Somayajulu {
37628f0722caSVikas Chaudhary 	struct scsi_qla_host *ha = to_qla_host(host);
3763afaf5a2dSDavid Somayajulu 	struct ddb_entry *ddb_entry = cmd->device->hostdata;
37647fb1921bSMike Christie 	struct iscsi_cls_session *sess = ddb_entry->sess;
3765afaf5a2dSDavid Somayajulu 	struct srb *srb;
3766afaf5a2dSDavid Somayajulu 	int rval;
3767afaf5a2dSDavid Somayajulu 
37682232be0dSLalit Chandivade 	if (test_bit(AF_EEH_BUSY, &ha->flags)) {
37692232be0dSLalit Chandivade 		if (test_bit(AF_PCI_CHANNEL_IO_PERM_FAILURE, &ha->flags))
37702232be0dSLalit Chandivade 			cmd->result = DID_NO_CONNECT << 16;
37712232be0dSLalit Chandivade 		else
37722232be0dSLalit Chandivade 			cmd->result = DID_REQUEUE << 16;
37732232be0dSLalit Chandivade 		goto qc_fail_command;
37742232be0dSLalit Chandivade 	}
37752232be0dSLalit Chandivade 
37767fb1921bSMike Christie 	if (!sess) {
37777fb1921bSMike Christie 		cmd->result = DID_IMM_RETRY << 16;
37787fb1921bSMike Christie 		goto qc_fail_command;
37797fb1921bSMike Christie 	}
37807fb1921bSMike Christie 
37817fb1921bSMike Christie 	rval = iscsi_session_chkready(sess);
37827fb1921bSMike Christie 	if (rval) {
37837fb1921bSMike Christie 		cmd->result = rval;
37847fb1921bSMike Christie 		goto qc_fail_command;
37857fb1921bSMike Christie 	}
37867fb1921bSMike Christie 
3787f4f5df23SVikas Chaudhary 	if (test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags) ||
3788f4f5df23SVikas Chaudhary 	    test_bit(DPC_RESET_ACTIVE, &ha->dpc_flags) ||
3789f4f5df23SVikas Chaudhary 	    test_bit(DPC_RESET_HA, &ha->dpc_flags) ||
3790f4f5df23SVikas Chaudhary 	    test_bit(DPC_HA_UNRECOVERABLE, &ha->dpc_flags) ||
3791f4f5df23SVikas Chaudhary 	    test_bit(DPC_HA_NEED_QUIESCENT, &ha->dpc_flags) ||
3792f4f5df23SVikas Chaudhary 	    !test_bit(AF_ONLINE, &ha->flags) ||
3793b3a271a9SManish Rangankar 	    !test_bit(AF_LINK_UP, &ha->flags) ||
3794026fbd3aSNilesh Javali 	    test_bit(AF_LOOPBACK, &ha->flags) ||
37957ab284c9SNilesh Javali 	    test_bit(DPC_POST_IDC_ACK, &ha->dpc_flags) ||
37967ab284c9SNilesh Javali 	    test_bit(DPC_RESTORE_ACB, &ha->dpc_flags) ||
3797f4f5df23SVikas Chaudhary 	    test_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags))
3798477ffb9dSDavid C Somayajulu 		goto qc_host_busy;
3799477ffb9dSDavid C Somayajulu 
38008f0722caSVikas Chaudhary 	srb = qla4xxx_get_new_srb(ha, ddb_entry, cmd);
3801afaf5a2dSDavid Somayajulu 	if (!srb)
38028f0722caSVikas Chaudhary 		goto qc_host_busy;
3803afaf5a2dSDavid Somayajulu 
3804afaf5a2dSDavid Somayajulu 	rval = qla4xxx_send_command_to_isp(ha, srb);
3805afaf5a2dSDavid Somayajulu 	if (rval != QLA_SUCCESS)
3806afaf5a2dSDavid Somayajulu 		goto qc_host_busy_free_sp;
3807afaf5a2dSDavid Somayajulu 
3808afaf5a2dSDavid Somayajulu 	return 0;
3809afaf5a2dSDavid Somayajulu 
3810afaf5a2dSDavid Somayajulu qc_host_busy_free_sp:
3811afaf5a2dSDavid Somayajulu 	qla4xxx_srb_free_dma(ha, srb);
3812afaf5a2dSDavid Somayajulu 	mempool_free(srb, ha->srb_mempool);
3813afaf5a2dSDavid Somayajulu 
3814afaf5a2dSDavid Somayajulu qc_host_busy:
3815afaf5a2dSDavid Somayajulu 	return SCSI_MLQUEUE_HOST_BUSY;
3816afaf5a2dSDavid Somayajulu 
3817afaf5a2dSDavid Somayajulu qc_fail_command:
38188f0722caSVikas Chaudhary 	cmd->scsi_done(cmd);
3819afaf5a2dSDavid Somayajulu 
3820afaf5a2dSDavid Somayajulu 	return 0;
3821afaf5a2dSDavid Somayajulu }
3822afaf5a2dSDavid Somayajulu 
3823afaf5a2dSDavid Somayajulu /**
3824afaf5a2dSDavid Somayajulu  * qla4xxx_mem_free - frees memory allocated to adapter
3825afaf5a2dSDavid Somayajulu  * @ha: Pointer to host adapter structure.
3826afaf5a2dSDavid Somayajulu  *
3827afaf5a2dSDavid Somayajulu  * Frees memory previously allocated by qla4xxx_mem_alloc
3828afaf5a2dSDavid Somayajulu  **/
3829afaf5a2dSDavid Somayajulu static void qla4xxx_mem_free(struct scsi_qla_host *ha)
3830afaf5a2dSDavid Somayajulu {
3831afaf5a2dSDavid Somayajulu 	if (ha->queues)
3832afaf5a2dSDavid Somayajulu 		dma_free_coherent(&ha->pdev->dev, ha->queues_len, ha->queues,
3833afaf5a2dSDavid Somayajulu 				  ha->queues_dma);
3834afaf5a2dSDavid Somayajulu 
3835068237c8STej Parkash 	 if (ha->fw_dump)
3836068237c8STej Parkash 		vfree(ha->fw_dump);
3837068237c8STej Parkash 
3838afaf5a2dSDavid Somayajulu 	ha->queues_len = 0;
3839afaf5a2dSDavid Somayajulu 	ha->queues = NULL;
3840afaf5a2dSDavid Somayajulu 	ha->queues_dma = 0;
3841afaf5a2dSDavid Somayajulu 	ha->request_ring = NULL;
3842afaf5a2dSDavid Somayajulu 	ha->request_dma = 0;
3843afaf5a2dSDavid Somayajulu 	ha->response_ring = NULL;
3844afaf5a2dSDavid Somayajulu 	ha->response_dma = 0;
3845afaf5a2dSDavid Somayajulu 	ha->shadow_regs = NULL;
3846afaf5a2dSDavid Somayajulu 	ha->shadow_regs_dma = 0;
3847068237c8STej Parkash 	ha->fw_dump = NULL;
3848068237c8STej Parkash 	ha->fw_dump_size = 0;
3849afaf5a2dSDavid Somayajulu 
3850afaf5a2dSDavid Somayajulu 	/* Free srb pool. */
3851afaf5a2dSDavid Somayajulu 	if (ha->srb_mempool)
3852afaf5a2dSDavid Somayajulu 		mempool_destroy(ha->srb_mempool);
3853afaf5a2dSDavid Somayajulu 
3854afaf5a2dSDavid Somayajulu 	ha->srb_mempool = NULL;
3855afaf5a2dSDavid Somayajulu 
3856b3a271a9SManish Rangankar 	if (ha->chap_dma_pool)
3857b3a271a9SManish Rangankar 		dma_pool_destroy(ha->chap_dma_pool);
3858b3a271a9SManish Rangankar 
38594549415aSLalit Chandivade 	if (ha->chap_list)
38604549415aSLalit Chandivade 		vfree(ha->chap_list);
38614549415aSLalit Chandivade 	ha->chap_list = NULL;
38624549415aSLalit Chandivade 
386313483730SMike Christie 	if (ha->fw_ddb_dma_pool)
386413483730SMike Christie 		dma_pool_destroy(ha->fw_ddb_dma_pool);
386513483730SMike Christie 
3866afaf5a2dSDavid Somayajulu 	/* release io space registers  */
3867f4f5df23SVikas Chaudhary 	if (is_qla8022(ha)) {
3868f4f5df23SVikas Chaudhary 		if (ha->nx_pcibase)
3869f4f5df23SVikas Chaudhary 			iounmap(
3870f4f5df23SVikas Chaudhary 			    (struct device_reg_82xx __iomem *)ha->nx_pcibase);
3871b37ca418SVikas Chaudhary 	} else if (is_qla8032(ha) || is_qla8042(ha)) {
38726e7b4292SVikas Chaudhary 		if (ha->nx_pcibase)
38736e7b4292SVikas Chaudhary 			iounmap(
38746e7b4292SVikas Chaudhary 			    (struct device_reg_83xx __iomem *)ha->nx_pcibase);
38756e7b4292SVikas Chaudhary 	} else if (ha->reg) {
3876afaf5a2dSDavid Somayajulu 		iounmap(ha->reg);
38776e7b4292SVikas Chaudhary 	}
38786e7b4292SVikas Chaudhary 
38796e7b4292SVikas Chaudhary 	if (ha->reset_tmplt.buff)
38806e7b4292SVikas Chaudhary 		vfree(ha->reset_tmplt.buff);
38816e7b4292SVikas Chaudhary 
3882afaf5a2dSDavid Somayajulu 	pci_release_regions(ha->pdev);
3883afaf5a2dSDavid Somayajulu }
3884afaf5a2dSDavid Somayajulu 
3885afaf5a2dSDavid Somayajulu /**
3886afaf5a2dSDavid Somayajulu  * qla4xxx_mem_alloc - allocates memory for use by adapter.
3887afaf5a2dSDavid Somayajulu  * @ha: Pointer to host adapter structure
3888afaf5a2dSDavid Somayajulu  *
3889afaf5a2dSDavid Somayajulu  * Allocates DMA memory for request and response queues. Also allocates memory
3890afaf5a2dSDavid Somayajulu  * for srbs.
3891afaf5a2dSDavid Somayajulu  **/
3892afaf5a2dSDavid Somayajulu static int qla4xxx_mem_alloc(struct scsi_qla_host *ha)
3893afaf5a2dSDavid Somayajulu {
3894afaf5a2dSDavid Somayajulu 	unsigned long align;
3895afaf5a2dSDavid Somayajulu 
3896afaf5a2dSDavid Somayajulu 	/* Allocate contiguous block of DMA memory for queues. */
3897afaf5a2dSDavid Somayajulu 	ha->queues_len = ((REQUEST_QUEUE_DEPTH * QUEUE_SIZE) +
3898afaf5a2dSDavid Somayajulu 			  (RESPONSE_QUEUE_DEPTH * QUEUE_SIZE) +
3899afaf5a2dSDavid Somayajulu 			  sizeof(struct shadow_regs) +
3900afaf5a2dSDavid Somayajulu 			  MEM_ALIGN_VALUE +
3901afaf5a2dSDavid Somayajulu 			  (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1);
3902afaf5a2dSDavid Somayajulu 	ha->queues = dma_alloc_coherent(&ha->pdev->dev, ha->queues_len,
3903afaf5a2dSDavid Somayajulu 					&ha->queues_dma, GFP_KERNEL);
3904afaf5a2dSDavid Somayajulu 	if (ha->queues == NULL) {
3905c2660df3SVikas Chaudhary 		ql4_printk(KERN_WARNING, ha,
3906afaf5a2dSDavid Somayajulu 		    "Memory Allocation failed - queues.\n");
3907afaf5a2dSDavid Somayajulu 
3908afaf5a2dSDavid Somayajulu 		goto mem_alloc_error_exit;
3909afaf5a2dSDavid Somayajulu 	}
3910afaf5a2dSDavid Somayajulu 	memset(ha->queues, 0, ha->queues_len);
3911afaf5a2dSDavid Somayajulu 
3912afaf5a2dSDavid Somayajulu 	/*
3913afaf5a2dSDavid Somayajulu 	 * As per RISC alignment requirements -- the bus-address must be a
3914afaf5a2dSDavid Somayajulu 	 * multiple of the request-ring size (in bytes).
3915afaf5a2dSDavid Somayajulu 	 */
3916afaf5a2dSDavid Somayajulu 	align = 0;
3917afaf5a2dSDavid Somayajulu 	if ((unsigned long)ha->queues_dma & (MEM_ALIGN_VALUE - 1))
3918afaf5a2dSDavid Somayajulu 		align = MEM_ALIGN_VALUE - ((unsigned long)ha->queues_dma &
3919afaf5a2dSDavid Somayajulu 					   (MEM_ALIGN_VALUE - 1));
3920afaf5a2dSDavid Somayajulu 
3921afaf5a2dSDavid Somayajulu 	/* Update request and response queue pointers. */
3922afaf5a2dSDavid Somayajulu 	ha->request_dma = ha->queues_dma + align;
3923afaf5a2dSDavid Somayajulu 	ha->request_ring = (struct queue_entry *) (ha->queues + align);
3924afaf5a2dSDavid Somayajulu 	ha->response_dma = ha->queues_dma + align +
3925afaf5a2dSDavid Somayajulu 		(REQUEST_QUEUE_DEPTH * QUEUE_SIZE);
3926afaf5a2dSDavid Somayajulu 	ha->response_ring = (struct queue_entry *) (ha->queues + align +
3927afaf5a2dSDavid Somayajulu 						    (REQUEST_QUEUE_DEPTH *
3928afaf5a2dSDavid Somayajulu 						     QUEUE_SIZE));
3929afaf5a2dSDavid Somayajulu 	ha->shadow_regs_dma = ha->queues_dma + align +
3930afaf5a2dSDavid Somayajulu 		(REQUEST_QUEUE_DEPTH * QUEUE_SIZE) +
3931afaf5a2dSDavid Somayajulu 		(RESPONSE_QUEUE_DEPTH * QUEUE_SIZE);
3932afaf5a2dSDavid Somayajulu 	ha->shadow_regs = (struct shadow_regs *) (ha->queues + align +
3933afaf5a2dSDavid Somayajulu 						  (REQUEST_QUEUE_DEPTH *
3934afaf5a2dSDavid Somayajulu 						   QUEUE_SIZE) +
3935afaf5a2dSDavid Somayajulu 						  (RESPONSE_QUEUE_DEPTH *
3936afaf5a2dSDavid Somayajulu 						   QUEUE_SIZE));
3937afaf5a2dSDavid Somayajulu 
3938afaf5a2dSDavid Somayajulu 	/* Allocate memory for srb pool. */
3939afaf5a2dSDavid Somayajulu 	ha->srb_mempool = mempool_create(SRB_MIN_REQ, mempool_alloc_slab,
3940afaf5a2dSDavid Somayajulu 					 mempool_free_slab, srb_cachep);
3941afaf5a2dSDavid Somayajulu 	if (ha->srb_mempool == NULL) {
3942c2660df3SVikas Chaudhary 		ql4_printk(KERN_WARNING, ha,
3943afaf5a2dSDavid Somayajulu 		    "Memory Allocation failed - SRB Pool.\n");
3944afaf5a2dSDavid Somayajulu 
3945afaf5a2dSDavid Somayajulu 		goto mem_alloc_error_exit;
3946afaf5a2dSDavid Somayajulu 	}
3947afaf5a2dSDavid Somayajulu 
3948b3a271a9SManish Rangankar 	ha->chap_dma_pool = dma_pool_create("ql4_chap", &ha->pdev->dev,
3949b3a271a9SManish Rangankar 					    CHAP_DMA_BLOCK_SIZE, 8, 0);
3950b3a271a9SManish Rangankar 
3951b3a271a9SManish Rangankar 	if (ha->chap_dma_pool == NULL) {
3952b3a271a9SManish Rangankar 		ql4_printk(KERN_WARNING, ha,
3953b3a271a9SManish Rangankar 		    "%s: chap_dma_pool allocation failed..\n", __func__);
3954b3a271a9SManish Rangankar 		goto mem_alloc_error_exit;
3955b3a271a9SManish Rangankar 	}
3956b3a271a9SManish Rangankar 
395713483730SMike Christie 	ha->fw_ddb_dma_pool = dma_pool_create("ql4_fw_ddb", &ha->pdev->dev,
395813483730SMike Christie 					      DDB_DMA_BLOCK_SIZE, 8, 0);
395913483730SMike Christie 
396013483730SMike Christie 	if (ha->fw_ddb_dma_pool == NULL) {
396113483730SMike Christie 		ql4_printk(KERN_WARNING, ha,
396213483730SMike Christie 			   "%s: fw_ddb_dma_pool allocation failed..\n",
396313483730SMike Christie 			   __func__);
396413483730SMike Christie 		goto mem_alloc_error_exit;
396513483730SMike Christie 	}
396613483730SMike Christie 
3967afaf5a2dSDavid Somayajulu 	return QLA_SUCCESS;
3968afaf5a2dSDavid Somayajulu 
3969afaf5a2dSDavid Somayajulu mem_alloc_error_exit:
3970afaf5a2dSDavid Somayajulu 	qla4xxx_mem_free(ha);
3971afaf5a2dSDavid Somayajulu 	return QLA_ERROR;
3972afaf5a2dSDavid Somayajulu }
3973afaf5a2dSDavid Somayajulu 
3974afaf5a2dSDavid Somayajulu /**
39754f77083eSMike Hernandez  * qla4_8xxx_check_temp - Check the ISP82XX temperature.
39764f77083eSMike Hernandez  * @ha: adapter block pointer.
39774f77083eSMike Hernandez  *
39784f77083eSMike Hernandez  * Note: The caller should not hold the idc lock.
39794f77083eSMike Hernandez  **/
39804f77083eSMike Hernandez static int qla4_8xxx_check_temp(struct scsi_qla_host *ha)
39814f77083eSMike Hernandez {
39824f77083eSMike Hernandez 	uint32_t temp, temp_state, temp_val;
39834f77083eSMike Hernandez 	int status = QLA_SUCCESS;
39844f77083eSMike Hernandez 
398533693c7aSVikas Chaudhary 	temp = qla4_8xxx_rd_direct(ha, QLA8XXX_CRB_TEMP_STATE);
39864f77083eSMike Hernandez 
39874f77083eSMike Hernandez 	temp_state = qla82xx_get_temp_state(temp);
39884f77083eSMike Hernandez 	temp_val = qla82xx_get_temp_val(temp);
39894f77083eSMike Hernandez 
39904f77083eSMike Hernandez 	if (temp_state == QLA82XX_TEMP_PANIC) {
39914f77083eSMike Hernandez 		ql4_printk(KERN_WARNING, ha, "Device temperature %d degrees C"
39924f77083eSMike Hernandez 			   " exceeds maximum allowed. Hardware has been shut"
39934f77083eSMike Hernandez 			   " down.\n", temp_val);
39944f77083eSMike Hernandez 		status = QLA_ERROR;
39954f77083eSMike Hernandez 	} else if (temp_state == QLA82XX_TEMP_WARN) {
39964f77083eSMike Hernandez 		if (ha->temperature == QLA82XX_TEMP_NORMAL)
39974f77083eSMike Hernandez 			ql4_printk(KERN_WARNING, ha, "Device temperature %d"
39984f77083eSMike Hernandez 				   " degrees C exceeds operating range."
39994f77083eSMike Hernandez 				   " Immediate action needed.\n", temp_val);
40004f77083eSMike Hernandez 	} else {
40014f77083eSMike Hernandez 		if (ha->temperature == QLA82XX_TEMP_WARN)
40024f77083eSMike Hernandez 			ql4_printk(KERN_INFO, ha, "Device temperature is"
40034f77083eSMike Hernandez 				   " now %d degrees C in normal range.\n",
40044f77083eSMike Hernandez 				   temp_val);
40054f77083eSMike Hernandez 	}
40064f77083eSMike Hernandez 	ha->temperature = temp_state;
40074f77083eSMike Hernandez 	return status;
40084f77083eSMike Hernandez }
40094f77083eSMike Hernandez 
40104f77083eSMike Hernandez /**
4011f4f5df23SVikas Chaudhary  * qla4_8xxx_check_fw_alive  - Check firmware health
4012f4f5df23SVikas Chaudhary  * @ha: Pointer to host adapter structure.
4013f4f5df23SVikas Chaudhary  *
4014f4f5df23SVikas Chaudhary  * Context: Interrupt
4015f4f5df23SVikas Chaudhary  **/
40169ee91a38SShyam Sunder static int qla4_8xxx_check_fw_alive(struct scsi_qla_host *ha)
4017f4f5df23SVikas Chaudhary {
40189ee91a38SShyam Sunder 	uint32_t fw_heartbeat_counter;
40199ee91a38SShyam Sunder 	int status = QLA_SUCCESS;
4020f4f5df23SVikas Chaudhary 
402133693c7aSVikas Chaudhary 	fw_heartbeat_counter = qla4_8xxx_rd_direct(ha,
402233693c7aSVikas Chaudhary 						   QLA8XXX_PEG_ALIVE_COUNTER);
40232232be0dSLalit Chandivade 	/* If PEG_ALIVE_COUNTER is 0xffffffff, AER/EEH is in progress, ignore */
40242232be0dSLalit Chandivade 	if (fw_heartbeat_counter == 0xffffffff) {
40252232be0dSLalit Chandivade 		DEBUG2(printk(KERN_WARNING "scsi%ld: %s: Device in frozen "
40262232be0dSLalit Chandivade 		    "state, QLA82XX_PEG_ALIVE_COUNTER is 0xffffffff\n",
40272232be0dSLalit Chandivade 		    ha->host_no, __func__));
40289ee91a38SShyam Sunder 		return status;
40292232be0dSLalit Chandivade 	}
4030f4f5df23SVikas Chaudhary 
4031f4f5df23SVikas Chaudhary 	if (ha->fw_heartbeat_counter == fw_heartbeat_counter) {
4032f4f5df23SVikas Chaudhary 		ha->seconds_since_last_heartbeat++;
4033f4f5df23SVikas Chaudhary 		/* FW not alive after 2 seconds */
4034f4f5df23SVikas Chaudhary 		if (ha->seconds_since_last_heartbeat == 2) {
4035f4f5df23SVikas Chaudhary 			ha->seconds_since_last_heartbeat = 0;
40366e7b4292SVikas Chaudhary 			qla4_8xxx_dump_peg_reg(ha);
40379ee91a38SShyam Sunder 			status = QLA_ERROR;
4038f4f5df23SVikas Chaudhary 		}
403999457d75SLalit Chandivade 	} else
404099457d75SLalit Chandivade 		ha->seconds_since_last_heartbeat = 0;
404199457d75SLalit Chandivade 
4042f4f5df23SVikas Chaudhary 	ha->fw_heartbeat_counter = fw_heartbeat_counter;
40439ee91a38SShyam Sunder 	return status;
4044f4f5df23SVikas Chaudhary }
4045f4f5df23SVikas Chaudhary 
40466e7b4292SVikas Chaudhary static void qla4_8xxx_process_fw_error(struct scsi_qla_host *ha)
40476e7b4292SVikas Chaudhary {
40486e7b4292SVikas Chaudhary 	uint32_t halt_status;
40496e7b4292SVikas Chaudhary 	int halt_status_unrecoverable = 0;
40506e7b4292SVikas Chaudhary 
40516e7b4292SVikas Chaudhary 	halt_status = qla4_8xxx_rd_direct(ha, QLA8XXX_PEG_HALT_STATUS1);
40526e7b4292SVikas Chaudhary 
40536e7b4292SVikas Chaudhary 	if (is_qla8022(ha)) {
40546e7b4292SVikas Chaudhary 		ql4_printk(KERN_INFO, ha, "%s: disabling pause transmit on port 0 & 1.\n",
40556e7b4292SVikas Chaudhary 			   __func__);
40566e7b4292SVikas Chaudhary 		qla4_82xx_wr_32(ha, QLA82XX_CRB_NIU + 0x98,
40576e7b4292SVikas Chaudhary 				CRB_NIU_XG_PAUSE_CTL_P0 |
40586e7b4292SVikas Chaudhary 				CRB_NIU_XG_PAUSE_CTL_P1);
40596e7b4292SVikas Chaudhary 
40606e7b4292SVikas Chaudhary 		if (QLA82XX_FWERROR_CODE(halt_status) == 0x67)
40616e7b4292SVikas Chaudhary 			ql4_printk(KERN_ERR, ha, "%s: Firmware aborted with error code 0x00006700. Device is being reset\n",
40626e7b4292SVikas Chaudhary 				   __func__);
40636e7b4292SVikas Chaudhary 		if (halt_status & HALT_STATUS_UNRECOVERABLE)
40646e7b4292SVikas Chaudhary 			halt_status_unrecoverable = 1;
4065b37ca418SVikas Chaudhary 	} else if (is_qla8032(ha) || is_qla8042(ha)) {
40666e7b4292SVikas Chaudhary 		if (halt_status & QLA83XX_HALT_STATUS_FW_RESET)
40676e7b4292SVikas Chaudhary 			ql4_printk(KERN_ERR, ha, "%s: Firmware error detected device is being reset\n",
40686e7b4292SVikas Chaudhary 				   __func__);
40696e7b4292SVikas Chaudhary 		else if (halt_status & QLA83XX_HALT_STATUS_UNRECOVERABLE)
40706e7b4292SVikas Chaudhary 			halt_status_unrecoverable = 1;
40716e7b4292SVikas Chaudhary 	}
40726e7b4292SVikas Chaudhary 
40736e7b4292SVikas Chaudhary 	/*
40746e7b4292SVikas Chaudhary 	 * Since we cannot change dev_state in interrupt context,
40756e7b4292SVikas Chaudhary 	 * set appropriate DPC flag then wakeup DPC
40766e7b4292SVikas Chaudhary 	 */
40776e7b4292SVikas Chaudhary 	if (halt_status_unrecoverable) {
40786e7b4292SVikas Chaudhary 		set_bit(DPC_HA_UNRECOVERABLE, &ha->dpc_flags);
40796e7b4292SVikas Chaudhary 	} else {
40806e7b4292SVikas Chaudhary 		ql4_printk(KERN_INFO, ha, "%s: detect abort needed!\n",
40816e7b4292SVikas Chaudhary 			   __func__);
40826e7b4292SVikas Chaudhary 		set_bit(DPC_RESET_HA, &ha->dpc_flags);
40836e7b4292SVikas Chaudhary 	}
40846e7b4292SVikas Chaudhary 	qla4xxx_mailbox_premature_completion(ha);
40856e7b4292SVikas Chaudhary 	qla4xxx_wake_dpc(ha);
40866e7b4292SVikas Chaudhary }
40876e7b4292SVikas Chaudhary 
4088f4f5df23SVikas Chaudhary /**
4089f4f5df23SVikas Chaudhary  * qla4_8xxx_watchdog - Poll dev state
4090f4f5df23SVikas Chaudhary  * @ha: Pointer to host adapter structure.
4091f4f5df23SVikas Chaudhary  *
4092f4f5df23SVikas Chaudhary  * Context: Interrupt
4093f4f5df23SVikas Chaudhary  **/
4094f4f5df23SVikas Chaudhary void qla4_8xxx_watchdog(struct scsi_qla_host *ha)
4095f4f5df23SVikas Chaudhary {
40966e7b4292SVikas Chaudhary 	uint32_t dev_state;
40976cf94121SVikas Chaudhary 	uint32_t idc_ctrl;
4098f4f5df23SVikas Chaudhary 
4099f4f5df23SVikas Chaudhary 	/* don't poll if reset is going on */
4100d56a1f7bSLalit Chandivade 	if (!(test_bit(DPC_RESET_ACTIVE, &ha->dpc_flags) ||
4101d56a1f7bSLalit Chandivade 	    test_bit(DPC_RESET_HA, &ha->dpc_flags) ||
4102977f46a4SVikas Chaudhary 	    test_bit(DPC_RETRY_RESET_HA, &ha->dpc_flags))) {
410333693c7aSVikas Chaudhary 		dev_state = qla4_8xxx_rd_direct(ha, QLA8XXX_CRB_DEV_STATE);
41044f77083eSMike Hernandez 
41054f77083eSMike Hernandez 		if (qla4_8xxx_check_temp(ha)) {
41066e7b4292SVikas Chaudhary 			if (is_qla8022(ha)) {
41076e7b4292SVikas Chaudhary 				ql4_printk(KERN_INFO, ha, "disabling pause transmit on port 0 & 1.\n");
4108f8086f4fSVikas Chaudhary 				qla4_82xx_wr_32(ha, QLA82XX_CRB_NIU + 0x98,
4109e6bd0ebdSGiridhar Malavali 						CRB_NIU_XG_PAUSE_CTL_P0 |
4110e6bd0ebdSGiridhar Malavali 						CRB_NIU_XG_PAUSE_CTL_P1);
41116e7b4292SVikas Chaudhary 			}
41124f77083eSMike Hernandez 			set_bit(DPC_HA_UNRECOVERABLE, &ha->dpc_flags);
41134f77083eSMike Hernandez 			qla4xxx_wake_dpc(ha);
4114de8c72daSVikas Chaudhary 		} else if (dev_state == QLA8XXX_DEV_NEED_RESET &&
4115f4f5df23SVikas Chaudhary 			   !test_bit(DPC_RESET_HA, &ha->dpc_flags)) {
41166cf94121SVikas Chaudhary 
41176cf94121SVikas Chaudhary 			ql4_printk(KERN_INFO, ha, "%s: HW State: NEED RESET!\n",
41186cf94121SVikas Chaudhary 				   __func__);
41196cf94121SVikas Chaudhary 
4120b37ca418SVikas Chaudhary 			if (is_qla8032(ha) || is_qla8042(ha)) {
41216cf94121SVikas Chaudhary 				idc_ctrl = qla4_83xx_rd_reg(ha,
41226cf94121SVikas Chaudhary 							QLA83XX_IDC_DRV_CTRL);
41236cf94121SVikas Chaudhary 				if (!(idc_ctrl & GRACEFUL_RESET_BIT1)) {
41246cf94121SVikas Chaudhary 					ql4_printk(KERN_INFO, ha, "%s: Graceful reset bit is not set\n",
41256cf94121SVikas Chaudhary 						   __func__);
41266cf94121SVikas Chaudhary 					qla4xxx_mailbox_premature_completion(
41276cf94121SVikas Chaudhary 									    ha);
41286cf94121SVikas Chaudhary 				}
41296cf94121SVikas Chaudhary 			}
41306cf94121SVikas Chaudhary 
4131b37ca418SVikas Chaudhary 			if ((is_qla8032(ha) || is_qla8042(ha)) ||
41326e7b4292SVikas Chaudhary 			    (is_qla8022(ha) && !ql4xdontresethba)) {
4133f4f5df23SVikas Chaudhary 				set_bit(DPC_RESET_HA, &ha->dpc_flags);
4134f4f5df23SVikas Chaudhary 				qla4xxx_wake_dpc(ha);
41353930b8c1SVikas Chaudhary 			}
4136de8c72daSVikas Chaudhary 		} else if (dev_state == QLA8XXX_DEV_NEED_QUIESCENT &&
4137f4f5df23SVikas Chaudhary 		    !test_bit(DPC_HA_NEED_QUIESCENT, &ha->dpc_flags)) {
41383930b8c1SVikas Chaudhary 			ql4_printk(KERN_INFO, ha, "%s: HW State: NEED QUIES!\n",
41393930b8c1SVikas Chaudhary 			    __func__);
4140f4f5df23SVikas Chaudhary 			set_bit(DPC_HA_NEED_QUIESCENT, &ha->dpc_flags);
4141f4f5df23SVikas Chaudhary 			qla4xxx_wake_dpc(ha);
4142f4f5df23SVikas Chaudhary 		} else  {
4143f4f5df23SVikas Chaudhary 			/* Check firmware health */
41446e7b4292SVikas Chaudhary 			if (qla4_8xxx_check_fw_alive(ha))
41456e7b4292SVikas Chaudhary 				qla4_8xxx_process_fw_error(ha);
4146f4f5df23SVikas Chaudhary 		}
4147f4f5df23SVikas Chaudhary 	}
4148f4f5df23SVikas Chaudhary }
4149f4f5df23SVikas Chaudhary 
41504a4bc2e9SLalit Chandivade static void qla4xxx_check_relogin_flash_ddb(struct iscsi_cls_session *cls_sess)
415113483730SMike Christie {
415213483730SMike Christie 	struct iscsi_session *sess;
415313483730SMike Christie 	struct ddb_entry *ddb_entry;
415413483730SMike Christie 	struct scsi_qla_host *ha;
415513483730SMike Christie 
415613483730SMike Christie 	sess = cls_sess->dd_data;
415713483730SMike Christie 	ddb_entry = sess->dd_data;
415813483730SMike Christie 	ha = ddb_entry->ha;
415913483730SMike Christie 
416013483730SMike Christie 	if (!(ddb_entry->ddb_type == FLASH_DDB))
416113483730SMike Christie 		return;
416213483730SMike Christie 
416313483730SMike Christie 	if (adapter_up(ha) && !test_bit(DF_RELOGIN, &ddb_entry->flags) &&
416413483730SMike Christie 	    !iscsi_is_session_online(cls_sess)) {
416513483730SMike Christie 		if (atomic_read(&ddb_entry->retry_relogin_timer) !=
416613483730SMike Christie 		    INVALID_ENTRY) {
416713483730SMike Christie 			if (atomic_read(&ddb_entry->retry_relogin_timer) ==
416813483730SMike Christie 					0) {
416913483730SMike Christie 				atomic_set(&ddb_entry->retry_relogin_timer,
417013483730SMike Christie 					   INVALID_ENTRY);
417113483730SMike Christie 				set_bit(DPC_RELOGIN_DEVICE, &ha->dpc_flags);
417213483730SMike Christie 				set_bit(DF_RELOGIN, &ddb_entry->flags);
417313483730SMike Christie 				DEBUG2(ql4_printk(KERN_INFO, ha,
417413483730SMike Christie 				       "%s: index [%d] login device\n",
417513483730SMike Christie 					__func__, ddb_entry->fw_ddb_index));
417613483730SMike Christie 			} else
417713483730SMike Christie 				atomic_dec(&ddb_entry->retry_relogin_timer);
417813483730SMike Christie 		}
417913483730SMike Christie 	}
418013483730SMike Christie 
418113483730SMike Christie 	/* Wait for relogin to timeout */
418213483730SMike Christie 	if (atomic_read(&ddb_entry->relogin_timer) &&
418313483730SMike Christie 	    (atomic_dec_and_test(&ddb_entry->relogin_timer) != 0)) {
418413483730SMike Christie 		/*
418513483730SMike Christie 		 * If the relogin times out and the device is
418613483730SMike Christie 		 * still NOT ONLINE then try and relogin again.
418713483730SMike Christie 		 */
418813483730SMike Christie 		if (!iscsi_is_session_online(cls_sess)) {
418913483730SMike Christie 			/* Reset retry relogin timer */
419013483730SMike Christie 			atomic_inc(&ddb_entry->relogin_retry_count);
419113483730SMike Christie 			DEBUG2(ql4_printk(KERN_INFO, ha,
419213483730SMike Christie 				"%s: index[%d] relogin timed out-retrying"
419313483730SMike Christie 				" relogin (%d), retry (%d)\n", __func__,
419413483730SMike Christie 				ddb_entry->fw_ddb_index,
419513483730SMike Christie 				atomic_read(&ddb_entry->relogin_retry_count),
419613483730SMike Christie 				ddb_entry->default_time2wait + 4));
419713483730SMike Christie 			set_bit(DPC_RELOGIN_DEVICE, &ha->dpc_flags);
419813483730SMike Christie 			atomic_set(&ddb_entry->retry_relogin_timer,
419913483730SMike Christie 				   ddb_entry->default_time2wait + 4);
420013483730SMike Christie 		}
420113483730SMike Christie 	}
420213483730SMike Christie }
420313483730SMike Christie 
4204f4f5df23SVikas Chaudhary /**
4205afaf5a2dSDavid Somayajulu  * qla4xxx_timer - checks every second for work to do.
4206afaf5a2dSDavid Somayajulu  * @ha: Pointer to host adapter structure.
4207afaf5a2dSDavid Somayajulu  **/
4208afaf5a2dSDavid Somayajulu static void qla4xxx_timer(struct scsi_qla_host *ha)
4209afaf5a2dSDavid Somayajulu {
4210afaf5a2dSDavid Somayajulu 	int start_dpc = 0;
42112232be0dSLalit Chandivade 	uint16_t w;
42122232be0dSLalit Chandivade 
421313483730SMike Christie 	iscsi_host_for_each_session(ha->host, qla4xxx_check_relogin_flash_ddb);
421413483730SMike Christie 
42152232be0dSLalit Chandivade 	/* If we are in the middle of AER/EEH processing
42162232be0dSLalit Chandivade 	 * skip any processing and reschedule the timer
42172232be0dSLalit Chandivade 	 */
42182232be0dSLalit Chandivade 	if (test_bit(AF_EEH_BUSY, &ha->flags)) {
42192232be0dSLalit Chandivade 		mod_timer(&ha->timer, jiffies + HZ);
42202232be0dSLalit Chandivade 		return;
42212232be0dSLalit Chandivade 	}
42222232be0dSLalit Chandivade 
42232232be0dSLalit Chandivade 	/* Hardware read to trigger an EEH error during mailbox waits. */
42242232be0dSLalit Chandivade 	if (!pci_channel_offline(ha->pdev))
42252232be0dSLalit Chandivade 		pci_read_config_word(ha->pdev, PCI_VENDOR_ID, &w);
4226afaf5a2dSDavid Somayajulu 
42276e7b4292SVikas Chaudhary 	if (is_qla80XX(ha))
4228f4f5df23SVikas Chaudhary 		qla4_8xxx_watchdog(ha);
4229f4f5df23SVikas Chaudhary 
4230ee996a69SVikas Chaudhary 	if (is_qla40XX(ha)) {
4231afaf5a2dSDavid Somayajulu 		/* Check for heartbeat interval. */
4232afaf5a2dSDavid Somayajulu 		if (ha->firmware_options & FWOPT_HEARTBEAT_ENABLE &&
4233afaf5a2dSDavid Somayajulu 		    ha->heartbeat_interval != 0) {
4234afaf5a2dSDavid Somayajulu 			ha->seconds_since_last_heartbeat++;
4235afaf5a2dSDavid Somayajulu 			if (ha->seconds_since_last_heartbeat >
4236afaf5a2dSDavid Somayajulu 			    ha->heartbeat_interval + 2)
4237afaf5a2dSDavid Somayajulu 				set_bit(DPC_RESET_HA, &ha->dpc_flags);
4238afaf5a2dSDavid Somayajulu 		}
4239f4f5df23SVikas Chaudhary 	}
4240afaf5a2dSDavid Somayajulu 
4241ff884430SVikas Chaudhary 	/* Process any deferred work. */
4242ff884430SVikas Chaudhary 	if (!list_empty(&ha->work_list))
4243ff884430SVikas Chaudhary 		start_dpc++;
4244ff884430SVikas Chaudhary 
4245afaf5a2dSDavid Somayajulu 	/* Wakeup the dpc routine for this adapter, if needed. */
42461b46807eSLalit Chandivade 	if (start_dpc ||
4247afaf5a2dSDavid Somayajulu 	     test_bit(DPC_RESET_HA, &ha->dpc_flags) ||
4248afaf5a2dSDavid Somayajulu 	     test_bit(DPC_RETRY_RESET_HA, &ha->dpc_flags) ||
4249afaf5a2dSDavid Somayajulu 	     test_bit(DPC_RELOGIN_DEVICE, &ha->dpc_flags) ||
4250f4f5df23SVikas Chaudhary 	     test_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags) ||
4251afaf5a2dSDavid Somayajulu 	     test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags) ||
4252afaf5a2dSDavid Somayajulu 	     test_bit(DPC_GET_DHCP_IP_ADDR, &ha->dpc_flags) ||
4253065aa1b4SVikas Chaudhary 	     test_bit(DPC_LINK_CHANGED, &ha->dpc_flags) ||
4254f4f5df23SVikas Chaudhary 	     test_bit(DPC_HA_UNRECOVERABLE, &ha->dpc_flags) ||
4255f4f5df23SVikas Chaudhary 	     test_bit(DPC_HA_NEED_QUIESCENT, &ha->dpc_flags) ||
42561b46807eSLalit Chandivade 	     test_bit(DPC_AEN, &ha->dpc_flags)) {
4257afaf5a2dSDavid Somayajulu 		DEBUG2(printk("scsi%ld: %s: scheduling dpc routine"
4258afaf5a2dSDavid Somayajulu 			      " - dpc flags = 0x%lx\n",
4259afaf5a2dSDavid Somayajulu 			      ha->host_no, __func__, ha->dpc_flags));
4260f4f5df23SVikas Chaudhary 		qla4xxx_wake_dpc(ha);
4261afaf5a2dSDavid Somayajulu 	}
4262afaf5a2dSDavid Somayajulu 
4263afaf5a2dSDavid Somayajulu 	/* Reschedule timer thread to call us back in one second */
4264afaf5a2dSDavid Somayajulu 	mod_timer(&ha->timer, jiffies + HZ);
4265afaf5a2dSDavid Somayajulu 
4266afaf5a2dSDavid Somayajulu 	DEBUG2(ha->seconds_since_last_intr++);
4267afaf5a2dSDavid Somayajulu }
4268afaf5a2dSDavid Somayajulu 
4269afaf5a2dSDavid Somayajulu /**
4270afaf5a2dSDavid Somayajulu  * qla4xxx_cmd_wait - waits for all outstanding commands to complete
4271afaf5a2dSDavid Somayajulu  * @ha: Pointer to host adapter structure.
4272afaf5a2dSDavid Somayajulu  *
4273afaf5a2dSDavid Somayajulu  * This routine stalls the driver until all outstanding commands are returned.
4274afaf5a2dSDavid Somayajulu  * Caller must release the Hardware Lock prior to calling this routine.
4275afaf5a2dSDavid Somayajulu  **/
4276afaf5a2dSDavid Somayajulu static int qla4xxx_cmd_wait(struct scsi_qla_host *ha)
4277afaf5a2dSDavid Somayajulu {
4278afaf5a2dSDavid Somayajulu 	uint32_t index = 0;
4279afaf5a2dSDavid Somayajulu 	unsigned long flags;
4280afaf5a2dSDavid Somayajulu 	struct scsi_cmnd *cmd;
4281afaf5a2dSDavid Somayajulu 
4282f4f5df23SVikas Chaudhary 	unsigned long wtime = jiffies + (WAIT_CMD_TOV * HZ);
4283f4f5df23SVikas Chaudhary 
4284f4f5df23SVikas Chaudhary 	DEBUG2(ql4_printk(KERN_INFO, ha, "Wait up to %d seconds for cmds to "
4285f4f5df23SVikas Chaudhary 	    "complete\n", WAIT_CMD_TOV));
4286f4f5df23SVikas Chaudhary 
4287f4f5df23SVikas Chaudhary 	while (!time_after_eq(jiffies, wtime)) {
4288afaf5a2dSDavid Somayajulu 		spin_lock_irqsave(&ha->hardware_lock, flags);
4289afaf5a2dSDavid Somayajulu 		/* Find a command that hasn't completed. */
4290afaf5a2dSDavid Somayajulu 		for (index = 0; index < ha->host->can_queue; index++) {
4291afaf5a2dSDavid Somayajulu 			cmd = scsi_host_find_tag(ha->host, index);
4292a1e0063dSMike Christie 			/*
4293a1e0063dSMike Christie 			 * We cannot just check if the index is valid,
4294a1e0063dSMike Christie 			 * becase if we are run from the scsi eh, then
4295a1e0063dSMike Christie 			 * the scsi/block layer is going to prevent
4296a1e0063dSMike Christie 			 * the tag from being released.
4297a1e0063dSMike Christie 			 */
4298a1e0063dSMike Christie 			if (cmd != NULL && CMD_SP(cmd))
4299afaf5a2dSDavid Somayajulu 				break;
4300afaf5a2dSDavid Somayajulu 		}
4301afaf5a2dSDavid Somayajulu 		spin_unlock_irqrestore(&ha->hardware_lock, flags);
4302afaf5a2dSDavid Somayajulu 
4303afaf5a2dSDavid Somayajulu 		/* If No Commands are pending, wait is complete */
4304f4f5df23SVikas Chaudhary 		if (index == ha->host->can_queue)
4305f4f5df23SVikas Chaudhary 			return QLA_SUCCESS;
4306afaf5a2dSDavid Somayajulu 
4307afaf5a2dSDavid Somayajulu 		msleep(1000);
4308afaf5a2dSDavid Somayajulu 	}
4309f4f5df23SVikas Chaudhary 	/* If we timed out on waiting for commands to come back
4310f4f5df23SVikas Chaudhary 	 * return ERROR. */
4311f4f5df23SVikas Chaudhary 	return QLA_ERROR;
4312afaf5a2dSDavid Somayajulu }
4313afaf5a2dSDavid Somayajulu 
4314f4f5df23SVikas Chaudhary int qla4xxx_hw_reset(struct scsi_qla_host *ha)
4315afaf5a2dSDavid Somayajulu {
4316afaf5a2dSDavid Somayajulu 	uint32_t ctrl_status;
4317477ffb9dSDavid C Somayajulu 	unsigned long flags = 0;
4318477ffb9dSDavid C Somayajulu 
4319477ffb9dSDavid C Somayajulu 	DEBUG2(printk(KERN_ERR "scsi%ld: %s\n", ha->host_no, __func__));
4320afaf5a2dSDavid Somayajulu 
4321f4f5df23SVikas Chaudhary 	if (ql4xxx_lock_drvr_wait(ha) != QLA_SUCCESS)
4322f4f5df23SVikas Chaudhary 		return QLA_ERROR;
4323f4f5df23SVikas Chaudhary 
4324afaf5a2dSDavid Somayajulu 	spin_lock_irqsave(&ha->hardware_lock, flags);
4325afaf5a2dSDavid Somayajulu 
4326afaf5a2dSDavid Somayajulu 	/*
4327afaf5a2dSDavid Somayajulu 	 * If the SCSI Reset Interrupt bit is set, clear it.
4328afaf5a2dSDavid Somayajulu 	 * Otherwise, the Soft Reset won't work.
4329afaf5a2dSDavid Somayajulu 	 */
4330afaf5a2dSDavid Somayajulu 	ctrl_status = readw(&ha->reg->ctrl_status);
4331afaf5a2dSDavid Somayajulu 	if ((ctrl_status & CSR_SCSI_RESET_INTR) != 0)
4332afaf5a2dSDavid Somayajulu 		writel(set_rmask(CSR_SCSI_RESET_INTR), &ha->reg->ctrl_status);
4333afaf5a2dSDavid Somayajulu 
4334afaf5a2dSDavid Somayajulu 	/* Issue Soft Reset */
4335afaf5a2dSDavid Somayajulu 	writel(set_rmask(CSR_SOFT_RESET), &ha->reg->ctrl_status);
4336afaf5a2dSDavid Somayajulu 	readl(&ha->reg->ctrl_status);
4337afaf5a2dSDavid Somayajulu 
4338afaf5a2dSDavid Somayajulu 	spin_unlock_irqrestore(&ha->hardware_lock, flags);
4339f4f5df23SVikas Chaudhary 	return QLA_SUCCESS;
4340477ffb9dSDavid C Somayajulu }
4341477ffb9dSDavid C Somayajulu 
4342477ffb9dSDavid C Somayajulu /**
4343477ffb9dSDavid C Somayajulu  * qla4xxx_soft_reset - performs soft reset.
4344477ffb9dSDavid C Somayajulu  * @ha: Pointer to host adapter structure.
4345477ffb9dSDavid C Somayajulu  **/
4346477ffb9dSDavid C Somayajulu int qla4xxx_soft_reset(struct scsi_qla_host *ha)
4347477ffb9dSDavid C Somayajulu {
4348477ffb9dSDavid C Somayajulu 	uint32_t max_wait_time;
4349477ffb9dSDavid C Somayajulu 	unsigned long flags = 0;
4350f931c534SVikas Chaudhary 	int status;
4351477ffb9dSDavid C Somayajulu 	uint32_t ctrl_status;
4352477ffb9dSDavid C Somayajulu 
4353f931c534SVikas Chaudhary 	status = qla4xxx_hw_reset(ha);
4354f931c534SVikas Chaudhary 	if (status != QLA_SUCCESS)
4355f931c534SVikas Chaudhary 		return status;
4356afaf5a2dSDavid Somayajulu 
4357f931c534SVikas Chaudhary 	status = QLA_ERROR;
4358afaf5a2dSDavid Somayajulu 	/* Wait until the Network Reset Intr bit is cleared */
4359afaf5a2dSDavid Somayajulu 	max_wait_time = RESET_INTR_TOV;
4360afaf5a2dSDavid Somayajulu 	do {
4361afaf5a2dSDavid Somayajulu 		spin_lock_irqsave(&ha->hardware_lock, flags);
4362afaf5a2dSDavid Somayajulu 		ctrl_status = readw(&ha->reg->ctrl_status);
4363afaf5a2dSDavid Somayajulu 		spin_unlock_irqrestore(&ha->hardware_lock, flags);
4364afaf5a2dSDavid Somayajulu 
4365afaf5a2dSDavid Somayajulu 		if ((ctrl_status & CSR_NET_RESET_INTR) == 0)
4366afaf5a2dSDavid Somayajulu 			break;
4367afaf5a2dSDavid Somayajulu 
4368afaf5a2dSDavid Somayajulu 		msleep(1000);
4369afaf5a2dSDavid Somayajulu 	} while ((--max_wait_time));
4370afaf5a2dSDavid Somayajulu 
4371afaf5a2dSDavid Somayajulu 	if ((ctrl_status & CSR_NET_RESET_INTR) != 0) {
4372afaf5a2dSDavid Somayajulu 		DEBUG2(printk(KERN_WARNING
4373afaf5a2dSDavid Somayajulu 			      "scsi%ld: Network Reset Intr not cleared by "
4374afaf5a2dSDavid Somayajulu 			      "Network function, clearing it now!\n",
4375afaf5a2dSDavid Somayajulu 			      ha->host_no));
4376afaf5a2dSDavid Somayajulu 		spin_lock_irqsave(&ha->hardware_lock, flags);
4377afaf5a2dSDavid Somayajulu 		writel(set_rmask(CSR_NET_RESET_INTR), &ha->reg->ctrl_status);
4378afaf5a2dSDavid Somayajulu 		readl(&ha->reg->ctrl_status);
4379afaf5a2dSDavid Somayajulu 		spin_unlock_irqrestore(&ha->hardware_lock, flags);
4380afaf5a2dSDavid Somayajulu 	}
4381afaf5a2dSDavid Somayajulu 
4382afaf5a2dSDavid Somayajulu 	/* Wait until the firmware tells us the Soft Reset is done */
4383afaf5a2dSDavid Somayajulu 	max_wait_time = SOFT_RESET_TOV;
4384afaf5a2dSDavid Somayajulu 	do {
4385afaf5a2dSDavid Somayajulu 		spin_lock_irqsave(&ha->hardware_lock, flags);
4386afaf5a2dSDavid Somayajulu 		ctrl_status = readw(&ha->reg->ctrl_status);
4387afaf5a2dSDavid Somayajulu 		spin_unlock_irqrestore(&ha->hardware_lock, flags);
4388afaf5a2dSDavid Somayajulu 
4389afaf5a2dSDavid Somayajulu 		if ((ctrl_status & CSR_SOFT_RESET) == 0) {
4390afaf5a2dSDavid Somayajulu 			status = QLA_SUCCESS;
4391afaf5a2dSDavid Somayajulu 			break;
4392afaf5a2dSDavid Somayajulu 		}
4393afaf5a2dSDavid Somayajulu 
4394afaf5a2dSDavid Somayajulu 		msleep(1000);
4395afaf5a2dSDavid Somayajulu 	} while ((--max_wait_time));
4396afaf5a2dSDavid Somayajulu 
4397afaf5a2dSDavid Somayajulu 	/*
4398afaf5a2dSDavid Somayajulu 	 * Also, make sure that the SCSI Reset Interrupt bit has been cleared
4399afaf5a2dSDavid Somayajulu 	 * after the soft reset has taken place.
4400afaf5a2dSDavid Somayajulu 	 */
4401afaf5a2dSDavid Somayajulu 	spin_lock_irqsave(&ha->hardware_lock, flags);
4402afaf5a2dSDavid Somayajulu 	ctrl_status = readw(&ha->reg->ctrl_status);
4403afaf5a2dSDavid Somayajulu 	if ((ctrl_status & CSR_SCSI_RESET_INTR) != 0) {
4404afaf5a2dSDavid Somayajulu 		writel(set_rmask(CSR_SCSI_RESET_INTR), &ha->reg->ctrl_status);
4405afaf5a2dSDavid Somayajulu 		readl(&ha->reg->ctrl_status);
4406afaf5a2dSDavid Somayajulu 	}
4407afaf5a2dSDavid Somayajulu 	spin_unlock_irqrestore(&ha->hardware_lock, flags);
4408afaf5a2dSDavid Somayajulu 
4409afaf5a2dSDavid Somayajulu 	/* If soft reset fails then most probably the bios on other
4410afaf5a2dSDavid Somayajulu 	 * function is also enabled.
4411afaf5a2dSDavid Somayajulu 	 * Since the initialization is sequential the other fn
4412afaf5a2dSDavid Somayajulu 	 * wont be able to acknowledge the soft reset.
4413afaf5a2dSDavid Somayajulu 	 * Issue a force soft reset to workaround this scenario.
4414afaf5a2dSDavid Somayajulu 	 */
4415afaf5a2dSDavid Somayajulu 	if (max_wait_time == 0) {
4416afaf5a2dSDavid Somayajulu 		/* Issue Force Soft Reset */
4417afaf5a2dSDavid Somayajulu 		spin_lock_irqsave(&ha->hardware_lock, flags);
4418afaf5a2dSDavid Somayajulu 		writel(set_rmask(CSR_FORCE_SOFT_RESET), &ha->reg->ctrl_status);
4419afaf5a2dSDavid Somayajulu 		readl(&ha->reg->ctrl_status);
4420afaf5a2dSDavid Somayajulu 		spin_unlock_irqrestore(&ha->hardware_lock, flags);
4421afaf5a2dSDavid Somayajulu 		/* Wait until the firmware tells us the Soft Reset is done */
4422afaf5a2dSDavid Somayajulu 		max_wait_time = SOFT_RESET_TOV;
4423afaf5a2dSDavid Somayajulu 		do {
4424afaf5a2dSDavid Somayajulu 			spin_lock_irqsave(&ha->hardware_lock, flags);
4425afaf5a2dSDavid Somayajulu 			ctrl_status = readw(&ha->reg->ctrl_status);
4426afaf5a2dSDavid Somayajulu 			spin_unlock_irqrestore(&ha->hardware_lock, flags);
4427afaf5a2dSDavid Somayajulu 
4428afaf5a2dSDavid Somayajulu 			if ((ctrl_status & CSR_FORCE_SOFT_RESET) == 0) {
4429afaf5a2dSDavid Somayajulu 				status = QLA_SUCCESS;
4430afaf5a2dSDavid Somayajulu 				break;
4431afaf5a2dSDavid Somayajulu 			}
4432afaf5a2dSDavid Somayajulu 
4433afaf5a2dSDavid Somayajulu 			msleep(1000);
4434afaf5a2dSDavid Somayajulu 		} while ((--max_wait_time));
4435afaf5a2dSDavid Somayajulu 	}
4436afaf5a2dSDavid Somayajulu 
4437afaf5a2dSDavid Somayajulu 	return status;
4438afaf5a2dSDavid Somayajulu }
4439afaf5a2dSDavid Somayajulu 
4440afaf5a2dSDavid Somayajulu /**
4441f4f5df23SVikas Chaudhary  * qla4xxx_abort_active_cmds - returns all outstanding i/o requests to O.S.
4442afaf5a2dSDavid Somayajulu  * @ha: Pointer to host adapter structure.
4443f4f5df23SVikas Chaudhary  * @res: returned scsi status
4444afaf5a2dSDavid Somayajulu  *
4445afaf5a2dSDavid Somayajulu  * This routine is called just prior to a HARD RESET to return all
4446afaf5a2dSDavid Somayajulu  * outstanding commands back to the Operating System.
4447afaf5a2dSDavid Somayajulu  * Caller should make sure that the following locks are released
4448afaf5a2dSDavid Somayajulu  * before this calling routine: Hardware lock, and io_request_lock.
4449afaf5a2dSDavid Somayajulu  **/
4450f4f5df23SVikas Chaudhary static void qla4xxx_abort_active_cmds(struct scsi_qla_host *ha, int res)
4451afaf5a2dSDavid Somayajulu {
4452afaf5a2dSDavid Somayajulu 	struct srb *srb;
4453afaf5a2dSDavid Somayajulu 	int i;
4454afaf5a2dSDavid Somayajulu 	unsigned long flags;
4455afaf5a2dSDavid Somayajulu 
4456afaf5a2dSDavid Somayajulu 	spin_lock_irqsave(&ha->hardware_lock, flags);
4457afaf5a2dSDavid Somayajulu 	for (i = 0; i < ha->host->can_queue; i++) {
4458afaf5a2dSDavid Somayajulu 		srb = qla4xxx_del_from_active_array(ha, i);
4459afaf5a2dSDavid Somayajulu 		if (srb != NULL) {
4460f4f5df23SVikas Chaudhary 			srb->cmd->result = res;
446109a0f719SVikas Chaudhary 			kref_put(&srb->srb_ref, qla4xxx_srb_compl);
4462afaf5a2dSDavid Somayajulu 		}
4463afaf5a2dSDavid Somayajulu 	}
4464afaf5a2dSDavid Somayajulu 	spin_unlock_irqrestore(&ha->hardware_lock, flags);
4465afaf5a2dSDavid Somayajulu }
4466afaf5a2dSDavid Somayajulu 
4467f4f5df23SVikas Chaudhary void qla4xxx_dead_adapter_cleanup(struct scsi_qla_host *ha)
4468f4f5df23SVikas Chaudhary {
4469f4f5df23SVikas Chaudhary 	clear_bit(AF_ONLINE, &ha->flags);
4470f4f5df23SVikas Chaudhary 
4471f4f5df23SVikas Chaudhary 	/* Disable the board */
4472f4f5df23SVikas Chaudhary 	ql4_printk(KERN_INFO, ha, "Disabling the board\n");
4473f4f5df23SVikas Chaudhary 
4474f4f5df23SVikas Chaudhary 	qla4xxx_abort_active_cmds(ha, DID_NO_CONNECT << 16);
4475f4f5df23SVikas Chaudhary 	qla4xxx_mark_all_devices_missing(ha);
4476f4f5df23SVikas Chaudhary 	clear_bit(AF_INIT_DONE, &ha->flags);
4477f4f5df23SVikas Chaudhary }
4478f4f5df23SVikas Chaudhary 
4479b3a271a9SManish Rangankar static void qla4xxx_fail_session(struct iscsi_cls_session *cls_session)
4480b3a271a9SManish Rangankar {
4481b3a271a9SManish Rangankar 	struct iscsi_session *sess;
4482b3a271a9SManish Rangankar 	struct ddb_entry *ddb_entry;
4483b3a271a9SManish Rangankar 
4484b3a271a9SManish Rangankar 	sess = cls_session->dd_data;
4485b3a271a9SManish Rangankar 	ddb_entry = sess->dd_data;
4486b3a271a9SManish Rangankar 	ddb_entry->fw_ddb_device_state = DDB_DS_SESSION_FAILED;
448713483730SMike Christie 
448813483730SMike Christie 	if (ddb_entry->ddb_type == FLASH_DDB)
448913483730SMike Christie 		iscsi_block_session(ddb_entry->sess);
449013483730SMike Christie 	else
449113483730SMike Christie 		iscsi_session_failure(cls_session->dd_data,
449213483730SMike Christie 				      ISCSI_ERR_CONN_FAILED);
4493b3a271a9SManish Rangankar }
4494b3a271a9SManish Rangankar 
4495afaf5a2dSDavid Somayajulu /**
4496afaf5a2dSDavid Somayajulu  * qla4xxx_recover_adapter - recovers adapter after a fatal error
4497afaf5a2dSDavid Somayajulu  * @ha: Pointer to host adapter structure.
4498afaf5a2dSDavid Somayajulu  **/
4499f4f5df23SVikas Chaudhary static int qla4xxx_recover_adapter(struct scsi_qla_host *ha)
4500afaf5a2dSDavid Somayajulu {
4501f4f5df23SVikas Chaudhary 	int status = QLA_ERROR;
4502f4f5df23SVikas Chaudhary 	uint8_t reset_chip = 0;
45038e0f3a66SSarang Radke 	uint32_t dev_state;
45049ee91a38SShyam Sunder 	unsigned long wait;
4505afaf5a2dSDavid Somayajulu 
4506afaf5a2dSDavid Somayajulu 	/* Stall incoming I/O until we are done */
4507f4f5df23SVikas Chaudhary 	scsi_block_requests(ha->host);
4508afaf5a2dSDavid Somayajulu 	clear_bit(AF_ONLINE, &ha->flags);
4509b3a271a9SManish Rangankar 	clear_bit(AF_LINK_UP, &ha->flags);
451050a29aecSMike Christie 
4511f4f5df23SVikas Chaudhary 	DEBUG2(ql4_printk(KERN_INFO, ha, "%s: adapter OFFLINE\n", __func__));
4512afaf5a2dSDavid Somayajulu 
4513f4f5df23SVikas Chaudhary 	set_bit(DPC_RESET_ACTIVE, &ha->dpc_flags);
4514afaf5a2dSDavid Somayajulu 
4515b37ca418SVikas Chaudhary 	if ((is_qla8032(ha) || is_qla8042(ha)) &&
4516546fef27STej Parkash 	    !test_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags)) {
4517546fef27STej Parkash 		ql4_printk(KERN_INFO, ha, "%s: disabling pause transmit on port 0 & 1.\n",
4518546fef27STej Parkash 			   __func__);
4519546fef27STej Parkash 		/* disable pause frame for ISP83xx */
4520546fef27STej Parkash 		qla4_83xx_disable_pause(ha);
4521546fef27STej Parkash 	}
4522546fef27STej Parkash 
4523b3a271a9SManish Rangankar 	iscsi_host_for_each_session(ha->host, qla4xxx_fail_session);
4524b3a271a9SManish Rangankar 
4525f4f5df23SVikas Chaudhary 	if (test_bit(DPC_RESET_HA, &ha->dpc_flags))
4526f4f5df23SVikas Chaudhary 		reset_chip = 1;
4527afaf5a2dSDavid Somayajulu 
4528f4f5df23SVikas Chaudhary 	/* For the DPC_RESET_HA_INTR case (ISP-4xxx specific)
4529f4f5df23SVikas Chaudhary 	 * do not reset adapter, jump to initialize_adapter */
4530f4f5df23SVikas Chaudhary 	if (test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags)) {
4531f4f5df23SVikas Chaudhary 		status = QLA_SUCCESS;
4532f4f5df23SVikas Chaudhary 		goto recover_ha_init_adapter;
4533afaf5a2dSDavid Somayajulu 	}
4534afaf5a2dSDavid Somayajulu 
45356e7b4292SVikas Chaudhary 	/* For the ISP-8xxx adapter, issue a stop_firmware if invoked
4536f4f5df23SVikas Chaudhary 	 * from eh_host_reset or ioctl module */
45376e7b4292SVikas Chaudhary 	if (is_qla80XX(ha) && !reset_chip &&
4538f4f5df23SVikas Chaudhary 	    test_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags)) {
4539f4f5df23SVikas Chaudhary 
4540f4f5df23SVikas Chaudhary 		DEBUG2(ql4_printk(KERN_INFO, ha,
4541f4f5df23SVikas Chaudhary 		    "scsi%ld: %s - Performing stop_firmware...\n",
4542f4f5df23SVikas Chaudhary 		    ha->host_no, __func__));
4543f4f5df23SVikas Chaudhary 		status = ha->isp_ops->reset_firmware(ha);
4544f4f5df23SVikas Chaudhary 		if (status == QLA_SUCCESS) {
45452bd1e2beSNilesh Javali 			if (!test_bit(AF_FW_RECOVERY, &ha->flags))
4546f4f5df23SVikas Chaudhary 				qla4xxx_cmd_wait(ha);
45475c19b92aSVikas Chaudhary 
4548f4f5df23SVikas Chaudhary 			ha->isp_ops->disable_intrs(ha);
4549f4f5df23SVikas Chaudhary 			qla4xxx_process_aen(ha, FLUSH_DDB_CHANGED_AENS);
4550f4f5df23SVikas Chaudhary 			qla4xxx_abort_active_cmds(ha, DID_RESET << 16);
4551f4f5df23SVikas Chaudhary 		} else {
4552f4f5df23SVikas Chaudhary 			/* If the stop_firmware fails then
4553f4f5df23SVikas Chaudhary 			 * reset the entire chip */
4554f4f5df23SVikas Chaudhary 			reset_chip = 1;
4555f4f5df23SVikas Chaudhary 			clear_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags);
4556f4f5df23SVikas Chaudhary 			set_bit(DPC_RESET_HA, &ha->dpc_flags);
4557f4f5df23SVikas Chaudhary 		}
4558f4f5df23SVikas Chaudhary 	}
4559f4f5df23SVikas Chaudhary 
4560f4f5df23SVikas Chaudhary 	/* Issue full chip reset if recovering from a catastrophic error,
45616e7b4292SVikas Chaudhary 	 * or if stop_firmware fails for ISP-8xxx.
4562f4f5df23SVikas Chaudhary 	 * This is the default case for ISP-4xxx */
4563ee996a69SVikas Chaudhary 	if (is_qla40XX(ha) || reset_chip) {
4564ee996a69SVikas Chaudhary 		if (is_qla40XX(ha))
45659ee91a38SShyam Sunder 			goto chip_reset;
45669ee91a38SShyam Sunder 
45676e7b4292SVikas Chaudhary 		/* Check if 8XXX firmware is alive or not
45689ee91a38SShyam Sunder 		 * We may have arrived here from NEED_RESET
45699ee91a38SShyam Sunder 		 * detection only */
45709ee91a38SShyam Sunder 		if (test_bit(AF_FW_RECOVERY, &ha->flags))
45719ee91a38SShyam Sunder 			goto chip_reset;
45729ee91a38SShyam Sunder 
45739ee91a38SShyam Sunder 		wait = jiffies + (FW_ALIVE_WAIT_TOV * HZ);
45749ee91a38SShyam Sunder 		while (time_before(jiffies, wait)) {
45759ee91a38SShyam Sunder 			if (qla4_8xxx_check_fw_alive(ha)) {
45769ee91a38SShyam Sunder 				qla4xxx_mailbox_premature_completion(ha);
45779ee91a38SShyam Sunder 				break;
45789ee91a38SShyam Sunder 			}
45799ee91a38SShyam Sunder 
45809ee91a38SShyam Sunder 			set_current_state(TASK_UNINTERRUPTIBLE);
45819ee91a38SShyam Sunder 			schedule_timeout(HZ);
45829ee91a38SShyam Sunder 		}
4583da106212SVikas Chaudhary chip_reset:
45842bd1e2beSNilesh Javali 		if (!test_bit(AF_FW_RECOVERY, &ha->flags))
4585f4f5df23SVikas Chaudhary 			qla4xxx_cmd_wait(ha);
4586da106212SVikas Chaudhary 
4587f4f5df23SVikas Chaudhary 		qla4xxx_process_aen(ha, FLUSH_DDB_CHANGED_AENS);
4588f4f5df23SVikas Chaudhary 		qla4xxx_abort_active_cmds(ha, DID_RESET << 16);
4589f4f5df23SVikas Chaudhary 		DEBUG2(ql4_printk(KERN_INFO, ha,
4590f4f5df23SVikas Chaudhary 		    "scsi%ld: %s - Performing chip reset..\n",
4591f4f5df23SVikas Chaudhary 		    ha->host_no, __func__));
4592f4f5df23SVikas Chaudhary 		status = ha->isp_ops->reset_chip(ha);
4593f4f5df23SVikas Chaudhary 	}
4594f4f5df23SVikas Chaudhary 
4595f4f5df23SVikas Chaudhary 	/* Flush any pending ddb changed AENs */
4596f4f5df23SVikas Chaudhary 	qla4xxx_process_aen(ha, FLUSH_DDB_CHANGED_AENS);
4597f4f5df23SVikas Chaudhary 
4598f4f5df23SVikas Chaudhary recover_ha_init_adapter:
4599f4f5df23SVikas Chaudhary 	/* Upon successful firmware/chip reset, re-initialize the adapter */
4600f4f5df23SVikas Chaudhary 	if (status == QLA_SUCCESS) {
4601f4f5df23SVikas Chaudhary 		/* For ISP-4xxx, force function 1 to always initialize
4602f4f5df23SVikas Chaudhary 		 * before function 3 to prevent both funcions from
4603f4f5df23SVikas Chaudhary 		 * stepping on top of the other */
4604ee996a69SVikas Chaudhary 		if (is_qla40XX(ha) && (ha->mac_index == 3))
4605f4f5df23SVikas Chaudhary 			ssleep(6);
4606f4f5df23SVikas Chaudhary 
4607f4f5df23SVikas Chaudhary 		/* NOTE: AF_ONLINE flag set upon successful completion of
4608f4f5df23SVikas Chaudhary 		 *       qla4xxx_initialize_adapter */
460913483730SMike Christie 		status = qla4xxx_initialize_adapter(ha, RESET_ADAPTER);
4610f4f5df23SVikas Chaudhary 	}
4611f4f5df23SVikas Chaudhary 
4612f4f5df23SVikas Chaudhary 	/* Retry failed adapter initialization, if necessary
4613f4f5df23SVikas Chaudhary 	 * Do not retry initialize_adapter for RESET_HA_INTR (ISP-4xxx specific)
4614f4f5df23SVikas Chaudhary 	 * case to prevent ping-pong resets between functions */
4615f4f5df23SVikas Chaudhary 	if (!test_bit(AF_ONLINE, &ha->flags) &&
4616f4f5df23SVikas Chaudhary 	    !test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags)) {
4617afaf5a2dSDavid Somayajulu 		/* Adapter initialization failed, see if we can retry
4618f4f5df23SVikas Chaudhary 		 * resetting the ha.
4619f4f5df23SVikas Chaudhary 		 * Since we don't want to block the DPC for too long
4620f4f5df23SVikas Chaudhary 		 * with multiple resets in the same thread,
4621f4f5df23SVikas Chaudhary 		 * utilize DPC to retry */
46226e7b4292SVikas Chaudhary 		if (is_qla80XX(ha)) {
462333693c7aSVikas Chaudhary 			ha->isp_ops->idc_lock(ha);
462433693c7aSVikas Chaudhary 			dev_state = qla4_8xxx_rd_direct(ha,
462533693c7aSVikas Chaudhary 							QLA8XXX_CRB_DEV_STATE);
462633693c7aSVikas Chaudhary 			ha->isp_ops->idc_unlock(ha);
4627de8c72daSVikas Chaudhary 			if (dev_state == QLA8XXX_DEV_FAILED) {
46288e0f3a66SSarang Radke 				ql4_printk(KERN_INFO, ha, "%s: don't retry "
46298e0f3a66SSarang Radke 					   "recover adapter. H/W is in Failed "
46308e0f3a66SSarang Radke 					   "state\n", __func__);
46318e0f3a66SSarang Radke 				qla4xxx_dead_adapter_cleanup(ha);
46328e0f3a66SSarang Radke 				clear_bit(DPC_RETRY_RESET_HA, &ha->dpc_flags);
46338e0f3a66SSarang Radke 				clear_bit(DPC_RESET_HA, &ha->dpc_flags);
46348e0f3a66SSarang Radke 				clear_bit(DPC_RESET_HA_FW_CONTEXT,
46358e0f3a66SSarang Radke 						&ha->dpc_flags);
46368e0f3a66SSarang Radke 				status = QLA_ERROR;
46378e0f3a66SSarang Radke 
46388e0f3a66SSarang Radke 				goto exit_recover;
46398e0f3a66SSarang Radke 			}
46408e0f3a66SSarang Radke 		}
46418e0f3a66SSarang Radke 
4642afaf5a2dSDavid Somayajulu 		if (!test_bit(DPC_RETRY_RESET_HA, &ha->dpc_flags)) {
4643afaf5a2dSDavid Somayajulu 			ha->retry_reset_ha_cnt = MAX_RESET_HA_RETRIES;
4644afaf5a2dSDavid Somayajulu 			DEBUG2(printk("scsi%ld: recover adapter - retrying "
4645afaf5a2dSDavid Somayajulu 				      "(%d) more times\n", ha->host_no,
4646afaf5a2dSDavid Somayajulu 				      ha->retry_reset_ha_cnt));
4647afaf5a2dSDavid Somayajulu 			set_bit(DPC_RETRY_RESET_HA, &ha->dpc_flags);
4648afaf5a2dSDavid Somayajulu 			status = QLA_ERROR;
4649afaf5a2dSDavid Somayajulu 		} else {
4650afaf5a2dSDavid Somayajulu 			if (ha->retry_reset_ha_cnt > 0) {
4651afaf5a2dSDavid Somayajulu 				/* Schedule another Reset HA--DPC will retry */
4652afaf5a2dSDavid Somayajulu 				ha->retry_reset_ha_cnt--;
4653afaf5a2dSDavid Somayajulu 				DEBUG2(printk("scsi%ld: recover adapter - "
4654afaf5a2dSDavid Somayajulu 					      "retry remaining %d\n",
4655afaf5a2dSDavid Somayajulu 					      ha->host_no,
4656afaf5a2dSDavid Somayajulu 					      ha->retry_reset_ha_cnt));
4657afaf5a2dSDavid Somayajulu 				status = QLA_ERROR;
4658afaf5a2dSDavid Somayajulu 			}
4659afaf5a2dSDavid Somayajulu 
4660afaf5a2dSDavid Somayajulu 			if (ha->retry_reset_ha_cnt == 0) {
4661afaf5a2dSDavid Somayajulu 				/* Recover adapter retries have been exhausted.
4662afaf5a2dSDavid Somayajulu 				 * Adapter DEAD */
4663afaf5a2dSDavid Somayajulu 				DEBUG2(printk("scsi%ld: recover adapter "
4664afaf5a2dSDavid Somayajulu 					      "failed - board disabled\n",
4665afaf5a2dSDavid Somayajulu 					      ha->host_no));
4666f4f5df23SVikas Chaudhary 				qla4xxx_dead_adapter_cleanup(ha);
4667afaf5a2dSDavid Somayajulu 				clear_bit(DPC_RETRY_RESET_HA, &ha->dpc_flags);
4668afaf5a2dSDavid Somayajulu 				clear_bit(DPC_RESET_HA, &ha->dpc_flags);
4669f4f5df23SVikas Chaudhary 				clear_bit(DPC_RESET_HA_FW_CONTEXT,
4670afaf5a2dSDavid Somayajulu 					  &ha->dpc_flags);
4671afaf5a2dSDavid Somayajulu 				status = QLA_ERROR;
4672afaf5a2dSDavid Somayajulu 			}
4673afaf5a2dSDavid Somayajulu 		}
4674afaf5a2dSDavid Somayajulu 	} else {
4675afaf5a2dSDavid Somayajulu 		clear_bit(DPC_RESET_HA, &ha->dpc_flags);
4676f4f5df23SVikas Chaudhary 		clear_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags);
4677afaf5a2dSDavid Somayajulu 		clear_bit(DPC_RETRY_RESET_HA, &ha->dpc_flags);
4678afaf5a2dSDavid Somayajulu 	}
4679afaf5a2dSDavid Somayajulu 
46808e0f3a66SSarang Radke exit_recover:
4681afaf5a2dSDavid Somayajulu 	ha->adapter_error_count++;
4682afaf5a2dSDavid Somayajulu 
4683f4f5df23SVikas Chaudhary 	if (test_bit(AF_ONLINE, &ha->flags))
4684f4f5df23SVikas Chaudhary 		ha->isp_ops->enable_intrs(ha);
4685afaf5a2dSDavid Somayajulu 
4686f4f5df23SVikas Chaudhary 	scsi_unblock_requests(ha->host);
4687f4f5df23SVikas Chaudhary 
4688f4f5df23SVikas Chaudhary 	clear_bit(DPC_RESET_ACTIVE, &ha->dpc_flags);
4689f4f5df23SVikas Chaudhary 	DEBUG2(printk("scsi%ld: recover adapter: %s\n", ha->host_no,
469025985edcSLucas De Marchi 	    status == QLA_ERROR ? "FAILED" : "SUCCEEDED"));
4691f4f5df23SVikas Chaudhary 
4692afaf5a2dSDavid Somayajulu 	return status;
4693afaf5a2dSDavid Somayajulu }
4694afaf5a2dSDavid Somayajulu 
4695b3a271a9SManish Rangankar static void qla4xxx_relogin_devices(struct iscsi_cls_session *cls_session)
4696b3a271a9SManish Rangankar {
4697b3a271a9SManish Rangankar 	struct iscsi_session *sess;
4698b3a271a9SManish Rangankar 	struct ddb_entry *ddb_entry;
4699b3a271a9SManish Rangankar 	struct scsi_qla_host *ha;
4700b3a271a9SManish Rangankar 
4701b3a271a9SManish Rangankar 	sess = cls_session->dd_data;
4702b3a271a9SManish Rangankar 	ddb_entry = sess->dd_data;
4703b3a271a9SManish Rangankar 	ha = ddb_entry->ha;
4704b3a271a9SManish Rangankar 	if (!iscsi_is_session_online(cls_session)) {
4705b3a271a9SManish Rangankar 		if (ddb_entry->fw_ddb_device_state == DDB_DS_SESSION_ACTIVE) {
4706b3a271a9SManish Rangankar 			ql4_printk(KERN_INFO, ha, "scsi%ld: %s: ddb[%d]"
4707b3a271a9SManish Rangankar 				   " unblock session\n", ha->host_no, __func__,
4708b3a271a9SManish Rangankar 				   ddb_entry->fw_ddb_index);
4709b3a271a9SManish Rangankar 			iscsi_unblock_session(ddb_entry->sess);
4710b3a271a9SManish Rangankar 		} else {
4711b3a271a9SManish Rangankar 			/* Trigger relogin */
471213483730SMike Christie 			if (ddb_entry->ddb_type == FLASH_DDB) {
471399c6a33bSAdheer Chandravanshi 				if (!(test_bit(DF_RELOGIN, &ddb_entry->flags) ||
471499c6a33bSAdheer Chandravanshi 				      test_bit(DF_DISABLE_RELOGIN,
471599c6a33bSAdheer Chandravanshi 					       &ddb_entry->flags)))
471613483730SMike Christie 					qla4xxx_arm_relogin_timer(ddb_entry);
471713483730SMike Christie 			} else
4718b3a271a9SManish Rangankar 				iscsi_session_failure(cls_session->dd_data,
4719b3a271a9SManish Rangankar 						      ISCSI_ERR_CONN_FAILED);
4720b3a271a9SManish Rangankar 		}
4721b3a271a9SManish Rangankar 	}
4722b3a271a9SManish Rangankar }
4723b3a271a9SManish Rangankar 
472413483730SMike Christie int qla4xxx_unblock_flash_ddb(struct iscsi_cls_session *cls_session)
472513483730SMike Christie {
472613483730SMike Christie 	struct iscsi_session *sess;
472713483730SMike Christie 	struct ddb_entry *ddb_entry;
472813483730SMike Christie 	struct scsi_qla_host *ha;
472913483730SMike Christie 
473013483730SMike Christie 	sess = cls_session->dd_data;
473113483730SMike Christie 	ddb_entry = sess->dd_data;
473213483730SMike Christie 	ha = ddb_entry->ha;
473313483730SMike Christie 	ql4_printk(KERN_INFO, ha, "scsi%ld: %s: ddb[%d]"
473413483730SMike Christie 		   " unblock session\n", ha->host_no, __func__,
473513483730SMike Christie 		   ddb_entry->fw_ddb_index);
473613483730SMike Christie 
473713483730SMike Christie 	iscsi_unblock_session(ddb_entry->sess);
473813483730SMike Christie 
473913483730SMike Christie 	/* Start scan target */
474013483730SMike Christie 	if (test_bit(AF_ONLINE, &ha->flags)) {
474113483730SMike Christie 		ql4_printk(KERN_INFO, ha, "scsi%ld: %s: ddb[%d]"
474213483730SMike Christie 			   " start scan\n", ha->host_no, __func__,
474313483730SMike Christie 			   ddb_entry->fw_ddb_index);
474413483730SMike Christie 		scsi_queue_work(ha->host, &ddb_entry->sess->scan_work);
474513483730SMike Christie 	}
474613483730SMike Christie 	return QLA_SUCCESS;
474713483730SMike Christie }
474813483730SMike Christie 
474913483730SMike Christie int qla4xxx_unblock_ddb(struct iscsi_cls_session *cls_session)
475013483730SMike Christie {
475113483730SMike Christie 	struct iscsi_session *sess;
475213483730SMike Christie 	struct ddb_entry *ddb_entry;
475313483730SMike Christie 	struct scsi_qla_host *ha;
475480c53e64SManish Rangankar 	int status = QLA_SUCCESS;
475513483730SMike Christie 
475613483730SMike Christie 	sess = cls_session->dd_data;
475713483730SMike Christie 	ddb_entry = sess->dd_data;
475813483730SMike Christie 	ha = ddb_entry->ha;
475913483730SMike Christie 	ql4_printk(KERN_INFO, ha, "scsi%ld: %s: ddb[%d]"
476013483730SMike Christie 		   " unblock user space session\n", ha->host_no, __func__,
476113483730SMike Christie 		   ddb_entry->fw_ddb_index);
476280c53e64SManish Rangankar 
476380c53e64SManish Rangankar 	if (!iscsi_is_session_online(cls_session)) {
476413483730SMike Christie 		iscsi_conn_start(ddb_entry->conn);
476513483730SMike Christie 		iscsi_conn_login_event(ddb_entry->conn,
476613483730SMike Christie 				       ISCSI_CONN_STATE_LOGGED_IN);
476780c53e64SManish Rangankar 	} else {
476880c53e64SManish Rangankar 		ql4_printk(KERN_INFO, ha,
476980c53e64SManish Rangankar 			   "scsi%ld: %s: ddb[%d] session [%d] already logged in\n",
477080c53e64SManish Rangankar 			   ha->host_no, __func__, ddb_entry->fw_ddb_index,
477180c53e64SManish Rangankar 			   cls_session->sid);
477280c53e64SManish Rangankar 		status = QLA_ERROR;
477380c53e64SManish Rangankar 	}
477413483730SMike Christie 
477580c53e64SManish Rangankar 	return status;
477613483730SMike Christie }
477713483730SMike Christie 
47782d7924e6SVikas Chaudhary static void qla4xxx_relogin_all_devices(struct scsi_qla_host *ha)
47792d7924e6SVikas Chaudhary {
4780b3a271a9SManish Rangankar 	iscsi_host_for_each_session(ha->host, qla4xxx_relogin_devices);
47812d7924e6SVikas Chaudhary }
47822d7924e6SVikas Chaudhary 
478313483730SMike Christie static void qla4xxx_relogin_flash_ddb(struct iscsi_cls_session *cls_sess)
478413483730SMike Christie {
478513483730SMike Christie 	uint16_t relogin_timer;
478613483730SMike Christie 	struct iscsi_session *sess;
478713483730SMike Christie 	struct ddb_entry *ddb_entry;
478813483730SMike Christie 	struct scsi_qla_host *ha;
478913483730SMike Christie 
479013483730SMike Christie 	sess = cls_sess->dd_data;
479113483730SMike Christie 	ddb_entry = sess->dd_data;
479213483730SMike Christie 	ha = ddb_entry->ha;
479313483730SMike Christie 
479413483730SMike Christie 	relogin_timer = max(ddb_entry->default_relogin_timeout,
479513483730SMike Christie 			    (uint16_t)RELOGIN_TOV);
479613483730SMike Christie 	atomic_set(&ddb_entry->relogin_timer, relogin_timer);
479713483730SMike Christie 
479813483730SMike Christie 	DEBUG2(ql4_printk(KERN_INFO, ha,
479913483730SMike Christie 			  "scsi%ld: Relogin index [%d]. TOV=%d\n", ha->host_no,
480013483730SMike Christie 			  ddb_entry->fw_ddb_index, relogin_timer));
480113483730SMike Christie 
480213483730SMike Christie 	qla4xxx_login_flash_ddb(cls_sess);
480313483730SMike Christie }
480413483730SMike Christie 
480513483730SMike Christie static void qla4xxx_dpc_relogin(struct iscsi_cls_session *cls_sess)
480613483730SMike Christie {
480713483730SMike Christie 	struct iscsi_session *sess;
480813483730SMike Christie 	struct ddb_entry *ddb_entry;
480913483730SMike Christie 	struct scsi_qla_host *ha;
481013483730SMike Christie 
481113483730SMike Christie 	sess = cls_sess->dd_data;
481213483730SMike Christie 	ddb_entry = sess->dd_data;
481313483730SMike Christie 	ha = ddb_entry->ha;
481413483730SMike Christie 
481513483730SMike Christie 	if (!(ddb_entry->ddb_type == FLASH_DDB))
481613483730SMike Christie 		return;
481713483730SMike Christie 
481899c6a33bSAdheer Chandravanshi 	if (test_bit(DF_DISABLE_RELOGIN, &ddb_entry->flags))
481999c6a33bSAdheer Chandravanshi 		return;
482099c6a33bSAdheer Chandravanshi 
482113483730SMike Christie 	if (test_and_clear_bit(DF_RELOGIN, &ddb_entry->flags) &&
482213483730SMike Christie 	    !iscsi_is_session_online(cls_sess)) {
482313483730SMike Christie 		DEBUG2(ql4_printk(KERN_INFO, ha,
482413483730SMike Christie 				  "relogin issued\n"));
482513483730SMike Christie 		qla4xxx_relogin_flash_ddb(cls_sess);
482613483730SMike Christie 	}
482713483730SMike Christie }
482813483730SMike Christie 
4829f4f5df23SVikas Chaudhary void qla4xxx_wake_dpc(struct scsi_qla_host *ha)
4830f4f5df23SVikas Chaudhary {
48311b46807eSLalit Chandivade 	if (ha->dpc_thread)
4832f4f5df23SVikas Chaudhary 		queue_work(ha->dpc_thread, &ha->dpc_work);
4833f4f5df23SVikas Chaudhary }
4834f4f5df23SVikas Chaudhary 
4835ff884430SVikas Chaudhary static struct qla4_work_evt *
4836ff884430SVikas Chaudhary qla4xxx_alloc_work(struct scsi_qla_host *ha, uint32_t data_size,
4837ff884430SVikas Chaudhary 		   enum qla4_work_type type)
4838ff884430SVikas Chaudhary {
4839ff884430SVikas Chaudhary 	struct qla4_work_evt *e;
4840ff884430SVikas Chaudhary 	uint32_t size = sizeof(struct qla4_work_evt) + data_size;
4841ff884430SVikas Chaudhary 
4842ff884430SVikas Chaudhary 	e = kzalloc(size, GFP_ATOMIC);
4843ff884430SVikas Chaudhary 	if (!e)
4844ff884430SVikas Chaudhary 		return NULL;
4845ff884430SVikas Chaudhary 
4846ff884430SVikas Chaudhary 	INIT_LIST_HEAD(&e->list);
4847ff884430SVikas Chaudhary 	e->type = type;
4848ff884430SVikas Chaudhary 	return e;
4849ff884430SVikas Chaudhary }
4850ff884430SVikas Chaudhary 
4851ff884430SVikas Chaudhary static void qla4xxx_post_work(struct scsi_qla_host *ha,
4852ff884430SVikas Chaudhary 			     struct qla4_work_evt *e)
4853ff884430SVikas Chaudhary {
4854ff884430SVikas Chaudhary 	unsigned long flags;
4855ff884430SVikas Chaudhary 
4856ff884430SVikas Chaudhary 	spin_lock_irqsave(&ha->work_lock, flags);
4857ff884430SVikas Chaudhary 	list_add_tail(&e->list, &ha->work_list);
4858ff884430SVikas Chaudhary 	spin_unlock_irqrestore(&ha->work_lock, flags);
4859ff884430SVikas Chaudhary 	qla4xxx_wake_dpc(ha);
4860ff884430SVikas Chaudhary }
4861ff884430SVikas Chaudhary 
4862ff884430SVikas Chaudhary int qla4xxx_post_aen_work(struct scsi_qla_host *ha,
4863ff884430SVikas Chaudhary 			  enum iscsi_host_event_code aen_code,
4864ff884430SVikas Chaudhary 			  uint32_t data_size, uint8_t *data)
4865ff884430SVikas Chaudhary {
4866ff884430SVikas Chaudhary 	struct qla4_work_evt *e;
4867ff884430SVikas Chaudhary 
4868ff884430SVikas Chaudhary 	e = qla4xxx_alloc_work(ha, data_size, QLA4_EVENT_AEN);
4869ff884430SVikas Chaudhary 	if (!e)
4870ff884430SVikas Chaudhary 		return QLA_ERROR;
4871ff884430SVikas Chaudhary 
4872ff884430SVikas Chaudhary 	e->u.aen.code = aen_code;
4873ff884430SVikas Chaudhary 	e->u.aen.data_size = data_size;
4874ff884430SVikas Chaudhary 	memcpy(e->u.aen.data, data, data_size);
4875ff884430SVikas Chaudhary 
4876ff884430SVikas Chaudhary 	qla4xxx_post_work(ha, e);
4877ff884430SVikas Chaudhary 
4878ff884430SVikas Chaudhary 	return QLA_SUCCESS;
4879ff884430SVikas Chaudhary }
4880ff884430SVikas Chaudhary 
4881c0b9d3f7SVikas Chaudhary int qla4xxx_post_ping_evt_work(struct scsi_qla_host *ha,
4882c0b9d3f7SVikas Chaudhary 			       uint32_t status, uint32_t pid,
4883c0b9d3f7SVikas Chaudhary 			       uint32_t data_size, uint8_t *data)
4884c0b9d3f7SVikas Chaudhary {
4885c0b9d3f7SVikas Chaudhary 	struct qla4_work_evt *e;
4886c0b9d3f7SVikas Chaudhary 
4887c0b9d3f7SVikas Chaudhary 	e = qla4xxx_alloc_work(ha, data_size, QLA4_EVENT_PING_STATUS);
4888c0b9d3f7SVikas Chaudhary 	if (!e)
4889c0b9d3f7SVikas Chaudhary 		return QLA_ERROR;
4890c0b9d3f7SVikas Chaudhary 
4891c0b9d3f7SVikas Chaudhary 	e->u.ping.status = status;
4892c0b9d3f7SVikas Chaudhary 	e->u.ping.pid = pid;
4893c0b9d3f7SVikas Chaudhary 	e->u.ping.data_size = data_size;
4894c0b9d3f7SVikas Chaudhary 	memcpy(e->u.ping.data, data, data_size);
4895c0b9d3f7SVikas Chaudhary 
4896c0b9d3f7SVikas Chaudhary 	qla4xxx_post_work(ha, e);
4897c0b9d3f7SVikas Chaudhary 
4898c0b9d3f7SVikas Chaudhary 	return QLA_SUCCESS;
4899c0b9d3f7SVikas Chaudhary }
4900c0b9d3f7SVikas Chaudhary 
4901a7380a65SVikas Chaudhary static void qla4xxx_do_work(struct scsi_qla_host *ha)
4902ff884430SVikas Chaudhary {
4903ff884430SVikas Chaudhary 	struct qla4_work_evt *e, *tmp;
4904ff884430SVikas Chaudhary 	unsigned long flags;
4905ff884430SVikas Chaudhary 	LIST_HEAD(work);
4906ff884430SVikas Chaudhary 
4907ff884430SVikas Chaudhary 	spin_lock_irqsave(&ha->work_lock, flags);
4908ff884430SVikas Chaudhary 	list_splice_init(&ha->work_list, &work);
4909ff884430SVikas Chaudhary 	spin_unlock_irqrestore(&ha->work_lock, flags);
4910ff884430SVikas Chaudhary 
4911ff884430SVikas Chaudhary 	list_for_each_entry_safe(e, tmp, &work, list) {
4912ff884430SVikas Chaudhary 		list_del_init(&e->list);
4913ff884430SVikas Chaudhary 
4914ff884430SVikas Chaudhary 		switch (e->type) {
4915ff884430SVikas Chaudhary 		case QLA4_EVENT_AEN:
4916ff884430SVikas Chaudhary 			iscsi_post_host_event(ha->host_no,
4917ff884430SVikas Chaudhary 					      &qla4xxx_iscsi_transport,
4918ff884430SVikas Chaudhary 					      e->u.aen.code,
4919ff884430SVikas Chaudhary 					      e->u.aen.data_size,
4920ff884430SVikas Chaudhary 					      e->u.aen.data);
4921ff884430SVikas Chaudhary 			break;
4922c0b9d3f7SVikas Chaudhary 		case QLA4_EVENT_PING_STATUS:
4923c0b9d3f7SVikas Chaudhary 			iscsi_ping_comp_event(ha->host_no,
4924c0b9d3f7SVikas Chaudhary 					      &qla4xxx_iscsi_transport,
4925c0b9d3f7SVikas Chaudhary 					      e->u.ping.status,
4926c0b9d3f7SVikas Chaudhary 					      e->u.ping.pid,
4927c0b9d3f7SVikas Chaudhary 					      e->u.ping.data_size,
4928c0b9d3f7SVikas Chaudhary 					      e->u.ping.data);
4929c0b9d3f7SVikas Chaudhary 			break;
4930ff884430SVikas Chaudhary 		default:
4931ff884430SVikas Chaudhary 			ql4_printk(KERN_WARNING, ha, "event type: 0x%x not "
4932ff884430SVikas Chaudhary 				   "supported", e->type);
4933ff884430SVikas Chaudhary 		}
4934ff884430SVikas Chaudhary 		kfree(e);
4935ff884430SVikas Chaudhary 	}
4936ff884430SVikas Chaudhary }
4937ff884430SVikas Chaudhary 
4938afaf5a2dSDavid Somayajulu /**
4939afaf5a2dSDavid Somayajulu  * qla4xxx_do_dpc - dpc routine
4940afaf5a2dSDavid Somayajulu  * @data: in our case pointer to adapter structure
4941afaf5a2dSDavid Somayajulu  *
4942afaf5a2dSDavid Somayajulu  * This routine is a task that is schedule by the interrupt handler
4943afaf5a2dSDavid Somayajulu  * to perform the background processing for interrupts.  We put it
4944afaf5a2dSDavid Somayajulu  * on a task queue that is consumed whenever the scheduler runs; that's
4945afaf5a2dSDavid Somayajulu  * so you can do anything (i.e. put the process to sleep etc).  In fact,
4946afaf5a2dSDavid Somayajulu  * the mid-level tries to sleep when it reaches the driver threshold
4947afaf5a2dSDavid Somayajulu  * "host->can_queue". This can cause a panic if we were in our interrupt code.
4948afaf5a2dSDavid Somayajulu  **/
4949c4028958SDavid Howells static void qla4xxx_do_dpc(struct work_struct *work)
4950afaf5a2dSDavid Somayajulu {
4951c4028958SDavid Howells 	struct scsi_qla_host *ha =
4952c4028958SDavid Howells 		container_of(work, struct scsi_qla_host, dpc_work);
4953477ffb9dSDavid C Somayajulu 	int status = QLA_ERROR;
4954afaf5a2dSDavid Somayajulu 
4955f26b9044SDavid C Somayajulu 	DEBUG2(printk("scsi%ld: %s: DPC handler waking up."
4956f4f5df23SVikas Chaudhary 	    "flags = 0x%08lx, dpc_flags = 0x%08lx\n",
4957f4f5df23SVikas Chaudhary 	    ha->host_no, __func__, ha->flags, ha->dpc_flags))
4958afaf5a2dSDavid Somayajulu 
4959afaf5a2dSDavid Somayajulu 	/* Initialization not yet finished. Don't do anything yet. */
4960afaf5a2dSDavid Somayajulu 	if (!test_bit(AF_INIT_DONE, &ha->flags))
49611b46807eSLalit Chandivade 		return;
4962afaf5a2dSDavid Somayajulu 
49632232be0dSLalit Chandivade 	if (test_bit(AF_EEH_BUSY, &ha->flags)) {
49642232be0dSLalit Chandivade 		DEBUG2(printk(KERN_INFO "scsi%ld: %s: flags = %lx\n",
49652232be0dSLalit Chandivade 		    ha->host_no, __func__, ha->flags));
49661b46807eSLalit Chandivade 		return;
49672232be0dSLalit Chandivade 	}
49682232be0dSLalit Chandivade 
4969ff884430SVikas Chaudhary 	/* post events to application */
4970ff884430SVikas Chaudhary 	qla4xxx_do_work(ha);
4971ff884430SVikas Chaudhary 
49726e7b4292SVikas Chaudhary 	if (is_qla80XX(ha)) {
4973f4f5df23SVikas Chaudhary 		if (test_bit(DPC_HA_UNRECOVERABLE, &ha->dpc_flags)) {
4974b37ca418SVikas Chaudhary 			if (is_qla8032(ha) || is_qla8042(ha)) {
4975546fef27STej Parkash 				ql4_printk(KERN_INFO, ha, "%s: disabling pause transmit on port 0 & 1.\n",
4976546fef27STej Parkash 					   __func__);
4977546fef27STej Parkash 				/* disable pause frame for ISP83xx */
4978546fef27STej Parkash 				qla4_83xx_disable_pause(ha);
4979546fef27STej Parkash 			}
4980546fef27STej Parkash 
498133693c7aSVikas Chaudhary 			ha->isp_ops->idc_lock(ha);
498233693c7aSVikas Chaudhary 			qla4_8xxx_wr_direct(ha, QLA8XXX_CRB_DEV_STATE,
4983de8c72daSVikas Chaudhary 					    QLA8XXX_DEV_FAILED);
498433693c7aSVikas Chaudhary 			ha->isp_ops->idc_unlock(ha);
4985f4f5df23SVikas Chaudhary 			ql4_printk(KERN_INFO, ha, "HW State: FAILED\n");
4986f4f5df23SVikas Chaudhary 			qla4_8xxx_device_state_handler(ha);
4987f4f5df23SVikas Chaudhary 		}
4988320a61deSNilesh Javali 
49897ab284c9SNilesh Javali 		if (test_bit(DPC_POST_IDC_ACK, &ha->dpc_flags)) {
49907ab284c9SNilesh Javali 			if (is_qla8042(ha)) {
49917ab284c9SNilesh Javali 				if (ha->idc_info.info2 &
49927ab284c9SNilesh Javali 				    ENABLE_INTERNAL_LOOPBACK) {
49937ab284c9SNilesh Javali 					ql4_printk(KERN_INFO, ha, "%s: Disabling ACB\n",
49947ab284c9SNilesh Javali 						   __func__);
49957ab284c9SNilesh Javali 					status = qla4_84xx_config_acb(ha,
49967ab284c9SNilesh Javali 							    ACB_CONFIG_DISABLE);
49977ab284c9SNilesh Javali 					if (status != QLA_SUCCESS) {
49987ab284c9SNilesh Javali 						ql4_printk(KERN_INFO, ha, "%s: ACB config failed\n",
49997ab284c9SNilesh Javali 							   __func__);
50007ab284c9SNilesh Javali 					}
50017ab284c9SNilesh Javali 				}
50027ab284c9SNilesh Javali 			}
5003320a61deSNilesh Javali 			qla4_83xx_post_idc_ack(ha);
50047ab284c9SNilesh Javali 			clear_bit(DPC_POST_IDC_ACK, &ha->dpc_flags);
50057ab284c9SNilesh Javali 		}
50067ab284c9SNilesh Javali 
50077ab284c9SNilesh Javali 		if (is_qla8042(ha) &&
50087ab284c9SNilesh Javali 		    test_bit(DPC_RESTORE_ACB, &ha->dpc_flags)) {
50097ab284c9SNilesh Javali 			ql4_printk(KERN_INFO, ha, "%s: Restoring ACB\n",
50107ab284c9SNilesh Javali 				   __func__);
50117ab284c9SNilesh Javali 			if (qla4_84xx_config_acb(ha, ACB_CONFIG_SET) !=
50127ab284c9SNilesh Javali 			    QLA_SUCCESS) {
50137ab284c9SNilesh Javali 				ql4_printk(KERN_INFO, ha, "%s: ACB config failed ",
50147ab284c9SNilesh Javali 					   __func__);
50157ab284c9SNilesh Javali 			}
50167ab284c9SNilesh Javali 			clear_bit(DPC_RESTORE_ACB, &ha->dpc_flags);
50177ab284c9SNilesh Javali 		}
5018320a61deSNilesh Javali 
5019f4f5df23SVikas Chaudhary 		if (test_and_clear_bit(DPC_HA_NEED_QUIESCENT, &ha->dpc_flags)) {
5020f4f5df23SVikas Chaudhary 			qla4_8xxx_need_qsnt_handler(ha);
5021f4f5df23SVikas Chaudhary 		}
5022f4f5df23SVikas Chaudhary 	}
5023f4f5df23SVikas Chaudhary 
5024f4f5df23SVikas Chaudhary 	if (!test_bit(DPC_RESET_ACTIVE, &ha->dpc_flags) &&
5025f4f5df23SVikas Chaudhary 	    (test_bit(DPC_RESET_HA, &ha->dpc_flags) ||
5026afaf5a2dSDavid Somayajulu 	    test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags) ||
5027f4f5df23SVikas Chaudhary 	    test_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags))) {
50286e7b4292SVikas Chaudhary 		if ((is_qla8022(ha) && ql4xdontresethba) ||
5029b37ca418SVikas Chaudhary 		    ((is_qla8032(ha) || is_qla8042(ha)) &&
5030b37ca418SVikas Chaudhary 		     qla4_83xx_idc_dontreset(ha))) {
5031f4f5df23SVikas Chaudhary 			DEBUG2(printk("scsi%ld: %s: Don't Reset HBA\n",
5032f4f5df23SVikas Chaudhary 			    ha->host_no, __func__));
5033f4f5df23SVikas Chaudhary 			clear_bit(DPC_RESET_HA, &ha->dpc_flags);
5034f4f5df23SVikas Chaudhary 			clear_bit(DPC_RESET_HA_INTR, &ha->dpc_flags);
5035f4f5df23SVikas Chaudhary 			clear_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags);
5036f4f5df23SVikas Chaudhary 			goto dpc_post_reset_ha;
5037f4f5df23SVikas Chaudhary 		}
5038f4f5df23SVikas Chaudhary 		if (test_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags) ||
5039f26b9044SDavid C Somayajulu 		    test_bit(DPC_RESET_HA, &ha->dpc_flags))
5040f4f5df23SVikas Chaudhary 			qla4xxx_recover_adapter(ha);
5041afaf5a2dSDavid Somayajulu 
5042477ffb9dSDavid C Somayajulu 		if (test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags)) {
5043afaf5a2dSDavid Somayajulu 			uint8_t wait_time = RESET_INTR_TOV;
5044afaf5a2dSDavid Somayajulu 
5045afaf5a2dSDavid Somayajulu 			while ((readw(&ha->reg->ctrl_status) &
5046afaf5a2dSDavid Somayajulu 				(CSR_SOFT_RESET | CSR_FORCE_SOFT_RESET)) != 0) {
5047afaf5a2dSDavid Somayajulu 				if (--wait_time == 0)
5048afaf5a2dSDavid Somayajulu 					break;
5049afaf5a2dSDavid Somayajulu 				msleep(1000);
5050afaf5a2dSDavid Somayajulu 			}
5051afaf5a2dSDavid Somayajulu 			if (wait_time == 0)
5052afaf5a2dSDavid Somayajulu 				DEBUG2(printk("scsi%ld: %s: SR|FSR "
5053afaf5a2dSDavid Somayajulu 					      "bit not cleared-- resetting\n",
5054afaf5a2dSDavid Somayajulu 					      ha->host_no, __func__));
5055f4f5df23SVikas Chaudhary 			qla4xxx_abort_active_cmds(ha, DID_RESET << 16);
5056477ffb9dSDavid C Somayajulu 			if (ql4xxx_lock_drvr_wait(ha) == QLA_SUCCESS) {
5057477ffb9dSDavid C Somayajulu 				qla4xxx_process_aen(ha, FLUSH_DDB_CHANGED_AENS);
5058f4f5df23SVikas Chaudhary 				status = qla4xxx_recover_adapter(ha);
5059477ffb9dSDavid C Somayajulu 			}
5060477ffb9dSDavid C Somayajulu 			clear_bit(DPC_RESET_HA_INTR, &ha->dpc_flags);
5061477ffb9dSDavid C Somayajulu 			if (status == QLA_SUCCESS)
5062f4f5df23SVikas Chaudhary 				ha->isp_ops->enable_intrs(ha);
5063afaf5a2dSDavid Somayajulu 		}
5064afaf5a2dSDavid Somayajulu 	}
5065afaf5a2dSDavid Somayajulu 
5066f4f5df23SVikas Chaudhary dpc_post_reset_ha:
5067afaf5a2dSDavid Somayajulu 	/* ---- process AEN? --- */
5068afaf5a2dSDavid Somayajulu 	if (test_and_clear_bit(DPC_AEN, &ha->dpc_flags))
5069afaf5a2dSDavid Somayajulu 		qla4xxx_process_aen(ha, PROCESS_ALL_AENS);
5070afaf5a2dSDavid Somayajulu 
5071afaf5a2dSDavid Somayajulu 	/* ---- Get DHCP IP Address? --- */
5072afaf5a2dSDavid Somayajulu 	if (test_and_clear_bit(DPC_GET_DHCP_IP_ADDR, &ha->dpc_flags))
5073afaf5a2dSDavid Somayajulu 		qla4xxx_get_dhcp_ip_address(ha);
5074afaf5a2dSDavid Somayajulu 
507513483730SMike Christie 	/* ---- relogin device? --- */
507613483730SMike Christie 	if (adapter_up(ha) &&
507713483730SMike Christie 	    test_and_clear_bit(DPC_RELOGIN_DEVICE, &ha->dpc_flags)) {
507813483730SMike Christie 		iscsi_host_for_each_session(ha->host, qla4xxx_dpc_relogin);
507913483730SMike Christie 	}
508013483730SMike Christie 
5081065aa1b4SVikas Chaudhary 	/* ---- link change? --- */
5082026fbd3aSNilesh Javali 	if (!test_bit(AF_LOOPBACK, &ha->flags) &&
5083026fbd3aSNilesh Javali 	    test_and_clear_bit(DPC_LINK_CHANGED, &ha->dpc_flags)) {
5084065aa1b4SVikas Chaudhary 		if (!test_bit(AF_LINK_UP, &ha->flags)) {
5085065aa1b4SVikas Chaudhary 			/* ---- link down? --- */
50862d7924e6SVikas Chaudhary 			qla4xxx_mark_all_devices_missing(ha);
5087065aa1b4SVikas Chaudhary 		} else {
5088065aa1b4SVikas Chaudhary 			/* ---- link up? --- *
5089065aa1b4SVikas Chaudhary 			 * F/W will auto login to all devices ONLY ONCE after
5090065aa1b4SVikas Chaudhary 			 * link up during driver initialization and runtime
5091065aa1b4SVikas Chaudhary 			 * fatal error recovery.  Therefore, the driver must
5092065aa1b4SVikas Chaudhary 			 * manually relogin to devices when recovering from
5093065aa1b4SVikas Chaudhary 			 * connection failures, logouts, expired KATO, etc. */
509413483730SMike Christie 			if (test_and_clear_bit(AF_BUILD_DDB_LIST, &ha->flags)) {
509513483730SMike Christie 				qla4xxx_build_ddb_list(ha, ha->is_reset);
509613483730SMike Christie 				iscsi_host_for_each_session(ha->host,
509713483730SMike Christie 						qla4xxx_login_flash_ddb);
509813483730SMike Christie 			} else
50992d7924e6SVikas Chaudhary 				qla4xxx_relogin_all_devices(ha);
5100065aa1b4SVikas Chaudhary 		}
5101065aa1b4SVikas Chaudhary 	}
5102afaf5a2dSDavid Somayajulu }
5103afaf5a2dSDavid Somayajulu 
5104afaf5a2dSDavid Somayajulu /**
5105afaf5a2dSDavid Somayajulu  * qla4xxx_free_adapter - release the adapter
5106afaf5a2dSDavid Somayajulu  * @ha: pointer to adapter structure
5107afaf5a2dSDavid Somayajulu  **/
5108afaf5a2dSDavid Somayajulu static void qla4xxx_free_adapter(struct scsi_qla_host *ha)
5109afaf5a2dSDavid Somayajulu {
51108a288960SSarang Radke 	qla4xxx_abort_active_cmds(ha, DID_NO_CONNECT << 16);
5111afaf5a2dSDavid Somayajulu 
5112afaf5a2dSDavid Somayajulu 	/* Turn-off interrupts on the card. */
5113f4f5df23SVikas Chaudhary 	ha->isp_ops->disable_intrs(ha);
5114afaf5a2dSDavid Somayajulu 
5115d9e62e51SVikas Chaudhary 	if (is_qla40XX(ha)) {
5116d9e62e51SVikas Chaudhary 		writel(set_rmask(CSR_SCSI_PROCESSOR_INTR),
5117d9e62e51SVikas Chaudhary 		       &ha->reg->ctrl_status);
5118d9e62e51SVikas Chaudhary 		readl(&ha->reg->ctrl_status);
5119d9e62e51SVikas Chaudhary 	} else if (is_qla8022(ha)) {
51207664a1fdSVikas Chaudhary 		writel(0, &ha->qla4_82xx_reg->host_int);
51217664a1fdSVikas Chaudhary 		readl(&ha->qla4_82xx_reg->host_int);
5122b37ca418SVikas Chaudhary 	} else if (is_qla8032(ha) || is_qla8042(ha)) {
5123fbd8107cSVikas Chaudhary 		writel(0, &ha->qla4_83xx_reg->risc_intr);
5124fbd8107cSVikas Chaudhary 		readl(&ha->qla4_83xx_reg->risc_intr);
5125d9e62e51SVikas Chaudhary 	}
5126d9e62e51SVikas Chaudhary 
5127afaf5a2dSDavid Somayajulu 	/* Remove timer thread, if present */
5128afaf5a2dSDavid Somayajulu 	if (ha->timer_active)
5129afaf5a2dSDavid Somayajulu 		qla4xxx_stop_timer(ha);
5130afaf5a2dSDavid Somayajulu 
5131f4f5df23SVikas Chaudhary 	/* Kill the kernel thread for this host */
5132f4f5df23SVikas Chaudhary 	if (ha->dpc_thread)
5133f4f5df23SVikas Chaudhary 		destroy_workqueue(ha->dpc_thread);
5134f4f5df23SVikas Chaudhary 
5135b3a271a9SManish Rangankar 	/* Kill the kernel thread for this host */
5136b3a271a9SManish Rangankar 	if (ha->task_wq)
5137b3a271a9SManish Rangankar 		destroy_workqueue(ha->task_wq);
5138b3a271a9SManish Rangankar 
5139f4f5df23SVikas Chaudhary 	/* Put firmware in known state */
5140f4f5df23SVikas Chaudhary 	ha->isp_ops->reset_firmware(ha);
5141f4f5df23SVikas Chaudhary 
51426e7b4292SVikas Chaudhary 	if (is_qla80XX(ha)) {
514333693c7aSVikas Chaudhary 		ha->isp_ops->idc_lock(ha);
5144f4f5df23SVikas Chaudhary 		qla4_8xxx_clear_drv_active(ha);
514533693c7aSVikas Chaudhary 		ha->isp_ops->idc_unlock(ha);
5146f4f5df23SVikas Chaudhary 	}
5147f4f5df23SVikas Chaudhary 
5148afaf5a2dSDavid Somayajulu 	/* Detach interrupts */
5149f4f5df23SVikas Chaudhary 	qla4xxx_free_irqs(ha);
5150afaf5a2dSDavid Somayajulu 
5151bee4fe8eSDavid C Somayajulu 	/* free extra memory */
5152bee4fe8eSDavid C Somayajulu 	qla4xxx_mem_free(ha);
5153f4f5df23SVikas Chaudhary }
5154bee4fe8eSDavid C Somayajulu 
5155f4f5df23SVikas Chaudhary int qla4_8xxx_iospace_config(struct scsi_qla_host *ha)
5156f4f5df23SVikas Chaudhary {
5157f4f5df23SVikas Chaudhary 	int status = 0;
5158f4f5df23SVikas Chaudhary 	unsigned long mem_base, mem_len, db_base, db_len;
5159f4f5df23SVikas Chaudhary 	struct pci_dev *pdev = ha->pdev;
5160afaf5a2dSDavid Somayajulu 
5161f4f5df23SVikas Chaudhary 	status = pci_request_regions(pdev, DRIVER_NAME);
5162f4f5df23SVikas Chaudhary 	if (status) {
5163f4f5df23SVikas Chaudhary 		printk(KERN_WARNING
5164f4f5df23SVikas Chaudhary 		    "scsi(%ld) Failed to reserve PIO regions (%s) "
5165f4f5df23SVikas Chaudhary 		    "status=%d\n", ha->host_no, pci_name(pdev), status);
5166f4f5df23SVikas Chaudhary 		goto iospace_error_exit;
5167f4f5df23SVikas Chaudhary 	}
5168f4f5df23SVikas Chaudhary 
5169f4f5df23SVikas Chaudhary 	DEBUG2(printk(KERN_INFO "%s: revision-id=%d\n",
51707d7311c4SSergei Shtylyov 	    __func__, pdev->revision));
51717d7311c4SSergei Shtylyov 	ha->revision_id = pdev->revision;
5172f4f5df23SVikas Chaudhary 
5173f4f5df23SVikas Chaudhary 	/* remap phys address */
5174f4f5df23SVikas Chaudhary 	mem_base = pci_resource_start(pdev, 0); /* 0 is for BAR 0 */
5175f4f5df23SVikas Chaudhary 	mem_len = pci_resource_len(pdev, 0);
5176f4f5df23SVikas Chaudhary 	DEBUG2(printk(KERN_INFO "%s: ioremap from %lx a size of %lx\n",
5177f4f5df23SVikas Chaudhary 	    __func__, mem_base, mem_len));
5178f4f5df23SVikas Chaudhary 
5179f4f5df23SVikas Chaudhary 	/* mapping of pcibase pointer */
5180f4f5df23SVikas Chaudhary 	ha->nx_pcibase = (unsigned long)ioremap(mem_base, mem_len);
5181f4f5df23SVikas Chaudhary 	if (!ha->nx_pcibase) {
5182f4f5df23SVikas Chaudhary 		printk(KERN_ERR
5183f4f5df23SVikas Chaudhary 		    "cannot remap MMIO (%s), aborting\n", pci_name(pdev));
5184f4f5df23SVikas Chaudhary 		pci_release_regions(ha->pdev);
5185f4f5df23SVikas Chaudhary 		goto iospace_error_exit;
5186f4f5df23SVikas Chaudhary 	}
5187f4f5df23SVikas Chaudhary 
5188f4f5df23SVikas Chaudhary 	/* Mapping of IO base pointer, door bell read and write pointer */
5189f4f5df23SVikas Chaudhary 
5190f4f5df23SVikas Chaudhary 	/* mapping of IO base pointer */
51916e7b4292SVikas Chaudhary 	if (is_qla8022(ha)) {
51926e7b4292SVikas Chaudhary 		ha->qla4_82xx_reg = (struct device_reg_82xx  __iomem *)
51936e7b4292SVikas Chaudhary 				    ((uint8_t *)ha->nx_pcibase + 0xbc000 +
51946e7b4292SVikas Chaudhary 				     (ha->pdev->devfn << 11));
51956e7b4292SVikas Chaudhary 		ha->nx_db_wr_ptr = (ha->pdev->devfn == 4 ? QLA82XX_CAM_RAM_DB1 :
51966e7b4292SVikas Chaudhary 				    QLA82XX_CAM_RAM_DB2);
5197b37ca418SVikas Chaudhary 	} else if (is_qla8032(ha) || is_qla8042(ha)) {
51986e7b4292SVikas Chaudhary 		ha->qla4_83xx_reg = (struct device_reg_83xx __iomem *)
51996e7b4292SVikas Chaudhary 				    ((uint8_t *)ha->nx_pcibase);
52006e7b4292SVikas Chaudhary 	}
5201f4f5df23SVikas Chaudhary 
5202f4f5df23SVikas Chaudhary 	db_base = pci_resource_start(pdev, 4);  /* doorbell is on bar 4 */
5203f4f5df23SVikas Chaudhary 	db_len = pci_resource_len(pdev, 4);
5204f4f5df23SVikas Chaudhary 
52052657c800SShyam Sundar 	return 0;
5206f4f5df23SVikas Chaudhary iospace_error_exit:
5207f4f5df23SVikas Chaudhary 	return -ENOMEM;
5208afaf5a2dSDavid Somayajulu }
5209afaf5a2dSDavid Somayajulu 
5210afaf5a2dSDavid Somayajulu /***
5211afaf5a2dSDavid Somayajulu  * qla4xxx_iospace_config - maps registers
5212afaf5a2dSDavid Somayajulu  * @ha: pointer to adapter structure
5213afaf5a2dSDavid Somayajulu  *
5214afaf5a2dSDavid Somayajulu  * This routines maps HBA's registers from the pci address space
5215afaf5a2dSDavid Somayajulu  * into the kernel virtual address space for memory mapped i/o.
5216afaf5a2dSDavid Somayajulu  **/
5217f4f5df23SVikas Chaudhary int qla4xxx_iospace_config(struct scsi_qla_host *ha)
5218afaf5a2dSDavid Somayajulu {
5219afaf5a2dSDavid Somayajulu 	unsigned long pio, pio_len, pio_flags;
5220afaf5a2dSDavid Somayajulu 	unsigned long mmio, mmio_len, mmio_flags;
5221afaf5a2dSDavid Somayajulu 
5222afaf5a2dSDavid Somayajulu 	pio = pci_resource_start(ha->pdev, 0);
5223afaf5a2dSDavid Somayajulu 	pio_len = pci_resource_len(ha->pdev, 0);
5224afaf5a2dSDavid Somayajulu 	pio_flags = pci_resource_flags(ha->pdev, 0);
5225afaf5a2dSDavid Somayajulu 	if (pio_flags & IORESOURCE_IO) {
5226afaf5a2dSDavid Somayajulu 		if (pio_len < MIN_IOBASE_LEN) {
5227c2660df3SVikas Chaudhary 			ql4_printk(KERN_WARNING, ha,
5228afaf5a2dSDavid Somayajulu 				"Invalid PCI I/O region size\n");
5229afaf5a2dSDavid Somayajulu 			pio = 0;
5230afaf5a2dSDavid Somayajulu 		}
5231afaf5a2dSDavid Somayajulu 	} else {
5232c2660df3SVikas Chaudhary 		ql4_printk(KERN_WARNING, ha, "region #0 not a PIO resource\n");
5233afaf5a2dSDavid Somayajulu 		pio = 0;
5234afaf5a2dSDavid Somayajulu 	}
5235afaf5a2dSDavid Somayajulu 
5236afaf5a2dSDavid Somayajulu 	/* Use MMIO operations for all accesses. */
5237afaf5a2dSDavid Somayajulu 	mmio = pci_resource_start(ha->pdev, 1);
5238afaf5a2dSDavid Somayajulu 	mmio_len = pci_resource_len(ha->pdev, 1);
5239afaf5a2dSDavid Somayajulu 	mmio_flags = pci_resource_flags(ha->pdev, 1);
5240afaf5a2dSDavid Somayajulu 
5241afaf5a2dSDavid Somayajulu 	if (!(mmio_flags & IORESOURCE_MEM)) {
5242c2660df3SVikas Chaudhary 		ql4_printk(KERN_ERR, ha,
5243afaf5a2dSDavid Somayajulu 		    "region #0 not an MMIO resource, aborting\n");
5244afaf5a2dSDavid Somayajulu 
5245afaf5a2dSDavid Somayajulu 		goto iospace_error_exit;
5246afaf5a2dSDavid Somayajulu 	}
5247c2660df3SVikas Chaudhary 
5248afaf5a2dSDavid Somayajulu 	if (mmio_len < MIN_IOBASE_LEN) {
5249c2660df3SVikas Chaudhary 		ql4_printk(KERN_ERR, ha,
5250afaf5a2dSDavid Somayajulu 		    "Invalid PCI mem region size, aborting\n");
5251afaf5a2dSDavid Somayajulu 		goto iospace_error_exit;
5252afaf5a2dSDavid Somayajulu 	}
5253afaf5a2dSDavid Somayajulu 
5254afaf5a2dSDavid Somayajulu 	if (pci_request_regions(ha->pdev, DRIVER_NAME)) {
5255c2660df3SVikas Chaudhary 		ql4_printk(KERN_WARNING, ha,
5256afaf5a2dSDavid Somayajulu 		    "Failed to reserve PIO/MMIO regions\n");
5257afaf5a2dSDavid Somayajulu 
5258afaf5a2dSDavid Somayajulu 		goto iospace_error_exit;
5259afaf5a2dSDavid Somayajulu 	}
5260afaf5a2dSDavid Somayajulu 
5261afaf5a2dSDavid Somayajulu 	ha->pio_address = pio;
5262afaf5a2dSDavid Somayajulu 	ha->pio_length = pio_len;
5263afaf5a2dSDavid Somayajulu 	ha->reg = ioremap(mmio, MIN_IOBASE_LEN);
5264afaf5a2dSDavid Somayajulu 	if (!ha->reg) {
5265c2660df3SVikas Chaudhary 		ql4_printk(KERN_ERR, ha,
5266afaf5a2dSDavid Somayajulu 		    "cannot remap MMIO, aborting\n");
5267afaf5a2dSDavid Somayajulu 
5268afaf5a2dSDavid Somayajulu 		goto iospace_error_exit;
5269afaf5a2dSDavid Somayajulu 	}
5270afaf5a2dSDavid Somayajulu 
5271afaf5a2dSDavid Somayajulu 	return 0;
5272afaf5a2dSDavid Somayajulu 
5273afaf5a2dSDavid Somayajulu iospace_error_exit:
5274afaf5a2dSDavid Somayajulu 	return -ENOMEM;
5275afaf5a2dSDavid Somayajulu }
5276afaf5a2dSDavid Somayajulu 
5277f4f5df23SVikas Chaudhary static struct isp_operations qla4xxx_isp_ops = {
5278f4f5df23SVikas Chaudhary 	.iospace_config         = qla4xxx_iospace_config,
5279f4f5df23SVikas Chaudhary 	.pci_config             = qla4xxx_pci_config,
5280f4f5df23SVikas Chaudhary 	.disable_intrs          = qla4xxx_disable_intrs,
5281f4f5df23SVikas Chaudhary 	.enable_intrs           = qla4xxx_enable_intrs,
5282f4f5df23SVikas Chaudhary 	.start_firmware         = qla4xxx_start_firmware,
5283f4f5df23SVikas Chaudhary 	.intr_handler           = qla4xxx_intr_handler,
5284f4f5df23SVikas Chaudhary 	.interrupt_service_routine = qla4xxx_interrupt_service_routine,
5285f4f5df23SVikas Chaudhary 	.reset_chip             = qla4xxx_soft_reset,
5286f4f5df23SVikas Chaudhary 	.reset_firmware         = qla4xxx_hw_reset,
5287f4f5df23SVikas Chaudhary 	.queue_iocb             = qla4xxx_queue_iocb,
5288f4f5df23SVikas Chaudhary 	.complete_iocb          = qla4xxx_complete_iocb,
5289f4f5df23SVikas Chaudhary 	.rd_shdw_req_q_out      = qla4xxx_rd_shdw_req_q_out,
5290f4f5df23SVikas Chaudhary 	.rd_shdw_rsp_q_in       = qla4xxx_rd_shdw_rsp_q_in,
5291f4f5df23SVikas Chaudhary 	.get_sys_info           = qla4xxx_get_sys_info,
529233693c7aSVikas Chaudhary 	.queue_mailbox_command	= qla4xxx_queue_mbox_cmd,
529333693c7aSVikas Chaudhary 	.process_mailbox_interrupt = qla4xxx_process_mbox_intr,
5294f4f5df23SVikas Chaudhary };
5295f4f5df23SVikas Chaudhary 
52967664a1fdSVikas Chaudhary static struct isp_operations qla4_82xx_isp_ops = {
5297f4f5df23SVikas Chaudhary 	.iospace_config         = qla4_8xxx_iospace_config,
5298f4f5df23SVikas Chaudhary 	.pci_config             = qla4_8xxx_pci_config,
5299f8086f4fSVikas Chaudhary 	.disable_intrs          = qla4_82xx_disable_intrs,
5300f8086f4fSVikas Chaudhary 	.enable_intrs           = qla4_82xx_enable_intrs,
5301f4f5df23SVikas Chaudhary 	.start_firmware         = qla4_8xxx_load_risc,
530233693c7aSVikas Chaudhary 	.restart_firmware	= qla4_82xx_try_start_fw,
5303f8086f4fSVikas Chaudhary 	.intr_handler           = qla4_82xx_intr_handler,
5304f8086f4fSVikas Chaudhary 	.interrupt_service_routine = qla4_82xx_interrupt_service_routine,
530533693c7aSVikas Chaudhary 	.need_reset		= qla4_8xxx_need_reset,
5306f8086f4fSVikas Chaudhary 	.reset_chip             = qla4_82xx_isp_reset,
5307f4f5df23SVikas Chaudhary 	.reset_firmware         = qla4_8xxx_stop_firmware,
5308f8086f4fSVikas Chaudhary 	.queue_iocb             = qla4_82xx_queue_iocb,
5309f8086f4fSVikas Chaudhary 	.complete_iocb          = qla4_82xx_complete_iocb,
5310f8086f4fSVikas Chaudhary 	.rd_shdw_req_q_out      = qla4_82xx_rd_shdw_req_q_out,
5311f8086f4fSVikas Chaudhary 	.rd_shdw_rsp_q_in       = qla4_82xx_rd_shdw_rsp_q_in,
5312f4f5df23SVikas Chaudhary 	.get_sys_info           = qla4_8xxx_get_sys_info,
531333693c7aSVikas Chaudhary 	.rd_reg_direct		= qla4_82xx_rd_32,
531433693c7aSVikas Chaudhary 	.wr_reg_direct		= qla4_82xx_wr_32,
531533693c7aSVikas Chaudhary 	.rd_reg_indirect	= qla4_82xx_md_rd_32,
531633693c7aSVikas Chaudhary 	.wr_reg_indirect	= qla4_82xx_md_wr_32,
531733693c7aSVikas Chaudhary 	.idc_lock		= qla4_82xx_idc_lock,
531833693c7aSVikas Chaudhary 	.idc_unlock		= qla4_82xx_idc_unlock,
531933693c7aSVikas Chaudhary 	.rom_lock_recovery	= qla4_82xx_rom_lock_recovery,
532033693c7aSVikas Chaudhary 	.queue_mailbox_command	= qla4_82xx_queue_mbox_cmd,
532133693c7aSVikas Chaudhary 	.process_mailbox_interrupt = qla4_82xx_process_mbox_intr,
5322f4f5df23SVikas Chaudhary };
5323f4f5df23SVikas Chaudhary 
53246e7b4292SVikas Chaudhary static struct isp_operations qla4_83xx_isp_ops = {
53256e7b4292SVikas Chaudhary 	.iospace_config		= qla4_8xxx_iospace_config,
53266e7b4292SVikas Chaudhary 	.pci_config		= qla4_8xxx_pci_config,
53276e7b4292SVikas Chaudhary 	.disable_intrs		= qla4_83xx_disable_intrs,
53286e7b4292SVikas Chaudhary 	.enable_intrs		= qla4_83xx_enable_intrs,
53296e7b4292SVikas Chaudhary 	.start_firmware		= qla4_8xxx_load_risc,
53306e7b4292SVikas Chaudhary 	.restart_firmware	= qla4_83xx_start_firmware,
53316e7b4292SVikas Chaudhary 	.intr_handler		= qla4_83xx_intr_handler,
53326e7b4292SVikas Chaudhary 	.interrupt_service_routine = qla4_83xx_interrupt_service_routine,
53336e7b4292SVikas Chaudhary 	.need_reset		= qla4_8xxx_need_reset,
53346e7b4292SVikas Chaudhary 	.reset_chip		= qla4_83xx_isp_reset,
53356e7b4292SVikas Chaudhary 	.reset_firmware		= qla4_8xxx_stop_firmware,
53366e7b4292SVikas Chaudhary 	.queue_iocb		= qla4_83xx_queue_iocb,
53376e7b4292SVikas Chaudhary 	.complete_iocb		= qla4_83xx_complete_iocb,
5338a24058f9STej Parkash 	.rd_shdw_req_q_out	= qla4xxx_rd_shdw_req_q_out,
5339a24058f9STej Parkash 	.rd_shdw_rsp_q_in	= qla4xxx_rd_shdw_rsp_q_in,
53406e7b4292SVikas Chaudhary 	.get_sys_info		= qla4_8xxx_get_sys_info,
53416e7b4292SVikas Chaudhary 	.rd_reg_direct		= qla4_83xx_rd_reg,
53426e7b4292SVikas Chaudhary 	.wr_reg_direct		= qla4_83xx_wr_reg,
53436e7b4292SVikas Chaudhary 	.rd_reg_indirect	= qla4_83xx_rd_reg_indirect,
53446e7b4292SVikas Chaudhary 	.wr_reg_indirect	= qla4_83xx_wr_reg_indirect,
53456e7b4292SVikas Chaudhary 	.idc_lock		= qla4_83xx_drv_lock,
53466e7b4292SVikas Chaudhary 	.idc_unlock		= qla4_83xx_drv_unlock,
53476e7b4292SVikas Chaudhary 	.rom_lock_recovery	= qla4_83xx_rom_lock_recovery,
53486e7b4292SVikas Chaudhary 	.queue_mailbox_command	= qla4_83xx_queue_mbox_cmd,
53496e7b4292SVikas Chaudhary 	.process_mailbox_interrupt = qla4_83xx_process_mbox_intr,
5350f4f5df23SVikas Chaudhary };
5351f4f5df23SVikas Chaudhary 
5352f4f5df23SVikas Chaudhary uint16_t qla4xxx_rd_shdw_req_q_out(struct scsi_qla_host *ha)
5353f4f5df23SVikas Chaudhary {
5354f4f5df23SVikas Chaudhary 	return (uint16_t)le32_to_cpu(ha->shadow_regs->req_q_out);
5355f4f5df23SVikas Chaudhary }
5356f4f5df23SVikas Chaudhary 
5357f8086f4fSVikas Chaudhary uint16_t qla4_82xx_rd_shdw_req_q_out(struct scsi_qla_host *ha)
5358f4f5df23SVikas Chaudhary {
53597664a1fdSVikas Chaudhary 	return (uint16_t)le32_to_cpu(readl(&ha->qla4_82xx_reg->req_q_out));
5360f4f5df23SVikas Chaudhary }
5361f4f5df23SVikas Chaudhary 
5362f4f5df23SVikas Chaudhary uint16_t qla4xxx_rd_shdw_rsp_q_in(struct scsi_qla_host *ha)
5363f4f5df23SVikas Chaudhary {
5364f4f5df23SVikas Chaudhary 	return (uint16_t)le32_to_cpu(ha->shadow_regs->rsp_q_in);
5365f4f5df23SVikas Chaudhary }
5366f4f5df23SVikas Chaudhary 
5367f8086f4fSVikas Chaudhary uint16_t qla4_82xx_rd_shdw_rsp_q_in(struct scsi_qla_host *ha)
5368f4f5df23SVikas Chaudhary {
53697664a1fdSVikas Chaudhary 	return (uint16_t)le32_to_cpu(readl(&ha->qla4_82xx_reg->rsp_q_in));
5370f4f5df23SVikas Chaudhary }
5371f4f5df23SVikas Chaudhary 
53722a991c21SManish Rangankar static ssize_t qla4xxx_show_boot_eth_info(void *data, int type, char *buf)
53732a991c21SManish Rangankar {
53742a991c21SManish Rangankar 	struct scsi_qla_host *ha = data;
53752a991c21SManish Rangankar 	char *str = buf;
53762a991c21SManish Rangankar 	int rc;
53772a991c21SManish Rangankar 
53782a991c21SManish Rangankar 	switch (type) {
53792a991c21SManish Rangankar 	case ISCSI_BOOT_ETH_FLAGS:
53802a991c21SManish Rangankar 		rc = sprintf(str, "%d\n", SYSFS_FLAG_FW_SEL_BOOT);
53812a991c21SManish Rangankar 		break;
53822a991c21SManish Rangankar 	case ISCSI_BOOT_ETH_INDEX:
53832a991c21SManish Rangankar 		rc = sprintf(str, "0\n");
53842a991c21SManish Rangankar 		break;
53852a991c21SManish Rangankar 	case ISCSI_BOOT_ETH_MAC:
53862a991c21SManish Rangankar 		rc = sysfs_format_mac(str, ha->my_mac,
53872a991c21SManish Rangankar 				      MAC_ADDR_LEN);
53882a991c21SManish Rangankar 		break;
53892a991c21SManish Rangankar 	default:
53902a991c21SManish Rangankar 		rc = -ENOSYS;
53912a991c21SManish Rangankar 		break;
53922a991c21SManish Rangankar 	}
53932a991c21SManish Rangankar 	return rc;
53942a991c21SManish Rangankar }
53952a991c21SManish Rangankar 
5396587a1f16SAl Viro static umode_t qla4xxx_eth_get_attr_visibility(void *data, int type)
53972a991c21SManish Rangankar {
53982a991c21SManish Rangankar 	int rc;
53992a991c21SManish Rangankar 
54002a991c21SManish Rangankar 	switch (type) {
54012a991c21SManish Rangankar 	case ISCSI_BOOT_ETH_FLAGS:
54022a991c21SManish Rangankar 	case ISCSI_BOOT_ETH_MAC:
54032a991c21SManish Rangankar 	case ISCSI_BOOT_ETH_INDEX:
54042a991c21SManish Rangankar 		rc = S_IRUGO;
54052a991c21SManish Rangankar 		break;
54062a991c21SManish Rangankar 	default:
54072a991c21SManish Rangankar 		rc = 0;
54082a991c21SManish Rangankar 		break;
54092a991c21SManish Rangankar 	}
54102a991c21SManish Rangankar 	return rc;
54112a991c21SManish Rangankar }
54122a991c21SManish Rangankar 
54132a991c21SManish Rangankar static ssize_t qla4xxx_show_boot_ini_info(void *data, int type, char *buf)
54142a991c21SManish Rangankar {
54152a991c21SManish Rangankar 	struct scsi_qla_host *ha = data;
54162a991c21SManish Rangankar 	char *str = buf;
54172a991c21SManish Rangankar 	int rc;
54182a991c21SManish Rangankar 
54192a991c21SManish Rangankar 	switch (type) {
54202a991c21SManish Rangankar 	case ISCSI_BOOT_INI_INITIATOR_NAME:
54212a991c21SManish Rangankar 		rc = sprintf(str, "%s\n", ha->name_string);
54222a991c21SManish Rangankar 		break;
54232a991c21SManish Rangankar 	default:
54242a991c21SManish Rangankar 		rc = -ENOSYS;
54252a991c21SManish Rangankar 		break;
54262a991c21SManish Rangankar 	}
54272a991c21SManish Rangankar 	return rc;
54282a991c21SManish Rangankar }
54292a991c21SManish Rangankar 
5430587a1f16SAl Viro static umode_t qla4xxx_ini_get_attr_visibility(void *data, int type)
54312a991c21SManish Rangankar {
54322a991c21SManish Rangankar 	int rc;
54332a991c21SManish Rangankar 
54342a991c21SManish Rangankar 	switch (type) {
54352a991c21SManish Rangankar 	case ISCSI_BOOT_INI_INITIATOR_NAME:
54362a991c21SManish Rangankar 		rc = S_IRUGO;
54372a991c21SManish Rangankar 		break;
54382a991c21SManish Rangankar 	default:
54392a991c21SManish Rangankar 		rc = 0;
54402a991c21SManish Rangankar 		break;
54412a991c21SManish Rangankar 	}
54422a991c21SManish Rangankar 	return rc;
54432a991c21SManish Rangankar }
54442a991c21SManish Rangankar 
54452a991c21SManish Rangankar static ssize_t
54462a991c21SManish Rangankar qla4xxx_show_boot_tgt_info(struct ql4_boot_session_info *boot_sess, int type,
54472a991c21SManish Rangankar 			   char *buf)
54482a991c21SManish Rangankar {
54492a991c21SManish Rangankar 	struct ql4_conn_info *boot_conn = &boot_sess->conn_list[0];
54502a991c21SManish Rangankar 	char *str = buf;
54512a991c21SManish Rangankar 	int rc;
54522a991c21SManish Rangankar 
54532a991c21SManish Rangankar 	switch (type) {
54542a991c21SManish Rangankar 	case ISCSI_BOOT_TGT_NAME:
54552a991c21SManish Rangankar 		rc = sprintf(buf, "%s\n", (char *)&boot_sess->target_name);
54562a991c21SManish Rangankar 		break;
54572a991c21SManish Rangankar 	case ISCSI_BOOT_TGT_IP_ADDR:
54582a991c21SManish Rangankar 		if (boot_sess->conn_list[0].dest_ipaddr.ip_type == 0x1)
54592a991c21SManish Rangankar 			rc = sprintf(buf, "%pI4\n",
54602a991c21SManish Rangankar 				     &boot_conn->dest_ipaddr.ip_address);
54612a991c21SManish Rangankar 		else
54622a991c21SManish Rangankar 			rc = sprintf(str, "%pI6\n",
54632a991c21SManish Rangankar 				     &boot_conn->dest_ipaddr.ip_address);
54642a991c21SManish Rangankar 		break;
54652a991c21SManish Rangankar 	case ISCSI_BOOT_TGT_PORT:
54662a991c21SManish Rangankar 			rc = sprintf(str, "%d\n", boot_conn->dest_port);
54672a991c21SManish Rangankar 		break;
54682a991c21SManish Rangankar 	case ISCSI_BOOT_TGT_CHAP_NAME:
54692a991c21SManish Rangankar 		rc = sprintf(str,  "%.*s\n",
54702a991c21SManish Rangankar 			     boot_conn->chap.target_chap_name_length,
54712a991c21SManish Rangankar 			     (char *)&boot_conn->chap.target_chap_name);
54722a991c21SManish Rangankar 		break;
54732a991c21SManish Rangankar 	case ISCSI_BOOT_TGT_CHAP_SECRET:
54742a991c21SManish Rangankar 		rc = sprintf(str,  "%.*s\n",
54752a991c21SManish Rangankar 			     boot_conn->chap.target_secret_length,
54762a991c21SManish Rangankar 			     (char *)&boot_conn->chap.target_secret);
54772a991c21SManish Rangankar 		break;
54782a991c21SManish Rangankar 	case ISCSI_BOOT_TGT_REV_CHAP_NAME:
54792a991c21SManish Rangankar 		rc = sprintf(str,  "%.*s\n",
54802a991c21SManish Rangankar 			     boot_conn->chap.intr_chap_name_length,
54812a991c21SManish Rangankar 			     (char *)&boot_conn->chap.intr_chap_name);
54822a991c21SManish Rangankar 		break;
54832a991c21SManish Rangankar 	case ISCSI_BOOT_TGT_REV_CHAP_SECRET:
54842a991c21SManish Rangankar 		rc = sprintf(str,  "%.*s\n",
54852a991c21SManish Rangankar 			     boot_conn->chap.intr_secret_length,
54862a991c21SManish Rangankar 			     (char *)&boot_conn->chap.intr_secret);
54872a991c21SManish Rangankar 		break;
54882a991c21SManish Rangankar 	case ISCSI_BOOT_TGT_FLAGS:
54892a991c21SManish Rangankar 		rc = sprintf(str, "%d\n", SYSFS_FLAG_FW_SEL_BOOT);
54902a991c21SManish Rangankar 		break;
54912a991c21SManish Rangankar 	case ISCSI_BOOT_TGT_NIC_ASSOC:
54922a991c21SManish Rangankar 		rc = sprintf(str, "0\n");
54932a991c21SManish Rangankar 		break;
54942a991c21SManish Rangankar 	default:
54952a991c21SManish Rangankar 		rc = -ENOSYS;
54962a991c21SManish Rangankar 		break;
54972a991c21SManish Rangankar 	}
54982a991c21SManish Rangankar 	return rc;
54992a991c21SManish Rangankar }
55002a991c21SManish Rangankar 
55012a991c21SManish Rangankar static ssize_t qla4xxx_show_boot_tgt_pri_info(void *data, int type, char *buf)
55022a991c21SManish Rangankar {
55032a991c21SManish Rangankar 	struct scsi_qla_host *ha = data;
55042a991c21SManish Rangankar 	struct ql4_boot_session_info *boot_sess = &(ha->boot_tgt.boot_pri_sess);
55052a991c21SManish Rangankar 
55062a991c21SManish Rangankar 	return qla4xxx_show_boot_tgt_info(boot_sess, type, buf);
55072a991c21SManish Rangankar }
55082a991c21SManish Rangankar 
55092a991c21SManish Rangankar static ssize_t qla4xxx_show_boot_tgt_sec_info(void *data, int type, char *buf)
55102a991c21SManish Rangankar {
55112a991c21SManish Rangankar 	struct scsi_qla_host *ha = data;
55122a991c21SManish Rangankar 	struct ql4_boot_session_info *boot_sess = &(ha->boot_tgt.boot_sec_sess);
55132a991c21SManish Rangankar 
55142a991c21SManish Rangankar 	return qla4xxx_show_boot_tgt_info(boot_sess, type, buf);
55152a991c21SManish Rangankar }
55162a991c21SManish Rangankar 
5517587a1f16SAl Viro static umode_t qla4xxx_tgt_get_attr_visibility(void *data, int type)
55182a991c21SManish Rangankar {
55192a991c21SManish Rangankar 	int rc;
55202a991c21SManish Rangankar 
55212a991c21SManish Rangankar 	switch (type) {
55222a991c21SManish Rangankar 	case ISCSI_BOOT_TGT_NAME:
55232a991c21SManish Rangankar 	case ISCSI_BOOT_TGT_IP_ADDR:
55242a991c21SManish Rangankar 	case ISCSI_BOOT_TGT_PORT:
55252a991c21SManish Rangankar 	case ISCSI_BOOT_TGT_CHAP_NAME:
55262a991c21SManish Rangankar 	case ISCSI_BOOT_TGT_CHAP_SECRET:
55272a991c21SManish Rangankar 	case ISCSI_BOOT_TGT_REV_CHAP_NAME:
55282a991c21SManish Rangankar 	case ISCSI_BOOT_TGT_REV_CHAP_SECRET:
55292a991c21SManish Rangankar 	case ISCSI_BOOT_TGT_NIC_ASSOC:
55302a991c21SManish Rangankar 	case ISCSI_BOOT_TGT_FLAGS:
55312a991c21SManish Rangankar 		rc = S_IRUGO;
55322a991c21SManish Rangankar 		break;
55332a991c21SManish Rangankar 	default:
55342a991c21SManish Rangankar 		rc = 0;
55352a991c21SManish Rangankar 		break;
55362a991c21SManish Rangankar 	}
55372a991c21SManish Rangankar 	return rc;
55382a991c21SManish Rangankar }
55392a991c21SManish Rangankar 
55402a991c21SManish Rangankar static void qla4xxx_boot_release(void *data)
55412a991c21SManish Rangankar {
55422a991c21SManish Rangankar 	struct scsi_qla_host *ha = data;
55432a991c21SManish Rangankar 
55442a991c21SManish Rangankar 	scsi_host_put(ha->host);
55452a991c21SManish Rangankar }
55462a991c21SManish Rangankar 
55472a991c21SManish Rangankar static int get_fw_boot_info(struct scsi_qla_host *ha, uint16_t ddb_index[])
55482a991c21SManish Rangankar {
55492a991c21SManish Rangankar 	dma_addr_t buf_dma;
55502a991c21SManish Rangankar 	uint32_t addr, pri_addr, sec_addr;
55512a991c21SManish Rangankar 	uint32_t offset;
55522a991c21SManish Rangankar 	uint16_t func_num;
55532a991c21SManish Rangankar 	uint8_t val;
55542a991c21SManish Rangankar 	uint8_t *buf = NULL;
55552a991c21SManish Rangankar 	size_t size = 13 * sizeof(uint8_t);
55562a991c21SManish Rangankar 	int ret = QLA_SUCCESS;
55572a991c21SManish Rangankar 
55582a991c21SManish Rangankar 	func_num = PCI_FUNC(ha->pdev->devfn);
55592a991c21SManish Rangankar 
55600d5b36b8SManish Rangankar 	ql4_printk(KERN_INFO, ha, "%s: Get FW boot info for 0x%x func %d\n",
55610d5b36b8SManish Rangankar 		   __func__, ha->pdev->device, func_num);
55622a991c21SManish Rangankar 
55630d5b36b8SManish Rangankar 	if (is_qla40XX(ha)) {
55642a991c21SManish Rangankar 		if (func_num == 1) {
55652a991c21SManish Rangankar 			addr = NVRAM_PORT0_BOOT_MODE;
55662a991c21SManish Rangankar 			pri_addr = NVRAM_PORT0_BOOT_PRI_TGT;
55672a991c21SManish Rangankar 			sec_addr = NVRAM_PORT0_BOOT_SEC_TGT;
55682a991c21SManish Rangankar 		} else if (func_num == 3) {
55692a991c21SManish Rangankar 			addr = NVRAM_PORT1_BOOT_MODE;
55702a991c21SManish Rangankar 			pri_addr = NVRAM_PORT1_BOOT_PRI_TGT;
55712a991c21SManish Rangankar 			sec_addr = NVRAM_PORT1_BOOT_SEC_TGT;
55722a991c21SManish Rangankar 		} else {
55732a991c21SManish Rangankar 			ret = QLA_ERROR;
55742a991c21SManish Rangankar 			goto exit_boot_info;
55752a991c21SManish Rangankar 		}
55762a991c21SManish Rangankar 
55772a991c21SManish Rangankar 		/* Check Boot Mode */
55782a991c21SManish Rangankar 		val = rd_nvram_byte(ha, addr);
55792a991c21SManish Rangankar 		if (!(val & 0x07)) {
5580e8fb00e0SManish Rangankar 			DEBUG2(ql4_printk(KERN_INFO, ha, "%s: Adapter boot "
5581e8fb00e0SManish Rangankar 					  "options : 0x%x\n", __func__, val));
55822a991c21SManish Rangankar 			ret = QLA_ERROR;
55832a991c21SManish Rangankar 			goto exit_boot_info;
55842a991c21SManish Rangankar 		}
55852a991c21SManish Rangankar 
55862a991c21SManish Rangankar 		/* get primary valid target index */
55872a991c21SManish Rangankar 		val = rd_nvram_byte(ha, pri_addr);
55882a991c21SManish Rangankar 		if (val & BIT_7)
55892a991c21SManish Rangankar 			ddb_index[0] = (val & 0x7f);
55902a991c21SManish Rangankar 
55912a991c21SManish Rangankar 		/* get secondary valid target index */
55922a991c21SManish Rangankar 		val = rd_nvram_byte(ha, sec_addr);
55932a991c21SManish Rangankar 		if (val & BIT_7)
55942a991c21SManish Rangankar 			ddb_index[1] = (val & 0x7f);
55952a991c21SManish Rangankar 
55963e788fb1SVikas Chaudhary 	} else if (is_qla80XX(ha)) {
55972a991c21SManish Rangankar 		buf = dma_alloc_coherent(&ha->pdev->dev, size,
55982a991c21SManish Rangankar 					 &buf_dma, GFP_KERNEL);
55992a991c21SManish Rangankar 		if (!buf) {
56002a991c21SManish Rangankar 			DEBUG2(ql4_printk(KERN_ERR, ha,
56012a991c21SManish Rangankar 					  "%s: Unable to allocate dma buffer\n",
56022a991c21SManish Rangankar 					   __func__));
56032a991c21SManish Rangankar 			ret = QLA_ERROR;
56042a991c21SManish Rangankar 			goto exit_boot_info;
56052a991c21SManish Rangankar 		}
56062a991c21SManish Rangankar 
56072a991c21SManish Rangankar 		if (ha->port_num == 0)
56082a991c21SManish Rangankar 			offset = BOOT_PARAM_OFFSET_PORT0;
56092a991c21SManish Rangankar 		else if (ha->port_num == 1)
56102a991c21SManish Rangankar 			offset = BOOT_PARAM_OFFSET_PORT1;
56112a991c21SManish Rangankar 		else {
56122a991c21SManish Rangankar 			ret = QLA_ERROR;
56132a991c21SManish Rangankar 			goto exit_boot_info_free;
56142a991c21SManish Rangankar 		}
56152a991c21SManish Rangankar 		addr = FLASH_RAW_ACCESS_ADDR + (ha->hw.flt_iscsi_param * 4) +
56162a991c21SManish Rangankar 		       offset;
56172a991c21SManish Rangankar 		if (qla4xxx_get_flash(ha, buf_dma, addr,
56182a991c21SManish Rangankar 				      13 * sizeof(uint8_t)) != QLA_SUCCESS) {
56192a991c21SManish Rangankar 			DEBUG2(ql4_printk(KERN_ERR, ha, "scsi%ld: %s: Get Flash"
56202a991c21SManish Rangankar 					  " failed\n", ha->host_no, __func__));
56212a991c21SManish Rangankar 			ret = QLA_ERROR;
56222a991c21SManish Rangankar 			goto exit_boot_info_free;
56232a991c21SManish Rangankar 		}
56242a991c21SManish Rangankar 		/* Check Boot Mode */
56252a991c21SManish Rangankar 		if (!(buf[1] & 0x07)) {
5626e8fb00e0SManish Rangankar 			DEBUG2(ql4_printk(KERN_INFO, ha, "Firmware boot options"
5627e8fb00e0SManish Rangankar 					  " : 0x%x\n", buf[1]));
56282a991c21SManish Rangankar 			ret = QLA_ERROR;
56292a991c21SManish Rangankar 			goto exit_boot_info_free;
56302a991c21SManish Rangankar 		}
56312a991c21SManish Rangankar 
56322a991c21SManish Rangankar 		/* get primary valid target index */
56332a991c21SManish Rangankar 		if (buf[2] & BIT_7)
56342a991c21SManish Rangankar 			ddb_index[0] = buf[2] & 0x7f;
56352a991c21SManish Rangankar 
56362a991c21SManish Rangankar 		/* get secondary valid target index */
56372a991c21SManish Rangankar 		if (buf[11] & BIT_7)
56382a991c21SManish Rangankar 			ddb_index[1] = buf[11] & 0x7f;
56392a991c21SManish Rangankar 	} else {
56402a991c21SManish Rangankar 		ret = QLA_ERROR;
56412a991c21SManish Rangankar 		goto exit_boot_info;
56422a991c21SManish Rangankar 	}
56432a991c21SManish Rangankar 
56442a991c21SManish Rangankar 	DEBUG2(ql4_printk(KERN_INFO, ha, "%s: Primary target ID %d, Secondary"
56452a991c21SManish Rangankar 			  " target ID %d\n", __func__, ddb_index[0],
56462a991c21SManish Rangankar 			  ddb_index[1]));
56472a991c21SManish Rangankar 
56482a991c21SManish Rangankar exit_boot_info_free:
56492a991c21SManish Rangankar 	dma_free_coherent(&ha->pdev->dev, size, buf, buf_dma);
56502a991c21SManish Rangankar exit_boot_info:
565120e835b4SLalit Chandivade 	ha->pri_ddb_idx = ddb_index[0];
565220e835b4SLalit Chandivade 	ha->sec_ddb_idx = ddb_index[1];
56532a991c21SManish Rangankar 	return ret;
56542a991c21SManish Rangankar }
56552a991c21SManish Rangankar 
565628deb45cSLalit Chandivade /**
565728deb45cSLalit Chandivade  * qla4xxx_get_bidi_chap - Get a BIDI CHAP user and password
565828deb45cSLalit Chandivade  * @ha: pointer to adapter structure
565928deb45cSLalit Chandivade  * @username: CHAP username to be returned
566028deb45cSLalit Chandivade  * @password: CHAP password to be returned
566128deb45cSLalit Chandivade  *
566228deb45cSLalit Chandivade  * If a boot entry has BIDI CHAP enabled then we need to set the BIDI CHAP
566328deb45cSLalit Chandivade  * user and password in the sysfs entry in /sys/firmware/iscsi_boot#/.
566428deb45cSLalit Chandivade  * So from the CHAP cache find the first BIDI CHAP entry and set it
566528deb45cSLalit Chandivade  * to the boot record in sysfs.
566628deb45cSLalit Chandivade  **/
566728deb45cSLalit Chandivade static int qla4xxx_get_bidi_chap(struct scsi_qla_host *ha, char *username,
566828deb45cSLalit Chandivade 			    char *password)
566928deb45cSLalit Chandivade {
567028deb45cSLalit Chandivade 	int i, ret = -EINVAL;
567128deb45cSLalit Chandivade 	int max_chap_entries = 0;
567228deb45cSLalit Chandivade 	struct ql4_chap_table *chap_table;
567328deb45cSLalit Chandivade 
5674d11b0ca3SVikas Chaudhary 	if (is_qla80XX(ha))
567528deb45cSLalit Chandivade 		max_chap_entries = (ha->hw.flt_chap_size / 2) /
567628deb45cSLalit Chandivade 						sizeof(struct ql4_chap_table);
567728deb45cSLalit Chandivade 	else
567828deb45cSLalit Chandivade 		max_chap_entries = MAX_CHAP_ENTRIES_40XX;
567928deb45cSLalit Chandivade 
568028deb45cSLalit Chandivade 	if (!ha->chap_list) {
568128deb45cSLalit Chandivade 		ql4_printk(KERN_ERR, ha, "Do not have CHAP table cache\n");
568228deb45cSLalit Chandivade 		return ret;
568328deb45cSLalit Chandivade 	}
568428deb45cSLalit Chandivade 
568528deb45cSLalit Chandivade 	mutex_lock(&ha->chap_sem);
568628deb45cSLalit Chandivade 	for (i = 0; i < max_chap_entries; i++) {
568728deb45cSLalit Chandivade 		chap_table = (struct ql4_chap_table *)ha->chap_list + i;
568828deb45cSLalit Chandivade 		if (chap_table->cookie !=
568928deb45cSLalit Chandivade 		    __constant_cpu_to_le16(CHAP_VALID_COOKIE)) {
569028deb45cSLalit Chandivade 			continue;
569128deb45cSLalit Chandivade 		}
569228deb45cSLalit Chandivade 
569328deb45cSLalit Chandivade 		if (chap_table->flags & BIT_7) /* local */
569428deb45cSLalit Chandivade 			continue;
569528deb45cSLalit Chandivade 
569628deb45cSLalit Chandivade 		if (!(chap_table->flags & BIT_6)) /* Not BIDI */
569728deb45cSLalit Chandivade 			continue;
569828deb45cSLalit Chandivade 
569928deb45cSLalit Chandivade 		strncpy(password, chap_table->secret, QL4_CHAP_MAX_SECRET_LEN);
570028deb45cSLalit Chandivade 		strncpy(username, chap_table->name, QL4_CHAP_MAX_NAME_LEN);
570128deb45cSLalit Chandivade 		ret = 0;
570228deb45cSLalit Chandivade 		break;
570328deb45cSLalit Chandivade 	}
570428deb45cSLalit Chandivade 	mutex_unlock(&ha->chap_sem);
570528deb45cSLalit Chandivade 
570628deb45cSLalit Chandivade 	return ret;
570728deb45cSLalit Chandivade }
570828deb45cSLalit Chandivade 
570928deb45cSLalit Chandivade 
57102a991c21SManish Rangankar static int qla4xxx_get_boot_target(struct scsi_qla_host *ha,
57112a991c21SManish Rangankar 				   struct ql4_boot_session_info *boot_sess,
57122a991c21SManish Rangankar 				   uint16_t ddb_index)
57132a991c21SManish Rangankar {
57142a991c21SManish Rangankar 	struct ql4_conn_info *boot_conn = &boot_sess->conn_list[0];
57152a991c21SManish Rangankar 	struct dev_db_entry *fw_ddb_entry;
57162a991c21SManish Rangankar 	dma_addr_t fw_ddb_entry_dma;
57172a991c21SManish Rangankar 	uint16_t idx;
57182a991c21SManish Rangankar 	uint16_t options;
57192a991c21SManish Rangankar 	int ret = QLA_SUCCESS;
57202a991c21SManish Rangankar 
57212a991c21SManish Rangankar 	fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
57222a991c21SManish Rangankar 					  &fw_ddb_entry_dma, GFP_KERNEL);
57232a991c21SManish Rangankar 	if (!fw_ddb_entry) {
57242a991c21SManish Rangankar 		DEBUG2(ql4_printk(KERN_ERR, ha,
57252a991c21SManish Rangankar 				  "%s: Unable to allocate dma buffer.\n",
57262a991c21SManish Rangankar 				  __func__));
57272a991c21SManish Rangankar 		ret = QLA_ERROR;
57282a991c21SManish Rangankar 		return ret;
57292a991c21SManish Rangankar 	}
57302a991c21SManish Rangankar 
57312a991c21SManish Rangankar 	if (qla4xxx_bootdb_by_index(ha, fw_ddb_entry,
57322a991c21SManish Rangankar 				   fw_ddb_entry_dma, ddb_index)) {
5733e8fb00e0SManish Rangankar 		DEBUG2(ql4_printk(KERN_INFO, ha, "%s: No Flash DDB found at "
5734e8fb00e0SManish Rangankar 				  "index [%d]\n", __func__, ddb_index));
57352a991c21SManish Rangankar 		ret = QLA_ERROR;
57362a991c21SManish Rangankar 		goto exit_boot_target;
57372a991c21SManish Rangankar 	}
57382a991c21SManish Rangankar 
57392a991c21SManish Rangankar 	/* Update target name and IP from DDB */
57402a991c21SManish Rangankar 	memcpy(boot_sess->target_name, fw_ddb_entry->iscsi_name,
57412a991c21SManish Rangankar 	       min(sizeof(boot_sess->target_name),
57422a991c21SManish Rangankar 		   sizeof(fw_ddb_entry->iscsi_name)));
57432a991c21SManish Rangankar 
57442a991c21SManish Rangankar 	options = le16_to_cpu(fw_ddb_entry->options);
57452a991c21SManish Rangankar 	if (options & DDB_OPT_IPV6_DEVICE) {
57462a991c21SManish Rangankar 		memcpy(&boot_conn->dest_ipaddr.ip_address,
57472a991c21SManish Rangankar 		       &fw_ddb_entry->ip_addr[0], IPv6_ADDR_LEN);
57482a991c21SManish Rangankar 	} else {
57492a991c21SManish Rangankar 		boot_conn->dest_ipaddr.ip_type = 0x1;
57502a991c21SManish Rangankar 		memcpy(&boot_conn->dest_ipaddr.ip_address,
57512a991c21SManish Rangankar 		       &fw_ddb_entry->ip_addr[0], IP_ADDR_LEN);
57522a991c21SManish Rangankar 	}
57532a991c21SManish Rangankar 
57542a991c21SManish Rangankar 	boot_conn->dest_port = le16_to_cpu(fw_ddb_entry->port);
57552a991c21SManish Rangankar 
57562a991c21SManish Rangankar 	/* update chap information */
57572a991c21SManish Rangankar 	idx = __le16_to_cpu(fw_ddb_entry->chap_tbl_idx);
57582a991c21SManish Rangankar 
57592a991c21SManish Rangankar 	if (BIT_7 & le16_to_cpu(fw_ddb_entry->iscsi_options))	{
57602a991c21SManish Rangankar 
57612a991c21SManish Rangankar 		DEBUG2(ql4_printk(KERN_INFO, ha, "Setting chap\n"));
57622a991c21SManish Rangankar 
57632a991c21SManish Rangankar 		ret = qla4xxx_get_chap(ha, (char *)&boot_conn->chap.
57642a991c21SManish Rangankar 				       target_chap_name,
57652a991c21SManish Rangankar 				       (char *)&boot_conn->chap.target_secret,
57662a991c21SManish Rangankar 				       idx);
57672a991c21SManish Rangankar 		if (ret) {
57682a991c21SManish Rangankar 			ql4_printk(KERN_ERR, ha, "Failed to set chap\n");
57692a991c21SManish Rangankar 			ret = QLA_ERROR;
57702a991c21SManish Rangankar 			goto exit_boot_target;
57712a991c21SManish Rangankar 		}
57722a991c21SManish Rangankar 
57732a991c21SManish Rangankar 		boot_conn->chap.target_chap_name_length = QL4_CHAP_MAX_NAME_LEN;
57742a991c21SManish Rangankar 		boot_conn->chap.target_secret_length = QL4_CHAP_MAX_SECRET_LEN;
57752a991c21SManish Rangankar 	}
57762a991c21SManish Rangankar 
57772a991c21SManish Rangankar 	if (BIT_4 & le16_to_cpu(fw_ddb_entry->iscsi_options)) {
57782a991c21SManish Rangankar 
57792a991c21SManish Rangankar 		DEBUG2(ql4_printk(KERN_INFO, ha, "Setting BIDI chap\n"));
57802a991c21SManish Rangankar 
578128deb45cSLalit Chandivade 		ret = qla4xxx_get_bidi_chap(ha,
578228deb45cSLalit Chandivade 				    (char *)&boot_conn->chap.intr_chap_name,
578328deb45cSLalit Chandivade 				    (char *)&boot_conn->chap.intr_secret);
578428deb45cSLalit Chandivade 
57852a991c21SManish Rangankar 		if (ret) {
57862a991c21SManish Rangankar 			ql4_printk(KERN_ERR, ha, "Failed to set BIDI chap\n");
57872a991c21SManish Rangankar 			ret = QLA_ERROR;
57882a991c21SManish Rangankar 			goto exit_boot_target;
57892a991c21SManish Rangankar 		}
57902a991c21SManish Rangankar 
57912a991c21SManish Rangankar 		boot_conn->chap.intr_chap_name_length = QL4_CHAP_MAX_NAME_LEN;
57922a991c21SManish Rangankar 		boot_conn->chap.intr_secret_length = QL4_CHAP_MAX_SECRET_LEN;
57932a991c21SManish Rangankar 	}
57942a991c21SManish Rangankar 
57952a991c21SManish Rangankar exit_boot_target:
57962a991c21SManish Rangankar 	dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
57972a991c21SManish Rangankar 			  fw_ddb_entry, fw_ddb_entry_dma);
57982a991c21SManish Rangankar 	return ret;
57992a991c21SManish Rangankar }
58002a991c21SManish Rangankar 
58012a991c21SManish Rangankar static int qla4xxx_get_boot_info(struct scsi_qla_host *ha)
58022a991c21SManish Rangankar {
58032a991c21SManish Rangankar 	uint16_t ddb_index[2];
58048de5b958SLalit Chandivade 	int ret = QLA_ERROR;
58058de5b958SLalit Chandivade 	int rval;
58062a991c21SManish Rangankar 
58072a991c21SManish Rangankar 	memset(ddb_index, 0, sizeof(ddb_index));
58088de5b958SLalit Chandivade 	ddb_index[0] = 0xffff;
58098de5b958SLalit Chandivade 	ddb_index[1] = 0xffff;
58102a991c21SManish Rangankar 	ret = get_fw_boot_info(ha, ddb_index);
58112a991c21SManish Rangankar 	if (ret != QLA_SUCCESS) {
5812e8fb00e0SManish Rangankar 		DEBUG2(ql4_printk(KERN_INFO, ha,
5813e8fb00e0SManish Rangankar 				"%s: No boot target configured.\n", __func__));
58142a991c21SManish Rangankar 		return ret;
58152a991c21SManish Rangankar 	}
58162a991c21SManish Rangankar 
581713483730SMike Christie 	if (ql4xdisablesysfsboot)
581813483730SMike Christie 		return QLA_SUCCESS;
581913483730SMike Christie 
58208de5b958SLalit Chandivade 	if (ddb_index[0] == 0xffff)
58218de5b958SLalit Chandivade 		goto sec_target;
58228de5b958SLalit Chandivade 
58238de5b958SLalit Chandivade 	rval = qla4xxx_get_boot_target(ha, &(ha->boot_tgt.boot_pri_sess),
58242a991c21SManish Rangankar 				      ddb_index[0]);
58258de5b958SLalit Chandivade 	if (rval != QLA_SUCCESS) {
5826e8fb00e0SManish Rangankar 		DEBUG2(ql4_printk(KERN_INFO, ha, "%s: Primary boot target not "
5827e8fb00e0SManish Rangankar 				  "configured\n", __func__));
58288de5b958SLalit Chandivade 	} else
58298de5b958SLalit Chandivade 		ret = QLA_SUCCESS;
58302a991c21SManish Rangankar 
58318de5b958SLalit Chandivade sec_target:
58328de5b958SLalit Chandivade 	if (ddb_index[1] == 0xffff)
58338de5b958SLalit Chandivade 		goto exit_get_boot_info;
58348de5b958SLalit Chandivade 
58358de5b958SLalit Chandivade 	rval = qla4xxx_get_boot_target(ha, &(ha->boot_tgt.boot_sec_sess),
58362a991c21SManish Rangankar 				      ddb_index[1]);
58378de5b958SLalit Chandivade 	if (rval != QLA_SUCCESS) {
5838e8fb00e0SManish Rangankar 		DEBUG2(ql4_printk(KERN_INFO, ha, "%s: Secondary boot target not"
5839e8fb00e0SManish Rangankar 				  " configured\n", __func__));
58408de5b958SLalit Chandivade 	} else
58418de5b958SLalit Chandivade 		ret = QLA_SUCCESS;
58428de5b958SLalit Chandivade 
58438de5b958SLalit Chandivade exit_get_boot_info:
58442a991c21SManish Rangankar 	return ret;
58452a991c21SManish Rangankar }
58462a991c21SManish Rangankar 
58472a991c21SManish Rangankar static int qla4xxx_setup_boot_info(struct scsi_qla_host *ha)
58482a991c21SManish Rangankar {
58492a991c21SManish Rangankar 	struct iscsi_boot_kobj *boot_kobj;
58502a991c21SManish Rangankar 
58512a991c21SManish Rangankar 	if (qla4xxx_get_boot_info(ha) != QLA_SUCCESS)
585213483730SMike Christie 		return QLA_ERROR;
585313483730SMike Christie 
585413483730SMike Christie 	if (ql4xdisablesysfsboot) {
585513483730SMike Christie 		ql4_printk(KERN_INFO, ha,
585613483730SMike Christie 			   "%s: syfsboot disabled - driver will trigger login "
585713483730SMike Christie 			   "and publish session for discovery .\n", __func__);
585813483730SMike Christie 		return QLA_SUCCESS;
585913483730SMike Christie 	}
586013483730SMike Christie 
58612a991c21SManish Rangankar 
58622a991c21SManish Rangankar 	ha->boot_kset = iscsi_boot_create_host_kset(ha->host->host_no);
58632a991c21SManish Rangankar 	if (!ha->boot_kset)
58642a991c21SManish Rangankar 		goto kset_free;
58652a991c21SManish Rangankar 
58662a991c21SManish Rangankar 	if (!scsi_host_get(ha->host))
58672a991c21SManish Rangankar 		goto kset_free;
58682a991c21SManish Rangankar 	boot_kobj = iscsi_boot_create_target(ha->boot_kset, 0, ha,
58692a991c21SManish Rangankar 					     qla4xxx_show_boot_tgt_pri_info,
58702a991c21SManish Rangankar 					     qla4xxx_tgt_get_attr_visibility,
58712a991c21SManish Rangankar 					     qla4xxx_boot_release);
58722a991c21SManish Rangankar 	if (!boot_kobj)
58732a991c21SManish Rangankar 		goto put_host;
58742a991c21SManish Rangankar 
58752a991c21SManish Rangankar 	if (!scsi_host_get(ha->host))
58762a991c21SManish Rangankar 		goto kset_free;
58772a991c21SManish Rangankar 	boot_kobj = iscsi_boot_create_target(ha->boot_kset, 1, ha,
58782a991c21SManish Rangankar 					     qla4xxx_show_boot_tgt_sec_info,
58792a991c21SManish Rangankar 					     qla4xxx_tgt_get_attr_visibility,
58802a991c21SManish Rangankar 					     qla4xxx_boot_release);
58812a991c21SManish Rangankar 	if (!boot_kobj)
58822a991c21SManish Rangankar 		goto put_host;
58832a991c21SManish Rangankar 
58842a991c21SManish Rangankar 	if (!scsi_host_get(ha->host))
58852a991c21SManish Rangankar 		goto kset_free;
58862a991c21SManish Rangankar 	boot_kobj = iscsi_boot_create_initiator(ha->boot_kset, 0, ha,
58872a991c21SManish Rangankar 					       qla4xxx_show_boot_ini_info,
58882a991c21SManish Rangankar 					       qla4xxx_ini_get_attr_visibility,
58892a991c21SManish Rangankar 					       qla4xxx_boot_release);
58902a991c21SManish Rangankar 	if (!boot_kobj)
58912a991c21SManish Rangankar 		goto put_host;
58922a991c21SManish Rangankar 
58932a991c21SManish Rangankar 	if (!scsi_host_get(ha->host))
58942a991c21SManish Rangankar 		goto kset_free;
58952a991c21SManish Rangankar 	boot_kobj = iscsi_boot_create_ethernet(ha->boot_kset, 0, ha,
58962a991c21SManish Rangankar 					       qla4xxx_show_boot_eth_info,
58972a991c21SManish Rangankar 					       qla4xxx_eth_get_attr_visibility,
58982a991c21SManish Rangankar 					       qla4xxx_boot_release);
58992a991c21SManish Rangankar 	if (!boot_kobj)
59002a991c21SManish Rangankar 		goto put_host;
59012a991c21SManish Rangankar 
590213483730SMike Christie 	return QLA_SUCCESS;
59032a991c21SManish Rangankar 
59042a991c21SManish Rangankar put_host:
59052a991c21SManish Rangankar 	scsi_host_put(ha->host);
59062a991c21SManish Rangankar kset_free:
59072a991c21SManish Rangankar 	iscsi_boot_destroy_kset(ha->boot_kset);
59082a991c21SManish Rangankar 	return -ENOMEM;
59092a991c21SManish Rangankar }
59102a991c21SManish Rangankar 
59114549415aSLalit Chandivade 
59124549415aSLalit Chandivade /**
59134549415aSLalit Chandivade  * qla4xxx_create chap_list - Create CHAP list from FLASH
59144549415aSLalit Chandivade  * @ha: pointer to adapter structure
59154549415aSLalit Chandivade  *
59164549415aSLalit Chandivade  * Read flash and make a list of CHAP entries, during login when a CHAP entry
59174549415aSLalit Chandivade  * is received, it will be checked in this list. If entry exist then the CHAP
59184549415aSLalit Chandivade  * entry index is set in the DDB. If CHAP entry does not exist in this list
59194549415aSLalit Chandivade  * then a new entry is added in FLASH in CHAP table and the index obtained is
59204549415aSLalit Chandivade  * used in the DDB.
59214549415aSLalit Chandivade  **/
59224549415aSLalit Chandivade static void qla4xxx_create_chap_list(struct scsi_qla_host *ha)
59234549415aSLalit Chandivade {
59244549415aSLalit Chandivade 	int rval = 0;
59254549415aSLalit Chandivade 	uint8_t *chap_flash_data = NULL;
59264549415aSLalit Chandivade 	uint32_t offset;
59274549415aSLalit Chandivade 	dma_addr_t chap_dma;
59284549415aSLalit Chandivade 	uint32_t chap_size = 0;
59294549415aSLalit Chandivade 
59304549415aSLalit Chandivade 	if (is_qla40XX(ha))
59314549415aSLalit Chandivade 		chap_size = MAX_CHAP_ENTRIES_40XX  *
59324549415aSLalit Chandivade 					sizeof(struct ql4_chap_table);
59334549415aSLalit Chandivade 	else	/* Single region contains CHAP info for both
59344549415aSLalit Chandivade 		 * ports which is divided into half for each port.
59354549415aSLalit Chandivade 		 */
59364549415aSLalit Chandivade 		chap_size = ha->hw.flt_chap_size / 2;
59374549415aSLalit Chandivade 
59384549415aSLalit Chandivade 	chap_flash_data = dma_alloc_coherent(&ha->pdev->dev, chap_size,
59394549415aSLalit Chandivade 					  &chap_dma, GFP_KERNEL);
59404549415aSLalit Chandivade 	if (!chap_flash_data) {
59414549415aSLalit Chandivade 		ql4_printk(KERN_ERR, ha, "No memory for chap_flash_data\n");
59424549415aSLalit Chandivade 		return;
59434549415aSLalit Chandivade 	}
59444549415aSLalit Chandivade 	if (is_qla40XX(ha))
59454549415aSLalit Chandivade 		offset = FLASH_CHAP_OFFSET;
59464549415aSLalit Chandivade 	else {
59474549415aSLalit Chandivade 		offset = FLASH_RAW_ACCESS_ADDR + (ha->hw.flt_region_chap << 2);
59484549415aSLalit Chandivade 		if (ha->port_num == 1)
59494549415aSLalit Chandivade 			offset += chap_size;
59504549415aSLalit Chandivade 	}
59514549415aSLalit Chandivade 
59524549415aSLalit Chandivade 	rval = qla4xxx_get_flash(ha, chap_dma, offset, chap_size);
59534549415aSLalit Chandivade 	if (rval != QLA_SUCCESS)
59544549415aSLalit Chandivade 		goto exit_chap_list;
59554549415aSLalit Chandivade 
59564549415aSLalit Chandivade 	if (ha->chap_list == NULL)
59574549415aSLalit Chandivade 		ha->chap_list = vmalloc(chap_size);
59584549415aSLalit Chandivade 	if (ha->chap_list == NULL) {
59594549415aSLalit Chandivade 		ql4_printk(KERN_ERR, ha, "No memory for ha->chap_list\n");
59604549415aSLalit Chandivade 		goto exit_chap_list;
59614549415aSLalit Chandivade 	}
59624549415aSLalit Chandivade 
59634549415aSLalit Chandivade 	memcpy(ha->chap_list, chap_flash_data, chap_size);
59644549415aSLalit Chandivade 
59654549415aSLalit Chandivade exit_chap_list:
59664549415aSLalit Chandivade 	dma_free_coherent(&ha->pdev->dev, chap_size,
59674549415aSLalit Chandivade 			chap_flash_data, chap_dma);
596813483730SMike Christie }
596913483730SMike Christie 
597013483730SMike Christie static void qla4xxx_get_param_ddb(struct ddb_entry *ddb_entry,
597113483730SMike Christie 				  struct ql4_tuple_ddb *tddb)
597213483730SMike Christie {
597313483730SMike Christie 	struct scsi_qla_host *ha;
597413483730SMike Christie 	struct iscsi_cls_session *cls_sess;
597513483730SMike Christie 	struct iscsi_cls_conn *cls_conn;
597613483730SMike Christie 	struct iscsi_session *sess;
597713483730SMike Christie 	struct iscsi_conn *conn;
597813483730SMike Christie 
597913483730SMike Christie 	DEBUG2(printk(KERN_INFO "Func: %s\n", __func__));
598013483730SMike Christie 	ha = ddb_entry->ha;
598113483730SMike Christie 	cls_sess = ddb_entry->sess;
598213483730SMike Christie 	sess = cls_sess->dd_data;
598313483730SMike Christie 	cls_conn = ddb_entry->conn;
598413483730SMike Christie 	conn = cls_conn->dd_data;
598513483730SMike Christie 
598613483730SMike Christie 	tddb->tpgt = sess->tpgt;
598713483730SMike Christie 	tddb->port = conn->persistent_port;
598813483730SMike Christie 	strncpy(tddb->iscsi_name, sess->targetname, ISCSI_NAME_SIZE);
598913483730SMike Christie 	strncpy(tddb->ip_addr, conn->persistent_address, DDB_IPADDR_LEN);
599013483730SMike Christie }
599113483730SMike Christie 
599213483730SMike Christie static void qla4xxx_convert_param_ddb(struct dev_db_entry *fw_ddb_entry,
59931cb78d73SVikas Chaudhary 				      struct ql4_tuple_ddb *tddb,
59941cb78d73SVikas Chaudhary 				      uint8_t *flash_isid)
599513483730SMike Christie {
599613483730SMike Christie 	uint16_t options = 0;
599713483730SMike Christie 
599813483730SMike Christie 	tddb->tpgt = le32_to_cpu(fw_ddb_entry->tgt_portal_grp);
599913483730SMike Christie 	memcpy(&tddb->iscsi_name[0], &fw_ddb_entry->iscsi_name[0],
600013483730SMike Christie 	       min(sizeof(tddb->iscsi_name), sizeof(fw_ddb_entry->iscsi_name)));
600113483730SMike Christie 
600213483730SMike Christie 	options = le16_to_cpu(fw_ddb_entry->options);
600313483730SMike Christie 	if (options & DDB_OPT_IPV6_DEVICE)
600413483730SMike Christie 		sprintf(tddb->ip_addr, "%pI6", fw_ddb_entry->ip_addr);
600513483730SMike Christie 	else
600613483730SMike Christie 		sprintf(tddb->ip_addr, "%pI4", fw_ddb_entry->ip_addr);
600713483730SMike Christie 
600813483730SMike Christie 	tddb->port = le16_to_cpu(fw_ddb_entry->port);
60091cb78d73SVikas Chaudhary 
60101cb78d73SVikas Chaudhary 	if (flash_isid == NULL)
60111cb78d73SVikas Chaudhary 		memcpy(&tddb->isid[0], &fw_ddb_entry->isid[0],
60121cb78d73SVikas Chaudhary 		       sizeof(tddb->isid));
60131cb78d73SVikas Chaudhary 	else
60141cb78d73SVikas Chaudhary 		memcpy(&tddb->isid[0], &flash_isid[0], sizeof(tddb->isid));
601513483730SMike Christie }
601613483730SMike Christie 
601713483730SMike Christie static int qla4xxx_compare_tuple_ddb(struct scsi_qla_host *ha,
601813483730SMike Christie 				     struct ql4_tuple_ddb *old_tddb,
6019173269efSManish Rangankar 				     struct ql4_tuple_ddb *new_tddb,
6020173269efSManish Rangankar 				     uint8_t is_isid_compare)
602113483730SMike Christie {
602213483730SMike Christie 	if (strcmp(old_tddb->iscsi_name, new_tddb->iscsi_name))
602313483730SMike Christie 		return QLA_ERROR;
602413483730SMike Christie 
602513483730SMike Christie 	if (strcmp(old_tddb->ip_addr, new_tddb->ip_addr))
602613483730SMike Christie 		return QLA_ERROR;
602713483730SMike Christie 
602813483730SMike Christie 	if (old_tddb->port != new_tddb->port)
602913483730SMike Christie 		return QLA_ERROR;
603013483730SMike Christie 
6031173269efSManish Rangankar 	/* For multi sessions, driver generates the ISID, so do not compare
603259e13d48SMasanari Iida 	 * ISID in reset path since it would be a comparison between the
6033173269efSManish Rangankar 	 * driver generated ISID and firmware generated ISID. This could
6034173269efSManish Rangankar 	 * lead to adding duplicated DDBs in the list as driver generated
6035173269efSManish Rangankar 	 * ISID would not match firmware generated ISID.
6036173269efSManish Rangankar 	 */
6037173269efSManish Rangankar 	if (is_isid_compare) {
6038173269efSManish Rangankar 		DEBUG2(ql4_printk(KERN_INFO, ha, "%s: old ISID [%02x%02x%02x"
6039173269efSManish Rangankar 			"%02x%02x%02x] New ISID [%02x%02x%02x%02x%02x%02x]\n",
6040173269efSManish Rangankar 			__func__, old_tddb->isid[5], old_tddb->isid[4],
6041173269efSManish Rangankar 			old_tddb->isid[3], old_tddb->isid[2], old_tddb->isid[1],
6042173269efSManish Rangankar 			old_tddb->isid[0], new_tddb->isid[5], new_tddb->isid[4],
6043173269efSManish Rangankar 			new_tddb->isid[3], new_tddb->isid[2], new_tddb->isid[1],
6044173269efSManish Rangankar 			new_tddb->isid[0]));
6045173269efSManish Rangankar 
6046173269efSManish Rangankar 		if (memcmp(&old_tddb->isid[0], &new_tddb->isid[0],
6047173269efSManish Rangankar 			   sizeof(old_tddb->isid)))
6048173269efSManish Rangankar 			return QLA_ERROR;
6049173269efSManish Rangankar 	}
6050173269efSManish Rangankar 
605113483730SMike Christie 	DEBUG2(ql4_printk(KERN_INFO, ha,
605213483730SMike Christie 			  "Match Found, fw[%d,%d,%s,%s], [%d,%d,%s,%s]",
605313483730SMike Christie 			  old_tddb->port, old_tddb->tpgt, old_tddb->ip_addr,
605413483730SMike Christie 			  old_tddb->iscsi_name, new_tddb->port, new_tddb->tpgt,
605513483730SMike Christie 			  new_tddb->ip_addr, new_tddb->iscsi_name));
605613483730SMike Christie 
605713483730SMike Christie 	return QLA_SUCCESS;
605813483730SMike Christie }
605913483730SMike Christie 
606013483730SMike Christie static int qla4xxx_is_session_exists(struct scsi_qla_host *ha,
6061ad8bd45eSManish Rangankar 				     struct dev_db_entry *fw_ddb_entry,
6062ad8bd45eSManish Rangankar 				     uint32_t *index)
606313483730SMike Christie {
606413483730SMike Christie 	struct ddb_entry *ddb_entry;
606513483730SMike Christie 	struct ql4_tuple_ddb *fw_tddb = NULL;
606613483730SMike Christie 	struct ql4_tuple_ddb *tmp_tddb = NULL;
606713483730SMike Christie 	int idx;
606813483730SMike Christie 	int ret = QLA_ERROR;
606913483730SMike Christie 
607013483730SMike Christie 	fw_tddb = vzalloc(sizeof(*fw_tddb));
607113483730SMike Christie 	if (!fw_tddb) {
607213483730SMike Christie 		DEBUG2(ql4_printk(KERN_WARNING, ha,
607313483730SMike Christie 				  "Memory Allocation failed.\n"));
607413483730SMike Christie 		ret = QLA_SUCCESS;
607513483730SMike Christie 		goto exit_check;
607613483730SMike Christie 	}
607713483730SMike Christie 
607813483730SMike Christie 	tmp_tddb = vzalloc(sizeof(*tmp_tddb));
607913483730SMike Christie 	if (!tmp_tddb) {
608013483730SMike Christie 		DEBUG2(ql4_printk(KERN_WARNING, ha,
608113483730SMike Christie 				  "Memory Allocation failed.\n"));
608213483730SMike Christie 		ret = QLA_SUCCESS;
608313483730SMike Christie 		goto exit_check;
608413483730SMike Christie 	}
608513483730SMike Christie 
60861cb78d73SVikas Chaudhary 	qla4xxx_convert_param_ddb(fw_ddb_entry, fw_tddb, NULL);
608713483730SMike Christie 
608813483730SMike Christie 	for (idx = 0; idx < MAX_DDB_ENTRIES; idx++) {
608913483730SMike Christie 		ddb_entry = qla4xxx_lookup_ddb_by_fw_index(ha, idx);
609013483730SMike Christie 		if (ddb_entry == NULL)
609113483730SMike Christie 			continue;
609213483730SMike Christie 
609313483730SMike Christie 		qla4xxx_get_param_ddb(ddb_entry, tmp_tddb);
6094173269efSManish Rangankar 		if (!qla4xxx_compare_tuple_ddb(ha, fw_tddb, tmp_tddb, false)) {
609513483730SMike Christie 			ret = QLA_SUCCESS; /* found */
6096ad8bd45eSManish Rangankar 			if (index != NULL)
6097ad8bd45eSManish Rangankar 				*index = idx;
609813483730SMike Christie 			goto exit_check;
609913483730SMike Christie 		}
610013483730SMike Christie 	}
610113483730SMike Christie 
610213483730SMike Christie exit_check:
610313483730SMike Christie 	if (fw_tddb)
610413483730SMike Christie 		vfree(fw_tddb);
610513483730SMike Christie 	if (tmp_tddb)
610613483730SMike Christie 		vfree(tmp_tddb);
610713483730SMike Christie 	return ret;
610813483730SMike Christie }
610913483730SMike Christie 
61101cb78d73SVikas Chaudhary /**
61111cb78d73SVikas Chaudhary  * qla4xxx_check_existing_isid - check if target with same isid exist
61121cb78d73SVikas Chaudhary  *				 in target list
61131cb78d73SVikas Chaudhary  * @list_nt: list of target
61141cb78d73SVikas Chaudhary  * @isid: isid to check
61151cb78d73SVikas Chaudhary  *
61161cb78d73SVikas Chaudhary  * This routine return QLA_SUCCESS if target with same isid exist
61171cb78d73SVikas Chaudhary  **/
61181cb78d73SVikas Chaudhary static int qla4xxx_check_existing_isid(struct list_head *list_nt, uint8_t *isid)
61191cb78d73SVikas Chaudhary {
61201cb78d73SVikas Chaudhary 	struct qla_ddb_index *nt_ddb_idx, *nt_ddb_idx_tmp;
61211cb78d73SVikas Chaudhary 	struct dev_db_entry *fw_ddb_entry;
61221cb78d73SVikas Chaudhary 
61231cb78d73SVikas Chaudhary 	list_for_each_entry_safe(nt_ddb_idx, nt_ddb_idx_tmp, list_nt, list) {
61241cb78d73SVikas Chaudhary 		fw_ddb_entry = &nt_ddb_idx->fw_ddb;
61251cb78d73SVikas Chaudhary 
61261cb78d73SVikas Chaudhary 		if (memcmp(&fw_ddb_entry->isid[0], &isid[0],
61271cb78d73SVikas Chaudhary 			   sizeof(nt_ddb_idx->fw_ddb.isid)) == 0) {
61281cb78d73SVikas Chaudhary 			return QLA_SUCCESS;
61291cb78d73SVikas Chaudhary 		}
61301cb78d73SVikas Chaudhary 	}
61311cb78d73SVikas Chaudhary 	return QLA_ERROR;
61321cb78d73SVikas Chaudhary }
61331cb78d73SVikas Chaudhary 
61341cb78d73SVikas Chaudhary /**
61351cb78d73SVikas Chaudhary  * qla4xxx_update_isid - compare ddbs and updated isid
61361cb78d73SVikas Chaudhary  * @ha: Pointer to host adapter structure.
61371cb78d73SVikas Chaudhary  * @list_nt: list of nt target
61381cb78d73SVikas Chaudhary  * @fw_ddb_entry: firmware ddb entry
61391cb78d73SVikas Chaudhary  *
61401cb78d73SVikas Chaudhary  * This routine update isid if ddbs have same iqn, same isid and
61411cb78d73SVikas Chaudhary  * different IP addr.
61421cb78d73SVikas Chaudhary  * Return QLA_SUCCESS if isid is updated.
61431cb78d73SVikas Chaudhary  **/
61441cb78d73SVikas Chaudhary static int qla4xxx_update_isid(struct scsi_qla_host *ha,
61451cb78d73SVikas Chaudhary 			       struct list_head *list_nt,
61461cb78d73SVikas Chaudhary 			       struct dev_db_entry *fw_ddb_entry)
61471cb78d73SVikas Chaudhary {
61481cb78d73SVikas Chaudhary 	uint8_t base_value, i;
61491cb78d73SVikas Chaudhary 
61501cb78d73SVikas Chaudhary 	base_value = fw_ddb_entry->isid[1] & 0x1f;
61511cb78d73SVikas Chaudhary 	for (i = 0; i < 8; i++) {
61521cb78d73SVikas Chaudhary 		fw_ddb_entry->isid[1] = (base_value | (i << 5));
61531cb78d73SVikas Chaudhary 		if (qla4xxx_check_existing_isid(list_nt, fw_ddb_entry->isid))
61541cb78d73SVikas Chaudhary 			break;
61551cb78d73SVikas Chaudhary 	}
61561cb78d73SVikas Chaudhary 
61571cb78d73SVikas Chaudhary 	if (!qla4xxx_check_existing_isid(list_nt, fw_ddb_entry->isid))
61581cb78d73SVikas Chaudhary 		return QLA_ERROR;
61591cb78d73SVikas Chaudhary 
61601cb78d73SVikas Chaudhary 	return QLA_SUCCESS;
61611cb78d73SVikas Chaudhary }
61621cb78d73SVikas Chaudhary 
61631cb78d73SVikas Chaudhary /**
61641cb78d73SVikas Chaudhary  * qla4xxx_should_update_isid - check if isid need to update
61651cb78d73SVikas Chaudhary  * @ha: Pointer to host adapter structure.
61661cb78d73SVikas Chaudhary  * @old_tddb: ddb tuple
61671cb78d73SVikas Chaudhary  * @new_tddb: ddb tuple
61681cb78d73SVikas Chaudhary  *
61691cb78d73SVikas Chaudhary  * Return QLA_SUCCESS if different IP, different PORT, same iqn,
61701cb78d73SVikas Chaudhary  * same isid
61711cb78d73SVikas Chaudhary  **/
61721cb78d73SVikas Chaudhary static int qla4xxx_should_update_isid(struct scsi_qla_host *ha,
61731cb78d73SVikas Chaudhary 				      struct ql4_tuple_ddb *old_tddb,
61741cb78d73SVikas Chaudhary 				      struct ql4_tuple_ddb *new_tddb)
61751cb78d73SVikas Chaudhary {
61761cb78d73SVikas Chaudhary 	if (strcmp(old_tddb->ip_addr, new_tddb->ip_addr) == 0) {
61771cb78d73SVikas Chaudhary 		/* Same ip */
61781cb78d73SVikas Chaudhary 		if (old_tddb->port == new_tddb->port)
61791cb78d73SVikas Chaudhary 			return QLA_ERROR;
61801cb78d73SVikas Chaudhary 	}
61811cb78d73SVikas Chaudhary 
61821cb78d73SVikas Chaudhary 	if (strcmp(old_tddb->iscsi_name, new_tddb->iscsi_name))
61831cb78d73SVikas Chaudhary 		/* different iqn */
61841cb78d73SVikas Chaudhary 		return QLA_ERROR;
61851cb78d73SVikas Chaudhary 
61861cb78d73SVikas Chaudhary 	if (memcmp(&old_tddb->isid[0], &new_tddb->isid[0],
61871cb78d73SVikas Chaudhary 		   sizeof(old_tddb->isid)))
61881cb78d73SVikas Chaudhary 		/* different isid */
61891cb78d73SVikas Chaudhary 		return QLA_ERROR;
61901cb78d73SVikas Chaudhary 
61911cb78d73SVikas Chaudhary 	return QLA_SUCCESS;
61921cb78d73SVikas Chaudhary }
61931cb78d73SVikas Chaudhary 
61941cb78d73SVikas Chaudhary /**
61951cb78d73SVikas Chaudhary  * qla4xxx_is_flash_ddb_exists - check if fw_ddb_entry already exists in list_nt
61961cb78d73SVikas Chaudhary  * @ha: Pointer to host adapter structure.
61971cb78d73SVikas Chaudhary  * @list_nt: list of nt target.
61981cb78d73SVikas Chaudhary  * @fw_ddb_entry: firmware ddb entry.
61991cb78d73SVikas Chaudhary  *
62001cb78d73SVikas Chaudhary  * This routine check if fw_ddb_entry already exists in list_nt to avoid
62011cb78d73SVikas Chaudhary  * duplicate ddb in list_nt.
62021cb78d73SVikas Chaudhary  * Return QLA_SUCCESS if duplicate ddb exit in list_nl.
62031cb78d73SVikas Chaudhary  * Note: This function also update isid of DDB if required.
62041cb78d73SVikas Chaudhary  **/
62051cb78d73SVikas Chaudhary 
620613483730SMike Christie static int qla4xxx_is_flash_ddb_exists(struct scsi_qla_host *ha,
620713483730SMike Christie 				       struct list_head *list_nt,
620813483730SMike Christie 				       struct dev_db_entry *fw_ddb_entry)
620913483730SMike Christie {
621013483730SMike Christie 	struct qla_ddb_index  *nt_ddb_idx, *nt_ddb_idx_tmp;
621113483730SMike Christie 	struct ql4_tuple_ddb *fw_tddb = NULL;
621213483730SMike Christie 	struct ql4_tuple_ddb *tmp_tddb = NULL;
62131cb78d73SVikas Chaudhary 	int rval, ret = QLA_ERROR;
621413483730SMike Christie 
621513483730SMike Christie 	fw_tddb = vzalloc(sizeof(*fw_tddb));
621613483730SMike Christie 	if (!fw_tddb) {
621713483730SMike Christie 		DEBUG2(ql4_printk(KERN_WARNING, ha,
621813483730SMike Christie 				  "Memory Allocation failed.\n"));
621913483730SMike Christie 		ret = QLA_SUCCESS;
622013483730SMike Christie 		goto exit_check;
622113483730SMike Christie 	}
622213483730SMike Christie 
622313483730SMike Christie 	tmp_tddb = vzalloc(sizeof(*tmp_tddb));
622413483730SMike Christie 	if (!tmp_tddb) {
622513483730SMike Christie 		DEBUG2(ql4_printk(KERN_WARNING, ha,
622613483730SMike Christie 				  "Memory Allocation failed.\n"));
622713483730SMike Christie 		ret = QLA_SUCCESS;
622813483730SMike Christie 		goto exit_check;
622913483730SMike Christie 	}
623013483730SMike Christie 
62311cb78d73SVikas Chaudhary 	qla4xxx_convert_param_ddb(fw_ddb_entry, fw_tddb, NULL);
623213483730SMike Christie 
623313483730SMike Christie 	list_for_each_entry_safe(nt_ddb_idx, nt_ddb_idx_tmp, list_nt, list) {
62341cb78d73SVikas Chaudhary 		qla4xxx_convert_param_ddb(&nt_ddb_idx->fw_ddb, tmp_tddb,
62351cb78d73SVikas Chaudhary 					  nt_ddb_idx->flash_isid);
62361cb78d73SVikas Chaudhary 		ret = qla4xxx_compare_tuple_ddb(ha, fw_tddb, tmp_tddb, true);
62371cb78d73SVikas Chaudhary 		/* found duplicate ddb */
62381cb78d73SVikas Chaudhary 		if (ret == QLA_SUCCESS)
62391cb78d73SVikas Chaudhary 			goto exit_check;
62401cb78d73SVikas Chaudhary 	}
62411cb78d73SVikas Chaudhary 
62421cb78d73SVikas Chaudhary 	list_for_each_entry_safe(nt_ddb_idx, nt_ddb_idx_tmp, list_nt, list) {
62431cb78d73SVikas Chaudhary 		qla4xxx_convert_param_ddb(&nt_ddb_idx->fw_ddb, tmp_tddb, NULL);
62441cb78d73SVikas Chaudhary 
62451cb78d73SVikas Chaudhary 		ret = qla4xxx_should_update_isid(ha, tmp_tddb, fw_tddb);
62461cb78d73SVikas Chaudhary 		if (ret == QLA_SUCCESS) {
62471cb78d73SVikas Chaudhary 			rval = qla4xxx_update_isid(ha, list_nt, fw_ddb_entry);
62481cb78d73SVikas Chaudhary 			if (rval == QLA_SUCCESS)
62491cb78d73SVikas Chaudhary 				ret = QLA_ERROR;
62501cb78d73SVikas Chaudhary 			else
62511cb78d73SVikas Chaudhary 				ret = QLA_SUCCESS;
62521cb78d73SVikas Chaudhary 
625313483730SMike Christie 			goto exit_check;
625413483730SMike Christie 		}
625513483730SMike Christie 	}
625613483730SMike Christie 
625713483730SMike Christie exit_check:
625813483730SMike Christie 	if (fw_tddb)
625913483730SMike Christie 		vfree(fw_tddb);
626013483730SMike Christie 	if (tmp_tddb)
626113483730SMike Christie 		vfree(tmp_tddb);
626213483730SMike Christie 	return ret;
626313483730SMike Christie }
626413483730SMike Christie 
62654a4bc2e9SLalit Chandivade static void qla4xxx_free_ddb_list(struct list_head *list_ddb)
626613483730SMike Christie {
62674a4bc2e9SLalit Chandivade 	struct qla_ddb_index  *ddb_idx, *ddb_idx_tmp;
626813483730SMike Christie 
62694a4bc2e9SLalit Chandivade 	list_for_each_entry_safe(ddb_idx, ddb_idx_tmp, list_ddb, list) {
62704a4bc2e9SLalit Chandivade 		list_del_init(&ddb_idx->list);
62714a4bc2e9SLalit Chandivade 		vfree(ddb_idx);
627213483730SMike Christie 	}
627313483730SMike Christie }
627413483730SMike Christie 
627513483730SMike Christie static struct iscsi_endpoint *qla4xxx_get_ep_fwdb(struct scsi_qla_host *ha,
627613483730SMike Christie 					struct dev_db_entry *fw_ddb_entry)
627713483730SMike Christie {
627813483730SMike Christie 	struct iscsi_endpoint *ep;
627913483730SMike Christie 	struct sockaddr_in *addr;
628013483730SMike Christie 	struct sockaddr_in6 *addr6;
62813dd4849cSManish Rangankar 	struct sockaddr *t_addr;
62823dd4849cSManish Rangankar 	struct sockaddr_storage *dst_addr;
628313483730SMike Christie 	char *ip;
628413483730SMike Christie 
628513483730SMike Christie 	/* TODO: need to destroy on unload iscsi_endpoint*/
628613483730SMike Christie 	dst_addr = vmalloc(sizeof(*dst_addr));
628713483730SMike Christie 	if (!dst_addr)
628813483730SMike Christie 		return NULL;
628913483730SMike Christie 
629013483730SMike Christie 	if (fw_ddb_entry->options & DDB_OPT_IPV6_DEVICE) {
62913dd4849cSManish Rangankar 		t_addr = (struct sockaddr *)dst_addr;
62923dd4849cSManish Rangankar 		t_addr->sa_family = AF_INET6;
629313483730SMike Christie 		addr6 = (struct sockaddr_in6 *)dst_addr;
629413483730SMike Christie 		ip = (char *)&addr6->sin6_addr;
629513483730SMike Christie 		memcpy(ip, fw_ddb_entry->ip_addr, IPv6_ADDR_LEN);
629613483730SMike Christie 		addr6->sin6_port = htons(le16_to_cpu(fw_ddb_entry->port));
629713483730SMike Christie 
629813483730SMike Christie 	} else {
62993dd4849cSManish Rangankar 		t_addr = (struct sockaddr *)dst_addr;
63003dd4849cSManish Rangankar 		t_addr->sa_family = AF_INET;
630113483730SMike Christie 		addr = (struct sockaddr_in *)dst_addr;
630213483730SMike Christie 		ip = (char *)&addr->sin_addr;
630313483730SMike Christie 		memcpy(ip, fw_ddb_entry->ip_addr, IP_ADDR_LEN);
630413483730SMike Christie 		addr->sin_port = htons(le16_to_cpu(fw_ddb_entry->port));
630513483730SMike Christie 	}
630613483730SMike Christie 
63073dd4849cSManish Rangankar 	ep = qla4xxx_ep_connect(ha->host, (struct sockaddr *)dst_addr, 0);
630813483730SMike Christie 	vfree(dst_addr);
630913483730SMike Christie 	return ep;
631013483730SMike Christie }
631113483730SMike Christie 
631213483730SMike Christie static int qla4xxx_verify_boot_idx(struct scsi_qla_host *ha, uint16_t idx)
631313483730SMike Christie {
631413483730SMike Christie 	if (ql4xdisablesysfsboot)
631513483730SMike Christie 		return QLA_SUCCESS;
631613483730SMike Christie 	if (idx == ha->pri_ddb_idx || idx == ha->sec_ddb_idx)
631713483730SMike Christie 		return QLA_ERROR;
631813483730SMike Christie 	return QLA_SUCCESS;
631913483730SMike Christie }
632013483730SMike Christie 
632113483730SMike Christie static void qla4xxx_setup_flash_ddb_entry(struct scsi_qla_host *ha,
63221dc8ed5dSManish Rangankar 					  struct ddb_entry *ddb_entry,
63231dc8ed5dSManish Rangankar 					  uint16_t idx)
632413483730SMike Christie {
6325c28eaacaSNilesh Javali 	uint16_t def_timeout;
6326c28eaacaSNilesh Javali 
632713483730SMike Christie 	ddb_entry->ddb_type = FLASH_DDB;
632813483730SMike Christie 	ddb_entry->fw_ddb_index = INVALID_ENTRY;
632913483730SMike Christie 	ddb_entry->fw_ddb_device_state = DDB_DS_NO_CONNECTION_ACTIVE;
633013483730SMike Christie 	ddb_entry->ha = ha;
633113483730SMike Christie 	ddb_entry->unblock_sess = qla4xxx_unblock_flash_ddb;
633213483730SMike Christie 	ddb_entry->ddb_change = qla4xxx_flash_ddb_change;
6333946ac571SAdheer Chandravanshi 	ddb_entry->chap_tbl_idx = INVALID_ENTRY;
633413483730SMike Christie 
633513483730SMike Christie 	atomic_set(&ddb_entry->retry_relogin_timer, INVALID_ENTRY);
633613483730SMike Christie 	atomic_set(&ddb_entry->relogin_timer, 0);
633713483730SMike Christie 	atomic_set(&ddb_entry->relogin_retry_count, 0);
6338c28eaacaSNilesh Javali 	def_timeout = le16_to_cpu(ddb_entry->fw_ddb_entry.def_timeout);
633913483730SMike Christie 	ddb_entry->default_relogin_timeout =
6340c28eaacaSNilesh Javali 		(def_timeout > LOGIN_TOV) && (def_timeout < LOGIN_TOV * 10) ?
6341c28eaacaSNilesh Javali 		def_timeout : LOGIN_TOV;
634213483730SMike Christie 	ddb_entry->default_time2wait =
634313483730SMike Christie 		le16_to_cpu(ddb_entry->fw_ddb_entry.iscsi_def_time2wait);
63441dc8ed5dSManish Rangankar 
63451dc8ed5dSManish Rangankar 	if (ql4xdisablesysfsboot &&
63461dc8ed5dSManish Rangankar 	    (idx == ha->pri_ddb_idx || idx == ha->sec_ddb_idx))
63471dc8ed5dSManish Rangankar 		set_bit(DF_BOOT_TGT, &ddb_entry->flags);
634813483730SMike Christie }
634913483730SMike Christie 
635013483730SMike Christie static void qla4xxx_wait_for_ip_configuration(struct scsi_qla_host *ha)
635113483730SMike Christie {
635213483730SMike Christie 	uint32_t idx = 0;
635313483730SMike Christie 	uint32_t ip_idx[IP_ADDR_COUNT] = {0, 1, 2, 3}; /* 4 IP interfaces */
635413483730SMike Christie 	uint32_t sts[MBOX_REG_COUNT];
635513483730SMike Christie 	uint32_t ip_state;
635613483730SMike Christie 	unsigned long wtime;
635713483730SMike Christie 	int ret;
635813483730SMike Christie 
635913483730SMike Christie 	wtime = jiffies + (HZ * IP_CONFIG_TOV);
636013483730SMike Christie 	do {
636113483730SMike Christie 		for (idx = 0; idx < IP_ADDR_COUNT; idx++) {
636213483730SMike Christie 			if (ip_idx[idx] == -1)
636313483730SMike Christie 				continue;
636413483730SMike Christie 
636513483730SMike Christie 			ret = qla4xxx_get_ip_state(ha, 0, ip_idx[idx], sts);
636613483730SMike Christie 
636713483730SMike Christie 			if (ret == QLA_ERROR) {
636813483730SMike Christie 				ip_idx[idx] = -1;
636913483730SMike Christie 				continue;
637013483730SMike Christie 			}
637113483730SMike Christie 
637213483730SMike Christie 			ip_state = (sts[1] & IP_STATE_MASK) >> IP_STATE_SHIFT;
637313483730SMike Christie 
637413483730SMike Christie 			DEBUG2(ql4_printk(KERN_INFO, ha,
637513483730SMike Christie 					  "Waiting for IP state for idx = %d, state = 0x%x\n",
637613483730SMike Christie 					  ip_idx[idx], ip_state));
637713483730SMike Christie 			if (ip_state == IP_ADDRSTATE_UNCONFIGURED ||
637813483730SMike Christie 			    ip_state == IP_ADDRSTATE_INVALID ||
637913483730SMike Christie 			    ip_state == IP_ADDRSTATE_PREFERRED ||
638013483730SMike Christie 			    ip_state == IP_ADDRSTATE_DEPRICATED ||
638113483730SMike Christie 			    ip_state == IP_ADDRSTATE_DISABLING)
638213483730SMike Christie 				ip_idx[idx] = -1;
638313483730SMike Christie 		}
638413483730SMike Christie 
638513483730SMike Christie 		/* Break if all IP states checked */
638613483730SMike Christie 		if ((ip_idx[0] == -1) &&
638713483730SMike Christie 		    (ip_idx[1] == -1) &&
638813483730SMike Christie 		    (ip_idx[2] == -1) &&
638913483730SMike Christie 		    (ip_idx[3] == -1))
639013483730SMike Christie 			break;
639113483730SMike Christie 		schedule_timeout_uninterruptible(HZ);
639213483730SMike Christie 	} while (time_after(wtime, jiffies));
639313483730SMike Christie }
639413483730SMike Christie 
6395ad8bd45eSManish Rangankar static int qla4xxx_cmp_fw_stentry(struct dev_db_entry *fw_ddb_entry,
6396ad8bd45eSManish Rangankar 				  struct dev_db_entry *flash_ddb_entry)
6397ad8bd45eSManish Rangankar {
6398ad8bd45eSManish Rangankar 	uint16_t options = 0;
6399ad8bd45eSManish Rangankar 	size_t ip_len = IP_ADDR_LEN;
6400ad8bd45eSManish Rangankar 
6401ad8bd45eSManish Rangankar 	options = le16_to_cpu(fw_ddb_entry->options);
6402ad8bd45eSManish Rangankar 	if (options & DDB_OPT_IPV6_DEVICE)
6403ad8bd45eSManish Rangankar 		ip_len = IPv6_ADDR_LEN;
6404ad8bd45eSManish Rangankar 
6405ad8bd45eSManish Rangankar 	if (memcmp(fw_ddb_entry->ip_addr, flash_ddb_entry->ip_addr, ip_len))
6406ad8bd45eSManish Rangankar 		return QLA_ERROR;
6407ad8bd45eSManish Rangankar 
6408ad8bd45eSManish Rangankar 	if (memcmp(&fw_ddb_entry->isid[0], &flash_ddb_entry->isid[0],
6409ad8bd45eSManish Rangankar 		   sizeof(fw_ddb_entry->isid)))
6410ad8bd45eSManish Rangankar 		return QLA_ERROR;
6411ad8bd45eSManish Rangankar 
6412ad8bd45eSManish Rangankar 	if (memcmp(&fw_ddb_entry->port, &flash_ddb_entry->port,
6413ad8bd45eSManish Rangankar 		   sizeof(fw_ddb_entry->port)))
6414ad8bd45eSManish Rangankar 		return QLA_ERROR;
6415ad8bd45eSManish Rangankar 
6416ad8bd45eSManish Rangankar 	return QLA_SUCCESS;
6417ad8bd45eSManish Rangankar }
6418ad8bd45eSManish Rangankar 
6419ad8bd45eSManish Rangankar static int qla4xxx_find_flash_st_idx(struct scsi_qla_host *ha,
6420ad8bd45eSManish Rangankar 				     struct dev_db_entry *fw_ddb_entry,
6421ad8bd45eSManish Rangankar 				     uint32_t fw_idx, uint32_t *flash_index)
6422ad8bd45eSManish Rangankar {
6423ad8bd45eSManish Rangankar 	struct dev_db_entry *flash_ddb_entry;
6424ad8bd45eSManish Rangankar 	dma_addr_t flash_ddb_entry_dma;
6425ad8bd45eSManish Rangankar 	uint32_t idx = 0;
6426ad8bd45eSManish Rangankar 	int max_ddbs;
6427ad8bd45eSManish Rangankar 	int ret = QLA_ERROR, status;
6428ad8bd45eSManish Rangankar 
6429ad8bd45eSManish Rangankar 	max_ddbs =  is_qla40XX(ha) ? MAX_DEV_DB_ENTRIES_40XX :
6430ad8bd45eSManish Rangankar 				     MAX_DEV_DB_ENTRIES;
6431ad8bd45eSManish Rangankar 
6432ad8bd45eSManish Rangankar 	flash_ddb_entry = dma_pool_alloc(ha->fw_ddb_dma_pool, GFP_KERNEL,
6433ad8bd45eSManish Rangankar 					 &flash_ddb_entry_dma);
6434ad8bd45eSManish Rangankar 	if (flash_ddb_entry == NULL || fw_ddb_entry == NULL) {
6435ad8bd45eSManish Rangankar 		ql4_printk(KERN_ERR, ha, "Out of memory\n");
6436ad8bd45eSManish Rangankar 		goto exit_find_st_idx;
6437ad8bd45eSManish Rangankar 	}
6438ad8bd45eSManish Rangankar 
6439ad8bd45eSManish Rangankar 	status = qla4xxx_flashdb_by_index(ha, flash_ddb_entry,
6440ad8bd45eSManish Rangankar 					  flash_ddb_entry_dma, fw_idx);
6441ad8bd45eSManish Rangankar 	if (status == QLA_SUCCESS) {
6442ad8bd45eSManish Rangankar 		status = qla4xxx_cmp_fw_stentry(fw_ddb_entry, flash_ddb_entry);
6443ad8bd45eSManish Rangankar 		if (status == QLA_SUCCESS) {
6444ad8bd45eSManish Rangankar 			*flash_index = fw_idx;
6445ad8bd45eSManish Rangankar 			ret = QLA_SUCCESS;
6446ad8bd45eSManish Rangankar 			goto exit_find_st_idx;
6447ad8bd45eSManish Rangankar 		}
6448ad8bd45eSManish Rangankar 	}
6449ad8bd45eSManish Rangankar 
6450ad8bd45eSManish Rangankar 	for (idx = 0; idx < max_ddbs; idx++) {
6451ad8bd45eSManish Rangankar 		status = qla4xxx_flashdb_by_index(ha, flash_ddb_entry,
6452ad8bd45eSManish Rangankar 						  flash_ddb_entry_dma, idx);
6453ad8bd45eSManish Rangankar 		if (status == QLA_ERROR)
6454ad8bd45eSManish Rangankar 			continue;
6455ad8bd45eSManish Rangankar 
6456ad8bd45eSManish Rangankar 		status = qla4xxx_cmp_fw_stentry(fw_ddb_entry, flash_ddb_entry);
6457ad8bd45eSManish Rangankar 		if (status == QLA_SUCCESS) {
6458ad8bd45eSManish Rangankar 			*flash_index = idx;
6459ad8bd45eSManish Rangankar 			ret = QLA_SUCCESS;
6460ad8bd45eSManish Rangankar 			goto exit_find_st_idx;
6461ad8bd45eSManish Rangankar 		}
6462ad8bd45eSManish Rangankar 	}
6463ad8bd45eSManish Rangankar 
6464ad8bd45eSManish Rangankar 	if (idx == max_ddbs)
6465ad8bd45eSManish Rangankar 		ql4_printk(KERN_ERR, ha, "Failed to find ST [%d] in flash\n",
6466ad8bd45eSManish Rangankar 			   fw_idx);
6467ad8bd45eSManish Rangankar 
6468ad8bd45eSManish Rangankar exit_find_st_idx:
6469ad8bd45eSManish Rangankar 	if (flash_ddb_entry)
6470ad8bd45eSManish Rangankar 		dma_pool_free(ha->fw_ddb_dma_pool, flash_ddb_entry,
6471ad8bd45eSManish Rangankar 			      flash_ddb_entry_dma);
6472ad8bd45eSManish Rangankar 
6473ad8bd45eSManish Rangankar 	return ret;
6474ad8bd45eSManish Rangankar }
6475ad8bd45eSManish Rangankar 
64764a4bc2e9SLalit Chandivade static void qla4xxx_build_st_list(struct scsi_qla_host *ha,
64774a4bc2e9SLalit Chandivade 				  struct list_head *list_st)
647813483730SMike Christie {
64794a4bc2e9SLalit Chandivade 	struct qla_ddb_index  *st_ddb_idx;
648013483730SMike Christie 	int max_ddbs;
64814a4bc2e9SLalit Chandivade 	int fw_idx_size;
64824a4bc2e9SLalit Chandivade 	struct dev_db_entry *fw_ddb_entry;
64834a4bc2e9SLalit Chandivade 	dma_addr_t fw_ddb_dma;
648413483730SMike Christie 	int ret;
648513483730SMike Christie 	uint32_t idx = 0, next_idx = 0;
648613483730SMike Christie 	uint32_t state = 0, conn_err = 0;
6487ad8bd45eSManish Rangankar 	uint32_t flash_index = -1;
64884a4bc2e9SLalit Chandivade 	uint16_t conn_id = 0;
648913483730SMike Christie 
649013483730SMike Christie 	fw_ddb_entry = dma_pool_alloc(ha->fw_ddb_dma_pool, GFP_KERNEL,
649113483730SMike Christie 				      &fw_ddb_dma);
649213483730SMike Christie 	if (fw_ddb_entry == NULL) {
649313483730SMike Christie 		DEBUG2(ql4_printk(KERN_ERR, ha, "Out of memory\n"));
64944a4bc2e9SLalit Chandivade 		goto exit_st_list;
649513483730SMike Christie 	}
649613483730SMike Christie 
64974a4bc2e9SLalit Chandivade 	max_ddbs =  is_qla40XX(ha) ? MAX_DEV_DB_ENTRIES_40XX :
64984a4bc2e9SLalit Chandivade 				     MAX_DEV_DB_ENTRIES;
649913483730SMike Christie 	fw_idx_size = sizeof(struct qla_ddb_index);
650013483730SMike Christie 
650113483730SMike Christie 	for (idx = 0; idx < max_ddbs; idx = next_idx) {
65024a4bc2e9SLalit Chandivade 		ret = qla4xxx_get_fwddb_entry(ha, idx, fw_ddb_entry, fw_ddb_dma,
65034a4bc2e9SLalit Chandivade 					      NULL, &next_idx, &state,
65044a4bc2e9SLalit Chandivade 					      &conn_err, NULL, &conn_id);
650513483730SMike Christie 		if (ret == QLA_ERROR)
650613483730SMike Christie 			break;
650713483730SMike Christie 
6508981c982cSLalit Chandivade 		/* Ignore DDB if invalid state (unassigned) */
6509981c982cSLalit Chandivade 		if (state == DDB_DS_UNASSIGNED)
6510981c982cSLalit Chandivade 			goto continue_next_st;
6511981c982cSLalit Chandivade 
651213483730SMike Christie 		/* Check if ST, add to the list_st */
651313483730SMike Christie 		if (strlen((char *) fw_ddb_entry->iscsi_name) != 0)
651413483730SMike Christie 			goto continue_next_st;
651513483730SMike Christie 
651613483730SMike Christie 		st_ddb_idx = vzalloc(fw_idx_size);
651713483730SMike Christie 		if (!st_ddb_idx)
651813483730SMike Christie 			break;
651913483730SMike Christie 
6520ad8bd45eSManish Rangankar 		ret = qla4xxx_find_flash_st_idx(ha, fw_ddb_entry, idx,
6521ad8bd45eSManish Rangankar 						&flash_index);
6522ad8bd45eSManish Rangankar 		if (ret == QLA_ERROR) {
6523ad8bd45eSManish Rangankar 			ql4_printk(KERN_ERR, ha,
6524ad8bd45eSManish Rangankar 				   "No flash entry for ST at idx [%d]\n", idx);
6525ad8bd45eSManish Rangankar 			st_ddb_idx->flash_ddb_idx = idx;
6526ad8bd45eSManish Rangankar 		} else {
6527ad8bd45eSManish Rangankar 			ql4_printk(KERN_INFO, ha,
6528ad8bd45eSManish Rangankar 				   "ST at idx [%d] is stored at flash [%d]\n",
6529ad8bd45eSManish Rangankar 				   idx, flash_index);
6530ad8bd45eSManish Rangankar 			st_ddb_idx->flash_ddb_idx = flash_index;
6531ad8bd45eSManish Rangankar 		}
6532ad8bd45eSManish Rangankar 
653313483730SMike Christie 		st_ddb_idx->fw_ddb_idx = idx;
653413483730SMike Christie 
65354a4bc2e9SLalit Chandivade 		list_add_tail(&st_ddb_idx->list, list_st);
653613483730SMike Christie continue_next_st:
653713483730SMike Christie 		if (next_idx == 0)
653813483730SMike Christie 			break;
653913483730SMike Christie 	}
654013483730SMike Christie 
65414a4bc2e9SLalit Chandivade exit_st_list:
65424a4bc2e9SLalit Chandivade 	if (fw_ddb_entry)
65434a4bc2e9SLalit Chandivade 		dma_pool_free(ha->fw_ddb_dma_pool, fw_ddb_entry, fw_ddb_dma);
65444a4bc2e9SLalit Chandivade }
65454a4bc2e9SLalit Chandivade 
65464a4bc2e9SLalit Chandivade /**
65474a4bc2e9SLalit Chandivade  * qla4xxx_remove_failed_ddb - Remove inactive or failed ddb from list
65484a4bc2e9SLalit Chandivade  * @ha: pointer to adapter structure
65494a4bc2e9SLalit Chandivade  * @list_ddb: List from which failed ddb to be removed
65504a4bc2e9SLalit Chandivade  *
65514a4bc2e9SLalit Chandivade  * Iterate over the list of DDBs and find and remove DDBs that are either in
65524a4bc2e9SLalit Chandivade  * no connection active state or failed state
65534a4bc2e9SLalit Chandivade  **/
65544a4bc2e9SLalit Chandivade static void qla4xxx_remove_failed_ddb(struct scsi_qla_host *ha,
65554a4bc2e9SLalit Chandivade 				      struct list_head *list_ddb)
65564a4bc2e9SLalit Chandivade {
65574a4bc2e9SLalit Chandivade 	struct qla_ddb_index  *ddb_idx, *ddb_idx_tmp;
65584a4bc2e9SLalit Chandivade 	uint32_t next_idx = 0;
65594a4bc2e9SLalit Chandivade 	uint32_t state = 0, conn_err = 0;
65604a4bc2e9SLalit Chandivade 	int ret;
65614a4bc2e9SLalit Chandivade 
65624a4bc2e9SLalit Chandivade 	list_for_each_entry_safe(ddb_idx, ddb_idx_tmp, list_ddb, list) {
65634a4bc2e9SLalit Chandivade 		ret = qla4xxx_get_fwddb_entry(ha, ddb_idx->fw_ddb_idx,
65644a4bc2e9SLalit Chandivade 					      NULL, 0, NULL, &next_idx, &state,
65654a4bc2e9SLalit Chandivade 					      &conn_err, NULL, NULL);
65664a4bc2e9SLalit Chandivade 		if (ret == QLA_ERROR)
65674a4bc2e9SLalit Chandivade 			continue;
65684a4bc2e9SLalit Chandivade 
65694a4bc2e9SLalit Chandivade 		if (state == DDB_DS_NO_CONNECTION_ACTIVE ||
65704a4bc2e9SLalit Chandivade 		    state == DDB_DS_SESSION_FAILED) {
65714a4bc2e9SLalit Chandivade 			list_del_init(&ddb_idx->list);
65724a4bc2e9SLalit Chandivade 			vfree(ddb_idx);
65734a4bc2e9SLalit Chandivade 		}
65744a4bc2e9SLalit Chandivade 	}
65754a4bc2e9SLalit Chandivade }
65764a4bc2e9SLalit Chandivade 
6577ad8bd45eSManish Rangankar static void qla4xxx_update_sess_disc_idx(struct scsi_qla_host *ha,
6578ad8bd45eSManish Rangankar 					 struct ddb_entry *ddb_entry,
6579ad8bd45eSManish Rangankar 					 struct dev_db_entry *fw_ddb_entry)
6580ad8bd45eSManish Rangankar {
6581ad8bd45eSManish Rangankar 	struct iscsi_cls_session *cls_sess;
6582ad8bd45eSManish Rangankar 	struct iscsi_session *sess;
6583ad8bd45eSManish Rangankar 	uint32_t max_ddbs = 0;
6584ad8bd45eSManish Rangankar 	uint16_t ddb_link = -1;
6585ad8bd45eSManish Rangankar 
6586ad8bd45eSManish Rangankar 	max_ddbs =  is_qla40XX(ha) ? MAX_DEV_DB_ENTRIES_40XX :
6587ad8bd45eSManish Rangankar 				     MAX_DEV_DB_ENTRIES;
6588ad8bd45eSManish Rangankar 
6589ad8bd45eSManish Rangankar 	cls_sess = ddb_entry->sess;
6590ad8bd45eSManish Rangankar 	sess = cls_sess->dd_data;
6591ad8bd45eSManish Rangankar 
6592ad8bd45eSManish Rangankar 	ddb_link = le16_to_cpu(fw_ddb_entry->ddb_link);
6593ad8bd45eSManish Rangankar 	if (ddb_link < max_ddbs)
6594ad8bd45eSManish Rangankar 		sess->discovery_parent_idx = ddb_link;
6595ad8bd45eSManish Rangankar 	else
6596ad8bd45eSManish Rangankar 		sess->discovery_parent_idx = DDB_NO_LINK;
6597ad8bd45eSManish Rangankar }
6598ad8bd45eSManish Rangankar 
65994a4bc2e9SLalit Chandivade static int qla4xxx_sess_conn_setup(struct scsi_qla_host *ha,
66004a4bc2e9SLalit Chandivade 				   struct dev_db_entry *fw_ddb_entry,
66011dc8ed5dSManish Rangankar 				   int is_reset, uint16_t idx)
66024a4bc2e9SLalit Chandivade {
66034a4bc2e9SLalit Chandivade 	struct iscsi_cls_session *cls_sess;
66044a4bc2e9SLalit Chandivade 	struct iscsi_session *sess;
66054a4bc2e9SLalit Chandivade 	struct iscsi_cls_conn *cls_conn;
66064a4bc2e9SLalit Chandivade 	struct iscsi_endpoint *ep;
66074a4bc2e9SLalit Chandivade 	uint16_t cmds_max = 32;
66084a4bc2e9SLalit Chandivade 	uint16_t conn_id = 0;
66094a4bc2e9SLalit Chandivade 	uint32_t initial_cmdsn = 0;
66104a4bc2e9SLalit Chandivade 	int ret = QLA_SUCCESS;
66114a4bc2e9SLalit Chandivade 
66124a4bc2e9SLalit Chandivade 	struct ddb_entry *ddb_entry = NULL;
66134a4bc2e9SLalit Chandivade 
66144a4bc2e9SLalit Chandivade 	/* Create session object, with INVALID_ENTRY,
66154a4bc2e9SLalit Chandivade 	 * the targer_id would get set when we issue the login
66164a4bc2e9SLalit Chandivade 	 */
66174a4bc2e9SLalit Chandivade 	cls_sess = iscsi_session_setup(&qla4xxx_iscsi_transport, ha->host,
66184a4bc2e9SLalit Chandivade 				       cmds_max, sizeof(struct ddb_entry),
66194a4bc2e9SLalit Chandivade 				       sizeof(struct ql4_task_data),
66204a4bc2e9SLalit Chandivade 				       initial_cmdsn, INVALID_ENTRY);
66214a4bc2e9SLalit Chandivade 	if (!cls_sess) {
66224a4bc2e9SLalit Chandivade 		ret = QLA_ERROR;
66234a4bc2e9SLalit Chandivade 		goto exit_setup;
66244a4bc2e9SLalit Chandivade 	}
66254a4bc2e9SLalit Chandivade 
66264a4bc2e9SLalit Chandivade 	/*
66274a4bc2e9SLalit Chandivade 	 * so calling module_put function to decrement the
66284a4bc2e9SLalit Chandivade 	 * reference count.
66294a4bc2e9SLalit Chandivade 	 **/
66304a4bc2e9SLalit Chandivade 	module_put(qla4xxx_iscsi_transport.owner);
66314a4bc2e9SLalit Chandivade 	sess = cls_sess->dd_data;
66324a4bc2e9SLalit Chandivade 	ddb_entry = sess->dd_data;
66334a4bc2e9SLalit Chandivade 	ddb_entry->sess = cls_sess;
66344a4bc2e9SLalit Chandivade 
66354a4bc2e9SLalit Chandivade 	cls_sess->recovery_tmo = ql4xsess_recovery_tmo;
66364a4bc2e9SLalit Chandivade 	memcpy(&ddb_entry->fw_ddb_entry, fw_ddb_entry,
66374a4bc2e9SLalit Chandivade 	       sizeof(struct dev_db_entry));
66384a4bc2e9SLalit Chandivade 
66391dc8ed5dSManish Rangankar 	qla4xxx_setup_flash_ddb_entry(ha, ddb_entry, idx);
66404a4bc2e9SLalit Chandivade 
66414a4bc2e9SLalit Chandivade 	cls_conn = iscsi_conn_setup(cls_sess, sizeof(struct qla_conn), conn_id);
66424a4bc2e9SLalit Chandivade 
66434a4bc2e9SLalit Chandivade 	if (!cls_conn) {
66444a4bc2e9SLalit Chandivade 		ret = QLA_ERROR;
66454a4bc2e9SLalit Chandivade 		goto exit_setup;
66464a4bc2e9SLalit Chandivade 	}
66474a4bc2e9SLalit Chandivade 
66484a4bc2e9SLalit Chandivade 	ddb_entry->conn = cls_conn;
66494a4bc2e9SLalit Chandivade 
66504a4bc2e9SLalit Chandivade 	/* Setup ep, for displaying attributes in sysfs */
66514a4bc2e9SLalit Chandivade 	ep = qla4xxx_get_ep_fwdb(ha, fw_ddb_entry);
66524a4bc2e9SLalit Chandivade 	if (ep) {
66534a4bc2e9SLalit Chandivade 		ep->conn = cls_conn;
66544a4bc2e9SLalit Chandivade 		cls_conn->ep = ep;
66554a4bc2e9SLalit Chandivade 	} else {
66564a4bc2e9SLalit Chandivade 		DEBUG2(ql4_printk(KERN_ERR, ha, "Unable to get ep\n"));
66574a4bc2e9SLalit Chandivade 		ret = QLA_ERROR;
66584a4bc2e9SLalit Chandivade 		goto exit_setup;
66594a4bc2e9SLalit Chandivade 	}
66604a4bc2e9SLalit Chandivade 
66614a4bc2e9SLalit Chandivade 	/* Update sess/conn params */
66624a4bc2e9SLalit Chandivade 	qla4xxx_copy_fwddb_param(ha, fw_ddb_entry, cls_sess, cls_conn);
6663ad8bd45eSManish Rangankar 	qla4xxx_update_sess_disc_idx(ha, ddb_entry, fw_ddb_entry);
66644a4bc2e9SLalit Chandivade 
66654a4bc2e9SLalit Chandivade 	if (is_reset == RESET_ADAPTER) {
66664a4bc2e9SLalit Chandivade 		iscsi_block_session(cls_sess);
66674a4bc2e9SLalit Chandivade 		/* Use the relogin path to discover new devices
66684a4bc2e9SLalit Chandivade 		 *  by short-circuting the logic of setting
66694a4bc2e9SLalit Chandivade 		 *  timer to relogin - instead set the flags
66704a4bc2e9SLalit Chandivade 		 *  to initiate login right away.
66714a4bc2e9SLalit Chandivade 		 */
66724a4bc2e9SLalit Chandivade 		set_bit(DPC_RELOGIN_DEVICE, &ha->dpc_flags);
66734a4bc2e9SLalit Chandivade 		set_bit(DF_RELOGIN, &ddb_entry->flags);
66744a4bc2e9SLalit Chandivade 	}
66754a4bc2e9SLalit Chandivade 
66764a4bc2e9SLalit Chandivade exit_setup:
66774a4bc2e9SLalit Chandivade 	return ret;
66784a4bc2e9SLalit Chandivade }
66794a4bc2e9SLalit Chandivade 
6680ad8bd45eSManish Rangankar static void qla4xxx_update_fw_ddb_link(struct scsi_qla_host *ha,
6681ad8bd45eSManish Rangankar 				       struct list_head *list_ddb,
6682ad8bd45eSManish Rangankar 				       struct dev_db_entry *fw_ddb_entry)
6683ad8bd45eSManish Rangankar {
6684ad8bd45eSManish Rangankar 	struct qla_ddb_index  *ddb_idx, *ddb_idx_tmp;
6685ad8bd45eSManish Rangankar 	uint16_t ddb_link;
6686ad8bd45eSManish Rangankar 
6687ad8bd45eSManish Rangankar 	ddb_link = le16_to_cpu(fw_ddb_entry->ddb_link);
6688ad8bd45eSManish Rangankar 
6689ad8bd45eSManish Rangankar 	list_for_each_entry_safe(ddb_idx, ddb_idx_tmp, list_ddb, list) {
6690ad8bd45eSManish Rangankar 		if (ddb_idx->fw_ddb_idx == ddb_link) {
6691ad8bd45eSManish Rangankar 			DEBUG2(ql4_printk(KERN_INFO, ha,
6692ad8bd45eSManish Rangankar 					  "Updating NT parent idx from [%d] to [%d]\n",
6693ad8bd45eSManish Rangankar 					  ddb_link, ddb_idx->flash_ddb_idx));
6694ad8bd45eSManish Rangankar 			fw_ddb_entry->ddb_link =
6695ad8bd45eSManish Rangankar 					    cpu_to_le16(ddb_idx->flash_ddb_idx);
6696ad8bd45eSManish Rangankar 			return;
6697ad8bd45eSManish Rangankar 		}
6698ad8bd45eSManish Rangankar 	}
6699ad8bd45eSManish Rangankar }
6700ad8bd45eSManish Rangankar 
67014a4bc2e9SLalit Chandivade static void qla4xxx_build_nt_list(struct scsi_qla_host *ha,
6702ad8bd45eSManish Rangankar 				  struct list_head *list_nt,
6703ad8bd45eSManish Rangankar 				  struct list_head *list_st,
6704ad8bd45eSManish Rangankar 				  int is_reset)
67054a4bc2e9SLalit Chandivade {
67064a4bc2e9SLalit Chandivade 	struct dev_db_entry *fw_ddb_entry;
6707ad8bd45eSManish Rangankar 	struct ddb_entry *ddb_entry = NULL;
67084a4bc2e9SLalit Chandivade 	dma_addr_t fw_ddb_dma;
67094a4bc2e9SLalit Chandivade 	int max_ddbs;
67104a4bc2e9SLalit Chandivade 	int fw_idx_size;
67114a4bc2e9SLalit Chandivade 	int ret;
67124a4bc2e9SLalit Chandivade 	uint32_t idx = 0, next_idx = 0;
67134a4bc2e9SLalit Chandivade 	uint32_t state = 0, conn_err = 0;
6714ad8bd45eSManish Rangankar 	uint32_t ddb_idx = -1;
67154a4bc2e9SLalit Chandivade 	uint16_t conn_id = 0;
6716ad8bd45eSManish Rangankar 	uint16_t ddb_link = -1;
67174a4bc2e9SLalit Chandivade 	struct qla_ddb_index  *nt_ddb_idx;
67184a4bc2e9SLalit Chandivade 
67194a4bc2e9SLalit Chandivade 	fw_ddb_entry = dma_pool_alloc(ha->fw_ddb_dma_pool, GFP_KERNEL,
67204a4bc2e9SLalit Chandivade 				      &fw_ddb_dma);
67214a4bc2e9SLalit Chandivade 	if (fw_ddb_entry == NULL) {
67224a4bc2e9SLalit Chandivade 		DEBUG2(ql4_printk(KERN_ERR, ha, "Out of memory\n"));
67234a4bc2e9SLalit Chandivade 		goto exit_nt_list;
67244a4bc2e9SLalit Chandivade 	}
67254a4bc2e9SLalit Chandivade 	max_ddbs =  is_qla40XX(ha) ? MAX_DEV_DB_ENTRIES_40XX :
67264a4bc2e9SLalit Chandivade 				     MAX_DEV_DB_ENTRIES;
67274a4bc2e9SLalit Chandivade 	fw_idx_size = sizeof(struct qla_ddb_index);
67284a4bc2e9SLalit Chandivade 
67294a4bc2e9SLalit Chandivade 	for (idx = 0; idx < max_ddbs; idx = next_idx) {
67304a4bc2e9SLalit Chandivade 		ret = qla4xxx_get_fwddb_entry(ha, idx, fw_ddb_entry, fw_ddb_dma,
67314a4bc2e9SLalit Chandivade 					      NULL, &next_idx, &state,
67324a4bc2e9SLalit Chandivade 					      &conn_err, NULL, &conn_id);
67334a4bc2e9SLalit Chandivade 		if (ret == QLA_ERROR)
67344a4bc2e9SLalit Chandivade 			break;
67354a4bc2e9SLalit Chandivade 
67364a4bc2e9SLalit Chandivade 		if (qla4xxx_verify_boot_idx(ha, idx) != QLA_SUCCESS)
67374a4bc2e9SLalit Chandivade 			goto continue_next_nt;
67384a4bc2e9SLalit Chandivade 
67394a4bc2e9SLalit Chandivade 		/* Check if NT, then add to list it */
67404a4bc2e9SLalit Chandivade 		if (strlen((char *) fw_ddb_entry->iscsi_name) == 0)
67414a4bc2e9SLalit Chandivade 			goto continue_next_nt;
67424a4bc2e9SLalit Chandivade 
6743ad8bd45eSManish Rangankar 		ddb_link = le16_to_cpu(fw_ddb_entry->ddb_link);
6744ad8bd45eSManish Rangankar 		if (ddb_link < max_ddbs)
6745ad8bd45eSManish Rangankar 			qla4xxx_update_fw_ddb_link(ha, list_st, fw_ddb_entry);
6746ad8bd45eSManish Rangankar 
67474a4bc2e9SLalit Chandivade 		if (!(state == DDB_DS_NO_CONNECTION_ACTIVE ||
6748ad8bd45eSManish Rangankar 		    state == DDB_DS_SESSION_FAILED) &&
6749ad8bd45eSManish Rangankar 		    (is_reset == INIT_ADAPTER))
67504a4bc2e9SLalit Chandivade 			goto continue_next_nt;
67514a4bc2e9SLalit Chandivade 
67524a4bc2e9SLalit Chandivade 		DEBUG2(ql4_printk(KERN_INFO, ha,
67534a4bc2e9SLalit Chandivade 				  "Adding  DDB to session = 0x%x\n", idx));
6754ad8bd45eSManish Rangankar 
67554a4bc2e9SLalit Chandivade 		if (is_reset == INIT_ADAPTER) {
67564a4bc2e9SLalit Chandivade 			nt_ddb_idx = vmalloc(fw_idx_size);
67574a4bc2e9SLalit Chandivade 			if (!nt_ddb_idx)
67584a4bc2e9SLalit Chandivade 				break;
67594a4bc2e9SLalit Chandivade 
67604a4bc2e9SLalit Chandivade 			nt_ddb_idx->fw_ddb_idx = idx;
67614a4bc2e9SLalit Chandivade 
67621cb78d73SVikas Chaudhary 			/* Copy original isid as it may get updated in function
67631cb78d73SVikas Chaudhary 			 * qla4xxx_update_isid(). We need original isid in
67641cb78d73SVikas Chaudhary 			 * function qla4xxx_compare_tuple_ddb to find duplicate
67651cb78d73SVikas Chaudhary 			 * target */
67661cb78d73SVikas Chaudhary 			memcpy(&nt_ddb_idx->flash_isid[0],
67671cb78d73SVikas Chaudhary 			       &fw_ddb_entry->isid[0],
67681cb78d73SVikas Chaudhary 			       sizeof(nt_ddb_idx->flash_isid));
67694a4bc2e9SLalit Chandivade 
67701cb78d73SVikas Chaudhary 			ret = qla4xxx_is_flash_ddb_exists(ha, list_nt,
67711cb78d73SVikas Chaudhary 							  fw_ddb_entry);
67721cb78d73SVikas Chaudhary 			if (ret == QLA_SUCCESS) {
67731cb78d73SVikas Chaudhary 				/* free nt_ddb_idx and do not add to list_nt */
67744a4bc2e9SLalit Chandivade 				vfree(nt_ddb_idx);
67754a4bc2e9SLalit Chandivade 				goto continue_next_nt;
67764a4bc2e9SLalit Chandivade 			}
67771cb78d73SVikas Chaudhary 
67781cb78d73SVikas Chaudhary 			/* Copy updated isid */
67791cb78d73SVikas Chaudhary 			memcpy(&nt_ddb_idx->fw_ddb, fw_ddb_entry,
67801cb78d73SVikas Chaudhary 			       sizeof(struct dev_db_entry));
67811cb78d73SVikas Chaudhary 
67824a4bc2e9SLalit Chandivade 			list_add_tail(&nt_ddb_idx->list, list_nt);
67834a4bc2e9SLalit Chandivade 		} else if (is_reset == RESET_ADAPTER) {
6784ad8bd45eSManish Rangankar 			ret = qla4xxx_is_session_exists(ha, fw_ddb_entry,
6785ad8bd45eSManish Rangankar 							&ddb_idx);
6786ad8bd45eSManish Rangankar 			if (ret == QLA_SUCCESS) {
6787ad8bd45eSManish Rangankar 				ddb_entry = qla4xxx_lookup_ddb_by_fw_index(ha,
6788ad8bd45eSManish Rangankar 								       ddb_idx);
6789ad8bd45eSManish Rangankar 				if (ddb_entry != NULL)
6790ad8bd45eSManish Rangankar 					qla4xxx_update_sess_disc_idx(ha,
6791ad8bd45eSManish Rangankar 								     ddb_entry,
6792ad8bd45eSManish Rangankar 								  fw_ddb_entry);
67934a4bc2e9SLalit Chandivade 				goto continue_next_nt;
67944a4bc2e9SLalit Chandivade 			}
6795ad8bd45eSManish Rangankar 		}
67964a4bc2e9SLalit Chandivade 
67971dc8ed5dSManish Rangankar 		ret = qla4xxx_sess_conn_setup(ha, fw_ddb_entry, is_reset, idx);
67984a4bc2e9SLalit Chandivade 		if (ret == QLA_ERROR)
67994a4bc2e9SLalit Chandivade 			goto exit_nt_list;
68004a4bc2e9SLalit Chandivade 
68014a4bc2e9SLalit Chandivade continue_next_nt:
68024a4bc2e9SLalit Chandivade 		if (next_idx == 0)
68034a4bc2e9SLalit Chandivade 			break;
68044a4bc2e9SLalit Chandivade 	}
68054a4bc2e9SLalit Chandivade 
68064a4bc2e9SLalit Chandivade exit_nt_list:
68074a4bc2e9SLalit Chandivade 	if (fw_ddb_entry)
68084a4bc2e9SLalit Chandivade 		dma_pool_free(ha->fw_ddb_dma_pool, fw_ddb_entry, fw_ddb_dma);
68094a4bc2e9SLalit Chandivade }
68104a4bc2e9SLalit Chandivade 
68111e9e2be3SAdheer Chandravanshi static void qla4xxx_build_new_nt_list(struct scsi_qla_host *ha,
6812ad8bd45eSManish Rangankar 				      struct list_head *list_nt,
6813ad8bd45eSManish Rangankar 				      uint16_t target_id)
68141e9e2be3SAdheer Chandravanshi {
68151e9e2be3SAdheer Chandravanshi 	struct dev_db_entry *fw_ddb_entry;
68161e9e2be3SAdheer Chandravanshi 	dma_addr_t fw_ddb_dma;
68171e9e2be3SAdheer Chandravanshi 	int max_ddbs;
68181e9e2be3SAdheer Chandravanshi 	int fw_idx_size;
68191e9e2be3SAdheer Chandravanshi 	int ret;
68201e9e2be3SAdheer Chandravanshi 	uint32_t idx = 0, next_idx = 0;
68211e9e2be3SAdheer Chandravanshi 	uint32_t state = 0, conn_err = 0;
68221e9e2be3SAdheer Chandravanshi 	uint16_t conn_id = 0;
68231e9e2be3SAdheer Chandravanshi 	struct qla_ddb_index  *nt_ddb_idx;
68241e9e2be3SAdheer Chandravanshi 
68251e9e2be3SAdheer Chandravanshi 	fw_ddb_entry = dma_pool_alloc(ha->fw_ddb_dma_pool, GFP_KERNEL,
68261e9e2be3SAdheer Chandravanshi 				      &fw_ddb_dma);
68271e9e2be3SAdheer Chandravanshi 	if (fw_ddb_entry == NULL) {
68281e9e2be3SAdheer Chandravanshi 		DEBUG2(ql4_printk(KERN_ERR, ha, "Out of memory\n"));
68291e9e2be3SAdheer Chandravanshi 		goto exit_new_nt_list;
68301e9e2be3SAdheer Chandravanshi 	}
68311e9e2be3SAdheer Chandravanshi 	max_ddbs =  is_qla40XX(ha) ? MAX_DEV_DB_ENTRIES_40XX :
68321e9e2be3SAdheer Chandravanshi 				     MAX_DEV_DB_ENTRIES;
68331e9e2be3SAdheer Chandravanshi 	fw_idx_size = sizeof(struct qla_ddb_index);
68341e9e2be3SAdheer Chandravanshi 
68351e9e2be3SAdheer Chandravanshi 	for (idx = 0; idx < max_ddbs; idx = next_idx) {
68361e9e2be3SAdheer Chandravanshi 		ret = qla4xxx_get_fwddb_entry(ha, idx, fw_ddb_entry, fw_ddb_dma,
68371e9e2be3SAdheer Chandravanshi 					      NULL, &next_idx, &state,
68381e9e2be3SAdheer Chandravanshi 					      &conn_err, NULL, &conn_id);
68391e9e2be3SAdheer Chandravanshi 		if (ret == QLA_ERROR)
68401e9e2be3SAdheer Chandravanshi 			break;
68411e9e2be3SAdheer Chandravanshi 
68421e9e2be3SAdheer Chandravanshi 		/* Check if NT, then add it to list */
68431e9e2be3SAdheer Chandravanshi 		if (strlen((char *)fw_ddb_entry->iscsi_name) == 0)
68441e9e2be3SAdheer Chandravanshi 			goto continue_next_new_nt;
68451e9e2be3SAdheer Chandravanshi 
68461e9e2be3SAdheer Chandravanshi 		if (!(state == DDB_DS_NO_CONNECTION_ACTIVE))
68471e9e2be3SAdheer Chandravanshi 			goto continue_next_new_nt;
68481e9e2be3SAdheer Chandravanshi 
68491e9e2be3SAdheer Chandravanshi 		DEBUG2(ql4_printk(KERN_INFO, ha,
68501e9e2be3SAdheer Chandravanshi 				  "Adding  DDB to session = 0x%x\n", idx));
68511e9e2be3SAdheer Chandravanshi 
68521e9e2be3SAdheer Chandravanshi 		nt_ddb_idx = vmalloc(fw_idx_size);
68531e9e2be3SAdheer Chandravanshi 		if (!nt_ddb_idx)
68541e9e2be3SAdheer Chandravanshi 			break;
68551e9e2be3SAdheer Chandravanshi 
68561e9e2be3SAdheer Chandravanshi 		nt_ddb_idx->fw_ddb_idx = idx;
68571e9e2be3SAdheer Chandravanshi 
6858ad8bd45eSManish Rangankar 		ret = qla4xxx_is_session_exists(ha, fw_ddb_entry, NULL);
68591e9e2be3SAdheer Chandravanshi 		if (ret == QLA_SUCCESS) {
68601e9e2be3SAdheer Chandravanshi 			/* free nt_ddb_idx and do not add to list_nt */
68611e9e2be3SAdheer Chandravanshi 			vfree(nt_ddb_idx);
68621e9e2be3SAdheer Chandravanshi 			goto continue_next_new_nt;
68631e9e2be3SAdheer Chandravanshi 		}
68641e9e2be3SAdheer Chandravanshi 
6865ad8bd45eSManish Rangankar 		if (target_id < max_ddbs)
6866ad8bd45eSManish Rangankar 			fw_ddb_entry->ddb_link = cpu_to_le16(target_id);
6867ad8bd45eSManish Rangankar 
68681e9e2be3SAdheer Chandravanshi 		list_add_tail(&nt_ddb_idx->list, list_nt);
68691e9e2be3SAdheer Chandravanshi 
68701e9e2be3SAdheer Chandravanshi 		ret = qla4xxx_sess_conn_setup(ha, fw_ddb_entry, RESET_ADAPTER,
68711e9e2be3SAdheer Chandravanshi 					      idx);
68721e9e2be3SAdheer Chandravanshi 		if (ret == QLA_ERROR)
68731e9e2be3SAdheer Chandravanshi 			goto exit_new_nt_list;
68741e9e2be3SAdheer Chandravanshi 
68751e9e2be3SAdheer Chandravanshi continue_next_new_nt:
68761e9e2be3SAdheer Chandravanshi 		if (next_idx == 0)
68771e9e2be3SAdheer Chandravanshi 			break;
68781e9e2be3SAdheer Chandravanshi 	}
68791e9e2be3SAdheer Chandravanshi 
68801e9e2be3SAdheer Chandravanshi exit_new_nt_list:
68811e9e2be3SAdheer Chandravanshi 	if (fw_ddb_entry)
68821e9e2be3SAdheer Chandravanshi 		dma_pool_free(ha->fw_ddb_dma_pool, fw_ddb_entry, fw_ddb_dma);
68831e9e2be3SAdheer Chandravanshi }
68841e9e2be3SAdheer Chandravanshi 
68851e9e2be3SAdheer Chandravanshi /**
68861e9e2be3SAdheer Chandravanshi  * qla4xxx_sysfs_ddb_is_non_persistent - check for non-persistence of ddb entry
68871e9e2be3SAdheer Chandravanshi  * @dev: dev associated with the sysfs entry
68881e9e2be3SAdheer Chandravanshi  * @data: pointer to flashnode session object
68891e9e2be3SAdheer Chandravanshi  *
68901e9e2be3SAdheer Chandravanshi  * Returns:
68911e9e2be3SAdheer Chandravanshi  *	1: if flashnode entry is non-persistent
68921e9e2be3SAdheer Chandravanshi  *	0: if flashnode entry is persistent
68931e9e2be3SAdheer Chandravanshi  **/
68941e9e2be3SAdheer Chandravanshi static int qla4xxx_sysfs_ddb_is_non_persistent(struct device *dev, void *data)
68951e9e2be3SAdheer Chandravanshi {
68961e9e2be3SAdheer Chandravanshi 	struct iscsi_bus_flash_session *fnode_sess;
68971e9e2be3SAdheer Chandravanshi 
68981e9e2be3SAdheer Chandravanshi 	if (!iscsi_flashnode_bus_match(dev, NULL))
68991e9e2be3SAdheer Chandravanshi 		return 0;
69001e9e2be3SAdheer Chandravanshi 
69011e9e2be3SAdheer Chandravanshi 	fnode_sess = iscsi_dev_to_flash_session(dev);
69021e9e2be3SAdheer Chandravanshi 
69031e9e2be3SAdheer Chandravanshi 	return (fnode_sess->flash_state == DEV_DB_NON_PERSISTENT);
69041e9e2be3SAdheer Chandravanshi }
69051e9e2be3SAdheer Chandravanshi 
69061e9e2be3SAdheer Chandravanshi /**
69071e9e2be3SAdheer Chandravanshi  * qla4xxx_sysfs_ddb_tgt_create - Create sysfs entry for target
69081e9e2be3SAdheer Chandravanshi  * @ha: pointer to host
69091e9e2be3SAdheer Chandravanshi  * @fw_ddb_entry: flash ddb data
69101e9e2be3SAdheer Chandravanshi  * @idx: target index
69111e9e2be3SAdheer Chandravanshi  * @user: if set then this call is made from userland else from kernel
69121e9e2be3SAdheer Chandravanshi  *
69131e9e2be3SAdheer Chandravanshi  * Returns:
69141e9e2be3SAdheer Chandravanshi  * On sucess: QLA_SUCCESS
69151e9e2be3SAdheer Chandravanshi  * On failure: QLA_ERROR
69161e9e2be3SAdheer Chandravanshi  *
69171e9e2be3SAdheer Chandravanshi  * This create separate sysfs entries for session and connection attributes of
69181e9e2be3SAdheer Chandravanshi  * the given fw ddb entry.
69191e9e2be3SAdheer Chandravanshi  * If this is invoked as a result of a userspace call then the entry is marked
69201e9e2be3SAdheer Chandravanshi  * as nonpersistent using flash_state field.
69211e9e2be3SAdheer Chandravanshi  **/
692228e02f1aSVikas Chaudhary static int qla4xxx_sysfs_ddb_tgt_create(struct scsi_qla_host *ha,
69231e9e2be3SAdheer Chandravanshi 					struct dev_db_entry *fw_ddb_entry,
69241e9e2be3SAdheer Chandravanshi 					uint16_t *idx, int user)
69251e9e2be3SAdheer Chandravanshi {
69261e9e2be3SAdheer Chandravanshi 	struct iscsi_bus_flash_session *fnode_sess = NULL;
69271e9e2be3SAdheer Chandravanshi 	struct iscsi_bus_flash_conn *fnode_conn = NULL;
69281e9e2be3SAdheer Chandravanshi 	int rc = QLA_ERROR;
69291e9e2be3SAdheer Chandravanshi 
69301e9e2be3SAdheer Chandravanshi 	fnode_sess = iscsi_create_flashnode_sess(ha->host, *idx,
69311e9e2be3SAdheer Chandravanshi 						 &qla4xxx_iscsi_transport, 0);
69321e9e2be3SAdheer Chandravanshi 	if (!fnode_sess) {
69331e9e2be3SAdheer Chandravanshi 		ql4_printk(KERN_ERR, ha,
69341e9e2be3SAdheer Chandravanshi 			   "%s: Unable to create session sysfs entry for flashnode %d of host%lu\n",
69351e9e2be3SAdheer Chandravanshi 			   __func__, *idx, ha->host_no);
69361e9e2be3SAdheer Chandravanshi 		goto exit_tgt_create;
69371e9e2be3SAdheer Chandravanshi 	}
69381e9e2be3SAdheer Chandravanshi 
69391e9e2be3SAdheer Chandravanshi 	fnode_conn = iscsi_create_flashnode_conn(ha->host, fnode_sess,
69401e9e2be3SAdheer Chandravanshi 						 &qla4xxx_iscsi_transport, 0);
69411e9e2be3SAdheer Chandravanshi 	if (!fnode_conn) {
69421e9e2be3SAdheer Chandravanshi 		ql4_printk(KERN_ERR, ha,
69431e9e2be3SAdheer Chandravanshi 			   "%s: Unable to create conn sysfs entry for flashnode %d of host%lu\n",
69441e9e2be3SAdheer Chandravanshi 			   __func__, *idx, ha->host_no);
69451e9e2be3SAdheer Chandravanshi 		goto free_sess;
69461e9e2be3SAdheer Chandravanshi 	}
69471e9e2be3SAdheer Chandravanshi 
69481e9e2be3SAdheer Chandravanshi 	if (user) {
69491e9e2be3SAdheer Chandravanshi 		fnode_sess->flash_state = DEV_DB_NON_PERSISTENT;
69501e9e2be3SAdheer Chandravanshi 	} else {
69511e9e2be3SAdheer Chandravanshi 		fnode_sess->flash_state = DEV_DB_PERSISTENT;
69521e9e2be3SAdheer Chandravanshi 
69531e9e2be3SAdheer Chandravanshi 		if (*idx == ha->pri_ddb_idx || *idx == ha->sec_ddb_idx)
69541e9e2be3SAdheer Chandravanshi 			fnode_sess->is_boot_target = 1;
69551e9e2be3SAdheer Chandravanshi 		else
69561e9e2be3SAdheer Chandravanshi 			fnode_sess->is_boot_target = 0;
69571e9e2be3SAdheer Chandravanshi 	}
69581e9e2be3SAdheer Chandravanshi 
69591e9e2be3SAdheer Chandravanshi 	rc = qla4xxx_copy_from_fwddb_param(fnode_sess, fnode_conn,
69601e9e2be3SAdheer Chandravanshi 					   fw_ddb_entry);
69611e9e2be3SAdheer Chandravanshi 
69621e9e2be3SAdheer Chandravanshi 	ql4_printk(KERN_INFO, ha, "%s: sysfs entry %s created\n",
69631e9e2be3SAdheer Chandravanshi 		   __func__, fnode_sess->dev.kobj.name);
69641e9e2be3SAdheer Chandravanshi 
69651e9e2be3SAdheer Chandravanshi 	ql4_printk(KERN_INFO, ha, "%s: sysfs entry %s created\n",
69661e9e2be3SAdheer Chandravanshi 		   __func__, fnode_conn->dev.kobj.name);
69671e9e2be3SAdheer Chandravanshi 
69681e9e2be3SAdheer Chandravanshi 	return QLA_SUCCESS;
69691e9e2be3SAdheer Chandravanshi 
69701e9e2be3SAdheer Chandravanshi free_sess:
69711e9e2be3SAdheer Chandravanshi 	iscsi_destroy_flashnode_sess(fnode_sess);
69721e9e2be3SAdheer Chandravanshi 
69731e9e2be3SAdheer Chandravanshi exit_tgt_create:
69741e9e2be3SAdheer Chandravanshi 	return QLA_ERROR;
69751e9e2be3SAdheer Chandravanshi }
69761e9e2be3SAdheer Chandravanshi 
69771e9e2be3SAdheer Chandravanshi /**
69781e9e2be3SAdheer Chandravanshi  * qla4xxx_sysfs_ddb_add - Add new ddb entry in flash
69791e9e2be3SAdheer Chandravanshi  * @shost: pointer to host
69801e9e2be3SAdheer Chandravanshi  * @buf: type of ddb entry (ipv4/ipv6)
69811e9e2be3SAdheer Chandravanshi  * @len: length of buf
69821e9e2be3SAdheer Chandravanshi  *
69831e9e2be3SAdheer Chandravanshi  * This creates new ddb entry in the flash by finding first free index and
69841e9e2be3SAdheer Chandravanshi  * storing default ddb there. And then create sysfs entry for the new ddb entry.
69851e9e2be3SAdheer Chandravanshi  **/
69861e9e2be3SAdheer Chandravanshi static int qla4xxx_sysfs_ddb_add(struct Scsi_Host *shost, const char *buf,
69871e9e2be3SAdheer Chandravanshi 				 int len)
69881e9e2be3SAdheer Chandravanshi {
69891e9e2be3SAdheer Chandravanshi 	struct scsi_qla_host *ha = to_qla_host(shost);
69901e9e2be3SAdheer Chandravanshi 	struct dev_db_entry *fw_ddb_entry = NULL;
69911e9e2be3SAdheer Chandravanshi 	dma_addr_t fw_ddb_entry_dma;
69921e9e2be3SAdheer Chandravanshi 	struct device *dev;
69931e9e2be3SAdheer Chandravanshi 	uint16_t idx = 0;
69941e9e2be3SAdheer Chandravanshi 	uint16_t max_ddbs = 0;
69951e9e2be3SAdheer Chandravanshi 	uint32_t options = 0;
69961e9e2be3SAdheer Chandravanshi 	uint32_t rval = QLA_ERROR;
69971e9e2be3SAdheer Chandravanshi 
6998c962c18bSAdheer Chandravanshi 	if (strncasecmp(PORTAL_TYPE_IPV4, buf, 4) &&
6999c962c18bSAdheer Chandravanshi 	    strncasecmp(PORTAL_TYPE_IPV6, buf, 4)) {
70001e9e2be3SAdheer Chandravanshi 		DEBUG2(ql4_printk(KERN_ERR, ha, "%s: Invalid portal type\n",
70011e9e2be3SAdheer Chandravanshi 				  __func__));
70021e9e2be3SAdheer Chandravanshi 		goto exit_ddb_add;
70031e9e2be3SAdheer Chandravanshi 	}
70041e9e2be3SAdheer Chandravanshi 
7005a957a7d7SAdheer Chandravanshi 	max_ddbs =  is_qla40XX(ha) ? MAX_PRST_DEV_DB_ENTRIES :
70061e9e2be3SAdheer Chandravanshi 				     MAX_DEV_DB_ENTRIES;
70071e9e2be3SAdheer Chandravanshi 
70081e9e2be3SAdheer Chandravanshi 	fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
70091e9e2be3SAdheer Chandravanshi 					  &fw_ddb_entry_dma, GFP_KERNEL);
70101e9e2be3SAdheer Chandravanshi 	if (!fw_ddb_entry) {
70111e9e2be3SAdheer Chandravanshi 		DEBUG2(ql4_printk(KERN_ERR, ha,
70121e9e2be3SAdheer Chandravanshi 				  "%s: Unable to allocate dma buffer\n",
70131e9e2be3SAdheer Chandravanshi 				  __func__));
70141e9e2be3SAdheer Chandravanshi 		goto exit_ddb_add;
70151e9e2be3SAdheer Chandravanshi 	}
70161e9e2be3SAdheer Chandravanshi 
70171e9e2be3SAdheer Chandravanshi 	dev = iscsi_find_flashnode_sess(ha->host, NULL,
70181e9e2be3SAdheer Chandravanshi 					qla4xxx_sysfs_ddb_is_non_persistent);
70191e9e2be3SAdheer Chandravanshi 	if (dev) {
70201e9e2be3SAdheer Chandravanshi 		ql4_printk(KERN_ERR, ha,
70211e9e2be3SAdheer Chandravanshi 			   "%s: A non-persistent entry %s found\n",
70221e9e2be3SAdheer Chandravanshi 			   __func__, dev->kobj.name);
70238526cb11SMike Christie 		put_device(dev);
70241e9e2be3SAdheer Chandravanshi 		goto exit_ddb_add;
70251e9e2be3SAdheer Chandravanshi 	}
70261e9e2be3SAdheer Chandravanshi 
702799937574SAdheer Chandravanshi 	/* Index 0 and 1 are reserved for boot target entries */
702899937574SAdheer Chandravanshi 	for (idx = 2; idx < max_ddbs; idx++) {
70291e9e2be3SAdheer Chandravanshi 		if (qla4xxx_flashdb_by_index(ha, fw_ddb_entry,
70301e9e2be3SAdheer Chandravanshi 					     fw_ddb_entry_dma, idx))
70311e9e2be3SAdheer Chandravanshi 			break;
70321e9e2be3SAdheer Chandravanshi 	}
70331e9e2be3SAdheer Chandravanshi 
70341e9e2be3SAdheer Chandravanshi 	if (idx == max_ddbs)
70351e9e2be3SAdheer Chandravanshi 		goto exit_ddb_add;
70361e9e2be3SAdheer Chandravanshi 
70371e9e2be3SAdheer Chandravanshi 	if (!strncasecmp("ipv6", buf, 4))
70381e9e2be3SAdheer Chandravanshi 		options |= IPV6_DEFAULT_DDB_ENTRY;
70391e9e2be3SAdheer Chandravanshi 
70401e9e2be3SAdheer Chandravanshi 	rval = qla4xxx_get_default_ddb(ha, options, fw_ddb_entry_dma);
70411e9e2be3SAdheer Chandravanshi 	if (rval == QLA_ERROR)
70421e9e2be3SAdheer Chandravanshi 		goto exit_ddb_add;
70431e9e2be3SAdheer Chandravanshi 
70441e9e2be3SAdheer Chandravanshi 	rval = qla4xxx_sysfs_ddb_tgt_create(ha, fw_ddb_entry, &idx, 1);
70451e9e2be3SAdheer Chandravanshi 
70461e9e2be3SAdheer Chandravanshi exit_ddb_add:
70471e9e2be3SAdheer Chandravanshi 	if (fw_ddb_entry)
70481e9e2be3SAdheer Chandravanshi 		dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
70491e9e2be3SAdheer Chandravanshi 				  fw_ddb_entry, fw_ddb_entry_dma);
70501e9e2be3SAdheer Chandravanshi 	if (rval == QLA_SUCCESS)
70511e9e2be3SAdheer Chandravanshi 		return idx;
70521e9e2be3SAdheer Chandravanshi 	else
70531e9e2be3SAdheer Chandravanshi 		return -EIO;
70541e9e2be3SAdheer Chandravanshi }
70551e9e2be3SAdheer Chandravanshi 
70561e9e2be3SAdheer Chandravanshi /**
70571e9e2be3SAdheer Chandravanshi  * qla4xxx_sysfs_ddb_apply - write the target ddb contents to Flash
70581e9e2be3SAdheer Chandravanshi  * @fnode_sess: pointer to session attrs of flash ddb entry
70591e9e2be3SAdheer Chandravanshi  * @fnode_conn: pointer to connection attrs of flash ddb entry
70601e9e2be3SAdheer Chandravanshi  *
70611e9e2be3SAdheer Chandravanshi  * This writes the contents of target ddb buffer to Flash with a valid cookie
70621e9e2be3SAdheer Chandravanshi  * value in order to make the ddb entry persistent.
70631e9e2be3SAdheer Chandravanshi  **/
70641e9e2be3SAdheer Chandravanshi static int  qla4xxx_sysfs_ddb_apply(struct iscsi_bus_flash_session *fnode_sess,
70651e9e2be3SAdheer Chandravanshi 				    struct iscsi_bus_flash_conn *fnode_conn)
70661e9e2be3SAdheer Chandravanshi {
70671e9e2be3SAdheer Chandravanshi 	struct Scsi_Host *shost = iscsi_flash_session_to_shost(fnode_sess);
70681e9e2be3SAdheer Chandravanshi 	struct scsi_qla_host *ha = to_qla_host(shost);
70691e9e2be3SAdheer Chandravanshi 	uint32_t dev_db_start_offset = FLASH_OFFSET_DB_INFO;
70701e9e2be3SAdheer Chandravanshi 	struct dev_db_entry *fw_ddb_entry = NULL;
70711e9e2be3SAdheer Chandravanshi 	dma_addr_t fw_ddb_entry_dma;
70721e9e2be3SAdheer Chandravanshi 	uint32_t options = 0;
70731e9e2be3SAdheer Chandravanshi 	int rval = 0;
70741e9e2be3SAdheer Chandravanshi 
70751e9e2be3SAdheer Chandravanshi 	fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
70761e9e2be3SAdheer Chandravanshi 					  &fw_ddb_entry_dma, GFP_KERNEL);
70771e9e2be3SAdheer Chandravanshi 	if (!fw_ddb_entry) {
70781e9e2be3SAdheer Chandravanshi 		DEBUG2(ql4_printk(KERN_ERR, ha,
70791e9e2be3SAdheer Chandravanshi 				  "%s: Unable to allocate dma buffer\n",
70801e9e2be3SAdheer Chandravanshi 				  __func__));
70811e9e2be3SAdheer Chandravanshi 		rval = -ENOMEM;
70821e9e2be3SAdheer Chandravanshi 		goto exit_ddb_apply;
70831e9e2be3SAdheer Chandravanshi 	}
70841e9e2be3SAdheer Chandravanshi 
7085c962c18bSAdheer Chandravanshi 	if (!strncasecmp(fnode_sess->portal_type, PORTAL_TYPE_IPV6, 4))
70861e9e2be3SAdheer Chandravanshi 		options |= IPV6_DEFAULT_DDB_ENTRY;
70871e9e2be3SAdheer Chandravanshi 
70881e9e2be3SAdheer Chandravanshi 	rval = qla4xxx_get_default_ddb(ha, options, fw_ddb_entry_dma);
70891e9e2be3SAdheer Chandravanshi 	if (rval == QLA_ERROR)
70901e9e2be3SAdheer Chandravanshi 		goto exit_ddb_apply;
70911e9e2be3SAdheer Chandravanshi 
70921e9e2be3SAdheer Chandravanshi 	dev_db_start_offset += (fnode_sess->target_id *
70931e9e2be3SAdheer Chandravanshi 				sizeof(*fw_ddb_entry));
70941e9e2be3SAdheer Chandravanshi 
70951e9e2be3SAdheer Chandravanshi 	qla4xxx_copy_to_fwddb_param(fnode_sess, fnode_conn, fw_ddb_entry);
70961e9e2be3SAdheer Chandravanshi 	fw_ddb_entry->cookie = DDB_VALID_COOKIE;
70971e9e2be3SAdheer Chandravanshi 
70981e9e2be3SAdheer Chandravanshi 	rval = qla4xxx_set_flash(ha, fw_ddb_entry_dma, dev_db_start_offset,
70991e9e2be3SAdheer Chandravanshi 				 sizeof(*fw_ddb_entry), FLASH_OPT_RMW_COMMIT);
71001e9e2be3SAdheer Chandravanshi 
71011e9e2be3SAdheer Chandravanshi 	if (rval == QLA_SUCCESS) {
71021e9e2be3SAdheer Chandravanshi 		fnode_sess->flash_state = DEV_DB_PERSISTENT;
71031e9e2be3SAdheer Chandravanshi 		ql4_printk(KERN_INFO, ha,
71041e9e2be3SAdheer Chandravanshi 			   "%s: flash node %u of host %lu written to flash\n",
71051e9e2be3SAdheer Chandravanshi 			   __func__, fnode_sess->target_id, ha->host_no);
71061e9e2be3SAdheer Chandravanshi 	} else {
71071e9e2be3SAdheer Chandravanshi 		rval = -EIO;
71081e9e2be3SAdheer Chandravanshi 		ql4_printk(KERN_ERR, ha,
71091e9e2be3SAdheer Chandravanshi 			   "%s: Error while writing flash node %u of host %lu to flash\n",
71101e9e2be3SAdheer Chandravanshi 			   __func__, fnode_sess->target_id, ha->host_no);
71111e9e2be3SAdheer Chandravanshi 	}
71121e9e2be3SAdheer Chandravanshi 
71131e9e2be3SAdheer Chandravanshi exit_ddb_apply:
71141e9e2be3SAdheer Chandravanshi 	if (fw_ddb_entry)
71151e9e2be3SAdheer Chandravanshi 		dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
71161e9e2be3SAdheer Chandravanshi 				  fw_ddb_entry, fw_ddb_entry_dma);
71171e9e2be3SAdheer Chandravanshi 	return rval;
71181e9e2be3SAdheer Chandravanshi }
71191e9e2be3SAdheer Chandravanshi 
71201e9e2be3SAdheer Chandravanshi static ssize_t qla4xxx_sysfs_ddb_conn_open(struct scsi_qla_host *ha,
71211e9e2be3SAdheer Chandravanshi 					   struct dev_db_entry *fw_ddb_entry,
71221e9e2be3SAdheer Chandravanshi 					   uint16_t idx)
71231e9e2be3SAdheer Chandravanshi {
71241e9e2be3SAdheer Chandravanshi 	struct dev_db_entry *ddb_entry = NULL;
71251e9e2be3SAdheer Chandravanshi 	dma_addr_t ddb_entry_dma;
71261e9e2be3SAdheer Chandravanshi 	unsigned long wtime;
71271e9e2be3SAdheer Chandravanshi 	uint32_t mbx_sts = 0;
71281e9e2be3SAdheer Chandravanshi 	uint32_t state = 0, conn_err = 0;
71291e9e2be3SAdheer Chandravanshi 	uint16_t tmo = 0;
71301e9e2be3SAdheer Chandravanshi 	int ret = 0;
71311e9e2be3SAdheer Chandravanshi 
71321e9e2be3SAdheer Chandravanshi 	ddb_entry = dma_alloc_coherent(&ha->pdev->dev, sizeof(*ddb_entry),
71331e9e2be3SAdheer Chandravanshi 				       &ddb_entry_dma, GFP_KERNEL);
71341e9e2be3SAdheer Chandravanshi 	if (!ddb_entry) {
71351e9e2be3SAdheer Chandravanshi 		DEBUG2(ql4_printk(KERN_ERR, ha,
71361e9e2be3SAdheer Chandravanshi 				  "%s: Unable to allocate dma buffer\n",
71371e9e2be3SAdheer Chandravanshi 				  __func__));
71381e9e2be3SAdheer Chandravanshi 		return QLA_ERROR;
71391e9e2be3SAdheer Chandravanshi 	}
71401e9e2be3SAdheer Chandravanshi 
71411e9e2be3SAdheer Chandravanshi 	memcpy(ddb_entry, fw_ddb_entry, sizeof(*ddb_entry));
71421e9e2be3SAdheer Chandravanshi 
71431e9e2be3SAdheer Chandravanshi 	ret = qla4xxx_set_ddb_entry(ha, idx, ddb_entry_dma, &mbx_sts);
71441e9e2be3SAdheer Chandravanshi 	if (ret != QLA_SUCCESS) {
71451e9e2be3SAdheer Chandravanshi 		DEBUG2(ql4_printk(KERN_ERR, ha,
71461e9e2be3SAdheer Chandravanshi 				  "%s: Unable to set ddb entry for index %d\n",
71471e9e2be3SAdheer Chandravanshi 				  __func__, idx));
71481e9e2be3SAdheer Chandravanshi 		goto exit_ddb_conn_open;
71491e9e2be3SAdheer Chandravanshi 	}
71501e9e2be3SAdheer Chandravanshi 
71511e9e2be3SAdheer Chandravanshi 	qla4xxx_conn_open(ha, idx);
71521e9e2be3SAdheer Chandravanshi 
71531e9e2be3SAdheer Chandravanshi 	/* To ensure that sendtargets is done, wait for at least 12 secs */
71541e9e2be3SAdheer Chandravanshi 	tmo = ((ha->def_timeout > LOGIN_TOV) &&
71551e9e2be3SAdheer Chandravanshi 	       (ha->def_timeout < LOGIN_TOV * 10) ?
71561e9e2be3SAdheer Chandravanshi 	       ha->def_timeout : LOGIN_TOV);
71571e9e2be3SAdheer Chandravanshi 
71581e9e2be3SAdheer Chandravanshi 	DEBUG2(ql4_printk(KERN_INFO, ha,
71591e9e2be3SAdheer Chandravanshi 			  "Default time to wait for login to ddb %d\n", tmo));
71601e9e2be3SAdheer Chandravanshi 
71611e9e2be3SAdheer Chandravanshi 	wtime = jiffies + (HZ * tmo);
71621e9e2be3SAdheer Chandravanshi 	do {
71631e9e2be3SAdheer Chandravanshi 		ret = qla4xxx_get_fwddb_entry(ha, idx, NULL, 0, NULL,
71641e9e2be3SAdheer Chandravanshi 					      NULL, &state, &conn_err, NULL,
71651e9e2be3SAdheer Chandravanshi 					      NULL);
71661e9e2be3SAdheer Chandravanshi 		if (ret == QLA_ERROR)
71671e9e2be3SAdheer Chandravanshi 			continue;
71681e9e2be3SAdheer Chandravanshi 
71691e9e2be3SAdheer Chandravanshi 		if (state == DDB_DS_NO_CONNECTION_ACTIVE ||
71701e9e2be3SAdheer Chandravanshi 		    state == DDB_DS_SESSION_FAILED)
71711e9e2be3SAdheer Chandravanshi 			break;
71721e9e2be3SAdheer Chandravanshi 
71731e9e2be3SAdheer Chandravanshi 		schedule_timeout_uninterruptible(HZ / 10);
71741e9e2be3SAdheer Chandravanshi 	} while (time_after(wtime, jiffies));
71751e9e2be3SAdheer Chandravanshi 
71761e9e2be3SAdheer Chandravanshi exit_ddb_conn_open:
71771e9e2be3SAdheer Chandravanshi 	if (ddb_entry)
71781e9e2be3SAdheer Chandravanshi 		dma_free_coherent(&ha->pdev->dev, sizeof(*ddb_entry),
71791e9e2be3SAdheer Chandravanshi 				  ddb_entry, ddb_entry_dma);
71801e9e2be3SAdheer Chandravanshi 	return ret;
71811e9e2be3SAdheer Chandravanshi }
71821e9e2be3SAdheer Chandravanshi 
71831e9e2be3SAdheer Chandravanshi static int qla4xxx_ddb_login_st(struct scsi_qla_host *ha,
7184ad8bd45eSManish Rangankar 				struct dev_db_entry *fw_ddb_entry,
7185ad8bd45eSManish Rangankar 				uint16_t target_id)
71861e9e2be3SAdheer Chandravanshi {
71871e9e2be3SAdheer Chandravanshi 	struct qla_ddb_index *ddb_idx, *ddb_idx_tmp;
71881e9e2be3SAdheer Chandravanshi 	struct list_head list_nt;
71891e9e2be3SAdheer Chandravanshi 	uint16_t ddb_index;
71901e9e2be3SAdheer Chandravanshi 	int ret = 0;
71911e9e2be3SAdheer Chandravanshi 
71921e9e2be3SAdheer Chandravanshi 	if (test_bit(AF_ST_DISCOVERY_IN_PROGRESS, &ha->flags)) {
71931e9e2be3SAdheer Chandravanshi 		ql4_printk(KERN_WARNING, ha,
71941e9e2be3SAdheer Chandravanshi 			   "%s: A discovery already in progress!\n", __func__);
71951e9e2be3SAdheer Chandravanshi 		return QLA_ERROR;
71961e9e2be3SAdheer Chandravanshi 	}
71971e9e2be3SAdheer Chandravanshi 
71981e9e2be3SAdheer Chandravanshi 	INIT_LIST_HEAD(&list_nt);
71991e9e2be3SAdheer Chandravanshi 
72001e9e2be3SAdheer Chandravanshi 	set_bit(AF_ST_DISCOVERY_IN_PROGRESS, &ha->flags);
72011e9e2be3SAdheer Chandravanshi 
72021e9e2be3SAdheer Chandravanshi 	ret = qla4xxx_get_ddb_index(ha, &ddb_index);
72031e9e2be3SAdheer Chandravanshi 	if (ret == QLA_ERROR)
72041e9e2be3SAdheer Chandravanshi 		goto exit_login_st_clr_bit;
72051e9e2be3SAdheer Chandravanshi 
72061e9e2be3SAdheer Chandravanshi 	ret = qla4xxx_sysfs_ddb_conn_open(ha, fw_ddb_entry, ddb_index);
72071e9e2be3SAdheer Chandravanshi 	if (ret == QLA_ERROR)
72081e9e2be3SAdheer Chandravanshi 		goto exit_login_st;
72091e9e2be3SAdheer Chandravanshi 
7210ad8bd45eSManish Rangankar 	qla4xxx_build_new_nt_list(ha, &list_nt, target_id);
72111e9e2be3SAdheer Chandravanshi 
72121e9e2be3SAdheer Chandravanshi 	list_for_each_entry_safe(ddb_idx, ddb_idx_tmp, &list_nt, list) {
72131e9e2be3SAdheer Chandravanshi 		list_del_init(&ddb_idx->list);
72141e9e2be3SAdheer Chandravanshi 		qla4xxx_clear_ddb_entry(ha, ddb_idx->fw_ddb_idx);
72151e9e2be3SAdheer Chandravanshi 		vfree(ddb_idx);
72161e9e2be3SAdheer Chandravanshi 	}
72171e9e2be3SAdheer Chandravanshi 
72181e9e2be3SAdheer Chandravanshi exit_login_st:
72191e9e2be3SAdheer Chandravanshi 	if (qla4xxx_clear_ddb_entry(ha, ddb_index) == QLA_ERROR) {
72201e9e2be3SAdheer Chandravanshi 		ql4_printk(KERN_ERR, ha,
72211e9e2be3SAdheer Chandravanshi 			   "Unable to clear DDB index = 0x%x\n", ddb_index);
72221e9e2be3SAdheer Chandravanshi 	}
72231e9e2be3SAdheer Chandravanshi 
72241e9e2be3SAdheer Chandravanshi 	clear_bit(ddb_index, ha->ddb_idx_map);
72251e9e2be3SAdheer Chandravanshi 
72261e9e2be3SAdheer Chandravanshi exit_login_st_clr_bit:
72271e9e2be3SAdheer Chandravanshi 	clear_bit(AF_ST_DISCOVERY_IN_PROGRESS, &ha->flags);
72281e9e2be3SAdheer Chandravanshi 	return ret;
72291e9e2be3SAdheer Chandravanshi }
72301e9e2be3SAdheer Chandravanshi 
72311e9e2be3SAdheer Chandravanshi static int qla4xxx_ddb_login_nt(struct scsi_qla_host *ha,
72321e9e2be3SAdheer Chandravanshi 				struct dev_db_entry *fw_ddb_entry,
72331e9e2be3SAdheer Chandravanshi 				uint16_t idx)
72341e9e2be3SAdheer Chandravanshi {
72351e9e2be3SAdheer Chandravanshi 	int ret = QLA_ERROR;
72361e9e2be3SAdheer Chandravanshi 
7237ad8bd45eSManish Rangankar 	ret = qla4xxx_is_session_exists(ha, fw_ddb_entry, NULL);
72381e9e2be3SAdheer Chandravanshi 	if (ret != QLA_SUCCESS)
72391e9e2be3SAdheer Chandravanshi 		ret = qla4xxx_sess_conn_setup(ha, fw_ddb_entry, RESET_ADAPTER,
72401e9e2be3SAdheer Chandravanshi 					      idx);
72411e9e2be3SAdheer Chandravanshi 	else
72421e9e2be3SAdheer Chandravanshi 		ret = -EPERM;
72431e9e2be3SAdheer Chandravanshi 
72441e9e2be3SAdheer Chandravanshi 	return ret;
72451e9e2be3SAdheer Chandravanshi }
72461e9e2be3SAdheer Chandravanshi 
72471e9e2be3SAdheer Chandravanshi /**
72481e9e2be3SAdheer Chandravanshi  * qla4xxx_sysfs_ddb_login - Login to the specified target
72491e9e2be3SAdheer Chandravanshi  * @fnode_sess: pointer to session attrs of flash ddb entry
72501e9e2be3SAdheer Chandravanshi  * @fnode_conn: pointer to connection attrs of flash ddb entry
72511e9e2be3SAdheer Chandravanshi  *
72521e9e2be3SAdheer Chandravanshi  * This logs in to the specified target
72531e9e2be3SAdheer Chandravanshi  **/
72541e9e2be3SAdheer Chandravanshi static int qla4xxx_sysfs_ddb_login(struct iscsi_bus_flash_session *fnode_sess,
72551e9e2be3SAdheer Chandravanshi 				   struct iscsi_bus_flash_conn *fnode_conn)
72561e9e2be3SAdheer Chandravanshi {
72571e9e2be3SAdheer Chandravanshi 	struct Scsi_Host *shost = iscsi_flash_session_to_shost(fnode_sess);
72581e9e2be3SAdheer Chandravanshi 	struct scsi_qla_host *ha = to_qla_host(shost);
72591e9e2be3SAdheer Chandravanshi 	struct dev_db_entry *fw_ddb_entry = NULL;
72601e9e2be3SAdheer Chandravanshi 	dma_addr_t fw_ddb_entry_dma;
72611e9e2be3SAdheer Chandravanshi 	uint32_t options = 0;
72621e9e2be3SAdheer Chandravanshi 	int ret = 0;
72631e9e2be3SAdheer Chandravanshi 
72641e9e2be3SAdheer Chandravanshi 	if (fnode_sess->flash_state == DEV_DB_NON_PERSISTENT) {
72651e9e2be3SAdheer Chandravanshi 		ql4_printk(KERN_ERR, ha,
72661e9e2be3SAdheer Chandravanshi 			   "%s: Target info is not persistent\n", __func__);
72671e9e2be3SAdheer Chandravanshi 		ret = -EIO;
72681e9e2be3SAdheer Chandravanshi 		goto exit_ddb_login;
72691e9e2be3SAdheer Chandravanshi 	}
72701e9e2be3SAdheer Chandravanshi 
72711e9e2be3SAdheer Chandravanshi 	fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
72721e9e2be3SAdheer Chandravanshi 					  &fw_ddb_entry_dma, GFP_KERNEL);
72731e9e2be3SAdheer Chandravanshi 	if (!fw_ddb_entry) {
72741e9e2be3SAdheer Chandravanshi 		DEBUG2(ql4_printk(KERN_ERR, ha,
72751e9e2be3SAdheer Chandravanshi 				  "%s: Unable to allocate dma buffer\n",
72761e9e2be3SAdheer Chandravanshi 				  __func__));
72771e9e2be3SAdheer Chandravanshi 		ret = -ENOMEM;
72781e9e2be3SAdheer Chandravanshi 		goto exit_ddb_login;
72791e9e2be3SAdheer Chandravanshi 	}
72801e9e2be3SAdheer Chandravanshi 
7281c962c18bSAdheer Chandravanshi 	if (!strncasecmp(fnode_sess->portal_type, PORTAL_TYPE_IPV6, 4))
72821e9e2be3SAdheer Chandravanshi 		options |= IPV6_DEFAULT_DDB_ENTRY;
72831e9e2be3SAdheer Chandravanshi 
72841e9e2be3SAdheer Chandravanshi 	ret = qla4xxx_get_default_ddb(ha, options, fw_ddb_entry_dma);
72851e9e2be3SAdheer Chandravanshi 	if (ret == QLA_ERROR)
72861e9e2be3SAdheer Chandravanshi 		goto exit_ddb_login;
72871e9e2be3SAdheer Chandravanshi 
72881e9e2be3SAdheer Chandravanshi 	qla4xxx_copy_to_fwddb_param(fnode_sess, fnode_conn, fw_ddb_entry);
72891e9e2be3SAdheer Chandravanshi 	fw_ddb_entry->cookie = DDB_VALID_COOKIE;
72901e9e2be3SAdheer Chandravanshi 
72911e9e2be3SAdheer Chandravanshi 	if (strlen((char *)fw_ddb_entry->iscsi_name) == 0)
7292ad8bd45eSManish Rangankar 		ret = qla4xxx_ddb_login_st(ha, fw_ddb_entry,
7293ad8bd45eSManish Rangankar 					   fnode_sess->target_id);
72941e9e2be3SAdheer Chandravanshi 	else
72951e9e2be3SAdheer Chandravanshi 		ret = qla4xxx_ddb_login_nt(ha, fw_ddb_entry,
72961e9e2be3SAdheer Chandravanshi 					   fnode_sess->target_id);
72971e9e2be3SAdheer Chandravanshi 
72981e9e2be3SAdheer Chandravanshi 	if (ret > 0)
72991e9e2be3SAdheer Chandravanshi 		ret = -EIO;
73001e9e2be3SAdheer Chandravanshi 
73011e9e2be3SAdheer Chandravanshi exit_ddb_login:
73021e9e2be3SAdheer Chandravanshi 	if (fw_ddb_entry)
73031e9e2be3SAdheer Chandravanshi 		dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
73041e9e2be3SAdheer Chandravanshi 				  fw_ddb_entry, fw_ddb_entry_dma);
73051e9e2be3SAdheer Chandravanshi 	return ret;
73061e9e2be3SAdheer Chandravanshi }
73071e9e2be3SAdheer Chandravanshi 
73081e9e2be3SAdheer Chandravanshi /**
73091e9e2be3SAdheer Chandravanshi  * qla4xxx_sysfs_ddb_logout_sid - Logout session for the specified target
73101e9e2be3SAdheer Chandravanshi  * @cls_sess: pointer to session to be logged out
73111e9e2be3SAdheer Chandravanshi  *
73121e9e2be3SAdheer Chandravanshi  * This performs session log out from the specified target
73131e9e2be3SAdheer Chandravanshi  **/
73141e9e2be3SAdheer Chandravanshi static int qla4xxx_sysfs_ddb_logout_sid(struct iscsi_cls_session *cls_sess)
73151e9e2be3SAdheer Chandravanshi {
73161e9e2be3SAdheer Chandravanshi 	struct iscsi_session *sess;
73171e9e2be3SAdheer Chandravanshi 	struct ddb_entry *ddb_entry = NULL;
73181e9e2be3SAdheer Chandravanshi 	struct scsi_qla_host *ha;
73191e9e2be3SAdheer Chandravanshi 	struct dev_db_entry *fw_ddb_entry = NULL;
73201e9e2be3SAdheer Chandravanshi 	dma_addr_t fw_ddb_entry_dma;
73211e9e2be3SAdheer Chandravanshi 	unsigned long flags;
73221e9e2be3SAdheer Chandravanshi 	unsigned long wtime;
73231e9e2be3SAdheer Chandravanshi 	uint32_t ddb_state;
73241e9e2be3SAdheer Chandravanshi 	int options;
73251e9e2be3SAdheer Chandravanshi 	int ret = 0;
73261e9e2be3SAdheer Chandravanshi 
73271e9e2be3SAdheer Chandravanshi 	sess = cls_sess->dd_data;
73281e9e2be3SAdheer Chandravanshi 	ddb_entry = sess->dd_data;
73291e9e2be3SAdheer Chandravanshi 	ha = ddb_entry->ha;
73301e9e2be3SAdheer Chandravanshi 
73311e9e2be3SAdheer Chandravanshi 	if (ddb_entry->ddb_type != FLASH_DDB) {
73321e9e2be3SAdheer Chandravanshi 		ql4_printk(KERN_ERR, ha, "%s: Not a flash node session\n",
73331e9e2be3SAdheer Chandravanshi 			   __func__);
73341e9e2be3SAdheer Chandravanshi 		ret = -ENXIO;
73351e9e2be3SAdheer Chandravanshi 		goto exit_ddb_logout;
73361e9e2be3SAdheer Chandravanshi 	}
73371e9e2be3SAdheer Chandravanshi 
733837719c2aSAdheer Chandravanshi 	if (test_bit(DF_BOOT_TGT, &ddb_entry->flags)) {
733937719c2aSAdheer Chandravanshi 		ql4_printk(KERN_ERR, ha,
734037719c2aSAdheer Chandravanshi 			   "%s: Logout from boot target entry is not permitted.\n",
734137719c2aSAdheer Chandravanshi 			   __func__);
734237719c2aSAdheer Chandravanshi 		ret = -EPERM;
734337719c2aSAdheer Chandravanshi 		goto exit_ddb_logout;
734437719c2aSAdheer Chandravanshi 	}
734537719c2aSAdheer Chandravanshi 
73461e9e2be3SAdheer Chandravanshi 	fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
73471e9e2be3SAdheer Chandravanshi 					  &fw_ddb_entry_dma, GFP_KERNEL);
73481e9e2be3SAdheer Chandravanshi 	if (!fw_ddb_entry) {
73491e9e2be3SAdheer Chandravanshi 		ql4_printk(KERN_ERR, ha,
73501e9e2be3SAdheer Chandravanshi 			   "%s: Unable to allocate dma buffer\n", __func__);
73511e9e2be3SAdheer Chandravanshi 		ret = -ENOMEM;
73521e9e2be3SAdheer Chandravanshi 		goto exit_ddb_logout;
73531e9e2be3SAdheer Chandravanshi 	}
73541e9e2be3SAdheer Chandravanshi 
735599c6a33bSAdheer Chandravanshi 	if (test_and_set_bit(DF_DISABLE_RELOGIN, &ddb_entry->flags))
735699c6a33bSAdheer Chandravanshi 		goto ddb_logout_init;
735799c6a33bSAdheer Chandravanshi 
735899c6a33bSAdheer Chandravanshi 	ret = qla4xxx_get_fwddb_entry(ha, ddb_entry->fw_ddb_index,
735999c6a33bSAdheer Chandravanshi 				      fw_ddb_entry, fw_ddb_entry_dma,
736099c6a33bSAdheer Chandravanshi 				      NULL, NULL, &ddb_state, NULL,
736199c6a33bSAdheer Chandravanshi 				      NULL, NULL);
736299c6a33bSAdheer Chandravanshi 	if (ret == QLA_ERROR)
736399c6a33bSAdheer Chandravanshi 		goto ddb_logout_init;
736499c6a33bSAdheer Chandravanshi 
736599c6a33bSAdheer Chandravanshi 	if (ddb_state == DDB_DS_SESSION_ACTIVE)
736699c6a33bSAdheer Chandravanshi 		goto ddb_logout_init;
736799c6a33bSAdheer Chandravanshi 
736899c6a33bSAdheer Chandravanshi 	/* wait until next relogin is triggered using DF_RELOGIN and
736999c6a33bSAdheer Chandravanshi 	 * clear DF_RELOGIN to avoid invocation of further relogin
737099c6a33bSAdheer Chandravanshi 	 */
737199c6a33bSAdheer Chandravanshi 	wtime = jiffies + (HZ * RELOGIN_TOV);
737299c6a33bSAdheer Chandravanshi 	do {
737399c6a33bSAdheer Chandravanshi 		if (test_and_clear_bit(DF_RELOGIN, &ddb_entry->flags))
737499c6a33bSAdheer Chandravanshi 			goto ddb_logout_init;
737599c6a33bSAdheer Chandravanshi 
737699c6a33bSAdheer Chandravanshi 		schedule_timeout_uninterruptible(HZ);
737799c6a33bSAdheer Chandravanshi 	} while ((time_after(wtime, jiffies)));
737899c6a33bSAdheer Chandravanshi 
737999c6a33bSAdheer Chandravanshi ddb_logout_init:
738099c6a33bSAdheer Chandravanshi 	atomic_set(&ddb_entry->retry_relogin_timer, INVALID_ENTRY);
738199c6a33bSAdheer Chandravanshi 	atomic_set(&ddb_entry->relogin_timer, 0);
738299c6a33bSAdheer Chandravanshi 
738399c6a33bSAdheer Chandravanshi 	options = LOGOUT_OPTION_CLOSE_SESSION;
738499c6a33bSAdheer Chandravanshi 	qla4xxx_session_logout_ddb(ha, ddb_entry, options);
738599c6a33bSAdheer Chandravanshi 
738699c6a33bSAdheer Chandravanshi 	memset(fw_ddb_entry, 0, sizeof(*fw_ddb_entry));
73871e9e2be3SAdheer Chandravanshi 	wtime = jiffies + (HZ * LOGOUT_TOV);
73881e9e2be3SAdheer Chandravanshi 	do {
73891e9e2be3SAdheer Chandravanshi 		ret = qla4xxx_get_fwddb_entry(ha, ddb_entry->fw_ddb_index,
73901e9e2be3SAdheer Chandravanshi 					      fw_ddb_entry, fw_ddb_entry_dma,
73911e9e2be3SAdheer Chandravanshi 					      NULL, NULL, &ddb_state, NULL,
73921e9e2be3SAdheer Chandravanshi 					      NULL, NULL);
73931e9e2be3SAdheer Chandravanshi 		if (ret == QLA_ERROR)
73941e9e2be3SAdheer Chandravanshi 			goto ddb_logout_clr_sess;
73951e9e2be3SAdheer Chandravanshi 
73961e9e2be3SAdheer Chandravanshi 		if ((ddb_state == DDB_DS_NO_CONNECTION_ACTIVE) ||
73971e9e2be3SAdheer Chandravanshi 		    (ddb_state == DDB_DS_SESSION_FAILED))
73981e9e2be3SAdheer Chandravanshi 			goto ddb_logout_clr_sess;
73991e9e2be3SAdheer Chandravanshi 
74001e9e2be3SAdheer Chandravanshi 		schedule_timeout_uninterruptible(HZ);
74011e9e2be3SAdheer Chandravanshi 	} while ((time_after(wtime, jiffies)));
74021e9e2be3SAdheer Chandravanshi 
74031e9e2be3SAdheer Chandravanshi ddb_logout_clr_sess:
74041e9e2be3SAdheer Chandravanshi 	qla4xxx_clear_ddb_entry(ha, ddb_entry->fw_ddb_index);
74051e9e2be3SAdheer Chandravanshi 	/*
74061e9e2be3SAdheer Chandravanshi 	 * we have decremented the reference count of the driver
74071e9e2be3SAdheer Chandravanshi 	 * when we setup the session to have the driver unload
74081e9e2be3SAdheer Chandravanshi 	 * to be seamless without actually destroying the
74091e9e2be3SAdheer Chandravanshi 	 * session
74101e9e2be3SAdheer Chandravanshi 	 **/
74111e9e2be3SAdheer Chandravanshi 	try_module_get(qla4xxx_iscsi_transport.owner);
74121e9e2be3SAdheer Chandravanshi 	iscsi_destroy_endpoint(ddb_entry->conn->ep);
74131e9e2be3SAdheer Chandravanshi 
74141e9e2be3SAdheer Chandravanshi 	spin_lock_irqsave(&ha->hardware_lock, flags);
74151e9e2be3SAdheer Chandravanshi 	qla4xxx_free_ddb(ha, ddb_entry);
741699c6a33bSAdheer Chandravanshi 	clear_bit(ddb_entry->fw_ddb_index, ha->ddb_idx_map);
74171e9e2be3SAdheer Chandravanshi 	spin_unlock_irqrestore(&ha->hardware_lock, flags);
74181e9e2be3SAdheer Chandravanshi 
74191e9e2be3SAdheer Chandravanshi 	iscsi_session_teardown(ddb_entry->sess);
74201e9e2be3SAdheer Chandravanshi 
742199c6a33bSAdheer Chandravanshi 	clear_bit(DF_DISABLE_RELOGIN, &ddb_entry->flags);
74221e9e2be3SAdheer Chandravanshi 	ret = QLA_SUCCESS;
74231e9e2be3SAdheer Chandravanshi 
74241e9e2be3SAdheer Chandravanshi exit_ddb_logout:
74251e9e2be3SAdheer Chandravanshi 	if (fw_ddb_entry)
74261e9e2be3SAdheer Chandravanshi 		dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
74271e9e2be3SAdheer Chandravanshi 				  fw_ddb_entry, fw_ddb_entry_dma);
74281e9e2be3SAdheer Chandravanshi 	return ret;
74291e9e2be3SAdheer Chandravanshi }
74301e9e2be3SAdheer Chandravanshi 
74311e9e2be3SAdheer Chandravanshi /**
74321e9e2be3SAdheer Chandravanshi  * qla4xxx_sysfs_ddb_logout - Logout from the specified target
74331e9e2be3SAdheer Chandravanshi  * @fnode_sess: pointer to session attrs of flash ddb entry
74341e9e2be3SAdheer Chandravanshi  * @fnode_conn: pointer to connection attrs of flash ddb entry
74351e9e2be3SAdheer Chandravanshi  *
74361e9e2be3SAdheer Chandravanshi  * This performs log out from the specified target
74371e9e2be3SAdheer Chandravanshi  **/
74381e9e2be3SAdheer Chandravanshi static int qla4xxx_sysfs_ddb_logout(struct iscsi_bus_flash_session *fnode_sess,
74391e9e2be3SAdheer Chandravanshi 				    struct iscsi_bus_flash_conn *fnode_conn)
74401e9e2be3SAdheer Chandravanshi {
74411e9e2be3SAdheer Chandravanshi 	struct Scsi_Host *shost = iscsi_flash_session_to_shost(fnode_sess);
74421e9e2be3SAdheer Chandravanshi 	struct scsi_qla_host *ha = to_qla_host(shost);
74431e9e2be3SAdheer Chandravanshi 	struct ql4_tuple_ddb *flash_tddb = NULL;
74441e9e2be3SAdheer Chandravanshi 	struct ql4_tuple_ddb *tmp_tddb = NULL;
74451e9e2be3SAdheer Chandravanshi 	struct dev_db_entry *fw_ddb_entry = NULL;
74461e9e2be3SAdheer Chandravanshi 	struct ddb_entry *ddb_entry = NULL;
74471e9e2be3SAdheer Chandravanshi 	dma_addr_t fw_ddb_dma;
74481e9e2be3SAdheer Chandravanshi 	uint32_t next_idx = 0;
74491e9e2be3SAdheer Chandravanshi 	uint32_t state = 0, conn_err = 0;
74501e9e2be3SAdheer Chandravanshi 	uint16_t conn_id = 0;
74511e9e2be3SAdheer Chandravanshi 	int idx, index;
74521e9e2be3SAdheer Chandravanshi 	int status, ret = 0;
74531e9e2be3SAdheer Chandravanshi 
74541e9e2be3SAdheer Chandravanshi 	fw_ddb_entry = dma_pool_alloc(ha->fw_ddb_dma_pool, GFP_KERNEL,
74551e9e2be3SAdheer Chandravanshi 				      &fw_ddb_dma);
74561e9e2be3SAdheer Chandravanshi 	if (fw_ddb_entry == NULL) {
74571e9e2be3SAdheer Chandravanshi 		ql4_printk(KERN_ERR, ha, "%s:Out of memory\n", __func__);
74581e9e2be3SAdheer Chandravanshi 		ret = -ENOMEM;
74591e9e2be3SAdheer Chandravanshi 		goto exit_ddb_logout;
74601e9e2be3SAdheer Chandravanshi 	}
74611e9e2be3SAdheer Chandravanshi 
74621e9e2be3SAdheer Chandravanshi 	flash_tddb = vzalloc(sizeof(*flash_tddb));
74631e9e2be3SAdheer Chandravanshi 	if (!flash_tddb) {
74641e9e2be3SAdheer Chandravanshi 		ql4_printk(KERN_WARNING, ha,
74651e9e2be3SAdheer Chandravanshi 			   "%s:Memory Allocation failed.\n", __func__);
74661e9e2be3SAdheer Chandravanshi 		ret = -ENOMEM;
74671e9e2be3SAdheer Chandravanshi 		goto exit_ddb_logout;
74681e9e2be3SAdheer Chandravanshi 	}
74691e9e2be3SAdheer Chandravanshi 
74701e9e2be3SAdheer Chandravanshi 	tmp_tddb = vzalloc(sizeof(*tmp_tddb));
74711e9e2be3SAdheer Chandravanshi 	if (!tmp_tddb) {
74721e9e2be3SAdheer Chandravanshi 		ql4_printk(KERN_WARNING, ha,
74731e9e2be3SAdheer Chandravanshi 			   "%s:Memory Allocation failed.\n", __func__);
74741e9e2be3SAdheer Chandravanshi 		ret = -ENOMEM;
74751e9e2be3SAdheer Chandravanshi 		goto exit_ddb_logout;
74761e9e2be3SAdheer Chandravanshi 	}
74771e9e2be3SAdheer Chandravanshi 
74781e9e2be3SAdheer Chandravanshi 	if (!fnode_sess->targetname) {
74791e9e2be3SAdheer Chandravanshi 		ql4_printk(KERN_ERR, ha,
74801e9e2be3SAdheer Chandravanshi 			   "%s:Cannot logout from SendTarget entry\n",
74811e9e2be3SAdheer Chandravanshi 			   __func__);
74821e9e2be3SAdheer Chandravanshi 		ret = -EPERM;
74831e9e2be3SAdheer Chandravanshi 		goto exit_ddb_logout;
74841e9e2be3SAdheer Chandravanshi 	}
74851e9e2be3SAdheer Chandravanshi 
74861e9e2be3SAdheer Chandravanshi 	if (fnode_sess->is_boot_target) {
74871e9e2be3SAdheer Chandravanshi 		ql4_printk(KERN_ERR, ha,
74881e9e2be3SAdheer Chandravanshi 			   "%s: Logout from boot target entry is not permitted.\n",
74891e9e2be3SAdheer Chandravanshi 			   __func__);
74901e9e2be3SAdheer Chandravanshi 		ret = -EPERM;
74911e9e2be3SAdheer Chandravanshi 		goto exit_ddb_logout;
74921e9e2be3SAdheer Chandravanshi 	}
74931e9e2be3SAdheer Chandravanshi 
74941e9e2be3SAdheer Chandravanshi 	strncpy(flash_tddb->iscsi_name, fnode_sess->targetname,
74951e9e2be3SAdheer Chandravanshi 		ISCSI_NAME_SIZE);
74961e9e2be3SAdheer Chandravanshi 
7497c962c18bSAdheer Chandravanshi 	if (!strncmp(fnode_sess->portal_type, PORTAL_TYPE_IPV6, 4))
74981e9e2be3SAdheer Chandravanshi 		sprintf(flash_tddb->ip_addr, "%pI6", fnode_conn->ipaddress);
74991e9e2be3SAdheer Chandravanshi 	else
75001e9e2be3SAdheer Chandravanshi 		sprintf(flash_tddb->ip_addr, "%pI4", fnode_conn->ipaddress);
75011e9e2be3SAdheer Chandravanshi 
75021e9e2be3SAdheer Chandravanshi 	flash_tddb->tpgt = fnode_sess->tpgt;
75031e9e2be3SAdheer Chandravanshi 	flash_tddb->port = fnode_conn->port;
75041e9e2be3SAdheer Chandravanshi 
75051e9e2be3SAdheer Chandravanshi 	COPY_ISID(flash_tddb->isid, fnode_sess->isid);
75061e9e2be3SAdheer Chandravanshi 
75071e9e2be3SAdheer Chandravanshi 	for (idx = 0; idx < MAX_DDB_ENTRIES; idx++) {
75081e9e2be3SAdheer Chandravanshi 		ddb_entry = qla4xxx_lookup_ddb_by_fw_index(ha, idx);
75091e9e2be3SAdheer Chandravanshi 		if (ddb_entry == NULL)
75101e9e2be3SAdheer Chandravanshi 			continue;
75111e9e2be3SAdheer Chandravanshi 
75121e9e2be3SAdheer Chandravanshi 		if (ddb_entry->ddb_type != FLASH_DDB)
75131e9e2be3SAdheer Chandravanshi 			continue;
75141e9e2be3SAdheer Chandravanshi 
75151e9e2be3SAdheer Chandravanshi 		index = ddb_entry->sess->target_id;
75161e9e2be3SAdheer Chandravanshi 		status = qla4xxx_get_fwddb_entry(ha, index, fw_ddb_entry,
75171e9e2be3SAdheer Chandravanshi 						 fw_ddb_dma, NULL, &next_idx,
75181e9e2be3SAdheer Chandravanshi 						 &state, &conn_err, NULL,
75191e9e2be3SAdheer Chandravanshi 						 &conn_id);
75201e9e2be3SAdheer Chandravanshi 		if (status == QLA_ERROR) {
75211e9e2be3SAdheer Chandravanshi 			ret = -ENOMEM;
75221e9e2be3SAdheer Chandravanshi 			break;
75231e9e2be3SAdheer Chandravanshi 		}
75241e9e2be3SAdheer Chandravanshi 
75251e9e2be3SAdheer Chandravanshi 		qla4xxx_convert_param_ddb(fw_ddb_entry, tmp_tddb, NULL);
75261e9e2be3SAdheer Chandravanshi 
75271e9e2be3SAdheer Chandravanshi 		status = qla4xxx_compare_tuple_ddb(ha, flash_tddb, tmp_tddb,
75281e9e2be3SAdheer Chandravanshi 						   true);
75291e9e2be3SAdheer Chandravanshi 		if (status == QLA_SUCCESS) {
75301e9e2be3SAdheer Chandravanshi 			ret = qla4xxx_sysfs_ddb_logout_sid(ddb_entry->sess);
75311e9e2be3SAdheer Chandravanshi 			break;
75321e9e2be3SAdheer Chandravanshi 		}
75331e9e2be3SAdheer Chandravanshi 	}
75341e9e2be3SAdheer Chandravanshi 
75351e9e2be3SAdheer Chandravanshi 	if (idx == MAX_DDB_ENTRIES)
75361e9e2be3SAdheer Chandravanshi 		ret = -ESRCH;
75371e9e2be3SAdheer Chandravanshi 
75381e9e2be3SAdheer Chandravanshi exit_ddb_logout:
75391e9e2be3SAdheer Chandravanshi 	if (flash_tddb)
75401e9e2be3SAdheer Chandravanshi 		vfree(flash_tddb);
75411e9e2be3SAdheer Chandravanshi 	if (tmp_tddb)
75421e9e2be3SAdheer Chandravanshi 		vfree(tmp_tddb);
75431e9e2be3SAdheer Chandravanshi 	if (fw_ddb_entry)
75441e9e2be3SAdheer Chandravanshi 		dma_pool_free(ha->fw_ddb_dma_pool, fw_ddb_entry, fw_ddb_dma);
75451e9e2be3SAdheer Chandravanshi 
75461e9e2be3SAdheer Chandravanshi 	return ret;
75471e9e2be3SAdheer Chandravanshi }
75481e9e2be3SAdheer Chandravanshi 
75491e9e2be3SAdheer Chandravanshi static int
75501e9e2be3SAdheer Chandravanshi qla4xxx_sysfs_ddb_get_param(struct iscsi_bus_flash_session *fnode_sess,
75511e9e2be3SAdheer Chandravanshi 			    int param, char *buf)
75521e9e2be3SAdheer Chandravanshi {
75531e9e2be3SAdheer Chandravanshi 	struct Scsi_Host *shost = iscsi_flash_session_to_shost(fnode_sess);
75541e9e2be3SAdheer Chandravanshi 	struct scsi_qla_host *ha = to_qla_host(shost);
75551e9e2be3SAdheer Chandravanshi 	struct iscsi_bus_flash_conn *fnode_conn;
75561e9e2be3SAdheer Chandravanshi 	struct ql4_chap_table chap_tbl;
75571e9e2be3SAdheer Chandravanshi 	struct device *dev;
7558a2f76636SAdheer Chandravanshi 	int parent_type;
75591e9e2be3SAdheer Chandravanshi 	int rc = 0;
75601e9e2be3SAdheer Chandravanshi 
75618526cb11SMike Christie 	dev = iscsi_find_flashnode_conn(fnode_sess);
75621e9e2be3SAdheer Chandravanshi 	if (!dev)
75631e9e2be3SAdheer Chandravanshi 		return -EIO;
75641e9e2be3SAdheer Chandravanshi 
75651e9e2be3SAdheer Chandravanshi 	fnode_conn = iscsi_dev_to_flash_conn(dev);
75661e9e2be3SAdheer Chandravanshi 
75671e9e2be3SAdheer Chandravanshi 	switch (param) {
75681e9e2be3SAdheer Chandravanshi 	case ISCSI_FLASHNODE_IS_FW_ASSIGNED_IPV6:
75691e9e2be3SAdheer Chandravanshi 		rc = sprintf(buf, "%u\n", fnode_conn->is_fw_assigned_ipv6);
75701e9e2be3SAdheer Chandravanshi 		break;
75711e9e2be3SAdheer Chandravanshi 	case ISCSI_FLASHNODE_PORTAL_TYPE:
75721e9e2be3SAdheer Chandravanshi 		rc = sprintf(buf, "%s\n", fnode_sess->portal_type);
75731e9e2be3SAdheer Chandravanshi 		break;
75741e9e2be3SAdheer Chandravanshi 	case ISCSI_FLASHNODE_AUTO_SND_TGT_DISABLE:
75751e9e2be3SAdheer Chandravanshi 		rc = sprintf(buf, "%u\n", fnode_sess->auto_snd_tgt_disable);
75761e9e2be3SAdheer Chandravanshi 		break;
75771e9e2be3SAdheer Chandravanshi 	case ISCSI_FLASHNODE_DISCOVERY_SESS:
75781e9e2be3SAdheer Chandravanshi 		rc = sprintf(buf, "%u\n", fnode_sess->discovery_sess);
75791e9e2be3SAdheer Chandravanshi 		break;
75801e9e2be3SAdheer Chandravanshi 	case ISCSI_FLASHNODE_ENTRY_EN:
75811e9e2be3SAdheer Chandravanshi 		rc = sprintf(buf, "%u\n", fnode_sess->entry_state);
75821e9e2be3SAdheer Chandravanshi 		break;
75831e9e2be3SAdheer Chandravanshi 	case ISCSI_FLASHNODE_HDR_DGST_EN:
75841e9e2be3SAdheer Chandravanshi 		rc = sprintf(buf, "%u\n", fnode_conn->hdrdgst_en);
75851e9e2be3SAdheer Chandravanshi 		break;
75861e9e2be3SAdheer Chandravanshi 	case ISCSI_FLASHNODE_DATA_DGST_EN:
75871e9e2be3SAdheer Chandravanshi 		rc = sprintf(buf, "%u\n", fnode_conn->datadgst_en);
75881e9e2be3SAdheer Chandravanshi 		break;
75891e9e2be3SAdheer Chandravanshi 	case ISCSI_FLASHNODE_IMM_DATA_EN:
75901e9e2be3SAdheer Chandravanshi 		rc = sprintf(buf, "%u\n", fnode_sess->imm_data_en);
75911e9e2be3SAdheer Chandravanshi 		break;
75921e9e2be3SAdheer Chandravanshi 	case ISCSI_FLASHNODE_INITIAL_R2T_EN:
75931e9e2be3SAdheer Chandravanshi 		rc = sprintf(buf, "%u\n", fnode_sess->initial_r2t_en);
75941e9e2be3SAdheer Chandravanshi 		break;
75951e9e2be3SAdheer Chandravanshi 	case ISCSI_FLASHNODE_DATASEQ_INORDER:
75961e9e2be3SAdheer Chandravanshi 		rc = sprintf(buf, "%u\n", fnode_sess->dataseq_inorder_en);
75971e9e2be3SAdheer Chandravanshi 		break;
75981e9e2be3SAdheer Chandravanshi 	case ISCSI_FLASHNODE_PDU_INORDER:
75991e9e2be3SAdheer Chandravanshi 		rc = sprintf(buf, "%u\n", fnode_sess->pdu_inorder_en);
76001e9e2be3SAdheer Chandravanshi 		break;
76011e9e2be3SAdheer Chandravanshi 	case ISCSI_FLASHNODE_CHAP_AUTH_EN:
76021e9e2be3SAdheer Chandravanshi 		rc = sprintf(buf, "%u\n", fnode_sess->chap_auth_en);
76031e9e2be3SAdheer Chandravanshi 		break;
76041e9e2be3SAdheer Chandravanshi 	case ISCSI_FLASHNODE_SNACK_REQ_EN:
76051e9e2be3SAdheer Chandravanshi 		rc = sprintf(buf, "%u\n", fnode_conn->snack_req_en);
76061e9e2be3SAdheer Chandravanshi 		break;
76071e9e2be3SAdheer Chandravanshi 	case ISCSI_FLASHNODE_DISCOVERY_LOGOUT_EN:
76081e9e2be3SAdheer Chandravanshi 		rc = sprintf(buf, "%u\n", fnode_sess->discovery_logout_en);
76091e9e2be3SAdheer Chandravanshi 		break;
76101e9e2be3SAdheer Chandravanshi 	case ISCSI_FLASHNODE_BIDI_CHAP_EN:
76111e9e2be3SAdheer Chandravanshi 		rc = sprintf(buf, "%u\n", fnode_sess->bidi_chap_en);
76121e9e2be3SAdheer Chandravanshi 		break;
76131e9e2be3SAdheer Chandravanshi 	case ISCSI_FLASHNODE_DISCOVERY_AUTH_OPTIONAL:
76141e9e2be3SAdheer Chandravanshi 		rc = sprintf(buf, "%u\n", fnode_sess->discovery_auth_optional);
76151e9e2be3SAdheer Chandravanshi 		break;
76161e9e2be3SAdheer Chandravanshi 	case ISCSI_FLASHNODE_ERL:
76171e9e2be3SAdheer Chandravanshi 		rc = sprintf(buf, "%u\n", fnode_sess->erl);
76181e9e2be3SAdheer Chandravanshi 		break;
76191e9e2be3SAdheer Chandravanshi 	case ISCSI_FLASHNODE_TCP_TIMESTAMP_STAT:
76201e9e2be3SAdheer Chandravanshi 		rc = sprintf(buf, "%u\n", fnode_conn->tcp_timestamp_stat);
76211e9e2be3SAdheer Chandravanshi 		break;
76221e9e2be3SAdheer Chandravanshi 	case ISCSI_FLASHNODE_TCP_NAGLE_DISABLE:
76231e9e2be3SAdheer Chandravanshi 		rc = sprintf(buf, "%u\n", fnode_conn->tcp_nagle_disable);
76241e9e2be3SAdheer Chandravanshi 		break;
76251e9e2be3SAdheer Chandravanshi 	case ISCSI_FLASHNODE_TCP_WSF_DISABLE:
76261e9e2be3SAdheer Chandravanshi 		rc = sprintf(buf, "%u\n", fnode_conn->tcp_wsf_disable);
76271e9e2be3SAdheer Chandravanshi 		break;
76281e9e2be3SAdheer Chandravanshi 	case ISCSI_FLASHNODE_TCP_TIMER_SCALE:
76291e9e2be3SAdheer Chandravanshi 		rc = sprintf(buf, "%u\n", fnode_conn->tcp_timer_scale);
76301e9e2be3SAdheer Chandravanshi 		break;
76311e9e2be3SAdheer Chandravanshi 	case ISCSI_FLASHNODE_TCP_TIMESTAMP_EN:
76321e9e2be3SAdheer Chandravanshi 		rc = sprintf(buf, "%u\n", fnode_conn->tcp_timestamp_en);
76331e9e2be3SAdheer Chandravanshi 		break;
76341e9e2be3SAdheer Chandravanshi 	case ISCSI_FLASHNODE_IP_FRAG_DISABLE:
76351e9e2be3SAdheer Chandravanshi 		rc = sprintf(buf, "%u\n", fnode_conn->fragment_disable);
76361e9e2be3SAdheer Chandravanshi 		break;
76371e9e2be3SAdheer Chandravanshi 	case ISCSI_FLASHNODE_MAX_RECV_DLENGTH:
76381e9e2be3SAdheer Chandravanshi 		rc = sprintf(buf, "%u\n", fnode_conn->max_recv_dlength);
76391e9e2be3SAdheer Chandravanshi 		break;
76401e9e2be3SAdheer Chandravanshi 	case ISCSI_FLASHNODE_MAX_XMIT_DLENGTH:
76411e9e2be3SAdheer Chandravanshi 		rc = sprintf(buf, "%u\n", fnode_conn->max_xmit_dlength);
76421e9e2be3SAdheer Chandravanshi 		break;
76431e9e2be3SAdheer Chandravanshi 	case ISCSI_FLASHNODE_FIRST_BURST:
76441e9e2be3SAdheer Chandravanshi 		rc = sprintf(buf, "%u\n", fnode_sess->first_burst);
76451e9e2be3SAdheer Chandravanshi 		break;
76461e9e2be3SAdheer Chandravanshi 	case ISCSI_FLASHNODE_DEF_TIME2WAIT:
76471e9e2be3SAdheer Chandravanshi 		rc = sprintf(buf, "%u\n", fnode_sess->time2wait);
76481e9e2be3SAdheer Chandravanshi 		break;
76491e9e2be3SAdheer Chandravanshi 	case ISCSI_FLASHNODE_DEF_TIME2RETAIN:
76501e9e2be3SAdheer Chandravanshi 		rc = sprintf(buf, "%u\n", fnode_sess->time2retain);
76511e9e2be3SAdheer Chandravanshi 		break;
76521e9e2be3SAdheer Chandravanshi 	case ISCSI_FLASHNODE_MAX_R2T:
76531e9e2be3SAdheer Chandravanshi 		rc = sprintf(buf, "%u\n", fnode_sess->max_r2t);
76541e9e2be3SAdheer Chandravanshi 		break;
76551e9e2be3SAdheer Chandravanshi 	case ISCSI_FLASHNODE_KEEPALIVE_TMO:
76561e9e2be3SAdheer Chandravanshi 		rc = sprintf(buf, "%u\n", fnode_conn->keepalive_timeout);
76571e9e2be3SAdheer Chandravanshi 		break;
76581e9e2be3SAdheer Chandravanshi 	case ISCSI_FLASHNODE_ISID:
76591e9e2be3SAdheer Chandravanshi 		rc = sprintf(buf, "%02x%02x%02x%02x%02x%02x\n",
76601e9e2be3SAdheer Chandravanshi 			     fnode_sess->isid[0], fnode_sess->isid[1],
76611e9e2be3SAdheer Chandravanshi 			     fnode_sess->isid[2], fnode_sess->isid[3],
76621e9e2be3SAdheer Chandravanshi 			     fnode_sess->isid[4], fnode_sess->isid[5]);
76631e9e2be3SAdheer Chandravanshi 		break;
76641e9e2be3SAdheer Chandravanshi 	case ISCSI_FLASHNODE_TSID:
76651e9e2be3SAdheer Chandravanshi 		rc = sprintf(buf, "%u\n", fnode_sess->tsid);
76661e9e2be3SAdheer Chandravanshi 		break;
76671e9e2be3SAdheer Chandravanshi 	case ISCSI_FLASHNODE_PORT:
76681e9e2be3SAdheer Chandravanshi 		rc = sprintf(buf, "%d\n", fnode_conn->port);
76691e9e2be3SAdheer Chandravanshi 		break;
76701e9e2be3SAdheer Chandravanshi 	case ISCSI_FLASHNODE_MAX_BURST:
76711e9e2be3SAdheer Chandravanshi 		rc = sprintf(buf, "%u\n", fnode_sess->max_burst);
76721e9e2be3SAdheer Chandravanshi 		break;
76731e9e2be3SAdheer Chandravanshi 	case ISCSI_FLASHNODE_DEF_TASKMGMT_TMO:
76741e9e2be3SAdheer Chandravanshi 		rc = sprintf(buf, "%u\n",
76751e9e2be3SAdheer Chandravanshi 			     fnode_sess->default_taskmgmt_timeout);
76761e9e2be3SAdheer Chandravanshi 		break;
76771e9e2be3SAdheer Chandravanshi 	case ISCSI_FLASHNODE_IPADDR:
7678c962c18bSAdheer Chandravanshi 		if (!strncmp(fnode_sess->portal_type, PORTAL_TYPE_IPV6, 4))
76791e9e2be3SAdheer Chandravanshi 			rc = sprintf(buf, "%pI6\n", fnode_conn->ipaddress);
76801e9e2be3SAdheer Chandravanshi 		else
76811e9e2be3SAdheer Chandravanshi 			rc = sprintf(buf, "%pI4\n", fnode_conn->ipaddress);
76821e9e2be3SAdheer Chandravanshi 		break;
76831e9e2be3SAdheer Chandravanshi 	case ISCSI_FLASHNODE_ALIAS:
76841e9e2be3SAdheer Chandravanshi 		if (fnode_sess->targetalias)
76851e9e2be3SAdheer Chandravanshi 			rc = sprintf(buf, "%s\n", fnode_sess->targetalias);
76861e9e2be3SAdheer Chandravanshi 		else
76871e9e2be3SAdheer Chandravanshi 			rc = sprintf(buf, "\n");
76881e9e2be3SAdheer Chandravanshi 		break;
76891e9e2be3SAdheer Chandravanshi 	case ISCSI_FLASHNODE_REDIRECT_IPADDR:
7690c962c18bSAdheer Chandravanshi 		if (!strncmp(fnode_sess->portal_type, PORTAL_TYPE_IPV6, 4))
76911e9e2be3SAdheer Chandravanshi 			rc = sprintf(buf, "%pI6\n",
76921e9e2be3SAdheer Chandravanshi 				     fnode_conn->redirect_ipaddr);
76931e9e2be3SAdheer Chandravanshi 		else
76941e9e2be3SAdheer Chandravanshi 			rc = sprintf(buf, "%pI4\n",
76951e9e2be3SAdheer Chandravanshi 				     fnode_conn->redirect_ipaddr);
76961e9e2be3SAdheer Chandravanshi 		break;
76971e9e2be3SAdheer Chandravanshi 	case ISCSI_FLASHNODE_MAX_SEGMENT_SIZE:
76981e9e2be3SAdheer Chandravanshi 		rc = sprintf(buf, "%u\n", fnode_conn->max_segment_size);
76991e9e2be3SAdheer Chandravanshi 		break;
77001e9e2be3SAdheer Chandravanshi 	case ISCSI_FLASHNODE_LOCAL_PORT:
77011e9e2be3SAdheer Chandravanshi 		rc = sprintf(buf, "%u\n", fnode_conn->local_port);
77021e9e2be3SAdheer Chandravanshi 		break;
77031e9e2be3SAdheer Chandravanshi 	case ISCSI_FLASHNODE_IPV4_TOS:
77041e9e2be3SAdheer Chandravanshi 		rc = sprintf(buf, "%u\n", fnode_conn->ipv4_tos);
77051e9e2be3SAdheer Chandravanshi 		break;
77061e9e2be3SAdheer Chandravanshi 	case ISCSI_FLASHNODE_IPV6_TC:
7707c962c18bSAdheer Chandravanshi 		if (!strncmp(fnode_sess->portal_type, PORTAL_TYPE_IPV6, 4))
77081e9e2be3SAdheer Chandravanshi 			rc = sprintf(buf, "%u\n",
77091e9e2be3SAdheer Chandravanshi 				     fnode_conn->ipv6_traffic_class);
77101e9e2be3SAdheer Chandravanshi 		else
77111e9e2be3SAdheer Chandravanshi 			rc = sprintf(buf, "\n");
77121e9e2be3SAdheer Chandravanshi 		break;
77131e9e2be3SAdheer Chandravanshi 	case ISCSI_FLASHNODE_IPV6_FLOW_LABEL:
77141e9e2be3SAdheer Chandravanshi 		rc = sprintf(buf, "%u\n", fnode_conn->ipv6_flow_label);
77151e9e2be3SAdheer Chandravanshi 		break;
77161e9e2be3SAdheer Chandravanshi 	case ISCSI_FLASHNODE_LINK_LOCAL_IPV6:
7717c962c18bSAdheer Chandravanshi 		if (!strncmp(fnode_sess->portal_type, PORTAL_TYPE_IPV6, 4))
77181e9e2be3SAdheer Chandravanshi 			rc = sprintf(buf, "%pI6\n",
77191e9e2be3SAdheer Chandravanshi 				     fnode_conn->link_local_ipv6_addr);
77201e9e2be3SAdheer Chandravanshi 		else
77211e9e2be3SAdheer Chandravanshi 			rc = sprintf(buf, "\n");
77221e9e2be3SAdheer Chandravanshi 		break;
77231e9e2be3SAdheer Chandravanshi 	case ISCSI_FLASHNODE_DISCOVERY_PARENT_IDX:
7724a2f76636SAdheer Chandravanshi 		rc = sprintf(buf, "%u\n", fnode_sess->discovery_parent_idx);
77251e9e2be3SAdheer Chandravanshi 		break;
77261e9e2be3SAdheer Chandravanshi 	case ISCSI_FLASHNODE_DISCOVERY_PARENT_TYPE:
77271e9e2be3SAdheer Chandravanshi 		if (fnode_sess->discovery_parent_type == DDB_ISNS)
77281e9e2be3SAdheer Chandravanshi 			parent_type = ISCSI_DISC_PARENT_ISNS;
77291e9e2be3SAdheer Chandravanshi 		else if (fnode_sess->discovery_parent_type == DDB_NO_LINK)
77301e9e2be3SAdheer Chandravanshi 			parent_type = ISCSI_DISC_PARENT_UNKNOWN;
7731b6130ceaSVikas Chaudhary 		else if (fnode_sess->discovery_parent_type < MAX_DDB_ENTRIES)
77321e9e2be3SAdheer Chandravanshi 			parent_type = ISCSI_DISC_PARENT_SENDTGT;
77331e9e2be3SAdheer Chandravanshi 		else
77341e9e2be3SAdheer Chandravanshi 			parent_type = ISCSI_DISC_PARENT_UNKNOWN;
77351e9e2be3SAdheer Chandravanshi 
77361e9e2be3SAdheer Chandravanshi 		rc = sprintf(buf, "%s\n",
77371e9e2be3SAdheer Chandravanshi 			     iscsi_get_discovery_parent_name(parent_type));
77381e9e2be3SAdheer Chandravanshi 		break;
77391e9e2be3SAdheer Chandravanshi 	case ISCSI_FLASHNODE_NAME:
77401e9e2be3SAdheer Chandravanshi 		if (fnode_sess->targetname)
77411e9e2be3SAdheer Chandravanshi 			rc = sprintf(buf, "%s\n", fnode_sess->targetname);
77421e9e2be3SAdheer Chandravanshi 		else
77431e9e2be3SAdheer Chandravanshi 			rc = sprintf(buf, "\n");
77441e9e2be3SAdheer Chandravanshi 		break;
77451e9e2be3SAdheer Chandravanshi 	case ISCSI_FLASHNODE_TPGT:
77461e9e2be3SAdheer Chandravanshi 		rc = sprintf(buf, "%u\n", fnode_sess->tpgt);
77471e9e2be3SAdheer Chandravanshi 		break;
77481e9e2be3SAdheer Chandravanshi 	case ISCSI_FLASHNODE_TCP_XMIT_WSF:
77491e9e2be3SAdheer Chandravanshi 		rc = sprintf(buf, "%u\n", fnode_conn->tcp_xmit_wsf);
77501e9e2be3SAdheer Chandravanshi 		break;
77511e9e2be3SAdheer Chandravanshi 	case ISCSI_FLASHNODE_TCP_RECV_WSF:
77521e9e2be3SAdheer Chandravanshi 		rc = sprintf(buf, "%u\n", fnode_conn->tcp_recv_wsf);
77531e9e2be3SAdheer Chandravanshi 		break;
77541e9e2be3SAdheer Chandravanshi 	case ISCSI_FLASHNODE_CHAP_OUT_IDX:
77551e9e2be3SAdheer Chandravanshi 		rc = sprintf(buf, "%u\n", fnode_sess->chap_out_idx);
77561e9e2be3SAdheer Chandravanshi 		break;
77571e9e2be3SAdheer Chandravanshi 	case ISCSI_FLASHNODE_USERNAME:
77581e9e2be3SAdheer Chandravanshi 		if (fnode_sess->chap_auth_en) {
77591e9e2be3SAdheer Chandravanshi 			qla4xxx_get_uni_chap_at_index(ha,
77601e9e2be3SAdheer Chandravanshi 						      chap_tbl.name,
77611e9e2be3SAdheer Chandravanshi 						      chap_tbl.secret,
77621e9e2be3SAdheer Chandravanshi 						      fnode_sess->chap_out_idx);
77631e9e2be3SAdheer Chandravanshi 			rc = sprintf(buf, "%s\n", chap_tbl.name);
77641e9e2be3SAdheer Chandravanshi 		} else {
77651e9e2be3SAdheer Chandravanshi 			rc = sprintf(buf, "\n");
77661e9e2be3SAdheer Chandravanshi 		}
77671e9e2be3SAdheer Chandravanshi 		break;
77681e9e2be3SAdheer Chandravanshi 	case ISCSI_FLASHNODE_PASSWORD:
77691e9e2be3SAdheer Chandravanshi 		if (fnode_sess->chap_auth_en) {
77701e9e2be3SAdheer Chandravanshi 			qla4xxx_get_uni_chap_at_index(ha,
77711e9e2be3SAdheer Chandravanshi 						      chap_tbl.name,
77721e9e2be3SAdheer Chandravanshi 						      chap_tbl.secret,
77731e9e2be3SAdheer Chandravanshi 						      fnode_sess->chap_out_idx);
77741e9e2be3SAdheer Chandravanshi 			rc = sprintf(buf, "%s\n", chap_tbl.secret);
77751e9e2be3SAdheer Chandravanshi 		} else {
77761e9e2be3SAdheer Chandravanshi 			rc = sprintf(buf, "\n");
77771e9e2be3SAdheer Chandravanshi 		}
77781e9e2be3SAdheer Chandravanshi 		break;
77791e9e2be3SAdheer Chandravanshi 	case ISCSI_FLASHNODE_STATSN:
77801e9e2be3SAdheer Chandravanshi 		rc = sprintf(buf, "%u\n", fnode_conn->statsn);
77811e9e2be3SAdheer Chandravanshi 		break;
77821e9e2be3SAdheer Chandravanshi 	case ISCSI_FLASHNODE_EXP_STATSN:
77831e9e2be3SAdheer Chandravanshi 		rc = sprintf(buf, "%u\n", fnode_conn->exp_statsn);
77841e9e2be3SAdheer Chandravanshi 		break;
77851e9e2be3SAdheer Chandravanshi 	case ISCSI_FLASHNODE_IS_BOOT_TGT:
77861e9e2be3SAdheer Chandravanshi 		rc = sprintf(buf, "%u\n", fnode_sess->is_boot_target);
77871e9e2be3SAdheer Chandravanshi 		break;
77881e9e2be3SAdheer Chandravanshi 	default:
77891e9e2be3SAdheer Chandravanshi 		rc = -ENOSYS;
77901e9e2be3SAdheer Chandravanshi 		break;
77911e9e2be3SAdheer Chandravanshi 	}
77928526cb11SMike Christie 
77938526cb11SMike Christie 	put_device(dev);
77941e9e2be3SAdheer Chandravanshi 	return rc;
77951e9e2be3SAdheer Chandravanshi }
77961e9e2be3SAdheer Chandravanshi 
77971e9e2be3SAdheer Chandravanshi /**
77981e9e2be3SAdheer Chandravanshi  * qla4xxx_sysfs_ddb_set_param - Set parameter for firmware DDB entry
77991e9e2be3SAdheer Chandravanshi  * @fnode_sess: pointer to session attrs of flash ddb entry
78001e9e2be3SAdheer Chandravanshi  * @fnode_conn: pointer to connection attrs of flash ddb entry
78011e9e2be3SAdheer Chandravanshi  * @data: Parameters and their values to update
78021e9e2be3SAdheer Chandravanshi  * @len: len of data
78031e9e2be3SAdheer Chandravanshi  *
78041e9e2be3SAdheer Chandravanshi  * This sets the parameter of flash ddb entry and writes them to flash
78051e9e2be3SAdheer Chandravanshi  **/
78061e9e2be3SAdheer Chandravanshi static int
78071e9e2be3SAdheer Chandravanshi qla4xxx_sysfs_ddb_set_param(struct iscsi_bus_flash_session *fnode_sess,
78081e9e2be3SAdheer Chandravanshi 			    struct iscsi_bus_flash_conn *fnode_conn,
78091e9e2be3SAdheer Chandravanshi 			    void *data, int len)
78101e9e2be3SAdheer Chandravanshi {
78111e9e2be3SAdheer Chandravanshi 	struct Scsi_Host *shost = iscsi_flash_session_to_shost(fnode_sess);
78121e9e2be3SAdheer Chandravanshi 	struct scsi_qla_host *ha = to_qla_host(shost);
78131e9e2be3SAdheer Chandravanshi 	struct iscsi_flashnode_param_info *fnode_param;
7814244c079bSAdheer Chandravanshi 	struct ql4_chap_table chap_tbl;
78151e9e2be3SAdheer Chandravanshi 	struct nlattr *attr;
7816244c079bSAdheer Chandravanshi 	uint16_t chap_out_idx = INVALID_ENTRY;
78171e9e2be3SAdheer Chandravanshi 	int rc = QLA_ERROR;
78181e9e2be3SAdheer Chandravanshi 	uint32_t rem = len;
78191e9e2be3SAdheer Chandravanshi 
7820244c079bSAdheer Chandravanshi 	memset((void *)&chap_tbl, 0, sizeof(chap_tbl));
78211e9e2be3SAdheer Chandravanshi 	nla_for_each_attr(attr, data, len, rem) {
78221e9e2be3SAdheer Chandravanshi 		fnode_param = nla_data(attr);
78231e9e2be3SAdheer Chandravanshi 
78241e9e2be3SAdheer Chandravanshi 		switch (fnode_param->param) {
78251e9e2be3SAdheer Chandravanshi 		case ISCSI_FLASHNODE_IS_FW_ASSIGNED_IPV6:
78261e9e2be3SAdheer Chandravanshi 			fnode_conn->is_fw_assigned_ipv6 = fnode_param->value[0];
78271e9e2be3SAdheer Chandravanshi 			break;
78281e9e2be3SAdheer Chandravanshi 		case ISCSI_FLASHNODE_PORTAL_TYPE:
78291e9e2be3SAdheer Chandravanshi 			memcpy(fnode_sess->portal_type, fnode_param->value,
78301e9e2be3SAdheer Chandravanshi 			       strlen(fnode_sess->portal_type));
78311e9e2be3SAdheer Chandravanshi 			break;
78321e9e2be3SAdheer Chandravanshi 		case ISCSI_FLASHNODE_AUTO_SND_TGT_DISABLE:
78331e9e2be3SAdheer Chandravanshi 			fnode_sess->auto_snd_tgt_disable =
78341e9e2be3SAdheer Chandravanshi 							fnode_param->value[0];
78351e9e2be3SAdheer Chandravanshi 			break;
78361e9e2be3SAdheer Chandravanshi 		case ISCSI_FLASHNODE_DISCOVERY_SESS:
78371e9e2be3SAdheer Chandravanshi 			fnode_sess->discovery_sess = fnode_param->value[0];
78381e9e2be3SAdheer Chandravanshi 			break;
78391e9e2be3SAdheer Chandravanshi 		case ISCSI_FLASHNODE_ENTRY_EN:
78401e9e2be3SAdheer Chandravanshi 			fnode_sess->entry_state = fnode_param->value[0];
78411e9e2be3SAdheer Chandravanshi 			break;
78421e9e2be3SAdheer Chandravanshi 		case ISCSI_FLASHNODE_HDR_DGST_EN:
78431e9e2be3SAdheer Chandravanshi 			fnode_conn->hdrdgst_en = fnode_param->value[0];
78441e9e2be3SAdheer Chandravanshi 			break;
78451e9e2be3SAdheer Chandravanshi 		case ISCSI_FLASHNODE_DATA_DGST_EN:
78461e9e2be3SAdheer Chandravanshi 			fnode_conn->datadgst_en = fnode_param->value[0];
78471e9e2be3SAdheer Chandravanshi 			break;
78481e9e2be3SAdheer Chandravanshi 		case ISCSI_FLASHNODE_IMM_DATA_EN:
78491e9e2be3SAdheer Chandravanshi 			fnode_sess->imm_data_en = fnode_param->value[0];
78501e9e2be3SAdheer Chandravanshi 			break;
78511e9e2be3SAdheer Chandravanshi 		case ISCSI_FLASHNODE_INITIAL_R2T_EN:
78521e9e2be3SAdheer Chandravanshi 			fnode_sess->initial_r2t_en = fnode_param->value[0];
78531e9e2be3SAdheer Chandravanshi 			break;
78541e9e2be3SAdheer Chandravanshi 		case ISCSI_FLASHNODE_DATASEQ_INORDER:
78551e9e2be3SAdheer Chandravanshi 			fnode_sess->dataseq_inorder_en = fnode_param->value[0];
78561e9e2be3SAdheer Chandravanshi 			break;
78571e9e2be3SAdheer Chandravanshi 		case ISCSI_FLASHNODE_PDU_INORDER:
78581e9e2be3SAdheer Chandravanshi 			fnode_sess->pdu_inorder_en = fnode_param->value[0];
78591e9e2be3SAdheer Chandravanshi 			break;
78601e9e2be3SAdheer Chandravanshi 		case ISCSI_FLASHNODE_CHAP_AUTH_EN:
78611e9e2be3SAdheer Chandravanshi 			fnode_sess->chap_auth_en = fnode_param->value[0];
7862244c079bSAdheer Chandravanshi 			/* Invalidate chap index if chap auth is disabled */
7863244c079bSAdheer Chandravanshi 			if (!fnode_sess->chap_auth_en)
7864244c079bSAdheer Chandravanshi 				fnode_sess->chap_out_idx = INVALID_ENTRY;
7865244c079bSAdheer Chandravanshi 
78661e9e2be3SAdheer Chandravanshi 			break;
78671e9e2be3SAdheer Chandravanshi 		case ISCSI_FLASHNODE_SNACK_REQ_EN:
78681e9e2be3SAdheer Chandravanshi 			fnode_conn->snack_req_en = fnode_param->value[0];
78691e9e2be3SAdheer Chandravanshi 			break;
78701e9e2be3SAdheer Chandravanshi 		case ISCSI_FLASHNODE_DISCOVERY_LOGOUT_EN:
78711e9e2be3SAdheer Chandravanshi 			fnode_sess->discovery_logout_en = fnode_param->value[0];
78721e9e2be3SAdheer Chandravanshi 			break;
78731e9e2be3SAdheer Chandravanshi 		case ISCSI_FLASHNODE_BIDI_CHAP_EN:
78741e9e2be3SAdheer Chandravanshi 			fnode_sess->bidi_chap_en = fnode_param->value[0];
78751e9e2be3SAdheer Chandravanshi 			break;
78761e9e2be3SAdheer Chandravanshi 		case ISCSI_FLASHNODE_DISCOVERY_AUTH_OPTIONAL:
78771e9e2be3SAdheer Chandravanshi 			fnode_sess->discovery_auth_optional =
78781e9e2be3SAdheer Chandravanshi 							fnode_param->value[0];
78791e9e2be3SAdheer Chandravanshi 			break;
78801e9e2be3SAdheer Chandravanshi 		case ISCSI_FLASHNODE_ERL:
78811e9e2be3SAdheer Chandravanshi 			fnode_sess->erl = fnode_param->value[0];
78821e9e2be3SAdheer Chandravanshi 			break;
78831e9e2be3SAdheer Chandravanshi 		case ISCSI_FLASHNODE_TCP_TIMESTAMP_STAT:
78841e9e2be3SAdheer Chandravanshi 			fnode_conn->tcp_timestamp_stat = fnode_param->value[0];
78851e9e2be3SAdheer Chandravanshi 			break;
78861e9e2be3SAdheer Chandravanshi 		case ISCSI_FLASHNODE_TCP_NAGLE_DISABLE:
78871e9e2be3SAdheer Chandravanshi 			fnode_conn->tcp_nagle_disable = fnode_param->value[0];
78881e9e2be3SAdheer Chandravanshi 			break;
78891e9e2be3SAdheer Chandravanshi 		case ISCSI_FLASHNODE_TCP_WSF_DISABLE:
78901e9e2be3SAdheer Chandravanshi 			fnode_conn->tcp_wsf_disable = fnode_param->value[0];
78911e9e2be3SAdheer Chandravanshi 			break;
78921e9e2be3SAdheer Chandravanshi 		case ISCSI_FLASHNODE_TCP_TIMER_SCALE:
78931e9e2be3SAdheer Chandravanshi 			fnode_conn->tcp_timer_scale = fnode_param->value[0];
78941e9e2be3SAdheer Chandravanshi 			break;
78951e9e2be3SAdheer Chandravanshi 		case ISCSI_FLASHNODE_TCP_TIMESTAMP_EN:
78961e9e2be3SAdheer Chandravanshi 			fnode_conn->tcp_timestamp_en = fnode_param->value[0];
78971e9e2be3SAdheer Chandravanshi 			break;
78981e9e2be3SAdheer Chandravanshi 		case ISCSI_FLASHNODE_IP_FRAG_DISABLE:
78991e9e2be3SAdheer Chandravanshi 			fnode_conn->fragment_disable = fnode_param->value[0];
79001e9e2be3SAdheer Chandravanshi 			break;
79011e9e2be3SAdheer Chandravanshi 		case ISCSI_FLASHNODE_MAX_RECV_DLENGTH:
79021e9e2be3SAdheer Chandravanshi 			fnode_conn->max_recv_dlength =
79031e9e2be3SAdheer Chandravanshi 					*(unsigned *)fnode_param->value;
79041e9e2be3SAdheer Chandravanshi 			break;
79051e9e2be3SAdheer Chandravanshi 		case ISCSI_FLASHNODE_MAX_XMIT_DLENGTH:
79061e9e2be3SAdheer Chandravanshi 			fnode_conn->max_xmit_dlength =
79071e9e2be3SAdheer Chandravanshi 					*(unsigned *)fnode_param->value;
79081e9e2be3SAdheer Chandravanshi 			break;
79091e9e2be3SAdheer Chandravanshi 		case ISCSI_FLASHNODE_FIRST_BURST:
79101e9e2be3SAdheer Chandravanshi 			fnode_sess->first_burst =
79111e9e2be3SAdheer Chandravanshi 					*(unsigned *)fnode_param->value;
79121e9e2be3SAdheer Chandravanshi 			break;
79131e9e2be3SAdheer Chandravanshi 		case ISCSI_FLASHNODE_DEF_TIME2WAIT:
79141e9e2be3SAdheer Chandravanshi 			fnode_sess->time2wait = *(uint16_t *)fnode_param->value;
79151e9e2be3SAdheer Chandravanshi 			break;
79161e9e2be3SAdheer Chandravanshi 		case ISCSI_FLASHNODE_DEF_TIME2RETAIN:
79171e9e2be3SAdheer Chandravanshi 			fnode_sess->time2retain =
79181e9e2be3SAdheer Chandravanshi 						*(uint16_t *)fnode_param->value;
79191e9e2be3SAdheer Chandravanshi 			break;
79201e9e2be3SAdheer Chandravanshi 		case ISCSI_FLASHNODE_MAX_R2T:
79211e9e2be3SAdheer Chandravanshi 			fnode_sess->max_r2t =
79221e9e2be3SAdheer Chandravanshi 					*(uint16_t *)fnode_param->value;
79231e9e2be3SAdheer Chandravanshi 			break;
79241e9e2be3SAdheer Chandravanshi 		case ISCSI_FLASHNODE_KEEPALIVE_TMO:
79251e9e2be3SAdheer Chandravanshi 			fnode_conn->keepalive_timeout =
79261e9e2be3SAdheer Chandravanshi 				*(uint16_t *)fnode_param->value;
79271e9e2be3SAdheer Chandravanshi 			break;
79281e9e2be3SAdheer Chandravanshi 		case ISCSI_FLASHNODE_ISID:
79291e9e2be3SAdheer Chandravanshi 			memcpy(fnode_sess->isid, fnode_param->value,
79301e9e2be3SAdheer Chandravanshi 			       sizeof(fnode_sess->isid));
79311e9e2be3SAdheer Chandravanshi 			break;
79321e9e2be3SAdheer Chandravanshi 		case ISCSI_FLASHNODE_TSID:
79331e9e2be3SAdheer Chandravanshi 			fnode_sess->tsid = *(uint16_t *)fnode_param->value;
79341e9e2be3SAdheer Chandravanshi 			break;
79351e9e2be3SAdheer Chandravanshi 		case ISCSI_FLASHNODE_PORT:
79361e9e2be3SAdheer Chandravanshi 			fnode_conn->port = *(uint16_t *)fnode_param->value;
79371e9e2be3SAdheer Chandravanshi 			break;
79381e9e2be3SAdheer Chandravanshi 		case ISCSI_FLASHNODE_MAX_BURST:
79391e9e2be3SAdheer Chandravanshi 			fnode_sess->max_burst = *(unsigned *)fnode_param->value;
79401e9e2be3SAdheer Chandravanshi 			break;
79411e9e2be3SAdheer Chandravanshi 		case ISCSI_FLASHNODE_DEF_TASKMGMT_TMO:
79421e9e2be3SAdheer Chandravanshi 			fnode_sess->default_taskmgmt_timeout =
79431e9e2be3SAdheer Chandravanshi 						*(uint16_t *)fnode_param->value;
79441e9e2be3SAdheer Chandravanshi 			break;
79451e9e2be3SAdheer Chandravanshi 		case ISCSI_FLASHNODE_IPADDR:
79461e9e2be3SAdheer Chandravanshi 			memcpy(fnode_conn->ipaddress, fnode_param->value,
79471e9e2be3SAdheer Chandravanshi 			       IPv6_ADDR_LEN);
79481e9e2be3SAdheer Chandravanshi 			break;
79491e9e2be3SAdheer Chandravanshi 		case ISCSI_FLASHNODE_ALIAS:
79501e9e2be3SAdheer Chandravanshi 			rc = iscsi_switch_str_param(&fnode_sess->targetalias,
79511e9e2be3SAdheer Chandravanshi 						    (char *)fnode_param->value);
79521e9e2be3SAdheer Chandravanshi 			break;
79531e9e2be3SAdheer Chandravanshi 		case ISCSI_FLASHNODE_REDIRECT_IPADDR:
79541e9e2be3SAdheer Chandravanshi 			memcpy(fnode_conn->redirect_ipaddr, fnode_param->value,
79551e9e2be3SAdheer Chandravanshi 			       IPv6_ADDR_LEN);
79561e9e2be3SAdheer Chandravanshi 			break;
79571e9e2be3SAdheer Chandravanshi 		case ISCSI_FLASHNODE_MAX_SEGMENT_SIZE:
79581e9e2be3SAdheer Chandravanshi 			fnode_conn->max_segment_size =
79591e9e2be3SAdheer Chandravanshi 					*(unsigned *)fnode_param->value;
79601e9e2be3SAdheer Chandravanshi 			break;
79611e9e2be3SAdheer Chandravanshi 		case ISCSI_FLASHNODE_LOCAL_PORT:
79621e9e2be3SAdheer Chandravanshi 			fnode_conn->local_port =
79631e9e2be3SAdheer Chandravanshi 						*(uint16_t *)fnode_param->value;
79641e9e2be3SAdheer Chandravanshi 			break;
79651e9e2be3SAdheer Chandravanshi 		case ISCSI_FLASHNODE_IPV4_TOS:
79661e9e2be3SAdheer Chandravanshi 			fnode_conn->ipv4_tos = fnode_param->value[0];
79671e9e2be3SAdheer Chandravanshi 			break;
79681e9e2be3SAdheer Chandravanshi 		case ISCSI_FLASHNODE_IPV6_TC:
79691e9e2be3SAdheer Chandravanshi 			fnode_conn->ipv6_traffic_class = fnode_param->value[0];
79701e9e2be3SAdheer Chandravanshi 			break;
79711e9e2be3SAdheer Chandravanshi 		case ISCSI_FLASHNODE_IPV6_FLOW_LABEL:
79721e9e2be3SAdheer Chandravanshi 			fnode_conn->ipv6_flow_label = fnode_param->value[0];
79731e9e2be3SAdheer Chandravanshi 			break;
79741e9e2be3SAdheer Chandravanshi 		case ISCSI_FLASHNODE_NAME:
79751e9e2be3SAdheer Chandravanshi 			rc = iscsi_switch_str_param(&fnode_sess->targetname,
79761e9e2be3SAdheer Chandravanshi 						    (char *)fnode_param->value);
79771e9e2be3SAdheer Chandravanshi 			break;
79781e9e2be3SAdheer Chandravanshi 		case ISCSI_FLASHNODE_TPGT:
79791e9e2be3SAdheer Chandravanshi 			fnode_sess->tpgt = *(uint16_t *)fnode_param->value;
79801e9e2be3SAdheer Chandravanshi 			break;
79811e9e2be3SAdheer Chandravanshi 		case ISCSI_FLASHNODE_LINK_LOCAL_IPV6:
79821e9e2be3SAdheer Chandravanshi 			memcpy(fnode_conn->link_local_ipv6_addr,
79831e9e2be3SAdheer Chandravanshi 			       fnode_param->value, IPv6_ADDR_LEN);
79841e9e2be3SAdheer Chandravanshi 			break;
798565560166SAdheer Chandravanshi 		case ISCSI_FLASHNODE_DISCOVERY_PARENT_IDX:
798665560166SAdheer Chandravanshi 			fnode_sess->discovery_parent_idx =
79871e9e2be3SAdheer Chandravanshi 						*(uint16_t *)fnode_param->value;
79881e9e2be3SAdheer Chandravanshi 			break;
79891e9e2be3SAdheer Chandravanshi 		case ISCSI_FLASHNODE_TCP_XMIT_WSF:
79901e9e2be3SAdheer Chandravanshi 			fnode_conn->tcp_xmit_wsf =
79911e9e2be3SAdheer Chandravanshi 						*(uint8_t *)fnode_param->value;
79921e9e2be3SAdheer Chandravanshi 			break;
79931e9e2be3SAdheer Chandravanshi 		case ISCSI_FLASHNODE_TCP_RECV_WSF:
79941e9e2be3SAdheer Chandravanshi 			fnode_conn->tcp_recv_wsf =
79951e9e2be3SAdheer Chandravanshi 						*(uint8_t *)fnode_param->value;
79961e9e2be3SAdheer Chandravanshi 			break;
79971e9e2be3SAdheer Chandravanshi 		case ISCSI_FLASHNODE_STATSN:
79981e9e2be3SAdheer Chandravanshi 			fnode_conn->statsn = *(uint32_t *)fnode_param->value;
79991e9e2be3SAdheer Chandravanshi 			break;
80001e9e2be3SAdheer Chandravanshi 		case ISCSI_FLASHNODE_EXP_STATSN:
80011e9e2be3SAdheer Chandravanshi 			fnode_conn->exp_statsn =
80021e9e2be3SAdheer Chandravanshi 						*(uint32_t *)fnode_param->value;
80031e9e2be3SAdheer Chandravanshi 			break;
8004244c079bSAdheer Chandravanshi 		case ISCSI_FLASHNODE_CHAP_OUT_IDX:
8005244c079bSAdheer Chandravanshi 			chap_out_idx = *(uint16_t *)fnode_param->value;
8006244c079bSAdheer Chandravanshi 			if (!qla4xxx_get_uni_chap_at_index(ha,
8007244c079bSAdheer Chandravanshi 							   chap_tbl.name,
8008244c079bSAdheer Chandravanshi 							   chap_tbl.secret,
8009244c079bSAdheer Chandravanshi 							   chap_out_idx)) {
8010244c079bSAdheer Chandravanshi 				fnode_sess->chap_out_idx = chap_out_idx;
8011244c079bSAdheer Chandravanshi 				/* Enable chap auth if chap index is valid */
8012244c079bSAdheer Chandravanshi 				fnode_sess->chap_auth_en = QL4_PARAM_ENABLE;
8013244c079bSAdheer Chandravanshi 			}
8014244c079bSAdheer Chandravanshi 			break;
80151e9e2be3SAdheer Chandravanshi 		default:
80161e9e2be3SAdheer Chandravanshi 			ql4_printk(KERN_ERR, ha,
80171e9e2be3SAdheer Chandravanshi 				   "%s: No such sysfs attribute\n", __func__);
80181e9e2be3SAdheer Chandravanshi 			rc = -ENOSYS;
80191e9e2be3SAdheer Chandravanshi 			goto exit_set_param;
80201e9e2be3SAdheer Chandravanshi 		}
80211e9e2be3SAdheer Chandravanshi 	}
80221e9e2be3SAdheer Chandravanshi 
80231e9e2be3SAdheer Chandravanshi 	rc = qla4xxx_sysfs_ddb_apply(fnode_sess, fnode_conn);
80241e9e2be3SAdheer Chandravanshi 
80251e9e2be3SAdheer Chandravanshi exit_set_param:
80261e9e2be3SAdheer Chandravanshi 	return rc;
80271e9e2be3SAdheer Chandravanshi }
80281e9e2be3SAdheer Chandravanshi 
80291e9e2be3SAdheer Chandravanshi /**
80301e9e2be3SAdheer Chandravanshi  * qla4xxx_sysfs_ddb_delete - Delete firmware DDB entry
80311e9e2be3SAdheer Chandravanshi  * @fnode_sess: pointer to session attrs of flash ddb entry
80321e9e2be3SAdheer Chandravanshi  *
80331e9e2be3SAdheer Chandravanshi  * This invalidates the flash ddb entry at the given index
80341e9e2be3SAdheer Chandravanshi  **/
80351e9e2be3SAdheer Chandravanshi static int qla4xxx_sysfs_ddb_delete(struct iscsi_bus_flash_session *fnode_sess)
80361e9e2be3SAdheer Chandravanshi {
80371e9e2be3SAdheer Chandravanshi 	struct Scsi_Host *shost = iscsi_flash_session_to_shost(fnode_sess);
80381e9e2be3SAdheer Chandravanshi 	struct scsi_qla_host *ha = to_qla_host(shost);
80391e9e2be3SAdheer Chandravanshi 	uint32_t dev_db_start_offset;
80401e9e2be3SAdheer Chandravanshi 	uint32_t dev_db_end_offset;
80411e9e2be3SAdheer Chandravanshi 	struct dev_db_entry *fw_ddb_entry = NULL;
80421e9e2be3SAdheer Chandravanshi 	dma_addr_t fw_ddb_entry_dma;
80431e9e2be3SAdheer Chandravanshi 	uint16_t *ddb_cookie = NULL;
8044b6130ceaSVikas Chaudhary 	size_t ddb_size = 0;
8045039acc1eSAdheer Chandravanshi 	void *pddb = NULL;
80461e9e2be3SAdheer Chandravanshi 	int target_id;
80471e9e2be3SAdheer Chandravanshi 	int rc = 0;
80481e9e2be3SAdheer Chandravanshi 
80491e9e2be3SAdheer Chandravanshi 	if (fnode_sess->is_boot_target) {
80501e9e2be3SAdheer Chandravanshi 		rc = -EPERM;
80511e9e2be3SAdheer Chandravanshi 		DEBUG2(ql4_printk(KERN_ERR, ha,
80521e9e2be3SAdheer Chandravanshi 				  "%s: Deletion of boot target entry is not permitted.\n",
80531e9e2be3SAdheer Chandravanshi 				  __func__));
80541e9e2be3SAdheer Chandravanshi 		goto exit_ddb_del;
80551e9e2be3SAdheer Chandravanshi 	}
80561e9e2be3SAdheer Chandravanshi 
80571e9e2be3SAdheer Chandravanshi 	if (fnode_sess->flash_state == DEV_DB_NON_PERSISTENT)
80581e9e2be3SAdheer Chandravanshi 		goto sysfs_ddb_del;
80591e9e2be3SAdheer Chandravanshi 
80601e9e2be3SAdheer Chandravanshi 	if (is_qla40XX(ha)) {
80611e9e2be3SAdheer Chandravanshi 		dev_db_start_offset = FLASH_OFFSET_DB_INFO;
8062039acc1eSAdheer Chandravanshi 		dev_db_end_offset = FLASH_OFFSET_DB_END;
8063039acc1eSAdheer Chandravanshi 		dev_db_start_offset += (fnode_sess->target_id *
8064039acc1eSAdheer Chandravanshi 				       sizeof(*fw_ddb_entry));
8065039acc1eSAdheer Chandravanshi 		ddb_size = sizeof(*fw_ddb_entry);
80661e9e2be3SAdheer Chandravanshi 	} else {
80671e9e2be3SAdheer Chandravanshi 		dev_db_start_offset = FLASH_RAW_ACCESS_ADDR +
80681e9e2be3SAdheer Chandravanshi 				      (ha->hw.flt_region_ddb << 2);
80691e9e2be3SAdheer Chandravanshi 		/* flt_ddb_size is DDB table size for both ports
80701e9e2be3SAdheer Chandravanshi 		 * so divide it by 2 to calculate the offset for second port
80711e9e2be3SAdheer Chandravanshi 		 */
80721e9e2be3SAdheer Chandravanshi 		if (ha->port_num == 1)
80731e9e2be3SAdheer Chandravanshi 			dev_db_start_offset += (ha->hw.flt_ddb_size / 2);
80741e9e2be3SAdheer Chandravanshi 
8075039acc1eSAdheer Chandravanshi 		dev_db_end_offset = dev_db_start_offset +
8076039acc1eSAdheer Chandravanshi 				    (ha->hw.flt_ddb_size / 2);
8077039acc1eSAdheer Chandravanshi 
8078039acc1eSAdheer Chandravanshi 		dev_db_start_offset += (fnode_sess->target_id *
8079039acc1eSAdheer Chandravanshi 				       sizeof(*fw_ddb_entry));
80801bcb5619SAdheer Chandravanshi 		dev_db_start_offset += offsetof(struct dev_db_entry, cookie);
80811e9e2be3SAdheer Chandravanshi 
8082039acc1eSAdheer Chandravanshi 		ddb_size = sizeof(*ddb_cookie);
8083039acc1eSAdheer Chandravanshi 	}
8084039acc1eSAdheer Chandravanshi 
80851e9e2be3SAdheer Chandravanshi 	DEBUG2(ql4_printk(KERN_ERR, ha, "%s: start offset=%u, end offset=%u\n",
80861e9e2be3SAdheer Chandravanshi 			  __func__, dev_db_start_offset, dev_db_end_offset));
80871e9e2be3SAdheer Chandravanshi 
80881e9e2be3SAdheer Chandravanshi 	if (dev_db_start_offset > dev_db_end_offset) {
80891e9e2be3SAdheer Chandravanshi 		rc = -EIO;
80901e9e2be3SAdheer Chandravanshi 		DEBUG2(ql4_printk(KERN_ERR, ha, "%s:Invalid DDB index %u\n",
80911e9e2be3SAdheer Chandravanshi 				  __func__, fnode_sess->target_id));
80921e9e2be3SAdheer Chandravanshi 		goto exit_ddb_del;
80931e9e2be3SAdheer Chandravanshi 	}
80941e9e2be3SAdheer Chandravanshi 
8095039acc1eSAdheer Chandravanshi 	pddb = dma_alloc_coherent(&ha->pdev->dev, ddb_size,
8096039acc1eSAdheer Chandravanshi 				  &fw_ddb_entry_dma, GFP_KERNEL);
8097039acc1eSAdheer Chandravanshi 	if (!pddb) {
8098039acc1eSAdheer Chandravanshi 		rc = -ENOMEM;
8099039acc1eSAdheer Chandravanshi 		DEBUG2(ql4_printk(KERN_ERR, ha,
8100039acc1eSAdheer Chandravanshi 				  "%s: Unable to allocate dma buffer\n",
8101039acc1eSAdheer Chandravanshi 				  __func__));
8102039acc1eSAdheer Chandravanshi 		goto exit_ddb_del;
8103039acc1eSAdheer Chandravanshi 	}
8104039acc1eSAdheer Chandravanshi 
8105039acc1eSAdheer Chandravanshi 	if (is_qla40XX(ha)) {
8106039acc1eSAdheer Chandravanshi 		fw_ddb_entry = pddb;
8107039acc1eSAdheer Chandravanshi 		memset(fw_ddb_entry, 0, ddb_size);
8108039acc1eSAdheer Chandravanshi 		ddb_cookie = &fw_ddb_entry->cookie;
8109039acc1eSAdheer Chandravanshi 	} else {
8110039acc1eSAdheer Chandravanshi 		ddb_cookie = pddb;
8111039acc1eSAdheer Chandravanshi 	}
8112039acc1eSAdheer Chandravanshi 
81131e9e2be3SAdheer Chandravanshi 	/* invalidate the cookie */
81141e9e2be3SAdheer Chandravanshi 	*ddb_cookie = 0xFFEE;
81151e9e2be3SAdheer Chandravanshi 	qla4xxx_set_flash(ha, fw_ddb_entry_dma, dev_db_start_offset,
8116039acc1eSAdheer Chandravanshi 			  ddb_size, FLASH_OPT_RMW_COMMIT);
81171e9e2be3SAdheer Chandravanshi 
81181e9e2be3SAdheer Chandravanshi sysfs_ddb_del:
81191e9e2be3SAdheer Chandravanshi 	target_id = fnode_sess->target_id;
81201e9e2be3SAdheer Chandravanshi 	iscsi_destroy_flashnode_sess(fnode_sess);
81211e9e2be3SAdheer Chandravanshi 	ql4_printk(KERN_INFO, ha,
81221e9e2be3SAdheer Chandravanshi 		   "%s: session and conn entries for flashnode %u of host %lu deleted\n",
81231e9e2be3SAdheer Chandravanshi 		   __func__, target_id, ha->host_no);
81241e9e2be3SAdheer Chandravanshi exit_ddb_del:
8125039acc1eSAdheer Chandravanshi 	if (pddb)
8126039acc1eSAdheer Chandravanshi 		dma_free_coherent(&ha->pdev->dev, ddb_size, pddb,
8127039acc1eSAdheer Chandravanshi 				  fw_ddb_entry_dma);
81281e9e2be3SAdheer Chandravanshi 	return rc;
81291e9e2be3SAdheer Chandravanshi }
81301e9e2be3SAdheer Chandravanshi 
81311e9e2be3SAdheer Chandravanshi /**
81321e9e2be3SAdheer Chandravanshi  * qla4xxx_sysfs_ddb_export - Create sysfs entries for firmware DDBs
81331e9e2be3SAdheer Chandravanshi  * @ha: pointer to adapter structure
81341e9e2be3SAdheer Chandravanshi  *
81351e9e2be3SAdheer Chandravanshi  * Export the firmware DDB for all send targets and normal targets to sysfs.
81361e9e2be3SAdheer Chandravanshi  **/
81371e9e2be3SAdheer Chandravanshi static int qla4xxx_sysfs_ddb_export(struct scsi_qla_host *ha)
81381e9e2be3SAdheer Chandravanshi {
81391e9e2be3SAdheer Chandravanshi 	struct dev_db_entry *fw_ddb_entry = NULL;
81401e9e2be3SAdheer Chandravanshi 	dma_addr_t fw_ddb_entry_dma;
81411e9e2be3SAdheer Chandravanshi 	uint16_t max_ddbs;
81421e9e2be3SAdheer Chandravanshi 	uint16_t idx = 0;
81431e9e2be3SAdheer Chandravanshi 	int ret = QLA_SUCCESS;
81441e9e2be3SAdheer Chandravanshi 
81451e9e2be3SAdheer Chandravanshi 	fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev,
81461e9e2be3SAdheer Chandravanshi 					  sizeof(*fw_ddb_entry),
81471e9e2be3SAdheer Chandravanshi 					  &fw_ddb_entry_dma, GFP_KERNEL);
81481e9e2be3SAdheer Chandravanshi 	if (!fw_ddb_entry) {
81491e9e2be3SAdheer Chandravanshi 		DEBUG2(ql4_printk(KERN_ERR, ha,
81501e9e2be3SAdheer Chandravanshi 				  "%s: Unable to allocate dma buffer\n",
81511e9e2be3SAdheer Chandravanshi 				  __func__));
81521e9e2be3SAdheer Chandravanshi 		return -ENOMEM;
81531e9e2be3SAdheer Chandravanshi 	}
81541e9e2be3SAdheer Chandravanshi 
8155a957a7d7SAdheer Chandravanshi 	max_ddbs =  is_qla40XX(ha) ? MAX_PRST_DEV_DB_ENTRIES :
81561e9e2be3SAdheer Chandravanshi 				     MAX_DEV_DB_ENTRIES;
81571e9e2be3SAdheer Chandravanshi 
81581e9e2be3SAdheer Chandravanshi 	for (idx = 0; idx < max_ddbs; idx++) {
81591e9e2be3SAdheer Chandravanshi 		if (qla4xxx_flashdb_by_index(ha, fw_ddb_entry, fw_ddb_entry_dma,
81601e9e2be3SAdheer Chandravanshi 					     idx))
81611e9e2be3SAdheer Chandravanshi 			continue;
81621e9e2be3SAdheer Chandravanshi 
81631e9e2be3SAdheer Chandravanshi 		ret = qla4xxx_sysfs_ddb_tgt_create(ha, fw_ddb_entry, &idx, 0);
81641e9e2be3SAdheer Chandravanshi 		if (ret) {
81651e9e2be3SAdheer Chandravanshi 			ret = -EIO;
81661e9e2be3SAdheer Chandravanshi 			break;
81671e9e2be3SAdheer Chandravanshi 		}
81681e9e2be3SAdheer Chandravanshi 	}
81691e9e2be3SAdheer Chandravanshi 
81701e9e2be3SAdheer Chandravanshi 	dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), fw_ddb_entry,
81711e9e2be3SAdheer Chandravanshi 			  fw_ddb_entry_dma);
81721e9e2be3SAdheer Chandravanshi 
81731e9e2be3SAdheer Chandravanshi 	return ret;
81741e9e2be3SAdheer Chandravanshi }
81751e9e2be3SAdheer Chandravanshi 
81761e9e2be3SAdheer Chandravanshi static void qla4xxx_sysfs_ddb_remove(struct scsi_qla_host *ha)
81771e9e2be3SAdheer Chandravanshi {
81781e9e2be3SAdheer Chandravanshi 	iscsi_destroy_all_flashnode(ha->host);
81791e9e2be3SAdheer Chandravanshi }
81801e9e2be3SAdheer Chandravanshi 
81814a4bc2e9SLalit Chandivade /**
81824a4bc2e9SLalit Chandivade  * qla4xxx_build_ddb_list - Build ddb list and setup sessions
81834a4bc2e9SLalit Chandivade  * @ha: pointer to adapter structure
81844a4bc2e9SLalit Chandivade  * @is_reset: Is this init path or reset path
81854a4bc2e9SLalit Chandivade  *
81864a4bc2e9SLalit Chandivade  * Create a list of sendtargets (st) from firmware DDBs, issue send targets
81874a4bc2e9SLalit Chandivade  * using connection open, then create the list of normal targets (nt)
81884a4bc2e9SLalit Chandivade  * from firmware DDBs. Based on the list of nt setup session and connection
81894a4bc2e9SLalit Chandivade  * objects.
81904a4bc2e9SLalit Chandivade  **/
81914a4bc2e9SLalit Chandivade void qla4xxx_build_ddb_list(struct scsi_qla_host *ha, int is_reset)
81924a4bc2e9SLalit Chandivade {
81934a4bc2e9SLalit Chandivade 	uint16_t tmo = 0;
81944a4bc2e9SLalit Chandivade 	struct list_head list_st, list_nt;
81954a4bc2e9SLalit Chandivade 	struct qla_ddb_index  *st_ddb_idx, *st_ddb_idx_tmp;
81964a4bc2e9SLalit Chandivade 	unsigned long wtime;
81974a4bc2e9SLalit Chandivade 
81984a4bc2e9SLalit Chandivade 	if (!test_bit(AF_LINK_UP, &ha->flags)) {
81994a4bc2e9SLalit Chandivade 		set_bit(AF_BUILD_DDB_LIST, &ha->flags);
82004a4bc2e9SLalit Chandivade 		ha->is_reset = is_reset;
82014a4bc2e9SLalit Chandivade 		return;
82024a4bc2e9SLalit Chandivade 	}
82034a4bc2e9SLalit Chandivade 
82044a4bc2e9SLalit Chandivade 	INIT_LIST_HEAD(&list_st);
82054a4bc2e9SLalit Chandivade 	INIT_LIST_HEAD(&list_nt);
82064a4bc2e9SLalit Chandivade 
82074a4bc2e9SLalit Chandivade 	qla4xxx_build_st_list(ha, &list_st);
82084a4bc2e9SLalit Chandivade 
820913483730SMike Christie 	/* Before issuing conn open mbox, ensure all IPs states are configured
821013483730SMike Christie 	 * Note, conn open fails if IPs are not configured
821113483730SMike Christie 	 */
821213483730SMike Christie 	qla4xxx_wait_for_ip_configuration(ha);
821313483730SMike Christie 
821413483730SMike Christie 	/* Go thru the STs and fire the sendtargets by issuing conn open mbx */
821513483730SMike Christie 	list_for_each_entry_safe(st_ddb_idx, st_ddb_idx_tmp, &list_st, list) {
821613483730SMike Christie 		qla4xxx_conn_open(ha, st_ddb_idx->fw_ddb_idx);
821713483730SMike Christie 	}
821813483730SMike Christie 
821913483730SMike Christie 	/* Wait to ensure all sendtargets are done for min 12 sec wait */
8220c28eaacaSNilesh Javali 	tmo = ((ha->def_timeout > LOGIN_TOV) &&
8221c28eaacaSNilesh Javali 	       (ha->def_timeout < LOGIN_TOV * 10) ?
8222c28eaacaSNilesh Javali 	       ha->def_timeout : LOGIN_TOV);
8223c28eaacaSNilesh Javali 
822413483730SMike Christie 	DEBUG2(ql4_printk(KERN_INFO, ha,
822513483730SMike Christie 			  "Default time to wait for build ddb %d\n", tmo));
822613483730SMike Christie 
822713483730SMike Christie 	wtime = jiffies + (HZ * tmo);
822813483730SMike Christie 	do {
8229f1f2e60eSNilesh Javali 		if (list_empty(&list_st))
8230f1f2e60eSNilesh Javali 			break;
8231f1f2e60eSNilesh Javali 
82324a4bc2e9SLalit Chandivade 		qla4xxx_remove_failed_ddb(ha, &list_st);
823313483730SMike Christie 		schedule_timeout_uninterruptible(HZ / 10);
823413483730SMike Christie 	} while (time_after(wtime, jiffies));
823513483730SMike Christie 
8236ad8bd45eSManish Rangankar 
8237ad8bd45eSManish Rangankar 	qla4xxx_build_nt_list(ha, &list_nt, &list_st, is_reset);
8238ad8bd45eSManish Rangankar 
82394a4bc2e9SLalit Chandivade 	qla4xxx_free_ddb_list(&list_st);
82404a4bc2e9SLalit Chandivade 	qla4xxx_free_ddb_list(&list_nt);
824113483730SMike Christie 
824213483730SMike Christie 	qla4xxx_free_ddb_index(ha);
824313483730SMike Christie }
824413483730SMike Christie 
8245afaf5a2dSDavid Somayajulu /**
82461dc8ed5dSManish Rangankar  * qla4xxx_wait_login_resp_boot_tgt -  Wait for iSCSI boot target login
82471dc8ed5dSManish Rangankar  * response.
82481dc8ed5dSManish Rangankar  * @ha: pointer to adapter structure
82491dc8ed5dSManish Rangankar  *
82501dc8ed5dSManish Rangankar  * When the boot entry is normal iSCSI target then DF_BOOT_TGT flag will be
82511dc8ed5dSManish Rangankar  * set in DDB and we will wait for login response of boot targets during
82521dc8ed5dSManish Rangankar  * probe.
82531dc8ed5dSManish Rangankar  **/
82541dc8ed5dSManish Rangankar static void qla4xxx_wait_login_resp_boot_tgt(struct scsi_qla_host *ha)
82551dc8ed5dSManish Rangankar {
82561dc8ed5dSManish Rangankar 	struct ddb_entry *ddb_entry;
82571dc8ed5dSManish Rangankar 	struct dev_db_entry *fw_ddb_entry = NULL;
82581dc8ed5dSManish Rangankar 	dma_addr_t fw_ddb_entry_dma;
82591dc8ed5dSManish Rangankar 	unsigned long wtime;
82601dc8ed5dSManish Rangankar 	uint32_t ddb_state;
82611dc8ed5dSManish Rangankar 	int max_ddbs, idx, ret;
82621dc8ed5dSManish Rangankar 
82631dc8ed5dSManish Rangankar 	max_ddbs =  is_qla40XX(ha) ? MAX_DEV_DB_ENTRIES_40XX :
82641dc8ed5dSManish Rangankar 				     MAX_DEV_DB_ENTRIES;
82651dc8ed5dSManish Rangankar 
82661dc8ed5dSManish Rangankar 	fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
82671dc8ed5dSManish Rangankar 					  &fw_ddb_entry_dma, GFP_KERNEL);
82681dc8ed5dSManish Rangankar 	if (!fw_ddb_entry) {
82691dc8ed5dSManish Rangankar 		ql4_printk(KERN_ERR, ha,
82701dc8ed5dSManish Rangankar 			   "%s: Unable to allocate dma buffer\n", __func__);
82711dc8ed5dSManish Rangankar 		goto exit_login_resp;
82721dc8ed5dSManish Rangankar 	}
82731dc8ed5dSManish Rangankar 
82741dc8ed5dSManish Rangankar 	wtime = jiffies + (HZ * BOOT_LOGIN_RESP_TOV);
82751dc8ed5dSManish Rangankar 
82761dc8ed5dSManish Rangankar 	for (idx = 0; idx < max_ddbs; idx++) {
82771dc8ed5dSManish Rangankar 		ddb_entry = qla4xxx_lookup_ddb_by_fw_index(ha, idx);
82781dc8ed5dSManish Rangankar 		if (ddb_entry == NULL)
82791dc8ed5dSManish Rangankar 			continue;
82801dc8ed5dSManish Rangankar 
82811dc8ed5dSManish Rangankar 		if (test_bit(DF_BOOT_TGT, &ddb_entry->flags)) {
82821dc8ed5dSManish Rangankar 			DEBUG2(ql4_printk(KERN_INFO, ha,
82831dc8ed5dSManish Rangankar 					  "%s: DDB index [%d]\n", __func__,
82841dc8ed5dSManish Rangankar 					  ddb_entry->fw_ddb_index));
82851dc8ed5dSManish Rangankar 			do {
82861dc8ed5dSManish Rangankar 				ret = qla4xxx_get_fwddb_entry(ha,
82871dc8ed5dSManish Rangankar 						ddb_entry->fw_ddb_index,
82881dc8ed5dSManish Rangankar 						fw_ddb_entry, fw_ddb_entry_dma,
82891dc8ed5dSManish Rangankar 						NULL, NULL, &ddb_state, NULL,
82901dc8ed5dSManish Rangankar 						NULL, NULL);
82911dc8ed5dSManish Rangankar 				if (ret == QLA_ERROR)
82921dc8ed5dSManish Rangankar 					goto exit_login_resp;
82931dc8ed5dSManish Rangankar 
82941dc8ed5dSManish Rangankar 				if ((ddb_state == DDB_DS_SESSION_ACTIVE) ||
82951dc8ed5dSManish Rangankar 				    (ddb_state == DDB_DS_SESSION_FAILED))
82961dc8ed5dSManish Rangankar 					break;
82971dc8ed5dSManish Rangankar 
82981dc8ed5dSManish Rangankar 				schedule_timeout_uninterruptible(HZ);
82991dc8ed5dSManish Rangankar 
83001dc8ed5dSManish Rangankar 			} while ((time_after(wtime, jiffies)));
83011dc8ed5dSManish Rangankar 
83021dc8ed5dSManish Rangankar 			if (!time_after(wtime, jiffies)) {
83031dc8ed5dSManish Rangankar 				DEBUG2(ql4_printk(KERN_INFO, ha,
83041dc8ed5dSManish Rangankar 						  "%s: Login response wait timer expired\n",
83051dc8ed5dSManish Rangankar 						  __func__));
83061dc8ed5dSManish Rangankar 				 goto exit_login_resp;
83071dc8ed5dSManish Rangankar 			}
83081dc8ed5dSManish Rangankar 		}
83091dc8ed5dSManish Rangankar 	}
83101dc8ed5dSManish Rangankar 
83111dc8ed5dSManish Rangankar exit_login_resp:
83121dc8ed5dSManish Rangankar 	if (fw_ddb_entry)
83131dc8ed5dSManish Rangankar 		dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
83141dc8ed5dSManish Rangankar 				  fw_ddb_entry, fw_ddb_entry_dma);
83151dc8ed5dSManish Rangankar }
83161dc8ed5dSManish Rangankar 
83171dc8ed5dSManish Rangankar /**
8318afaf5a2dSDavid Somayajulu  * qla4xxx_probe_adapter - callback function to probe HBA
8319afaf5a2dSDavid Somayajulu  * @pdev: pointer to pci_dev structure
8320afaf5a2dSDavid Somayajulu  * @pci_device_id: pointer to pci_device entry
8321afaf5a2dSDavid Somayajulu  *
8322afaf5a2dSDavid Somayajulu  * This routine will probe for Qlogic 4xxx iSCSI host adapters.
8323afaf5a2dSDavid Somayajulu  * It returns zero if successful. It also initializes all data necessary for
8324afaf5a2dSDavid Somayajulu  * the driver.
8325afaf5a2dSDavid Somayajulu  **/
83266f039790SGreg Kroah-Hartman static int qla4xxx_probe_adapter(struct pci_dev *pdev,
8327afaf5a2dSDavid Somayajulu 				 const struct pci_device_id *ent)
8328afaf5a2dSDavid Somayajulu {
8329afaf5a2dSDavid Somayajulu 	int ret = -ENODEV, status;
8330afaf5a2dSDavid Somayajulu 	struct Scsi_Host *host;
8331afaf5a2dSDavid Somayajulu 	struct scsi_qla_host *ha;
8332afaf5a2dSDavid Somayajulu 	uint8_t init_retry_count = 0;
8333afaf5a2dSDavid Somayajulu 	char buf[34];
8334f4f5df23SVikas Chaudhary 	struct qla4_8xxx_legacy_intr_set *nx_legacy_intr;
8335f9880e76SPrasanna Mumbai 	uint32_t dev_state;
8336afaf5a2dSDavid Somayajulu 
8337afaf5a2dSDavid Somayajulu 	if (pci_enable_device(pdev))
8338afaf5a2dSDavid Somayajulu 		return -1;
8339afaf5a2dSDavid Somayajulu 
8340b3a271a9SManish Rangankar 	host = iscsi_host_alloc(&qla4xxx_driver_template, sizeof(*ha), 0);
8341afaf5a2dSDavid Somayajulu 	if (host == NULL) {
8342afaf5a2dSDavid Somayajulu 		printk(KERN_WARNING
8343afaf5a2dSDavid Somayajulu 		       "qla4xxx: Couldn't allocate host from scsi layer!\n");
8344afaf5a2dSDavid Somayajulu 		goto probe_disable_device;
8345afaf5a2dSDavid Somayajulu 	}
8346afaf5a2dSDavid Somayajulu 
8347afaf5a2dSDavid Somayajulu 	/* Clear our data area */
8348b3a271a9SManish Rangankar 	ha = to_qla_host(host);
8349afaf5a2dSDavid Somayajulu 	memset(ha, 0, sizeof(*ha));
8350afaf5a2dSDavid Somayajulu 
8351afaf5a2dSDavid Somayajulu 	/* Save the information from PCI BIOS.	*/
8352afaf5a2dSDavid Somayajulu 	ha->pdev = pdev;
8353afaf5a2dSDavid Somayajulu 	ha->host = host;
8354afaf5a2dSDavid Somayajulu 	ha->host_no = host->host_no;
83556e7b4292SVikas Chaudhary 	ha->func_num = PCI_FUNC(ha->pdev->devfn);
8356afaf5a2dSDavid Somayajulu 
83572232be0dSLalit Chandivade 	pci_enable_pcie_error_reporting(pdev);
83582232be0dSLalit Chandivade 
8359f4f5df23SVikas Chaudhary 	/* Setup Runtime configurable options */
8360f4f5df23SVikas Chaudhary 	if (is_qla8022(ha)) {
83617664a1fdSVikas Chaudhary 		ha->isp_ops = &qla4_82xx_isp_ops;
836233693c7aSVikas Chaudhary 		ha->reg_tbl = (uint32_t *) qla4_82xx_reg_tbl;
8363f4f5df23SVikas Chaudhary 		ha->qdr_sn_window = -1;
8364f4f5df23SVikas Chaudhary 		ha->ddr_mn_window = -1;
8365f4f5df23SVikas Chaudhary 		ha->curr_window = 255;
8366f4f5df23SVikas Chaudhary 		nx_legacy_intr = &legacy_intr[ha->func_num];
8367f4f5df23SVikas Chaudhary 		ha->nx_legacy_intr.int_vec_bit = nx_legacy_intr->int_vec_bit;
8368f4f5df23SVikas Chaudhary 		ha->nx_legacy_intr.tgt_status_reg =
8369f4f5df23SVikas Chaudhary 			nx_legacy_intr->tgt_status_reg;
8370f4f5df23SVikas Chaudhary 		ha->nx_legacy_intr.tgt_mask_reg = nx_legacy_intr->tgt_mask_reg;
8371f4f5df23SVikas Chaudhary 		ha->nx_legacy_intr.pci_int_reg = nx_legacy_intr->pci_int_reg;
8372b37ca418SVikas Chaudhary 	} else if (is_qla8032(ha) || is_qla8042(ha)) {
83736e7b4292SVikas Chaudhary 		ha->isp_ops = &qla4_83xx_isp_ops;
83746e7b4292SVikas Chaudhary 		ha->reg_tbl = (uint32_t *)qla4_83xx_reg_tbl;
8375f4f5df23SVikas Chaudhary 	} else {
8376f4f5df23SVikas Chaudhary 		ha->isp_ops = &qla4xxx_isp_ops;
8377f4f5df23SVikas Chaudhary 	}
8378f4f5df23SVikas Chaudhary 
83796e7b4292SVikas Chaudhary 	if (is_qla80XX(ha)) {
83806e7b4292SVikas Chaudhary 		rwlock_init(&ha->hw_lock);
83816e7b4292SVikas Chaudhary 		ha->pf_bit = ha->func_num << 16;
83822232be0dSLalit Chandivade 		/* Set EEH reset type to fundamental if required by hba */
83832232be0dSLalit Chandivade 		pdev->needs_freset = 1;
83846e7b4292SVikas Chaudhary 	}
83852232be0dSLalit Chandivade 
8386afaf5a2dSDavid Somayajulu 	/* Configure PCI I/O space. */
8387f4f5df23SVikas Chaudhary 	ret = ha->isp_ops->iospace_config(ha);
8388afaf5a2dSDavid Somayajulu 	if (ret)
8389f4f5df23SVikas Chaudhary 		goto probe_failed_ioconfig;
8390afaf5a2dSDavid Somayajulu 
8391c2660df3SVikas Chaudhary 	ql4_printk(KERN_INFO, ha, "Found an ISP%04x, irq %d, iobase 0x%p\n",
8392afaf5a2dSDavid Somayajulu 		   pdev->device, pdev->irq, ha->reg);
8393afaf5a2dSDavid Somayajulu 
8394afaf5a2dSDavid Somayajulu 	qla4xxx_config_dma_addressing(ha);
8395afaf5a2dSDavid Somayajulu 
8396afaf5a2dSDavid Somayajulu 	/* Initialize lists and spinlocks. */
8397afaf5a2dSDavid Somayajulu 	INIT_LIST_HEAD(&ha->free_srb_q);
8398afaf5a2dSDavid Somayajulu 
8399afaf5a2dSDavid Somayajulu 	mutex_init(&ha->mbox_sem);
84004549415aSLalit Chandivade 	mutex_init(&ha->chap_sem);
8401f4f5df23SVikas Chaudhary 	init_completion(&ha->mbx_intr_comp);
840295d31262SVikas Chaudhary 	init_completion(&ha->disable_acb_comp);
8403df86f771SVikas Chaudhary 	init_completion(&ha->idc_comp);
8404df86f771SVikas Chaudhary 	init_completion(&ha->link_up_comp);
8405df86f771SVikas Chaudhary 	init_completion(&ha->disable_acb_comp);
8406afaf5a2dSDavid Somayajulu 
8407afaf5a2dSDavid Somayajulu 	spin_lock_init(&ha->hardware_lock);
84088e9157c8SVikas Chaudhary 	spin_lock_init(&ha->work_lock);
8409afaf5a2dSDavid Somayajulu 
8410ff884430SVikas Chaudhary 	/* Initialize work list */
8411ff884430SVikas Chaudhary 	INIT_LIST_HEAD(&ha->work_list);
8412ff884430SVikas Chaudhary 
8413afaf5a2dSDavid Somayajulu 	/* Allocate dma buffers */
8414afaf5a2dSDavid Somayajulu 	if (qla4xxx_mem_alloc(ha)) {
8415c2660df3SVikas Chaudhary 		ql4_printk(KERN_WARNING, ha,
8416afaf5a2dSDavid Somayajulu 		    "[ERROR] Failed to allocate memory for adapter\n");
8417afaf5a2dSDavid Somayajulu 
8418afaf5a2dSDavid Somayajulu 		ret = -ENOMEM;
8419afaf5a2dSDavid Somayajulu 		goto probe_failed;
8420afaf5a2dSDavid Somayajulu 	}
8421afaf5a2dSDavid Somayajulu 
8422b3a271a9SManish Rangankar 	host->cmd_per_lun = 3;
8423b3a271a9SManish Rangankar 	host->max_channel = 0;
8424b3a271a9SManish Rangankar 	host->max_lun = MAX_LUNS - 1;
8425b3a271a9SManish Rangankar 	host->max_id = MAX_TARGETS;
8426b3a271a9SManish Rangankar 	host->max_cmd_len = IOCB_MAX_CDB_LEN;
8427b3a271a9SManish Rangankar 	host->can_queue = MAX_SRBS ;
8428b3a271a9SManish Rangankar 	host->transportt = qla4xxx_scsi_transport;
8429b3a271a9SManish Rangankar 
8430b3a271a9SManish Rangankar 	ret = scsi_init_shared_tag_map(host, MAX_SRBS);
8431b3a271a9SManish Rangankar 	if (ret) {
8432b3a271a9SManish Rangankar 		ql4_printk(KERN_WARNING, ha,
8433b3a271a9SManish Rangankar 			   "%s: scsi_init_shared_tag_map failed\n", __func__);
8434b3a271a9SManish Rangankar 		goto probe_failed;
8435b3a271a9SManish Rangankar 	}
8436b3a271a9SManish Rangankar 
8437b3a271a9SManish Rangankar 	pci_set_drvdata(pdev, ha);
8438b3a271a9SManish Rangankar 
8439b3a271a9SManish Rangankar 	ret = scsi_add_host(host, &pdev->dev);
8440b3a271a9SManish Rangankar 	if (ret)
8441b3a271a9SManish Rangankar 		goto probe_failed;
8442b3a271a9SManish Rangankar 
84436e7b4292SVikas Chaudhary 	if (is_qla80XX(ha))
84446e7b4292SVikas Chaudhary 		qla4_8xxx_get_flash_info(ha);
84456e7b4292SVikas Chaudhary 
8446b37ca418SVikas Chaudhary 	if (is_qla8032(ha) || is_qla8042(ha)) {
84476e7b4292SVikas Chaudhary 		qla4_83xx_read_reset_template(ha);
84486e7b4292SVikas Chaudhary 		/*
84496e7b4292SVikas Chaudhary 		 * NOTE: If ql4dontresethba==1, set IDC_CTRL DONTRESET_BIT0.
84506e7b4292SVikas Chaudhary 		 * If DONRESET_BIT0 is set, drivers should not set dev_state
84516e7b4292SVikas Chaudhary 		 * to NEED_RESET. But if NEED_RESET is set, drivers should
84526e7b4292SVikas Chaudhary 		 * should honor the reset.
84536e7b4292SVikas Chaudhary 		 */
84546e7b4292SVikas Chaudhary 		if (ql4xdontresethba == 1)
84556e7b4292SVikas Chaudhary 			qla4_83xx_set_idc_dontreset(ha);
84566e7b4292SVikas Chaudhary 	}
8457f4f5df23SVikas Chaudhary 
8458afaf5a2dSDavid Somayajulu 	/*
8459afaf5a2dSDavid Somayajulu 	 * Initialize the Host adapter request/response queues and
8460afaf5a2dSDavid Somayajulu 	 * firmware
8461afaf5a2dSDavid Somayajulu 	 * NOTE: interrupts enabled upon successful completion
8462afaf5a2dSDavid Somayajulu 	 */
846313483730SMike Christie 	status = qla4xxx_initialize_adapter(ha, INIT_ADAPTER);
84647977f825SPoornima Vonti 
84657977f825SPoornima Vonti 	/* Dont retry adapter initialization if IRQ allocation failed */
846617801c96SNilesh Javali 	if (is_qla80XX(ha) && !test_bit(AF_IRQ_ATTACHED, &ha->flags)) {
846717801c96SNilesh Javali 		ql4_printk(KERN_WARNING, ha, "%s: Skipping retry of adapter initialization\n",
846817801c96SNilesh Javali 			   __func__);
84697977f825SPoornima Vonti 		goto skip_retry_init;
847017801c96SNilesh Javali 	}
84717977f825SPoornima Vonti 
8472f4f5df23SVikas Chaudhary 	while ((!test_bit(AF_ONLINE, &ha->flags)) &&
8473f4f5df23SVikas Chaudhary 	    init_retry_count++ < MAX_INIT_RETRIES) {
8474f9880e76SPrasanna Mumbai 
84756e7b4292SVikas Chaudhary 		if (is_qla80XX(ha)) {
847633693c7aSVikas Chaudhary 			ha->isp_ops->idc_lock(ha);
847733693c7aSVikas Chaudhary 			dev_state = qla4_8xxx_rd_direct(ha,
8478e951aca1SVikas Chaudhary 							QLA8XXX_CRB_DEV_STATE);
847933693c7aSVikas Chaudhary 			ha->isp_ops->idc_unlock(ha);
8480de8c72daSVikas Chaudhary 			if (dev_state == QLA8XXX_DEV_FAILED) {
8481f9880e76SPrasanna Mumbai 				ql4_printk(KERN_WARNING, ha, "%s: don't retry "
8482f9880e76SPrasanna Mumbai 				    "initialize adapter. H/W is in failed state\n",
8483f9880e76SPrasanna Mumbai 				    __func__);
8484f9880e76SPrasanna Mumbai 				break;
8485f9880e76SPrasanna Mumbai 			}
8486f9880e76SPrasanna Mumbai 		}
8487afaf5a2dSDavid Somayajulu 		DEBUG2(printk("scsi: %s: retrying adapter initialization "
8488afaf5a2dSDavid Somayajulu 			      "(%d)\n", __func__, init_retry_count));
8489f4f5df23SVikas Chaudhary 
8490f4f5df23SVikas Chaudhary 		if (ha->isp_ops->reset_chip(ha) == QLA_ERROR)
8491f4f5df23SVikas Chaudhary 			continue;
8492f4f5df23SVikas Chaudhary 
849313483730SMike Christie 		status = qla4xxx_initialize_adapter(ha, INIT_ADAPTER);
8494afaf5a2dSDavid Somayajulu 	}
8495f4f5df23SVikas Chaudhary 
84967977f825SPoornima Vonti skip_retry_init:
8497f4f5df23SVikas Chaudhary 	if (!test_bit(AF_ONLINE, &ha->flags)) {
8498c2660df3SVikas Chaudhary 		ql4_printk(KERN_WARNING, ha, "Failed to initialize adapter\n");
8499afaf5a2dSDavid Somayajulu 
85006e7b4292SVikas Chaudhary 		if ((is_qla8022(ha) && ql4xdontresethba) ||
8501b37ca418SVikas Chaudhary 		    ((is_qla8032(ha) || is_qla8042(ha)) &&
8502b37ca418SVikas Chaudhary 		     qla4_83xx_idc_dontreset(ha))) {
8503fe998527SLalit Chandivade 			/* Put the device in failed state. */
8504fe998527SLalit Chandivade 			DEBUG2(printk(KERN_ERR "HW STATE: FAILED\n"));
850533693c7aSVikas Chaudhary 			ha->isp_ops->idc_lock(ha);
850633693c7aSVikas Chaudhary 			qla4_8xxx_wr_direct(ha, QLA8XXX_CRB_DEV_STATE,
8507de8c72daSVikas Chaudhary 					    QLA8XXX_DEV_FAILED);
850833693c7aSVikas Chaudhary 			ha->isp_ops->idc_unlock(ha);
8509fe998527SLalit Chandivade 		}
8510afaf5a2dSDavid Somayajulu 		ret = -ENODEV;
8511b3a271a9SManish Rangankar 		goto remove_host;
8512afaf5a2dSDavid Somayajulu 	}
8513afaf5a2dSDavid Somayajulu 
8514afaf5a2dSDavid Somayajulu 	/* Startup the kernel thread for this host adapter. */
8515afaf5a2dSDavid Somayajulu 	DEBUG2(printk("scsi: %s: Starting kernel thread for "
8516afaf5a2dSDavid Somayajulu 		      "qla4xxx_dpc\n", __func__));
8517afaf5a2dSDavid Somayajulu 	sprintf(buf, "qla4xxx_%lu_dpc", ha->host_no);
8518afaf5a2dSDavid Somayajulu 	ha->dpc_thread = create_singlethread_workqueue(buf);
8519afaf5a2dSDavid Somayajulu 	if (!ha->dpc_thread) {
8520c2660df3SVikas Chaudhary 		ql4_printk(KERN_WARNING, ha, "Unable to start DPC thread!\n");
8521afaf5a2dSDavid Somayajulu 		ret = -ENODEV;
8522b3a271a9SManish Rangankar 		goto remove_host;
8523afaf5a2dSDavid Somayajulu 	}
8524c4028958SDavid Howells 	INIT_WORK(&ha->dpc_work, qla4xxx_do_dpc);
8525afaf5a2dSDavid Somayajulu 
8526d8537548SKees Cook 	ha->task_wq = alloc_workqueue("qla4xxx_%lu_task", WQ_MEM_RECLAIM, 1,
8527d8537548SKees Cook 				      ha->host_no);
8528b3a271a9SManish Rangankar 	if (!ha->task_wq) {
8529b3a271a9SManish Rangankar 		ql4_printk(KERN_WARNING, ha, "Unable to start task thread!\n");
8530b3a271a9SManish Rangankar 		ret = -ENODEV;
8531b3a271a9SManish Rangankar 		goto remove_host;
8532b3a271a9SManish Rangankar 	}
8533b3a271a9SManish Rangankar 
85346e7b4292SVikas Chaudhary 	/*
85356e7b4292SVikas Chaudhary 	 * For ISP-8XXX, request_irqs is called in qla4_8xxx_load_risc
8536f4f5df23SVikas Chaudhary 	 * (which is called indirectly by qla4xxx_initialize_adapter),
8537f4f5df23SVikas Chaudhary 	 * so that irqs will be registered after crbinit but before
8538f4f5df23SVikas Chaudhary 	 * mbx_intr_enable.
8539f4f5df23SVikas Chaudhary 	 */
8540ee996a69SVikas Chaudhary 	if (is_qla40XX(ha)) {
8541f4f5df23SVikas Chaudhary 		ret = qla4xxx_request_irqs(ha);
8542afaf5a2dSDavid Somayajulu 		if (ret) {
8543f4f5df23SVikas Chaudhary 			ql4_printk(KERN_WARNING, ha, "Failed to reserve "
8544f4f5df23SVikas Chaudhary 			    "interrupt %d already in use.\n", pdev->irq);
8545b3a271a9SManish Rangankar 			goto remove_host;
8546afaf5a2dSDavid Somayajulu 		}
8547f4f5df23SVikas Chaudhary 	}
8548afaf5a2dSDavid Somayajulu 
85492232be0dSLalit Chandivade 	pci_save_state(ha->pdev);
8550f4f5df23SVikas Chaudhary 	ha->isp_ops->enable_intrs(ha);
8551afaf5a2dSDavid Somayajulu 
8552afaf5a2dSDavid Somayajulu 	/* Start timer thread. */
8553afaf5a2dSDavid Somayajulu 	qla4xxx_start_timer(ha, qla4xxx_timer, 1);
8554afaf5a2dSDavid Somayajulu 
8555afaf5a2dSDavid Somayajulu 	set_bit(AF_INIT_DONE, &ha->flags);
8556afaf5a2dSDavid Somayajulu 
8557068237c8STej Parkash 	qla4_8xxx_alloc_sysfs_attr(ha);
8558068237c8STej Parkash 
8559afaf5a2dSDavid Somayajulu 	printk(KERN_INFO
8560afaf5a2dSDavid Somayajulu 	       " QLogic iSCSI HBA Driver version: %s\n"
8561afaf5a2dSDavid Somayajulu 	       "  QLogic ISP%04x @ %s, host#=%ld, fw=%02d.%02d.%02d.%02d\n",
8562afaf5a2dSDavid Somayajulu 	       qla4xxx_version_str, ha->pdev->device, pci_name(ha->pdev),
8563eee06a0fSAdheer Chandravanshi 	       ha->host_no, ha->fw_info.fw_major, ha->fw_info.fw_minor,
8564eee06a0fSAdheer Chandravanshi 	       ha->fw_info.fw_patch, ha->fw_info.fw_build);
8565ed1086e0SVikas Chaudhary 
8566cfb27874SManish Dusane 	/* Set the driver version */
8567cfb27874SManish Dusane 	if (is_qla80XX(ha))
8568cfb27874SManish Dusane 		qla4_8xxx_set_param(ha, SET_DRVR_VERSION);
8569cfb27874SManish Dusane 
85702a991c21SManish Rangankar 	if (qla4xxx_setup_boot_info(ha))
85713573bfb2SVikas Chaudhary 		ql4_printk(KERN_ERR, ha,
85723573bfb2SVikas Chaudhary 			   "%s: No iSCSI boot target configured\n", __func__);
85732a991c21SManish Rangankar 
85741e9e2be3SAdheer Chandravanshi 	if (qla4xxx_sysfs_ddb_export(ha))
85751e9e2be3SAdheer Chandravanshi 		ql4_printk(KERN_ERR, ha,
85761e9e2be3SAdheer Chandravanshi 			   "%s: Error exporting ddb to sysfs\n", __func__);
85771e9e2be3SAdheer Chandravanshi 
857813483730SMike Christie 		/* Perform the build ddb list and login to each */
857913483730SMike Christie 	qla4xxx_build_ddb_list(ha, INIT_ADAPTER);
858013483730SMike Christie 	iscsi_host_for_each_session(ha->host, qla4xxx_login_flash_ddb);
85811dc8ed5dSManish Rangankar 	qla4xxx_wait_login_resp_boot_tgt(ha);
858213483730SMike Christie 
858313483730SMike Christie 	qla4xxx_create_chap_list(ha);
858413483730SMike Christie 
8585ed1086e0SVikas Chaudhary 	qla4xxx_create_ifaces(ha);
8586afaf5a2dSDavid Somayajulu 	return 0;
8587afaf5a2dSDavid Somayajulu 
8588b3a271a9SManish Rangankar remove_host:
8589b3a271a9SManish Rangankar 	scsi_remove_host(ha->host);
8590b3a271a9SManish Rangankar 
8591afaf5a2dSDavid Somayajulu probe_failed:
8592afaf5a2dSDavid Somayajulu 	qla4xxx_free_adapter(ha);
8593f4f5df23SVikas Chaudhary 
8594f4f5df23SVikas Chaudhary probe_failed_ioconfig:
85952232be0dSLalit Chandivade 	pci_disable_pcie_error_reporting(pdev);
8596afaf5a2dSDavid Somayajulu 	scsi_host_put(ha->host);
8597afaf5a2dSDavid Somayajulu 
8598afaf5a2dSDavid Somayajulu probe_disable_device:
8599afaf5a2dSDavid Somayajulu 	pci_disable_device(pdev);
8600afaf5a2dSDavid Somayajulu 
8601afaf5a2dSDavid Somayajulu 	return ret;
8602afaf5a2dSDavid Somayajulu }
8603afaf5a2dSDavid Somayajulu 
8604afaf5a2dSDavid Somayajulu /**
86057eece5a0SKaren Higgins  * qla4xxx_prevent_other_port_reinit - prevent other port from re-initialize
86067eece5a0SKaren Higgins  * @ha: pointer to adapter structure
86077eece5a0SKaren Higgins  *
86087eece5a0SKaren Higgins  * Mark the other ISP-4xxx port to indicate that the driver is being removed,
86097eece5a0SKaren Higgins  * so that the other port will not re-initialize while in the process of
86107eece5a0SKaren Higgins  * removing the ha due to driver unload or hba hotplug.
86117eece5a0SKaren Higgins  **/
86127eece5a0SKaren Higgins static void qla4xxx_prevent_other_port_reinit(struct scsi_qla_host *ha)
86137eece5a0SKaren Higgins {
86147eece5a0SKaren Higgins 	struct scsi_qla_host *other_ha = NULL;
86157eece5a0SKaren Higgins 	struct pci_dev *other_pdev = NULL;
86167eece5a0SKaren Higgins 	int fn = ISP4XXX_PCI_FN_2;
86177eece5a0SKaren Higgins 
86187eece5a0SKaren Higgins 	/*iscsi function numbers for ISP4xxx is 1 and 3*/
86197eece5a0SKaren Higgins 	if (PCI_FUNC(ha->pdev->devfn) & BIT_1)
86207eece5a0SKaren Higgins 		fn = ISP4XXX_PCI_FN_1;
86217eece5a0SKaren Higgins 
86227eece5a0SKaren Higgins 	other_pdev =
86237eece5a0SKaren Higgins 		pci_get_domain_bus_and_slot(pci_domain_nr(ha->pdev->bus),
86247eece5a0SKaren Higgins 		ha->pdev->bus->number, PCI_DEVFN(PCI_SLOT(ha->pdev->devfn),
86257eece5a0SKaren Higgins 		fn));
86267eece5a0SKaren Higgins 
86277eece5a0SKaren Higgins 	/* Get other_ha if other_pdev is valid and state is enable*/
86287eece5a0SKaren Higgins 	if (other_pdev) {
86297eece5a0SKaren Higgins 		if (atomic_read(&other_pdev->enable_cnt)) {
86307eece5a0SKaren Higgins 			other_ha = pci_get_drvdata(other_pdev);
86317eece5a0SKaren Higgins 			if (other_ha) {
86327eece5a0SKaren Higgins 				set_bit(AF_HA_REMOVAL, &other_ha->flags);
86337eece5a0SKaren Higgins 				DEBUG2(ql4_printk(KERN_INFO, ha, "%s: "
86347eece5a0SKaren Higgins 				    "Prevent %s reinit\n", __func__,
86357eece5a0SKaren Higgins 				    dev_name(&other_ha->pdev->dev)));
86367eece5a0SKaren Higgins 			}
86377eece5a0SKaren Higgins 		}
86387eece5a0SKaren Higgins 		pci_dev_put(other_pdev);
86397eece5a0SKaren Higgins 	}
86407eece5a0SKaren Higgins }
86417eece5a0SKaren Higgins 
864213483730SMike Christie static void qla4xxx_destroy_fw_ddb_session(struct scsi_qla_host *ha)
864313483730SMike Christie {
864413483730SMike Christie 	struct ddb_entry *ddb_entry;
864513483730SMike Christie 	int options;
864613483730SMike Christie 	int idx;
864713483730SMike Christie 
864813483730SMike Christie 	for (idx = 0; idx < MAX_DDB_ENTRIES; idx++) {
864913483730SMike Christie 
865013483730SMike Christie 		ddb_entry = qla4xxx_lookup_ddb_by_fw_index(ha, idx);
865113483730SMike Christie 		if ((ddb_entry != NULL) &&
865213483730SMike Christie 		    (ddb_entry->ddb_type == FLASH_DDB)) {
865313483730SMike Christie 
865413483730SMike Christie 			options = LOGOUT_OPTION_CLOSE_SESSION;
865513483730SMike Christie 			if (qla4xxx_session_logout_ddb(ha, ddb_entry, options)
865613483730SMike Christie 			    == QLA_ERROR)
865713483730SMike Christie 				ql4_printk(KERN_ERR, ha, "%s: Logout failed\n",
865813483730SMike Christie 					   __func__);
865913483730SMike Christie 
866013483730SMike Christie 			qla4xxx_clear_ddb_entry(ha, ddb_entry->fw_ddb_index);
866113483730SMike Christie 			/*
866213483730SMike Christie 			 * we have decremented the reference count of the driver
866313483730SMike Christie 			 * when we setup the session to have the driver unload
866413483730SMike Christie 			 * to be seamless without actually destroying the
866513483730SMike Christie 			 * session
866613483730SMike Christie 			 **/
866713483730SMike Christie 			try_module_get(qla4xxx_iscsi_transport.owner);
866813483730SMike Christie 			iscsi_destroy_endpoint(ddb_entry->conn->ep);
866913483730SMike Christie 			qla4xxx_free_ddb(ha, ddb_entry);
867013483730SMike Christie 			iscsi_session_teardown(ddb_entry->sess);
867113483730SMike Christie 		}
867213483730SMike Christie 	}
867313483730SMike Christie }
86747eece5a0SKaren Higgins /**
867559e13d48SMasanari Iida  * qla4xxx_remove_adapter - callback function to remove adapter.
8676afaf5a2dSDavid Somayajulu  * @pci_dev: PCI device pointer
8677afaf5a2dSDavid Somayajulu  **/
86786f039790SGreg Kroah-Hartman static void qla4xxx_remove_adapter(struct pci_dev *pdev)
8679afaf5a2dSDavid Somayajulu {
8680afaf5a2dSDavid Somayajulu 	struct scsi_qla_host *ha;
8681afaf5a2dSDavid Somayajulu 
8682f8b0751dSVikas Chaudhary 	/*
8683f8b0751dSVikas Chaudhary 	 * If the PCI device is disabled then it means probe_adapter had
8684f8b0751dSVikas Chaudhary 	 * failed and resources already cleaned up on probe_adapter exit.
8685f8b0751dSVikas Chaudhary 	 */
8686f8b0751dSVikas Chaudhary 	if (!pci_is_enabled(pdev))
8687f8b0751dSVikas Chaudhary 		return;
8688f8b0751dSVikas Chaudhary 
8689afaf5a2dSDavid Somayajulu 	ha = pci_get_drvdata(pdev);
8690afaf5a2dSDavid Somayajulu 
8691ee996a69SVikas Chaudhary 	if (is_qla40XX(ha))
86927eece5a0SKaren Higgins 		qla4xxx_prevent_other_port_reinit(ha);
8693bee4fe8eSDavid C Somayajulu 
8694ed1086e0SVikas Chaudhary 	/* destroy iface from sysfs */
8695ed1086e0SVikas Chaudhary 	qla4xxx_destroy_ifaces(ha);
8696ed1086e0SVikas Chaudhary 
869713483730SMike Christie 	if ((!ql4xdisablesysfsboot) && ha->boot_kset)
86982a991c21SManish Rangankar 		iscsi_boot_destroy_kset(ha->boot_kset);
86992a991c21SManish Rangankar 
870013483730SMike Christie 	qla4xxx_destroy_fw_ddb_session(ha);
8701068237c8STej Parkash 	qla4_8xxx_free_sysfs_attr(ha);
870213483730SMike Christie 
87031e9e2be3SAdheer Chandravanshi 	qla4xxx_sysfs_ddb_remove(ha);
8704afaf5a2dSDavid Somayajulu 	scsi_remove_host(ha->host);
8705afaf5a2dSDavid Somayajulu 
8706afaf5a2dSDavid Somayajulu 	qla4xxx_free_adapter(ha);
8707afaf5a2dSDavid Somayajulu 
8708afaf5a2dSDavid Somayajulu 	scsi_host_put(ha->host);
8709afaf5a2dSDavid Somayajulu 
87102232be0dSLalit Chandivade 	pci_disable_pcie_error_reporting(pdev);
8711f4f5df23SVikas Chaudhary 	pci_disable_device(pdev);
8712afaf5a2dSDavid Somayajulu }
8713afaf5a2dSDavid Somayajulu 
8714afaf5a2dSDavid Somayajulu /**
8715afaf5a2dSDavid Somayajulu  * qla4xxx_config_dma_addressing() - Configure OS DMA addressing method.
8716afaf5a2dSDavid Somayajulu  * @ha: HA context
8717afaf5a2dSDavid Somayajulu  *
8718afaf5a2dSDavid Somayajulu  * At exit, the @ha's flags.enable_64bit_addressing set to indicated
8719afaf5a2dSDavid Somayajulu  * supported addressing method.
8720afaf5a2dSDavid Somayajulu  */
872147975477SAdrian Bunk static void qla4xxx_config_dma_addressing(struct scsi_qla_host *ha)
8722afaf5a2dSDavid Somayajulu {
8723afaf5a2dSDavid Somayajulu 	int retval;
8724afaf5a2dSDavid Somayajulu 
8725afaf5a2dSDavid Somayajulu 	/* Update our PCI device dma_mask for full 64 bit mask */
87266a35528aSYang Hongyang 	if (pci_set_dma_mask(ha->pdev, DMA_BIT_MASK(64)) == 0) {
87276a35528aSYang Hongyang 		if (pci_set_consistent_dma_mask(ha->pdev, DMA_BIT_MASK(64))) {
8728afaf5a2dSDavid Somayajulu 			dev_dbg(&ha->pdev->dev,
8729afaf5a2dSDavid Somayajulu 				  "Failed to set 64 bit PCI consistent mask; "
8730afaf5a2dSDavid Somayajulu 				   "using 32 bit.\n");
8731afaf5a2dSDavid Somayajulu 			retval = pci_set_consistent_dma_mask(ha->pdev,
8732284901a9SYang Hongyang 							     DMA_BIT_MASK(32));
8733afaf5a2dSDavid Somayajulu 		}
8734afaf5a2dSDavid Somayajulu 	} else
8735284901a9SYang Hongyang 		retval = pci_set_dma_mask(ha->pdev, DMA_BIT_MASK(32));
8736afaf5a2dSDavid Somayajulu }
8737afaf5a2dSDavid Somayajulu 
8738afaf5a2dSDavid Somayajulu static int qla4xxx_slave_alloc(struct scsi_device *sdev)
8739afaf5a2dSDavid Somayajulu {
8740b3a271a9SManish Rangankar 	struct iscsi_cls_session *cls_sess;
8741b3a271a9SManish Rangankar 	struct iscsi_session *sess;
8742b3a271a9SManish Rangankar 	struct ddb_entry *ddb;
87438bb4033dSVikas Chaudhary 	int queue_depth = QL4_DEF_QDEPTH;
8744afaf5a2dSDavid Somayajulu 
8745b3a271a9SManish Rangankar 	cls_sess = starget_to_session(sdev->sdev_target);
8746b3a271a9SManish Rangankar 	sess = cls_sess->dd_data;
8747b3a271a9SManish Rangankar 	ddb = sess->dd_data;
8748b3a271a9SManish Rangankar 
8749afaf5a2dSDavid Somayajulu 	sdev->hostdata = ddb;
8750afaf5a2dSDavid Somayajulu 	sdev->tagged_supported = 1;
87518bb4033dSVikas Chaudhary 
87528bb4033dSVikas Chaudhary 	if (ql4xmaxqdepth != 0 && ql4xmaxqdepth <= 0xffffU)
87538bb4033dSVikas Chaudhary 		queue_depth = ql4xmaxqdepth;
87548bb4033dSVikas Chaudhary 
87558bb4033dSVikas Chaudhary 	scsi_activate_tcq(sdev, queue_depth);
8756afaf5a2dSDavid Somayajulu 	return 0;
8757afaf5a2dSDavid Somayajulu }
8758afaf5a2dSDavid Somayajulu 
8759afaf5a2dSDavid Somayajulu static int qla4xxx_slave_configure(struct scsi_device *sdev)
8760afaf5a2dSDavid Somayajulu {
8761afaf5a2dSDavid Somayajulu 	sdev->tagged_supported = 1;
8762afaf5a2dSDavid Somayajulu 	return 0;
8763afaf5a2dSDavid Somayajulu }
8764afaf5a2dSDavid Somayajulu 
8765afaf5a2dSDavid Somayajulu static void qla4xxx_slave_destroy(struct scsi_device *sdev)
8766afaf5a2dSDavid Somayajulu {
8767afaf5a2dSDavid Somayajulu 	scsi_deactivate_tcq(sdev, 1);
8768afaf5a2dSDavid Somayajulu }
8769afaf5a2dSDavid Somayajulu 
8770f7b4aa63STej Parkash static int qla4xxx_change_queue_depth(struct scsi_device *sdev, int qdepth,
8771f7b4aa63STej Parkash 				      int reason)
8772f7b4aa63STej Parkash {
8773f7b4aa63STej Parkash 	if (!ql4xqfulltracking)
8774f7b4aa63STej Parkash 		return -EOPNOTSUPP;
8775f7b4aa63STej Parkash 
8776f7b4aa63STej Parkash 	return iscsi_change_queue_depth(sdev, qdepth, reason);
8777f7b4aa63STej Parkash }
8778f7b4aa63STej Parkash 
8779afaf5a2dSDavid Somayajulu /**
8780afaf5a2dSDavid Somayajulu  * qla4xxx_del_from_active_array - returns an active srb
8781afaf5a2dSDavid Somayajulu  * @ha: Pointer to host adapter structure.
8782fd589a8fSAnand Gadiyar  * @index: index into the active_array
8783afaf5a2dSDavid Somayajulu  *
8784afaf5a2dSDavid Somayajulu  * This routine removes and returns the srb at the specified index
8785afaf5a2dSDavid Somayajulu  **/
8786f4f5df23SVikas Chaudhary struct srb *qla4xxx_del_from_active_array(struct scsi_qla_host *ha,
8787f4f5df23SVikas Chaudhary     uint32_t index)
8788afaf5a2dSDavid Somayajulu {
8789afaf5a2dSDavid Somayajulu 	struct srb *srb = NULL;
87905369887aSVikas Chaudhary 	struct scsi_cmnd *cmd = NULL;
8791afaf5a2dSDavid Somayajulu 
87925369887aSVikas Chaudhary 	cmd = scsi_host_find_tag(ha->host, index);
87935369887aSVikas Chaudhary 	if (!cmd)
8794afaf5a2dSDavid Somayajulu 		return srb;
8795afaf5a2dSDavid Somayajulu 
87965369887aSVikas Chaudhary 	srb = (struct srb *)CMD_SP(cmd);
87975369887aSVikas Chaudhary 	if (!srb)
8798afaf5a2dSDavid Somayajulu 		return srb;
8799afaf5a2dSDavid Somayajulu 
8800afaf5a2dSDavid Somayajulu 	/* update counters */
8801afaf5a2dSDavid Somayajulu 	if (srb->flags & SRB_DMA_VALID) {
8802afaf5a2dSDavid Somayajulu 		ha->iocb_cnt -= srb->iocb_cnt;
8803afaf5a2dSDavid Somayajulu 		if (srb->cmd)
88045369887aSVikas Chaudhary 			srb->cmd->host_scribble =
88055369887aSVikas Chaudhary 				(unsigned char *)(unsigned long) MAX_SRBS;
8806afaf5a2dSDavid Somayajulu 	}
8807afaf5a2dSDavid Somayajulu 	return srb;
8808afaf5a2dSDavid Somayajulu }
8809afaf5a2dSDavid Somayajulu 
8810afaf5a2dSDavid Somayajulu /**
8811afaf5a2dSDavid Somayajulu  * qla4xxx_eh_wait_on_command - waits for command to be returned by firmware
881209a0f719SVikas Chaudhary  * @ha: Pointer to host adapter structure.
8813afaf5a2dSDavid Somayajulu  * @cmd: Scsi Command to wait on.
8814afaf5a2dSDavid Somayajulu  *
8815afaf5a2dSDavid Somayajulu  * This routine waits for the command to be returned by the Firmware
8816afaf5a2dSDavid Somayajulu  * for some max time.
8817afaf5a2dSDavid Somayajulu  **/
8818afaf5a2dSDavid Somayajulu static int qla4xxx_eh_wait_on_command(struct scsi_qla_host *ha,
8819afaf5a2dSDavid Somayajulu 				      struct scsi_cmnd *cmd)
8820afaf5a2dSDavid Somayajulu {
8821afaf5a2dSDavid Somayajulu 	int done = 0;
8822afaf5a2dSDavid Somayajulu 	struct srb *rp;
8823afaf5a2dSDavid Somayajulu 	uint32_t max_wait_time = EH_WAIT_CMD_TOV;
88242232be0dSLalit Chandivade 	int ret = SUCCESS;
88252232be0dSLalit Chandivade 
88262232be0dSLalit Chandivade 	/* Dont wait on command if PCI error is being handled
88272232be0dSLalit Chandivade 	 * by PCI AER driver
88282232be0dSLalit Chandivade 	 */
88292232be0dSLalit Chandivade 	if (unlikely(pci_channel_offline(ha->pdev)) ||
88302232be0dSLalit Chandivade 	    (test_bit(AF_EEH_BUSY, &ha->flags))) {
88312232be0dSLalit Chandivade 		ql4_printk(KERN_WARNING, ha, "scsi%ld: Return from %s\n",
88322232be0dSLalit Chandivade 		    ha->host_no, __func__);
88332232be0dSLalit Chandivade 		return ret;
88342232be0dSLalit Chandivade 	}
8835afaf5a2dSDavid Somayajulu 
8836afaf5a2dSDavid Somayajulu 	do {
8837afaf5a2dSDavid Somayajulu 		/* Checking to see if its returned to OS */
88385369887aSVikas Chaudhary 		rp = (struct srb *) CMD_SP(cmd);
8839afaf5a2dSDavid Somayajulu 		if (rp == NULL) {
8840afaf5a2dSDavid Somayajulu 			done++;
8841afaf5a2dSDavid Somayajulu 			break;
8842afaf5a2dSDavid Somayajulu 		}
8843afaf5a2dSDavid Somayajulu 
8844afaf5a2dSDavid Somayajulu 		msleep(2000);
8845afaf5a2dSDavid Somayajulu 	} while (max_wait_time--);
8846afaf5a2dSDavid Somayajulu 
8847afaf5a2dSDavid Somayajulu 	return done;
8848afaf5a2dSDavid Somayajulu }
8849afaf5a2dSDavid Somayajulu 
8850afaf5a2dSDavid Somayajulu /**
8851afaf5a2dSDavid Somayajulu  * qla4xxx_wait_for_hba_online - waits for HBA to come online
8852afaf5a2dSDavid Somayajulu  * @ha: Pointer to host adapter structure
8853afaf5a2dSDavid Somayajulu  **/
8854afaf5a2dSDavid Somayajulu static int qla4xxx_wait_for_hba_online(struct scsi_qla_host *ha)
8855afaf5a2dSDavid Somayajulu {
8856afaf5a2dSDavid Somayajulu 	unsigned long wait_online;
8857afaf5a2dSDavid Somayajulu 
8858f581a3f7SVikas Chaudhary 	wait_online = jiffies + (HBA_ONLINE_TOV * HZ);
8859afaf5a2dSDavid Somayajulu 	while (time_before(jiffies, wait_online)) {
8860afaf5a2dSDavid Somayajulu 
8861afaf5a2dSDavid Somayajulu 		if (adapter_up(ha))
8862afaf5a2dSDavid Somayajulu 			return QLA_SUCCESS;
8863afaf5a2dSDavid Somayajulu 
8864afaf5a2dSDavid Somayajulu 		msleep(2000);
8865afaf5a2dSDavid Somayajulu 	}
8866afaf5a2dSDavid Somayajulu 
8867afaf5a2dSDavid Somayajulu 	return QLA_ERROR;
8868afaf5a2dSDavid Somayajulu }
8869afaf5a2dSDavid Somayajulu 
8870afaf5a2dSDavid Somayajulu /**
8871ce545039SMike Christie  * qla4xxx_eh_wait_for_commands - wait for active cmds to finish.
8872fd589a8fSAnand Gadiyar  * @ha: pointer to HBA
8873afaf5a2dSDavid Somayajulu  * @t: target id
8874afaf5a2dSDavid Somayajulu  * @l: lun id
8875afaf5a2dSDavid Somayajulu  *
8876afaf5a2dSDavid Somayajulu  * This function waits for all outstanding commands to a lun to complete. It
8877afaf5a2dSDavid Somayajulu  * returns 0 if all pending commands are returned and 1 otherwise.
8878afaf5a2dSDavid Somayajulu  **/
8879ce545039SMike Christie static int qla4xxx_eh_wait_for_commands(struct scsi_qla_host *ha,
8880ce545039SMike Christie 					struct scsi_target *stgt,
8881ce545039SMike Christie 					struct scsi_device *sdev)
8882afaf5a2dSDavid Somayajulu {
8883afaf5a2dSDavid Somayajulu 	int cnt;
8884afaf5a2dSDavid Somayajulu 	int status = 0;
8885afaf5a2dSDavid Somayajulu 	struct scsi_cmnd *cmd;
8886afaf5a2dSDavid Somayajulu 
8887afaf5a2dSDavid Somayajulu 	/*
8888ce545039SMike Christie 	 * Waiting for all commands for the designated target or dev
8889ce545039SMike Christie 	 * in the active array
8890afaf5a2dSDavid Somayajulu 	 */
8891afaf5a2dSDavid Somayajulu 	for (cnt = 0; cnt < ha->host->can_queue; cnt++) {
8892afaf5a2dSDavid Somayajulu 		cmd = scsi_host_find_tag(ha->host, cnt);
8893ce545039SMike Christie 		if (cmd && stgt == scsi_target(cmd->device) &&
8894ce545039SMike Christie 		    (!sdev || sdev == cmd->device)) {
8895afaf5a2dSDavid Somayajulu 			if (!qla4xxx_eh_wait_on_command(ha, cmd)) {
8896afaf5a2dSDavid Somayajulu 				status++;
8897afaf5a2dSDavid Somayajulu 				break;
8898afaf5a2dSDavid Somayajulu 			}
8899afaf5a2dSDavid Somayajulu 		}
8900afaf5a2dSDavid Somayajulu 	}
8901afaf5a2dSDavid Somayajulu 	return status;
8902afaf5a2dSDavid Somayajulu }
8903afaf5a2dSDavid Somayajulu 
8904afaf5a2dSDavid Somayajulu /**
890509a0f719SVikas Chaudhary  * qla4xxx_eh_abort - callback for abort task.
890609a0f719SVikas Chaudhary  * @cmd: Pointer to Linux's SCSI command structure
890709a0f719SVikas Chaudhary  *
890809a0f719SVikas Chaudhary  * This routine is called by the Linux OS to abort the specified
890909a0f719SVikas Chaudhary  * command.
891009a0f719SVikas Chaudhary  **/
891109a0f719SVikas Chaudhary static int qla4xxx_eh_abort(struct scsi_cmnd *cmd)
891209a0f719SVikas Chaudhary {
891309a0f719SVikas Chaudhary 	struct scsi_qla_host *ha = to_qla_host(cmd->device->host);
891409a0f719SVikas Chaudhary 	unsigned int id = cmd->device->id;
891509a0f719SVikas Chaudhary 	unsigned int lun = cmd->device->lun;
891692b3e5bbSMike Christie 	unsigned long flags;
891709a0f719SVikas Chaudhary 	struct srb *srb = NULL;
891809a0f719SVikas Chaudhary 	int ret = SUCCESS;
891909a0f719SVikas Chaudhary 	int wait = 0;
892009a0f719SVikas Chaudhary 
8921c2660df3SVikas Chaudhary 	ql4_printk(KERN_INFO, ha,
89225cd049a5SChristoph Hellwig 	    "scsi%ld:%d:%d: Abort command issued cmd=%p\n",
89235cd049a5SChristoph Hellwig 	    ha->host_no, id, lun, cmd);
892409a0f719SVikas Chaudhary 
892592b3e5bbSMike Christie 	spin_lock_irqsave(&ha->hardware_lock, flags);
892609a0f719SVikas Chaudhary 	srb = (struct srb *) CMD_SP(cmd);
892792b3e5bbSMike Christie 	if (!srb) {
892892b3e5bbSMike Christie 		spin_unlock_irqrestore(&ha->hardware_lock, flags);
892909a0f719SVikas Chaudhary 		return SUCCESS;
893092b3e5bbSMike Christie 	}
893109a0f719SVikas Chaudhary 	kref_get(&srb->srb_ref);
893292b3e5bbSMike Christie 	spin_unlock_irqrestore(&ha->hardware_lock, flags);
893309a0f719SVikas Chaudhary 
893409a0f719SVikas Chaudhary 	if (qla4xxx_abort_task(ha, srb) != QLA_SUCCESS) {
893509a0f719SVikas Chaudhary 		DEBUG3(printk("scsi%ld:%d:%d: Abort_task mbx failed.\n",
893609a0f719SVikas Chaudhary 		    ha->host_no, id, lun));
893709a0f719SVikas Chaudhary 		ret = FAILED;
893809a0f719SVikas Chaudhary 	} else {
893909a0f719SVikas Chaudhary 		DEBUG3(printk("scsi%ld:%d:%d: Abort_task mbx success.\n",
894009a0f719SVikas Chaudhary 		    ha->host_no, id, lun));
894109a0f719SVikas Chaudhary 		wait = 1;
894209a0f719SVikas Chaudhary 	}
894309a0f719SVikas Chaudhary 
894409a0f719SVikas Chaudhary 	kref_put(&srb->srb_ref, qla4xxx_srb_compl);
894509a0f719SVikas Chaudhary 
894609a0f719SVikas Chaudhary 	/* Wait for command to complete */
894709a0f719SVikas Chaudhary 	if (wait) {
894809a0f719SVikas Chaudhary 		if (!qla4xxx_eh_wait_on_command(ha, cmd)) {
894909a0f719SVikas Chaudhary 			DEBUG2(printk("scsi%ld:%d:%d: Abort handler timed out\n",
895009a0f719SVikas Chaudhary 			    ha->host_no, id, lun));
895109a0f719SVikas Chaudhary 			ret = FAILED;
895209a0f719SVikas Chaudhary 		}
895309a0f719SVikas Chaudhary 	}
895409a0f719SVikas Chaudhary 
8955c2660df3SVikas Chaudhary 	ql4_printk(KERN_INFO, ha,
895609a0f719SVikas Chaudhary 	    "scsi%ld:%d:%d: Abort command - %s\n",
895725985edcSLucas De Marchi 	    ha->host_no, id, lun, (ret == SUCCESS) ? "succeeded" : "failed");
895809a0f719SVikas Chaudhary 
895909a0f719SVikas Chaudhary 	return ret;
896009a0f719SVikas Chaudhary }
896109a0f719SVikas Chaudhary 
896209a0f719SVikas Chaudhary /**
8963afaf5a2dSDavid Somayajulu  * qla4xxx_eh_device_reset - callback for target reset.
8964afaf5a2dSDavid Somayajulu  * @cmd: Pointer to Linux's SCSI command structure
8965afaf5a2dSDavid Somayajulu  *
8966afaf5a2dSDavid Somayajulu  * This routine is called by the Linux OS to reset all luns on the
8967afaf5a2dSDavid Somayajulu  * specified target.
8968afaf5a2dSDavid Somayajulu  **/
8969afaf5a2dSDavid Somayajulu static int qla4xxx_eh_device_reset(struct scsi_cmnd *cmd)
8970afaf5a2dSDavid Somayajulu {
8971afaf5a2dSDavid Somayajulu 	struct scsi_qla_host *ha = to_qla_host(cmd->device->host);
8972afaf5a2dSDavid Somayajulu 	struct ddb_entry *ddb_entry = cmd->device->hostdata;
8973afaf5a2dSDavid Somayajulu 	int ret = FAILED, stat;
8974afaf5a2dSDavid Somayajulu 
8975612f7348SKaren Higgins 	if (!ddb_entry)
8976afaf5a2dSDavid Somayajulu 		return ret;
8977afaf5a2dSDavid Somayajulu 
8978c01be6dcSMike Christie 	ret = iscsi_block_scsi_eh(cmd);
8979c01be6dcSMike Christie 	if (ret)
8980c01be6dcSMike Christie 		return ret;
8981c01be6dcSMike Christie 	ret = FAILED;
8982c01be6dcSMike Christie 
8983c2660df3SVikas Chaudhary 	ql4_printk(KERN_INFO, ha,
8984afaf5a2dSDavid Somayajulu 		   "scsi%ld:%d:%d:%d: DEVICE RESET ISSUED.\n", ha->host_no,
8985afaf5a2dSDavid Somayajulu 		   cmd->device->channel, cmd->device->id, cmd->device->lun);
8986afaf5a2dSDavid Somayajulu 
8987afaf5a2dSDavid Somayajulu 	DEBUG2(printk(KERN_INFO
8988afaf5a2dSDavid Somayajulu 		      "scsi%ld: DEVICE_RESET cmd=%p jiffies = 0x%lx, to=%x,"
8989afaf5a2dSDavid Somayajulu 		      "dpc_flags=%lx, status=%x allowed=%d\n", ha->host_no,
8990242f9dcbSJens Axboe 		      cmd, jiffies, cmd->request->timeout / HZ,
8991afaf5a2dSDavid Somayajulu 		      ha->dpc_flags, cmd->result, cmd->allowed));
8992afaf5a2dSDavid Somayajulu 
8993afaf5a2dSDavid Somayajulu 	/* FIXME: wait for hba to go online */
8994afaf5a2dSDavid Somayajulu 	stat = qla4xxx_reset_lun(ha, ddb_entry, cmd->device->lun);
8995afaf5a2dSDavid Somayajulu 	if (stat != QLA_SUCCESS) {
8996c2660df3SVikas Chaudhary 		ql4_printk(KERN_INFO, ha, "DEVICE RESET FAILED. %d\n", stat);
8997afaf5a2dSDavid Somayajulu 		goto eh_dev_reset_done;
8998afaf5a2dSDavid Somayajulu 	}
8999afaf5a2dSDavid Somayajulu 
9000ce545039SMike Christie 	if (qla4xxx_eh_wait_for_commands(ha, scsi_target(cmd->device),
9001ce545039SMike Christie 					 cmd->device)) {
9002c2660df3SVikas Chaudhary 		ql4_printk(KERN_INFO, ha,
9003afaf5a2dSDavid Somayajulu 			   "DEVICE RESET FAILED - waiting for "
9004afaf5a2dSDavid Somayajulu 			   "commands.\n");
9005afaf5a2dSDavid Somayajulu 		goto eh_dev_reset_done;
9006afaf5a2dSDavid Somayajulu 	}
9007afaf5a2dSDavid Somayajulu 
90089d562913SDavid C Somayajulu 	/* Send marker. */
90099d562913SDavid C Somayajulu 	if (qla4xxx_send_marker_iocb(ha, ddb_entry, cmd->device->lun,
90109d562913SDavid C Somayajulu 		MM_LUN_RESET) != QLA_SUCCESS)
90119d562913SDavid C Somayajulu 		goto eh_dev_reset_done;
90129d562913SDavid C Somayajulu 
9013c2660df3SVikas Chaudhary 	ql4_printk(KERN_INFO, ha,
9014afaf5a2dSDavid Somayajulu 		   "scsi(%ld:%d:%d:%d): DEVICE RESET SUCCEEDED.\n",
9015afaf5a2dSDavid Somayajulu 		   ha->host_no, cmd->device->channel, cmd->device->id,
9016afaf5a2dSDavid Somayajulu 		   cmd->device->lun);
9017afaf5a2dSDavid Somayajulu 
9018afaf5a2dSDavid Somayajulu 	ret = SUCCESS;
9019afaf5a2dSDavid Somayajulu 
9020afaf5a2dSDavid Somayajulu eh_dev_reset_done:
9021afaf5a2dSDavid Somayajulu 
9022afaf5a2dSDavid Somayajulu 	return ret;
9023afaf5a2dSDavid Somayajulu }
9024afaf5a2dSDavid Somayajulu 
9025afaf5a2dSDavid Somayajulu /**
9026ce545039SMike Christie  * qla4xxx_eh_target_reset - callback for target reset.
9027ce545039SMike Christie  * @cmd: Pointer to Linux's SCSI command structure
9028ce545039SMike Christie  *
9029ce545039SMike Christie  * This routine is called by the Linux OS to reset the target.
9030ce545039SMike Christie  **/
9031ce545039SMike Christie static int qla4xxx_eh_target_reset(struct scsi_cmnd *cmd)
9032ce545039SMike Christie {
9033ce545039SMike Christie 	struct scsi_qla_host *ha = to_qla_host(cmd->device->host);
9034ce545039SMike Christie 	struct ddb_entry *ddb_entry = cmd->device->hostdata;
9035c01be6dcSMike Christie 	int stat, ret;
9036ce545039SMike Christie 
9037ce545039SMike Christie 	if (!ddb_entry)
9038ce545039SMike Christie 		return FAILED;
9039ce545039SMike Christie 
9040c01be6dcSMike Christie 	ret = iscsi_block_scsi_eh(cmd);
9041c01be6dcSMike Christie 	if (ret)
9042c01be6dcSMike Christie 		return ret;
9043c01be6dcSMike Christie 
9044ce545039SMike Christie 	starget_printk(KERN_INFO, scsi_target(cmd->device),
9045ce545039SMike Christie 		       "WARM TARGET RESET ISSUED.\n");
9046ce545039SMike Christie 
9047ce545039SMike Christie 	DEBUG2(printk(KERN_INFO
9048ce545039SMike Christie 		      "scsi%ld: TARGET_DEVICE_RESET cmd=%p jiffies = 0x%lx, "
9049ce545039SMike Christie 		      "to=%x,dpc_flags=%lx, status=%x allowed=%d\n",
9050242f9dcbSJens Axboe 		      ha->host_no, cmd, jiffies, cmd->request->timeout / HZ,
9051ce545039SMike Christie 		      ha->dpc_flags, cmd->result, cmd->allowed));
9052ce545039SMike Christie 
9053ce545039SMike Christie 	stat = qla4xxx_reset_target(ha, ddb_entry);
9054ce545039SMike Christie 	if (stat != QLA_SUCCESS) {
9055ce545039SMike Christie 		starget_printk(KERN_INFO, scsi_target(cmd->device),
9056ce545039SMike Christie 			       "WARM TARGET RESET FAILED.\n");
9057ce545039SMike Christie 		return FAILED;
9058ce545039SMike Christie 	}
9059ce545039SMike Christie 
9060ce545039SMike Christie 	if (qla4xxx_eh_wait_for_commands(ha, scsi_target(cmd->device),
9061ce545039SMike Christie 					 NULL)) {
9062ce545039SMike Christie 		starget_printk(KERN_INFO, scsi_target(cmd->device),
9063ce545039SMike Christie 			       "WARM TARGET DEVICE RESET FAILED - "
9064ce545039SMike Christie 			       "waiting for commands.\n");
9065ce545039SMike Christie 		return FAILED;
9066ce545039SMike Christie 	}
9067ce545039SMike Christie 
90689d562913SDavid C Somayajulu 	/* Send marker. */
90699d562913SDavid C Somayajulu 	if (qla4xxx_send_marker_iocb(ha, ddb_entry, cmd->device->lun,
90709d562913SDavid C Somayajulu 		MM_TGT_WARM_RESET) != QLA_SUCCESS) {
90719d562913SDavid C Somayajulu 		starget_printk(KERN_INFO, scsi_target(cmd->device),
90729d562913SDavid C Somayajulu 			       "WARM TARGET DEVICE RESET FAILED - "
90739d562913SDavid C Somayajulu 			       "marker iocb failed.\n");
90749d562913SDavid C Somayajulu 		return FAILED;
90759d562913SDavid C Somayajulu 	}
90769d562913SDavid C Somayajulu 
9077ce545039SMike Christie 	starget_printk(KERN_INFO, scsi_target(cmd->device),
9078ce545039SMike Christie 		       "WARM TARGET RESET SUCCEEDED.\n");
9079ce545039SMike Christie 	return SUCCESS;
9080ce545039SMike Christie }
9081ce545039SMike Christie 
9082ce545039SMike Christie /**
90838a288960SSarang Radke  * qla4xxx_is_eh_active - check if error handler is running
90848a288960SSarang Radke  * @shost: Pointer to SCSI Host struct
90858a288960SSarang Radke  *
90868a288960SSarang Radke  * This routine finds that if reset host is called in EH
90878a288960SSarang Radke  * scenario or from some application like sg_reset
90888a288960SSarang Radke  **/
90898a288960SSarang Radke static int qla4xxx_is_eh_active(struct Scsi_Host *shost)
90908a288960SSarang Radke {
90918a288960SSarang Radke 	if (shost->shost_state == SHOST_RECOVERY)
90928a288960SSarang Radke 		return 1;
90938a288960SSarang Radke 	return 0;
90948a288960SSarang Radke }
90958a288960SSarang Radke 
90968a288960SSarang Radke /**
9097afaf5a2dSDavid Somayajulu  * qla4xxx_eh_host_reset - kernel callback
9098afaf5a2dSDavid Somayajulu  * @cmd: Pointer to Linux's SCSI command structure
9099afaf5a2dSDavid Somayajulu  *
9100afaf5a2dSDavid Somayajulu  * This routine is invoked by the Linux kernel to perform fatal error
9101afaf5a2dSDavid Somayajulu  * recovery on the specified adapter.
9102afaf5a2dSDavid Somayajulu  **/
9103afaf5a2dSDavid Somayajulu static int qla4xxx_eh_host_reset(struct scsi_cmnd *cmd)
9104afaf5a2dSDavid Somayajulu {
9105afaf5a2dSDavid Somayajulu 	int return_status = FAILED;
9106afaf5a2dSDavid Somayajulu 	struct scsi_qla_host *ha;
9107afaf5a2dSDavid Somayajulu 
9108b3a271a9SManish Rangankar 	ha = to_qla_host(cmd->device->host);
9109afaf5a2dSDavid Somayajulu 
9110b37ca418SVikas Chaudhary 	if ((is_qla8032(ha) || is_qla8042(ha)) && ql4xdontresethba)
91116e7b4292SVikas Chaudhary 		qla4_83xx_set_idc_dontreset(ha);
91126e7b4292SVikas Chaudhary 
91136e7b4292SVikas Chaudhary 	/*
9114b37ca418SVikas Chaudhary 	 * For ISP8324 and ISP8042, if IDC_CTRL DONTRESET_BIT0 is set by other
9115b37ca418SVikas Chaudhary 	 * protocol drivers, we should not set device_state to NEED_RESET
91166e7b4292SVikas Chaudhary 	 */
91176e7b4292SVikas Chaudhary 	if (ql4xdontresethba ||
9118b37ca418SVikas Chaudhary 	    ((is_qla8032(ha) || is_qla8042(ha)) &&
9119b37ca418SVikas Chaudhary 	     qla4_83xx_idc_dontreset(ha))) {
9120f4f5df23SVikas Chaudhary 		DEBUG2(printk("scsi%ld: %s: Don't Reset HBA\n",
9121f4f5df23SVikas Chaudhary 		     ha->host_no, __func__));
91228a288960SSarang Radke 
91238a288960SSarang Radke 		/* Clear outstanding srb in queues */
91248a288960SSarang Radke 		if (qla4xxx_is_eh_active(cmd->device->host))
91258a288960SSarang Radke 			qla4xxx_abort_active_cmds(ha, DID_ABORT << 16);
91268a288960SSarang Radke 
9127f4f5df23SVikas Chaudhary 		return FAILED;
9128f4f5df23SVikas Chaudhary 	}
9129f4f5df23SVikas Chaudhary 
9130c2660df3SVikas Chaudhary 	ql4_printk(KERN_INFO, ha,
9131dca05c4cSKaren Higgins 		   "scsi(%ld:%d:%d:%d): HOST RESET ISSUED.\n", ha->host_no,
9132afaf5a2dSDavid Somayajulu 		   cmd->device->channel, cmd->device->id, cmd->device->lun);
9133afaf5a2dSDavid Somayajulu 
9134afaf5a2dSDavid Somayajulu 	if (qla4xxx_wait_for_hba_online(ha) != QLA_SUCCESS) {
9135afaf5a2dSDavid Somayajulu 		DEBUG2(printk("scsi%ld:%d: %s: Unable to reset host.  Adapter "
9136afaf5a2dSDavid Somayajulu 			      "DEAD.\n", ha->host_no, cmd->device->channel,
9137afaf5a2dSDavid Somayajulu 			      __func__));
9138afaf5a2dSDavid Somayajulu 
9139afaf5a2dSDavid Somayajulu 		return FAILED;
9140afaf5a2dSDavid Somayajulu 	}
9141afaf5a2dSDavid Somayajulu 
9142f4f5df23SVikas Chaudhary 	if (!test_bit(DPC_RESET_HA, &ha->dpc_flags)) {
91436e7b4292SVikas Chaudhary 		if (is_qla80XX(ha))
9144f4f5df23SVikas Chaudhary 			set_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags);
9145f4f5df23SVikas Chaudhary 		else
9146f4f5df23SVikas Chaudhary 			set_bit(DPC_RESET_HA, &ha->dpc_flags);
9147f4f5df23SVikas Chaudhary 	}
914850a29aecSMike Christie 
9149f4f5df23SVikas Chaudhary 	if (qla4xxx_recover_adapter(ha) == QLA_SUCCESS)
9150afaf5a2dSDavid Somayajulu 		return_status = SUCCESS;
9151afaf5a2dSDavid Somayajulu 
9152c2660df3SVikas Chaudhary 	ql4_printk(KERN_INFO, ha, "HOST RESET %s.\n",
915325985edcSLucas De Marchi 		   return_status == FAILED ? "FAILED" : "SUCCEEDED");
9154afaf5a2dSDavid Somayajulu 
9155afaf5a2dSDavid Somayajulu 	return return_status;
9156afaf5a2dSDavid Somayajulu }
9157afaf5a2dSDavid Somayajulu 
915895d31262SVikas Chaudhary static int qla4xxx_context_reset(struct scsi_qla_host *ha)
915995d31262SVikas Chaudhary {
916095d31262SVikas Chaudhary 	uint32_t mbox_cmd[MBOX_REG_COUNT];
916195d31262SVikas Chaudhary 	uint32_t mbox_sts[MBOX_REG_COUNT];
916295d31262SVikas Chaudhary 	struct addr_ctrl_blk_def *acb = NULL;
916395d31262SVikas Chaudhary 	uint32_t acb_len = sizeof(struct addr_ctrl_blk_def);
916495d31262SVikas Chaudhary 	int rval = QLA_SUCCESS;
916595d31262SVikas Chaudhary 	dma_addr_t acb_dma;
916695d31262SVikas Chaudhary 
916795d31262SVikas Chaudhary 	acb = dma_alloc_coherent(&ha->pdev->dev,
916895d31262SVikas Chaudhary 				 sizeof(struct addr_ctrl_blk_def),
916995d31262SVikas Chaudhary 				 &acb_dma, GFP_KERNEL);
917095d31262SVikas Chaudhary 	if (!acb) {
917195d31262SVikas Chaudhary 		ql4_printk(KERN_ERR, ha, "%s: Unable to alloc acb\n",
917295d31262SVikas Chaudhary 			   __func__);
917395d31262SVikas Chaudhary 		rval = -ENOMEM;
917495d31262SVikas Chaudhary 		goto exit_port_reset;
917595d31262SVikas Chaudhary 	}
917695d31262SVikas Chaudhary 
917795d31262SVikas Chaudhary 	memset(acb, 0, acb_len);
917895d31262SVikas Chaudhary 
917995d31262SVikas Chaudhary 	rval = qla4xxx_get_acb(ha, acb_dma, PRIMARI_ACB, acb_len);
918095d31262SVikas Chaudhary 	if (rval != QLA_SUCCESS) {
918195d31262SVikas Chaudhary 		rval = -EIO;
918295d31262SVikas Chaudhary 		goto exit_free_acb;
918395d31262SVikas Chaudhary 	}
918495d31262SVikas Chaudhary 
918595d31262SVikas Chaudhary 	rval = qla4xxx_disable_acb(ha);
918695d31262SVikas Chaudhary 	if (rval != QLA_SUCCESS) {
918795d31262SVikas Chaudhary 		rval = -EIO;
918895d31262SVikas Chaudhary 		goto exit_free_acb;
918995d31262SVikas Chaudhary 	}
919095d31262SVikas Chaudhary 
919195d31262SVikas Chaudhary 	wait_for_completion_timeout(&ha->disable_acb_comp,
919295d31262SVikas Chaudhary 				    DISABLE_ACB_TOV * HZ);
919395d31262SVikas Chaudhary 
919495d31262SVikas Chaudhary 	rval = qla4xxx_set_acb(ha, &mbox_cmd[0], &mbox_sts[0], acb_dma);
919595d31262SVikas Chaudhary 	if (rval != QLA_SUCCESS) {
919695d31262SVikas Chaudhary 		rval = -EIO;
919795d31262SVikas Chaudhary 		goto exit_free_acb;
919895d31262SVikas Chaudhary 	}
919995d31262SVikas Chaudhary 
920095d31262SVikas Chaudhary exit_free_acb:
920195d31262SVikas Chaudhary 	dma_free_coherent(&ha->pdev->dev, sizeof(struct addr_ctrl_blk_def),
920295d31262SVikas Chaudhary 			  acb, acb_dma);
920395d31262SVikas Chaudhary exit_port_reset:
920495d31262SVikas Chaudhary 	DEBUG2(ql4_printk(KERN_INFO, ha, "%s %s\n", __func__,
920595d31262SVikas Chaudhary 			  rval == QLA_SUCCESS ? "SUCCEEDED" : "FAILED"));
920695d31262SVikas Chaudhary 	return rval;
920795d31262SVikas Chaudhary }
920895d31262SVikas Chaudhary 
920995d31262SVikas Chaudhary static int qla4xxx_host_reset(struct Scsi_Host *shost, int reset_type)
921095d31262SVikas Chaudhary {
921195d31262SVikas Chaudhary 	struct scsi_qla_host *ha = to_qla_host(shost);
921295d31262SVikas Chaudhary 	int rval = QLA_SUCCESS;
9213ebd777deSVikas Chaudhary 	uint32_t idc_ctrl;
921495d31262SVikas Chaudhary 
921595d31262SVikas Chaudhary 	if (ql4xdontresethba) {
921695d31262SVikas Chaudhary 		DEBUG2(ql4_printk(KERN_INFO, ha, "%s: Don't Reset HBA\n",
921795d31262SVikas Chaudhary 				  __func__));
921895d31262SVikas Chaudhary 		rval = -EPERM;
921995d31262SVikas Chaudhary 		goto exit_host_reset;
922095d31262SVikas Chaudhary 	}
922195d31262SVikas Chaudhary 
922295d31262SVikas Chaudhary 	if (test_bit(DPC_RESET_HA, &ha->dpc_flags))
922395d31262SVikas Chaudhary 		goto recover_adapter;
922495d31262SVikas Chaudhary 
922595d31262SVikas Chaudhary 	switch (reset_type) {
922695d31262SVikas Chaudhary 	case SCSI_ADAPTER_RESET:
922795d31262SVikas Chaudhary 		set_bit(DPC_RESET_HA, &ha->dpc_flags);
922895d31262SVikas Chaudhary 		break;
922995d31262SVikas Chaudhary 	case SCSI_FIRMWARE_RESET:
923095d31262SVikas Chaudhary 		if (!test_bit(DPC_RESET_HA, &ha->dpc_flags)) {
92316e7b4292SVikas Chaudhary 			if (is_qla80XX(ha))
923295d31262SVikas Chaudhary 				/* set firmware context reset */
923395d31262SVikas Chaudhary 				set_bit(DPC_RESET_HA_FW_CONTEXT,
923495d31262SVikas Chaudhary 					&ha->dpc_flags);
923595d31262SVikas Chaudhary 			else {
923695d31262SVikas Chaudhary 				rval = qla4xxx_context_reset(ha);
923795d31262SVikas Chaudhary 				goto exit_host_reset;
923895d31262SVikas Chaudhary 			}
923995d31262SVikas Chaudhary 		}
924095d31262SVikas Chaudhary 		break;
924195d31262SVikas Chaudhary 	}
924295d31262SVikas Chaudhary 
924395d31262SVikas Chaudhary recover_adapter:
9244b37ca418SVikas Chaudhary 	/* For ISP8324 and ISP8042 set graceful reset bit in IDC_DRV_CTRL if
9245ebd777deSVikas Chaudhary 	 * reset is issued by application */
9246b37ca418SVikas Chaudhary 	if ((is_qla8032(ha) || is_qla8042(ha)) &&
9247b37ca418SVikas Chaudhary 	    test_bit(DPC_RESET_HA, &ha->dpc_flags)) {
9248ebd777deSVikas Chaudhary 		idc_ctrl = qla4_83xx_rd_reg(ha, QLA83XX_IDC_DRV_CTRL);
9249ebd777deSVikas Chaudhary 		qla4_83xx_wr_reg(ha, QLA83XX_IDC_DRV_CTRL,
9250ebd777deSVikas Chaudhary 				 (idc_ctrl | GRACEFUL_RESET_BIT1));
9251ebd777deSVikas Chaudhary 	}
9252ebd777deSVikas Chaudhary 
925395d31262SVikas Chaudhary 	rval = qla4xxx_recover_adapter(ha);
925495d31262SVikas Chaudhary 	if (rval != QLA_SUCCESS) {
925595d31262SVikas Chaudhary 		DEBUG2(ql4_printk(KERN_INFO, ha, "%s: recover adapter fail\n",
925695d31262SVikas Chaudhary 				  __func__));
925795d31262SVikas Chaudhary 		rval = -EIO;
925895d31262SVikas Chaudhary 	}
925995d31262SVikas Chaudhary 
926095d31262SVikas Chaudhary exit_host_reset:
926195d31262SVikas Chaudhary 	return rval;
926295d31262SVikas Chaudhary }
926395d31262SVikas Chaudhary 
92642232be0dSLalit Chandivade /* PCI AER driver recovers from all correctable errors w/o
92652232be0dSLalit Chandivade  * driver intervention. For uncorrectable errors PCI AER
92662232be0dSLalit Chandivade  * driver calls the following device driver's callbacks
92672232be0dSLalit Chandivade  *
92682232be0dSLalit Chandivade  * - Fatal Errors - link_reset
92692232be0dSLalit Chandivade  * - Non-Fatal Errors - driver's pci_error_detected() which
92702232be0dSLalit Chandivade  * returns CAN_RECOVER, NEED_RESET or DISCONNECT.
92712232be0dSLalit Chandivade  *
92722232be0dSLalit Chandivade  * PCI AER driver calls
92732232be0dSLalit Chandivade  * CAN_RECOVER - driver's pci_mmio_enabled(), mmio_enabled
92742232be0dSLalit Chandivade  *               returns RECOVERED or NEED_RESET if fw_hung
92752232be0dSLalit Chandivade  * NEED_RESET - driver's slot_reset()
92762232be0dSLalit Chandivade  * DISCONNECT - device is dead & cannot recover
92772232be0dSLalit Chandivade  * RECOVERED - driver's pci_resume()
92782232be0dSLalit Chandivade  */
92792232be0dSLalit Chandivade static pci_ers_result_t
92802232be0dSLalit Chandivade qla4xxx_pci_error_detected(struct pci_dev *pdev, pci_channel_state_t state)
92812232be0dSLalit Chandivade {
92822232be0dSLalit Chandivade 	struct scsi_qla_host *ha = pci_get_drvdata(pdev);
92832232be0dSLalit Chandivade 
92842232be0dSLalit Chandivade 	ql4_printk(KERN_WARNING, ha, "scsi%ld: %s: error detected:state %x\n",
92852232be0dSLalit Chandivade 	    ha->host_no, __func__, state);
92862232be0dSLalit Chandivade 
92872232be0dSLalit Chandivade 	if (!is_aer_supported(ha))
92882232be0dSLalit Chandivade 		return PCI_ERS_RESULT_NONE;
92892232be0dSLalit Chandivade 
92902232be0dSLalit Chandivade 	switch (state) {
92912232be0dSLalit Chandivade 	case pci_channel_io_normal:
92922232be0dSLalit Chandivade 		clear_bit(AF_EEH_BUSY, &ha->flags);
92932232be0dSLalit Chandivade 		return PCI_ERS_RESULT_CAN_RECOVER;
92942232be0dSLalit Chandivade 	case pci_channel_io_frozen:
92952232be0dSLalit Chandivade 		set_bit(AF_EEH_BUSY, &ha->flags);
92962232be0dSLalit Chandivade 		qla4xxx_mailbox_premature_completion(ha);
92972232be0dSLalit Chandivade 		qla4xxx_free_irqs(ha);
92982232be0dSLalit Chandivade 		pci_disable_device(pdev);
92997b3595dfSVikas Chaudhary 		/* Return back all IOs */
93007b3595dfSVikas Chaudhary 		qla4xxx_abort_active_cmds(ha, DID_RESET << 16);
93012232be0dSLalit Chandivade 		return PCI_ERS_RESULT_NEED_RESET;
93022232be0dSLalit Chandivade 	case pci_channel_io_perm_failure:
93032232be0dSLalit Chandivade 		set_bit(AF_EEH_BUSY, &ha->flags);
93042232be0dSLalit Chandivade 		set_bit(AF_PCI_CHANNEL_IO_PERM_FAILURE, &ha->flags);
93052232be0dSLalit Chandivade 		qla4xxx_abort_active_cmds(ha, DID_NO_CONNECT << 16);
93062232be0dSLalit Chandivade 		return PCI_ERS_RESULT_DISCONNECT;
93072232be0dSLalit Chandivade 	}
93082232be0dSLalit Chandivade 	return PCI_ERS_RESULT_NEED_RESET;
93092232be0dSLalit Chandivade }
93102232be0dSLalit Chandivade 
93112232be0dSLalit Chandivade /**
93122232be0dSLalit Chandivade  * qla4xxx_pci_mmio_enabled() gets called if
93132232be0dSLalit Chandivade  * qla4xxx_pci_error_detected() returns PCI_ERS_RESULT_CAN_RECOVER
93142232be0dSLalit Chandivade  * and read/write to the device still works.
93152232be0dSLalit Chandivade  **/
93162232be0dSLalit Chandivade static pci_ers_result_t
93172232be0dSLalit Chandivade qla4xxx_pci_mmio_enabled(struct pci_dev *pdev)
93182232be0dSLalit Chandivade {
93192232be0dSLalit Chandivade 	struct scsi_qla_host *ha = pci_get_drvdata(pdev);
93202232be0dSLalit Chandivade 
93212232be0dSLalit Chandivade 	if (!is_aer_supported(ha))
93222232be0dSLalit Chandivade 		return PCI_ERS_RESULT_NONE;
93232232be0dSLalit Chandivade 
93242232be0dSLalit Chandivade 	return PCI_ERS_RESULT_RECOVERED;
93252232be0dSLalit Chandivade }
93262232be0dSLalit Chandivade 
93277b3595dfSVikas Chaudhary static uint32_t qla4_8xxx_error_recovery(struct scsi_qla_host *ha)
93282232be0dSLalit Chandivade {
93292232be0dSLalit Chandivade 	uint32_t rval = QLA_ERROR;
93302232be0dSLalit Chandivade 	int fn;
93312232be0dSLalit Chandivade 	struct pci_dev *other_pdev = NULL;
93322232be0dSLalit Chandivade 
93332232be0dSLalit Chandivade 	ql4_printk(KERN_WARNING, ha, "scsi%ld: In %s\n", ha->host_no, __func__);
93342232be0dSLalit Chandivade 
93352232be0dSLalit Chandivade 	set_bit(DPC_RESET_ACTIVE, &ha->dpc_flags);
93362232be0dSLalit Chandivade 
93372232be0dSLalit Chandivade 	if (test_bit(AF_ONLINE, &ha->flags)) {
93382232be0dSLalit Chandivade 		clear_bit(AF_ONLINE, &ha->flags);
9339b3a271a9SManish Rangankar 		clear_bit(AF_LINK_UP, &ha->flags);
9340b3a271a9SManish Rangankar 		iscsi_host_for_each_session(ha->host, qla4xxx_fail_session);
93412232be0dSLalit Chandivade 		qla4xxx_process_aen(ha, FLUSH_DDB_CHANGED_AENS);
93422232be0dSLalit Chandivade 	}
93432232be0dSLalit Chandivade 
93442232be0dSLalit Chandivade 	fn = PCI_FUNC(ha->pdev->devfn);
93452232be0dSLalit Chandivade 	while (fn > 0) {
93462232be0dSLalit Chandivade 		fn--;
93472232be0dSLalit Chandivade 		ql4_printk(KERN_INFO, ha, "scsi%ld: %s: Finding PCI device at "
93482232be0dSLalit Chandivade 		    "func %x\n", ha->host_no, __func__, fn);
93492232be0dSLalit Chandivade 		/* Get the pci device given the domain, bus,
93502232be0dSLalit Chandivade 		 * slot/function number */
93512232be0dSLalit Chandivade 		other_pdev =
93522232be0dSLalit Chandivade 		    pci_get_domain_bus_and_slot(pci_domain_nr(ha->pdev->bus),
93532232be0dSLalit Chandivade 		    ha->pdev->bus->number, PCI_DEVFN(PCI_SLOT(ha->pdev->devfn),
93542232be0dSLalit Chandivade 		    fn));
93552232be0dSLalit Chandivade 
93562232be0dSLalit Chandivade 		if (!other_pdev)
93572232be0dSLalit Chandivade 			continue;
93582232be0dSLalit Chandivade 
93592232be0dSLalit Chandivade 		if (atomic_read(&other_pdev->enable_cnt)) {
93602232be0dSLalit Chandivade 			ql4_printk(KERN_INFO, ha, "scsi%ld: %s: Found PCI "
93612232be0dSLalit Chandivade 			    "func in enabled state%x\n", ha->host_no,
93622232be0dSLalit Chandivade 			    __func__, fn);
93632232be0dSLalit Chandivade 			pci_dev_put(other_pdev);
93642232be0dSLalit Chandivade 			break;
93652232be0dSLalit Chandivade 		}
93662232be0dSLalit Chandivade 		pci_dev_put(other_pdev);
93672232be0dSLalit Chandivade 	}
93682232be0dSLalit Chandivade 
93692232be0dSLalit Chandivade 	/* The first function on the card, the reset owner will
93702232be0dSLalit Chandivade 	 * start & initialize the firmware. The other functions
93712232be0dSLalit Chandivade 	 * on the card will reset the firmware context
93722232be0dSLalit Chandivade 	 */
93732232be0dSLalit Chandivade 	if (!fn) {
93742232be0dSLalit Chandivade 		ql4_printk(KERN_INFO, ha, "scsi%ld: %s: devfn being reset "
93752232be0dSLalit Chandivade 		    "0x%x is the owner\n", ha->host_no, __func__,
93762232be0dSLalit Chandivade 		    ha->pdev->devfn);
93772232be0dSLalit Chandivade 
937833693c7aSVikas Chaudhary 		ha->isp_ops->idc_lock(ha);
937933693c7aSVikas Chaudhary 		qla4_8xxx_wr_direct(ha, QLA8XXX_CRB_DEV_STATE,
9380de8c72daSVikas Chaudhary 				    QLA8XXX_DEV_COLD);
938133693c7aSVikas Chaudhary 		ha->isp_ops->idc_unlock(ha);
93822232be0dSLalit Chandivade 
938339c95826SVikas Chaudhary 		rval = qla4_8xxx_update_idc_reg(ha);
938439c95826SVikas Chaudhary 		if (rval == QLA_ERROR) {
938539c95826SVikas Chaudhary 			ql4_printk(KERN_INFO, ha, "scsi%ld: %s: HW State: FAILED\n",
938639c95826SVikas Chaudhary 				   ha->host_no, __func__);
938739c95826SVikas Chaudhary 			ha->isp_ops->idc_lock(ha);
938839c95826SVikas Chaudhary 			qla4_8xxx_wr_direct(ha, QLA8XXX_CRB_DEV_STATE,
938939c95826SVikas Chaudhary 					    QLA8XXX_DEV_FAILED);
939039c95826SVikas Chaudhary 			ha->isp_ops->idc_unlock(ha);
939139c95826SVikas Chaudhary 			goto exit_error_recovery;
939239c95826SVikas Chaudhary 		}
93932232be0dSLalit Chandivade 
93942232be0dSLalit Chandivade 		clear_bit(AF_FW_RECOVERY, &ha->flags);
939513483730SMike Christie 		rval = qla4xxx_initialize_adapter(ha, RESET_ADAPTER);
93962232be0dSLalit Chandivade 
93972232be0dSLalit Chandivade 		if (rval != QLA_SUCCESS) {
93982232be0dSLalit Chandivade 			ql4_printk(KERN_INFO, ha, "scsi%ld: %s: HW State: "
93992232be0dSLalit Chandivade 			    "FAILED\n", ha->host_no, __func__);
940082761907SPoornima Vonti 			ha->isp_ops->idc_lock(ha);
94012232be0dSLalit Chandivade 			qla4_8xxx_clear_drv_active(ha);
940233693c7aSVikas Chaudhary 			qla4_8xxx_wr_direct(ha, QLA8XXX_CRB_DEV_STATE,
9403de8c72daSVikas Chaudhary 					    QLA8XXX_DEV_FAILED);
940482761907SPoornima Vonti 			ha->isp_ops->idc_unlock(ha);
94052232be0dSLalit Chandivade 		} else {
94062232be0dSLalit Chandivade 			ql4_printk(KERN_INFO, ha, "scsi%ld: %s: HW State: "
94072232be0dSLalit Chandivade 			    "READY\n", ha->host_no, __func__);
940882761907SPoornima Vonti 			ha->isp_ops->idc_lock(ha);
940933693c7aSVikas Chaudhary 			qla4_8xxx_wr_direct(ha, QLA8XXX_CRB_DEV_STATE,
9410de8c72daSVikas Chaudhary 					    QLA8XXX_DEV_READY);
94112232be0dSLalit Chandivade 			/* Clear driver state register */
941233693c7aSVikas Chaudhary 			qla4_8xxx_wr_direct(ha, QLA8XXX_CRB_DRV_STATE, 0);
94132232be0dSLalit Chandivade 			qla4_8xxx_set_drv_active(ha);
941482761907SPoornima Vonti 			ha->isp_ops->idc_unlock(ha);
94152232be0dSLalit Chandivade 			ha->isp_ops->enable_intrs(ha);
94162232be0dSLalit Chandivade 		}
94172232be0dSLalit Chandivade 	} else {
94182232be0dSLalit Chandivade 		ql4_printk(KERN_INFO, ha, "scsi%ld: %s: devfn 0x%x is not "
94192232be0dSLalit Chandivade 		    "the reset owner\n", ha->host_no, __func__,
94202232be0dSLalit Chandivade 		    ha->pdev->devfn);
942133693c7aSVikas Chaudhary 		if ((qla4_8xxx_rd_direct(ha, QLA8XXX_CRB_DEV_STATE) ==
9422de8c72daSVikas Chaudhary 		     QLA8XXX_DEV_READY)) {
94232232be0dSLalit Chandivade 			clear_bit(AF_FW_RECOVERY, &ha->flags);
942413483730SMike Christie 			rval = qla4xxx_initialize_adapter(ha, RESET_ADAPTER);
9425137257daSPoornima Vonti 			if (rval == QLA_SUCCESS)
94262232be0dSLalit Chandivade 				ha->isp_ops->enable_intrs(ha);
9427137257daSPoornima Vonti 
942833693c7aSVikas Chaudhary 			ha->isp_ops->idc_lock(ha);
94292232be0dSLalit Chandivade 			qla4_8xxx_set_drv_active(ha);
943033693c7aSVikas Chaudhary 			ha->isp_ops->idc_unlock(ha);
94312232be0dSLalit Chandivade 		}
94322232be0dSLalit Chandivade 	}
943339c95826SVikas Chaudhary exit_error_recovery:
94342232be0dSLalit Chandivade 	clear_bit(DPC_RESET_ACTIVE, &ha->dpc_flags);
94352232be0dSLalit Chandivade 	return rval;
94362232be0dSLalit Chandivade }
94372232be0dSLalit Chandivade 
94382232be0dSLalit Chandivade static pci_ers_result_t
94392232be0dSLalit Chandivade qla4xxx_pci_slot_reset(struct pci_dev *pdev)
94402232be0dSLalit Chandivade {
94412232be0dSLalit Chandivade 	pci_ers_result_t ret = PCI_ERS_RESULT_DISCONNECT;
94422232be0dSLalit Chandivade 	struct scsi_qla_host *ha = pci_get_drvdata(pdev);
94432232be0dSLalit Chandivade 	int rc;
94442232be0dSLalit Chandivade 
94452232be0dSLalit Chandivade 	ql4_printk(KERN_WARNING, ha, "scsi%ld: %s: slot_reset\n",
94462232be0dSLalit Chandivade 	    ha->host_no, __func__);
94472232be0dSLalit Chandivade 
94482232be0dSLalit Chandivade 	if (!is_aer_supported(ha))
94492232be0dSLalit Chandivade 		return PCI_ERS_RESULT_NONE;
94502232be0dSLalit Chandivade 
94512232be0dSLalit Chandivade 	/* Restore the saved state of PCIe device -
94522232be0dSLalit Chandivade 	 * BAR registers, PCI Config space, PCIX, MSI,
94532232be0dSLalit Chandivade 	 * IOV states
94542232be0dSLalit Chandivade 	 */
94552232be0dSLalit Chandivade 	pci_restore_state(pdev);
94562232be0dSLalit Chandivade 
94572232be0dSLalit Chandivade 	/* pci_restore_state() clears the saved_state flag of the device
94582232be0dSLalit Chandivade 	 * save restored state which resets saved_state flag
94592232be0dSLalit Chandivade 	 */
94602232be0dSLalit Chandivade 	pci_save_state(pdev);
94612232be0dSLalit Chandivade 
94622232be0dSLalit Chandivade 	/* Initialize device or resume if in suspended state */
94632232be0dSLalit Chandivade 	rc = pci_enable_device(pdev);
94642232be0dSLalit Chandivade 	if (rc) {
946525985edcSLucas De Marchi 		ql4_printk(KERN_WARNING, ha, "scsi%ld: %s: Can't re-enable "
94662232be0dSLalit Chandivade 		    "device after reset\n", ha->host_no, __func__);
94672232be0dSLalit Chandivade 		goto exit_slot_reset;
94682232be0dSLalit Chandivade 	}
94692232be0dSLalit Chandivade 
94707b3595dfSVikas Chaudhary 	ha->isp_ops->disable_intrs(ha);
94712232be0dSLalit Chandivade 
94726e7b4292SVikas Chaudhary 	if (is_qla80XX(ha)) {
94732232be0dSLalit Chandivade 		if (qla4_8xxx_error_recovery(ha) == QLA_SUCCESS) {
94742232be0dSLalit Chandivade 			ret = PCI_ERS_RESULT_RECOVERED;
94752232be0dSLalit Chandivade 			goto exit_slot_reset;
94762232be0dSLalit Chandivade 		} else
94772232be0dSLalit Chandivade 			goto exit_slot_reset;
94782232be0dSLalit Chandivade 	}
94792232be0dSLalit Chandivade 
94802232be0dSLalit Chandivade exit_slot_reset:
94812232be0dSLalit Chandivade 	ql4_printk(KERN_WARNING, ha, "scsi%ld: %s: Return=%x\n"
94822232be0dSLalit Chandivade 	    "device after reset\n", ha->host_no, __func__, ret);
94832232be0dSLalit Chandivade 	return ret;
94842232be0dSLalit Chandivade }
94852232be0dSLalit Chandivade 
94862232be0dSLalit Chandivade static void
94872232be0dSLalit Chandivade qla4xxx_pci_resume(struct pci_dev *pdev)
94882232be0dSLalit Chandivade {
94892232be0dSLalit Chandivade 	struct scsi_qla_host *ha = pci_get_drvdata(pdev);
94902232be0dSLalit Chandivade 	int ret;
94912232be0dSLalit Chandivade 
94922232be0dSLalit Chandivade 	ql4_printk(KERN_WARNING, ha, "scsi%ld: %s: pci_resume\n",
94932232be0dSLalit Chandivade 	    ha->host_no, __func__);
94942232be0dSLalit Chandivade 
94952232be0dSLalit Chandivade 	ret = qla4xxx_wait_for_hba_online(ha);
94962232be0dSLalit Chandivade 	if (ret != QLA_SUCCESS) {
94972232be0dSLalit Chandivade 		ql4_printk(KERN_ERR, ha, "scsi%ld: %s: the device failed to "
94982232be0dSLalit Chandivade 		    "resume I/O from slot/link_reset\n", ha->host_no,
94992232be0dSLalit Chandivade 		     __func__);
95002232be0dSLalit Chandivade 	}
95012232be0dSLalit Chandivade 
95022232be0dSLalit Chandivade 	pci_cleanup_aer_uncorrect_error_status(pdev);
95032232be0dSLalit Chandivade 	clear_bit(AF_EEH_BUSY, &ha->flags);
95042232be0dSLalit Chandivade }
95052232be0dSLalit Chandivade 
9506a55b2d21SStephen Hemminger static const struct pci_error_handlers qla4xxx_err_handler = {
95072232be0dSLalit Chandivade 	.error_detected = qla4xxx_pci_error_detected,
95082232be0dSLalit Chandivade 	.mmio_enabled = qla4xxx_pci_mmio_enabled,
95092232be0dSLalit Chandivade 	.slot_reset = qla4xxx_pci_slot_reset,
95102232be0dSLalit Chandivade 	.resume = qla4xxx_pci_resume,
95112232be0dSLalit Chandivade };
95122232be0dSLalit Chandivade 
9513afaf5a2dSDavid Somayajulu static struct pci_device_id qla4xxx_pci_tbl[] = {
9514afaf5a2dSDavid Somayajulu 	{
9515afaf5a2dSDavid Somayajulu 		.vendor		= PCI_VENDOR_ID_QLOGIC,
9516afaf5a2dSDavid Somayajulu 		.device		= PCI_DEVICE_ID_QLOGIC_ISP4010,
9517afaf5a2dSDavid Somayajulu 		.subvendor	= PCI_ANY_ID,
9518afaf5a2dSDavid Somayajulu 		.subdevice	= PCI_ANY_ID,
9519afaf5a2dSDavid Somayajulu 	},
9520afaf5a2dSDavid Somayajulu 	{
9521afaf5a2dSDavid Somayajulu 		.vendor		= PCI_VENDOR_ID_QLOGIC,
9522afaf5a2dSDavid Somayajulu 		.device		= PCI_DEVICE_ID_QLOGIC_ISP4022,
9523afaf5a2dSDavid Somayajulu 		.subvendor	= PCI_ANY_ID,
9524afaf5a2dSDavid Somayajulu 		.subdevice	= PCI_ANY_ID,
9525afaf5a2dSDavid Somayajulu 	},
9526d915058fSDavid C Somayajulu 	{
9527d915058fSDavid C Somayajulu 		.vendor		= PCI_VENDOR_ID_QLOGIC,
9528d915058fSDavid C Somayajulu 		.device		= PCI_DEVICE_ID_QLOGIC_ISP4032,
9529d915058fSDavid C Somayajulu 		.subvendor	= PCI_ANY_ID,
9530d915058fSDavid C Somayajulu 		.subdevice	= PCI_ANY_ID,
9531d915058fSDavid C Somayajulu 	},
9532f4f5df23SVikas Chaudhary 	{
9533f4f5df23SVikas Chaudhary 		.vendor         = PCI_VENDOR_ID_QLOGIC,
9534f4f5df23SVikas Chaudhary 		.device         = PCI_DEVICE_ID_QLOGIC_ISP8022,
9535f4f5df23SVikas Chaudhary 		.subvendor      = PCI_ANY_ID,
9536f4f5df23SVikas Chaudhary 		.subdevice      = PCI_ANY_ID,
9537f4f5df23SVikas Chaudhary 	},
95386e7b4292SVikas Chaudhary 	{
95396e7b4292SVikas Chaudhary 		.vendor		= PCI_VENDOR_ID_QLOGIC,
95406e7b4292SVikas Chaudhary 		.device		= PCI_DEVICE_ID_QLOGIC_ISP8324,
95416e7b4292SVikas Chaudhary 		.subvendor	= PCI_ANY_ID,
95426e7b4292SVikas Chaudhary 		.subdevice	= PCI_ANY_ID,
95436e7b4292SVikas Chaudhary 	},
9544b37ca418SVikas Chaudhary 	{
9545b37ca418SVikas Chaudhary 		.vendor		= PCI_VENDOR_ID_QLOGIC,
9546b37ca418SVikas Chaudhary 		.device		= PCI_DEVICE_ID_QLOGIC_ISP8042,
9547b37ca418SVikas Chaudhary 		.subvendor	= PCI_ANY_ID,
9548b37ca418SVikas Chaudhary 		.subdevice	= PCI_ANY_ID,
9549b37ca418SVikas Chaudhary 	},
9550afaf5a2dSDavid Somayajulu 	{0, 0},
9551afaf5a2dSDavid Somayajulu };
9552afaf5a2dSDavid Somayajulu MODULE_DEVICE_TABLE(pci, qla4xxx_pci_tbl);
9553afaf5a2dSDavid Somayajulu 
955447975477SAdrian Bunk static struct pci_driver qla4xxx_pci_driver = {
9555afaf5a2dSDavid Somayajulu 	.name		= DRIVER_NAME,
9556afaf5a2dSDavid Somayajulu 	.id_table	= qla4xxx_pci_tbl,
9557afaf5a2dSDavid Somayajulu 	.probe		= qla4xxx_probe_adapter,
9558afaf5a2dSDavid Somayajulu 	.remove		= qla4xxx_remove_adapter,
95592232be0dSLalit Chandivade 	.err_handler = &qla4xxx_err_handler,
9560afaf5a2dSDavid Somayajulu };
9561afaf5a2dSDavid Somayajulu 
9562afaf5a2dSDavid Somayajulu static int __init qla4xxx_module_init(void)
9563afaf5a2dSDavid Somayajulu {
9564afaf5a2dSDavid Somayajulu 	int ret;
9565afaf5a2dSDavid Somayajulu 
9566afaf5a2dSDavid Somayajulu 	/* Allocate cache for SRBs. */
9567afaf5a2dSDavid Somayajulu 	srb_cachep = kmem_cache_create("qla4xxx_srbs", sizeof(struct srb), 0,
956820c2df83SPaul Mundt 				       SLAB_HWCACHE_ALIGN, NULL);
9569afaf5a2dSDavid Somayajulu 	if (srb_cachep == NULL) {
9570afaf5a2dSDavid Somayajulu 		printk(KERN_ERR
9571afaf5a2dSDavid Somayajulu 		       "%s: Unable to allocate SRB cache..."
9572afaf5a2dSDavid Somayajulu 		       "Failing load!\n", DRIVER_NAME);
9573afaf5a2dSDavid Somayajulu 		ret = -ENOMEM;
9574afaf5a2dSDavid Somayajulu 		goto no_srp_cache;
9575afaf5a2dSDavid Somayajulu 	}
9576afaf5a2dSDavid Somayajulu 
9577afaf5a2dSDavid Somayajulu 	/* Derive version string. */
9578afaf5a2dSDavid Somayajulu 	strcpy(qla4xxx_version_str, QLA4XXX_DRIVER_VERSION);
957911010fecSAndrew Vasquez 	if (ql4xextended_error_logging)
9580afaf5a2dSDavid Somayajulu 		strcat(qla4xxx_version_str, "-debug");
9581afaf5a2dSDavid Somayajulu 
9582afaf5a2dSDavid Somayajulu 	qla4xxx_scsi_transport =
9583afaf5a2dSDavid Somayajulu 		iscsi_register_transport(&qla4xxx_iscsi_transport);
9584afaf5a2dSDavid Somayajulu 	if (!qla4xxx_scsi_transport){
9585afaf5a2dSDavid Somayajulu 		ret = -ENODEV;
9586afaf5a2dSDavid Somayajulu 		goto release_srb_cache;
9587afaf5a2dSDavid Somayajulu 	}
9588afaf5a2dSDavid Somayajulu 
9589afaf5a2dSDavid Somayajulu 	ret = pci_register_driver(&qla4xxx_pci_driver);
9590afaf5a2dSDavid Somayajulu 	if (ret)
9591afaf5a2dSDavid Somayajulu 		goto unregister_transport;
9592afaf5a2dSDavid Somayajulu 
9593afaf5a2dSDavid Somayajulu 	printk(KERN_INFO "QLogic iSCSI HBA Driver\n");
9594afaf5a2dSDavid Somayajulu 	return 0;
95955ae16db3SDoug Maxey 
9596afaf5a2dSDavid Somayajulu unregister_transport:
9597afaf5a2dSDavid Somayajulu 	iscsi_unregister_transport(&qla4xxx_iscsi_transport);
9598afaf5a2dSDavid Somayajulu release_srb_cache:
9599afaf5a2dSDavid Somayajulu 	kmem_cache_destroy(srb_cachep);
9600afaf5a2dSDavid Somayajulu no_srp_cache:
9601afaf5a2dSDavid Somayajulu 	return ret;
9602afaf5a2dSDavid Somayajulu }
9603afaf5a2dSDavid Somayajulu 
9604afaf5a2dSDavid Somayajulu static void __exit qla4xxx_module_exit(void)
9605afaf5a2dSDavid Somayajulu {
9606afaf5a2dSDavid Somayajulu 	pci_unregister_driver(&qla4xxx_pci_driver);
9607afaf5a2dSDavid Somayajulu 	iscsi_unregister_transport(&qla4xxx_iscsi_transport);
9608afaf5a2dSDavid Somayajulu 	kmem_cache_destroy(srb_cachep);
9609afaf5a2dSDavid Somayajulu }
9610afaf5a2dSDavid Somayajulu 
9611afaf5a2dSDavid Somayajulu module_init(qla4xxx_module_init);
9612afaf5a2dSDavid Somayajulu module_exit(qla4xxx_module_exit);
9613afaf5a2dSDavid Somayajulu 
9614afaf5a2dSDavid Somayajulu MODULE_AUTHOR("QLogic Corporation");
9615afaf5a2dSDavid Somayajulu MODULE_DESCRIPTION("QLogic iSCSI HBA Driver");
9616afaf5a2dSDavid Somayajulu MODULE_LICENSE("GPL");
9617afaf5a2dSDavid Somayajulu MODULE_VERSION(QLA4XXX_DRIVER_VERSION);
9618