xref: /OK3568_Linux_fs/kernel/drivers/scsi/qla4xxx/ql4_os.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * QLogic iSCSI HBA Driver
4*4882a593Smuzhiyun  * Copyright (c)  2003-2013 QLogic Corporation
5*4882a593Smuzhiyun  */
6*4882a593Smuzhiyun #include <linux/moduleparam.h>
7*4882a593Smuzhiyun #include <linux/slab.h>
8*4882a593Smuzhiyun #include <linux/blkdev.h>
9*4882a593Smuzhiyun #include <linux/iscsi_boot_sysfs.h>
10*4882a593Smuzhiyun #include <linux/inet.h>
11*4882a593Smuzhiyun 
12*4882a593Smuzhiyun #include <scsi/scsi_tcq.h>
13*4882a593Smuzhiyun #include <scsi/scsicam.h>
14*4882a593Smuzhiyun 
15*4882a593Smuzhiyun #include "ql4_def.h"
16*4882a593Smuzhiyun #include "ql4_version.h"
17*4882a593Smuzhiyun #include "ql4_glbl.h"
18*4882a593Smuzhiyun #include "ql4_dbg.h"
19*4882a593Smuzhiyun #include "ql4_inline.h"
20*4882a593Smuzhiyun #include "ql4_83xx.h"
21*4882a593Smuzhiyun 
22*4882a593Smuzhiyun /*
23*4882a593Smuzhiyun  * Driver version
24*4882a593Smuzhiyun  */
25*4882a593Smuzhiyun static char qla4xxx_version_str[40];
26*4882a593Smuzhiyun 
27*4882a593Smuzhiyun /*
28*4882a593Smuzhiyun  * SRB allocation cache
29*4882a593Smuzhiyun  */
30*4882a593Smuzhiyun static struct kmem_cache *srb_cachep;
31*4882a593Smuzhiyun 
32*4882a593Smuzhiyun /*
33*4882a593Smuzhiyun  * Module parameter information and variables
34*4882a593Smuzhiyun  */
35*4882a593Smuzhiyun static int ql4xdisablesysfsboot = 1;
36*4882a593Smuzhiyun module_param(ql4xdisablesysfsboot, int, S_IRUGO | S_IWUSR);
37*4882a593Smuzhiyun MODULE_PARM_DESC(ql4xdisablesysfsboot,
38*4882a593Smuzhiyun 		 " Set to disable exporting boot targets to sysfs.\n"
39*4882a593Smuzhiyun 		 "\t\t  0 - Export boot targets\n"
40*4882a593Smuzhiyun 		 "\t\t  1 - Do not export boot targets (Default)");
41*4882a593Smuzhiyun 
42*4882a593Smuzhiyun int ql4xdontresethba;
43*4882a593Smuzhiyun module_param(ql4xdontresethba, int, S_IRUGO | S_IWUSR);
44*4882a593Smuzhiyun MODULE_PARM_DESC(ql4xdontresethba,
45*4882a593Smuzhiyun 		 " Don't reset the HBA for driver recovery.\n"
46*4882a593Smuzhiyun 		 "\t\t  0 - It will reset HBA (Default)\n"
47*4882a593Smuzhiyun 		 "\t\t  1 - It will NOT reset HBA");
48*4882a593Smuzhiyun 
49*4882a593Smuzhiyun int ql4xextended_error_logging;
50*4882a593Smuzhiyun module_param(ql4xextended_error_logging, int, S_IRUGO | S_IWUSR);
51*4882a593Smuzhiyun MODULE_PARM_DESC(ql4xextended_error_logging,
52*4882a593Smuzhiyun 		 " Option to enable extended error logging.\n"
53*4882a593Smuzhiyun 		 "\t\t  0 - no logging (Default)\n"
54*4882a593Smuzhiyun 		 "\t\t  2 - debug logging");
55*4882a593Smuzhiyun 
56*4882a593Smuzhiyun int ql4xenablemsix = 1;
57*4882a593Smuzhiyun module_param(ql4xenablemsix, int, S_IRUGO|S_IWUSR);
58*4882a593Smuzhiyun MODULE_PARM_DESC(ql4xenablemsix,
59*4882a593Smuzhiyun 		 " Set to enable MSI or MSI-X interrupt mechanism.\n"
60*4882a593Smuzhiyun 		 "\t\t  0 = enable INTx interrupt mechanism.\n"
61*4882a593Smuzhiyun 		 "\t\t  1 = enable MSI-X interrupt mechanism (Default).\n"
62*4882a593Smuzhiyun 		 "\t\t  2 = enable MSI interrupt mechanism.");
63*4882a593Smuzhiyun 
64*4882a593Smuzhiyun #define QL4_DEF_QDEPTH 32
65*4882a593Smuzhiyun static int ql4xmaxqdepth = QL4_DEF_QDEPTH;
66*4882a593Smuzhiyun module_param(ql4xmaxqdepth, int, S_IRUGO | S_IWUSR);
67*4882a593Smuzhiyun MODULE_PARM_DESC(ql4xmaxqdepth,
68*4882a593Smuzhiyun 		 " Maximum queue depth to report for target devices.\n"
69*4882a593Smuzhiyun 		 "\t\t  Default: 32.");
70*4882a593Smuzhiyun 
71*4882a593Smuzhiyun static int ql4xqfulltracking = 1;
72*4882a593Smuzhiyun module_param(ql4xqfulltracking, int, S_IRUGO | S_IWUSR);
73*4882a593Smuzhiyun MODULE_PARM_DESC(ql4xqfulltracking,
74*4882a593Smuzhiyun 		 " Enable or disable dynamic tracking and adjustment of\n"
75*4882a593Smuzhiyun 		 "\t\t scsi device queue depth.\n"
76*4882a593Smuzhiyun 		 "\t\t  0 - Disable.\n"
77*4882a593Smuzhiyun 		 "\t\t  1 - Enable. (Default)");
78*4882a593Smuzhiyun 
79*4882a593Smuzhiyun static int ql4xsess_recovery_tmo = QL4_SESS_RECOVERY_TMO;
80*4882a593Smuzhiyun module_param(ql4xsess_recovery_tmo, int, S_IRUGO);
81*4882a593Smuzhiyun MODULE_PARM_DESC(ql4xsess_recovery_tmo,
82*4882a593Smuzhiyun 		" Target Session Recovery Timeout.\n"
83*4882a593Smuzhiyun 		"\t\t  Default: 120 sec.");
84*4882a593Smuzhiyun 
85*4882a593Smuzhiyun int ql4xmdcapmask = 0;
86*4882a593Smuzhiyun module_param(ql4xmdcapmask, int, S_IRUGO);
87*4882a593Smuzhiyun MODULE_PARM_DESC(ql4xmdcapmask,
88*4882a593Smuzhiyun 		 " Set the Minidump driver capture mask level.\n"
89*4882a593Smuzhiyun 		 "\t\t  Default is 0 (firmware default capture mask)\n"
90*4882a593Smuzhiyun 		 "\t\t  Can be set to 0x3, 0x7, 0xF, 0x1F, 0x3F, 0x7F, 0xFF");
91*4882a593Smuzhiyun 
92*4882a593Smuzhiyun int ql4xenablemd = 1;
93*4882a593Smuzhiyun module_param(ql4xenablemd, int, S_IRUGO | S_IWUSR);
94*4882a593Smuzhiyun MODULE_PARM_DESC(ql4xenablemd,
95*4882a593Smuzhiyun 		 " Set to enable minidump.\n"
96*4882a593Smuzhiyun 		 "\t\t  0 - disable minidump\n"
97*4882a593Smuzhiyun 		 "\t\t  1 - enable minidump (Default)");
98*4882a593Smuzhiyun 
99*4882a593Smuzhiyun static int qla4xxx_wait_for_hba_online(struct scsi_qla_host *ha);
100*4882a593Smuzhiyun /*
101*4882a593Smuzhiyun  * SCSI host template entry points
102*4882a593Smuzhiyun  */
103*4882a593Smuzhiyun static void qla4xxx_config_dma_addressing(struct scsi_qla_host *ha);
104*4882a593Smuzhiyun 
105*4882a593Smuzhiyun /*
106*4882a593Smuzhiyun  * iSCSI template entry points
107*4882a593Smuzhiyun  */
108*4882a593Smuzhiyun static int qla4xxx_session_get_param(struct iscsi_cls_session *cls_sess,
109*4882a593Smuzhiyun 				     enum iscsi_param param, char *buf);
110*4882a593Smuzhiyun static int qla4xxx_conn_get_param(struct iscsi_cls_conn *conn,
111*4882a593Smuzhiyun 				  enum iscsi_param param, char *buf);
112*4882a593Smuzhiyun static int qla4xxx_host_get_param(struct Scsi_Host *shost,
113*4882a593Smuzhiyun 				  enum iscsi_host_param param, char *buf);
114*4882a593Smuzhiyun static int qla4xxx_iface_set_param(struct Scsi_Host *shost, void *data,
115*4882a593Smuzhiyun 				   uint32_t len);
116*4882a593Smuzhiyun static int qla4xxx_get_iface_param(struct iscsi_iface *iface,
117*4882a593Smuzhiyun 				   enum iscsi_param_type param_type,
118*4882a593Smuzhiyun 				   int param, char *buf);
119*4882a593Smuzhiyun static enum blk_eh_timer_return qla4xxx_eh_cmd_timed_out(struct scsi_cmnd *sc);
120*4882a593Smuzhiyun static struct iscsi_endpoint *qla4xxx_ep_connect(struct Scsi_Host *shost,
121*4882a593Smuzhiyun 						 struct sockaddr *dst_addr,
122*4882a593Smuzhiyun 						 int non_blocking);
123*4882a593Smuzhiyun static int qla4xxx_ep_poll(struct iscsi_endpoint *ep, int timeout_ms);
124*4882a593Smuzhiyun static void qla4xxx_ep_disconnect(struct iscsi_endpoint *ep);
125*4882a593Smuzhiyun static int qla4xxx_get_ep_param(struct iscsi_endpoint *ep,
126*4882a593Smuzhiyun 				enum iscsi_param param, char *buf);
127*4882a593Smuzhiyun static int qla4xxx_conn_start(struct iscsi_cls_conn *conn);
128*4882a593Smuzhiyun static struct iscsi_cls_conn *
129*4882a593Smuzhiyun qla4xxx_conn_create(struct iscsi_cls_session *cls_sess, uint32_t conn_idx);
130*4882a593Smuzhiyun static int qla4xxx_conn_bind(struct iscsi_cls_session *cls_session,
131*4882a593Smuzhiyun 			     struct iscsi_cls_conn *cls_conn,
132*4882a593Smuzhiyun 			     uint64_t transport_fd, int is_leading);
133*4882a593Smuzhiyun static void qla4xxx_conn_destroy(struct iscsi_cls_conn *conn);
134*4882a593Smuzhiyun static struct iscsi_cls_session *
135*4882a593Smuzhiyun qla4xxx_session_create(struct iscsi_endpoint *ep, uint16_t cmds_max,
136*4882a593Smuzhiyun 			uint16_t qdepth, uint32_t initial_cmdsn);
137*4882a593Smuzhiyun static void qla4xxx_session_destroy(struct iscsi_cls_session *sess);
138*4882a593Smuzhiyun static void qla4xxx_task_work(struct work_struct *wdata);
139*4882a593Smuzhiyun static int qla4xxx_alloc_pdu(struct iscsi_task *, uint8_t);
140*4882a593Smuzhiyun static int qla4xxx_task_xmit(struct iscsi_task *);
141*4882a593Smuzhiyun static void qla4xxx_task_cleanup(struct iscsi_task *);
142*4882a593Smuzhiyun static void qla4xxx_fail_session(struct iscsi_cls_session *cls_session);
143*4882a593Smuzhiyun static void qla4xxx_conn_get_stats(struct iscsi_cls_conn *cls_conn,
144*4882a593Smuzhiyun 				   struct iscsi_stats *stats);
145*4882a593Smuzhiyun static int qla4xxx_send_ping(struct Scsi_Host *shost, uint32_t iface_num,
146*4882a593Smuzhiyun 			     uint32_t iface_type, uint32_t payload_size,
147*4882a593Smuzhiyun 			     uint32_t pid, struct sockaddr *dst_addr);
148*4882a593Smuzhiyun static int qla4xxx_get_chap_list(struct Scsi_Host *shost, uint16_t chap_tbl_idx,
149*4882a593Smuzhiyun 				 uint32_t *num_entries, char *buf);
150*4882a593Smuzhiyun static int qla4xxx_delete_chap(struct Scsi_Host *shost, uint16_t chap_tbl_idx);
151*4882a593Smuzhiyun static int qla4xxx_set_chap_entry(struct Scsi_Host *shost, void  *data,
152*4882a593Smuzhiyun 				  int len);
153*4882a593Smuzhiyun static int qla4xxx_get_host_stats(struct Scsi_Host *shost, char *buf, int len);
154*4882a593Smuzhiyun 
155*4882a593Smuzhiyun /*
156*4882a593Smuzhiyun  * SCSI host template entry points
157*4882a593Smuzhiyun  */
158*4882a593Smuzhiyun static int qla4xxx_queuecommand(struct Scsi_Host *h, struct scsi_cmnd *cmd);
159*4882a593Smuzhiyun static int qla4xxx_eh_abort(struct scsi_cmnd *cmd);
160*4882a593Smuzhiyun static int qla4xxx_eh_device_reset(struct scsi_cmnd *cmd);
161*4882a593Smuzhiyun static int qla4xxx_eh_target_reset(struct scsi_cmnd *cmd);
162*4882a593Smuzhiyun static int qla4xxx_eh_host_reset(struct scsi_cmnd *cmd);
163*4882a593Smuzhiyun static int qla4xxx_slave_alloc(struct scsi_device *device);
164*4882a593Smuzhiyun static umode_t qla4_attr_is_visible(int param_type, int param);
165*4882a593Smuzhiyun static int qla4xxx_host_reset(struct Scsi_Host *shost, int reset_type);
166*4882a593Smuzhiyun 
167*4882a593Smuzhiyun /*
168*4882a593Smuzhiyun  * iSCSI Flash DDB sysfs entry points
169*4882a593Smuzhiyun  */
170*4882a593Smuzhiyun static int
171*4882a593Smuzhiyun qla4xxx_sysfs_ddb_set_param(struct iscsi_bus_flash_session *fnode_sess,
172*4882a593Smuzhiyun 			    struct iscsi_bus_flash_conn *fnode_conn,
173*4882a593Smuzhiyun 			    void *data, int len);
174*4882a593Smuzhiyun static int
175*4882a593Smuzhiyun qla4xxx_sysfs_ddb_get_param(struct iscsi_bus_flash_session *fnode_sess,
176*4882a593Smuzhiyun 			    int param, char *buf);
177*4882a593Smuzhiyun static int qla4xxx_sysfs_ddb_add(struct Scsi_Host *shost, const char *buf,
178*4882a593Smuzhiyun 				 int len);
179*4882a593Smuzhiyun static int
180*4882a593Smuzhiyun qla4xxx_sysfs_ddb_delete(struct iscsi_bus_flash_session *fnode_sess);
181*4882a593Smuzhiyun static int qla4xxx_sysfs_ddb_login(struct iscsi_bus_flash_session *fnode_sess,
182*4882a593Smuzhiyun 				   struct iscsi_bus_flash_conn *fnode_conn);
183*4882a593Smuzhiyun static int qla4xxx_sysfs_ddb_logout(struct iscsi_bus_flash_session *fnode_sess,
184*4882a593Smuzhiyun 				    struct iscsi_bus_flash_conn *fnode_conn);
185*4882a593Smuzhiyun static int qla4xxx_sysfs_ddb_logout_sid(struct iscsi_cls_session *cls_sess);
186*4882a593Smuzhiyun 
187*4882a593Smuzhiyun static struct qla4_8xxx_legacy_intr_set legacy_intr[] =
188*4882a593Smuzhiyun     QLA82XX_LEGACY_INTR_CONFIG;
189*4882a593Smuzhiyun 
190*4882a593Smuzhiyun static const uint32_t qla4_82xx_reg_tbl[] = {
191*4882a593Smuzhiyun 	QLA82XX_PEG_HALT_STATUS1,
192*4882a593Smuzhiyun 	QLA82XX_PEG_HALT_STATUS2,
193*4882a593Smuzhiyun 	QLA82XX_PEG_ALIVE_COUNTER,
194*4882a593Smuzhiyun 	QLA82XX_CRB_DRV_ACTIVE,
195*4882a593Smuzhiyun 	QLA82XX_CRB_DEV_STATE,
196*4882a593Smuzhiyun 	QLA82XX_CRB_DRV_STATE,
197*4882a593Smuzhiyun 	QLA82XX_CRB_DRV_SCRATCH,
198*4882a593Smuzhiyun 	QLA82XX_CRB_DEV_PART_INFO,
199*4882a593Smuzhiyun 	QLA82XX_CRB_DRV_IDC_VERSION,
200*4882a593Smuzhiyun 	QLA82XX_FW_VERSION_MAJOR,
201*4882a593Smuzhiyun 	QLA82XX_FW_VERSION_MINOR,
202*4882a593Smuzhiyun 	QLA82XX_FW_VERSION_SUB,
203*4882a593Smuzhiyun 	CRB_CMDPEG_STATE,
204*4882a593Smuzhiyun 	CRB_TEMP_STATE,
205*4882a593Smuzhiyun };
206*4882a593Smuzhiyun 
207*4882a593Smuzhiyun static const uint32_t qla4_83xx_reg_tbl[] = {
208*4882a593Smuzhiyun 	QLA83XX_PEG_HALT_STATUS1,
209*4882a593Smuzhiyun 	QLA83XX_PEG_HALT_STATUS2,
210*4882a593Smuzhiyun 	QLA83XX_PEG_ALIVE_COUNTER,
211*4882a593Smuzhiyun 	QLA83XX_CRB_DRV_ACTIVE,
212*4882a593Smuzhiyun 	QLA83XX_CRB_DEV_STATE,
213*4882a593Smuzhiyun 	QLA83XX_CRB_DRV_STATE,
214*4882a593Smuzhiyun 	QLA83XX_CRB_DRV_SCRATCH,
215*4882a593Smuzhiyun 	QLA83XX_CRB_DEV_PART_INFO1,
216*4882a593Smuzhiyun 	QLA83XX_CRB_IDC_VER_MAJOR,
217*4882a593Smuzhiyun 	QLA83XX_FW_VER_MAJOR,
218*4882a593Smuzhiyun 	QLA83XX_FW_VER_MINOR,
219*4882a593Smuzhiyun 	QLA83XX_FW_VER_SUB,
220*4882a593Smuzhiyun 	QLA83XX_CMDPEG_STATE,
221*4882a593Smuzhiyun 	QLA83XX_ASIC_TEMP,
222*4882a593Smuzhiyun };
223*4882a593Smuzhiyun 
224*4882a593Smuzhiyun static struct scsi_host_template qla4xxx_driver_template = {
225*4882a593Smuzhiyun 	.module			= THIS_MODULE,
226*4882a593Smuzhiyun 	.name			= DRIVER_NAME,
227*4882a593Smuzhiyun 	.proc_name		= DRIVER_NAME,
228*4882a593Smuzhiyun 	.queuecommand		= qla4xxx_queuecommand,
229*4882a593Smuzhiyun 
230*4882a593Smuzhiyun 	.eh_abort_handler	= qla4xxx_eh_abort,
231*4882a593Smuzhiyun 	.eh_device_reset_handler = qla4xxx_eh_device_reset,
232*4882a593Smuzhiyun 	.eh_target_reset_handler = qla4xxx_eh_target_reset,
233*4882a593Smuzhiyun 	.eh_host_reset_handler	= qla4xxx_eh_host_reset,
234*4882a593Smuzhiyun 	.eh_timed_out		= qla4xxx_eh_cmd_timed_out,
235*4882a593Smuzhiyun 
236*4882a593Smuzhiyun 	.slave_alloc		= qla4xxx_slave_alloc,
237*4882a593Smuzhiyun 	.change_queue_depth	= scsi_change_queue_depth,
238*4882a593Smuzhiyun 
239*4882a593Smuzhiyun 	.this_id		= -1,
240*4882a593Smuzhiyun 	.cmd_per_lun		= 3,
241*4882a593Smuzhiyun 	.sg_tablesize		= SG_ALL,
242*4882a593Smuzhiyun 
243*4882a593Smuzhiyun 	.max_sectors		= 0xFFFF,
244*4882a593Smuzhiyun 	.shost_attrs		= qla4xxx_host_attrs,
245*4882a593Smuzhiyun 	.host_reset		= qla4xxx_host_reset,
246*4882a593Smuzhiyun 	.vendor_id		= SCSI_NL_VID_TYPE_PCI | PCI_VENDOR_ID_QLOGIC,
247*4882a593Smuzhiyun };
248*4882a593Smuzhiyun 
249*4882a593Smuzhiyun static struct iscsi_transport qla4xxx_iscsi_transport = {
250*4882a593Smuzhiyun 	.owner			= THIS_MODULE,
251*4882a593Smuzhiyun 	.name			= DRIVER_NAME,
252*4882a593Smuzhiyun 	.caps			= CAP_TEXT_NEGO |
253*4882a593Smuzhiyun 				  CAP_DATA_PATH_OFFLOAD | CAP_HDRDGST |
254*4882a593Smuzhiyun 				  CAP_DATADGST | CAP_LOGIN_OFFLOAD |
255*4882a593Smuzhiyun 				  CAP_MULTI_R2T,
256*4882a593Smuzhiyun 	.attr_is_visible	= qla4_attr_is_visible,
257*4882a593Smuzhiyun 	.create_session         = qla4xxx_session_create,
258*4882a593Smuzhiyun 	.destroy_session        = qla4xxx_session_destroy,
259*4882a593Smuzhiyun 	.start_conn             = qla4xxx_conn_start,
260*4882a593Smuzhiyun 	.create_conn            = qla4xxx_conn_create,
261*4882a593Smuzhiyun 	.bind_conn              = qla4xxx_conn_bind,
262*4882a593Smuzhiyun 	.unbind_conn		= iscsi_conn_unbind,
263*4882a593Smuzhiyun 	.stop_conn              = iscsi_conn_stop,
264*4882a593Smuzhiyun 	.destroy_conn           = qla4xxx_conn_destroy,
265*4882a593Smuzhiyun 	.set_param              = iscsi_set_param,
266*4882a593Smuzhiyun 	.get_conn_param		= qla4xxx_conn_get_param,
267*4882a593Smuzhiyun 	.get_session_param	= qla4xxx_session_get_param,
268*4882a593Smuzhiyun 	.get_ep_param           = qla4xxx_get_ep_param,
269*4882a593Smuzhiyun 	.ep_connect		= qla4xxx_ep_connect,
270*4882a593Smuzhiyun 	.ep_poll		= qla4xxx_ep_poll,
271*4882a593Smuzhiyun 	.ep_disconnect		= qla4xxx_ep_disconnect,
272*4882a593Smuzhiyun 	.get_stats		= qla4xxx_conn_get_stats,
273*4882a593Smuzhiyun 	.send_pdu		= iscsi_conn_send_pdu,
274*4882a593Smuzhiyun 	.xmit_task		= qla4xxx_task_xmit,
275*4882a593Smuzhiyun 	.cleanup_task		= qla4xxx_task_cleanup,
276*4882a593Smuzhiyun 	.alloc_pdu		= qla4xxx_alloc_pdu,
277*4882a593Smuzhiyun 
278*4882a593Smuzhiyun 	.get_host_param		= qla4xxx_host_get_param,
279*4882a593Smuzhiyun 	.set_iface_param	= qla4xxx_iface_set_param,
280*4882a593Smuzhiyun 	.get_iface_param	= qla4xxx_get_iface_param,
281*4882a593Smuzhiyun 	.bsg_request		= qla4xxx_bsg_request,
282*4882a593Smuzhiyun 	.send_ping		= qla4xxx_send_ping,
283*4882a593Smuzhiyun 	.get_chap		= qla4xxx_get_chap_list,
284*4882a593Smuzhiyun 	.delete_chap		= qla4xxx_delete_chap,
285*4882a593Smuzhiyun 	.set_chap		= qla4xxx_set_chap_entry,
286*4882a593Smuzhiyun 	.get_flashnode_param	= qla4xxx_sysfs_ddb_get_param,
287*4882a593Smuzhiyun 	.set_flashnode_param	= qla4xxx_sysfs_ddb_set_param,
288*4882a593Smuzhiyun 	.new_flashnode		= qla4xxx_sysfs_ddb_add,
289*4882a593Smuzhiyun 	.del_flashnode		= qla4xxx_sysfs_ddb_delete,
290*4882a593Smuzhiyun 	.login_flashnode	= qla4xxx_sysfs_ddb_login,
291*4882a593Smuzhiyun 	.logout_flashnode	= qla4xxx_sysfs_ddb_logout,
292*4882a593Smuzhiyun 	.logout_flashnode_sid	= qla4xxx_sysfs_ddb_logout_sid,
293*4882a593Smuzhiyun 	.get_host_stats		= qla4xxx_get_host_stats,
294*4882a593Smuzhiyun };
295*4882a593Smuzhiyun 
296*4882a593Smuzhiyun static struct scsi_transport_template *qla4xxx_scsi_transport;
297*4882a593Smuzhiyun 
qla4xxx_isp_check_reg(struct scsi_qla_host * ha)298*4882a593Smuzhiyun static int qla4xxx_isp_check_reg(struct scsi_qla_host *ha)
299*4882a593Smuzhiyun {
300*4882a593Smuzhiyun 	u32 reg_val = 0;
301*4882a593Smuzhiyun 	int rval = QLA_SUCCESS;
302*4882a593Smuzhiyun 
303*4882a593Smuzhiyun 	if (is_qla8022(ha))
304*4882a593Smuzhiyun 		reg_val = readl(&ha->qla4_82xx_reg->host_status);
305*4882a593Smuzhiyun 	else if (is_qla8032(ha) || is_qla8042(ha))
306*4882a593Smuzhiyun 		reg_val = qla4_8xxx_rd_direct(ha, QLA8XXX_PEG_ALIVE_COUNTER);
307*4882a593Smuzhiyun 	else
308*4882a593Smuzhiyun 		reg_val = readw(&ha->reg->ctrl_status);
309*4882a593Smuzhiyun 
310*4882a593Smuzhiyun 	if (reg_val == QL4_ISP_REG_DISCONNECT)
311*4882a593Smuzhiyun 		rval = QLA_ERROR;
312*4882a593Smuzhiyun 
313*4882a593Smuzhiyun 	return rval;
314*4882a593Smuzhiyun }
315*4882a593Smuzhiyun 
qla4xxx_send_ping(struct Scsi_Host * shost,uint32_t iface_num,uint32_t iface_type,uint32_t payload_size,uint32_t pid,struct sockaddr * dst_addr)316*4882a593Smuzhiyun static int qla4xxx_send_ping(struct Scsi_Host *shost, uint32_t iface_num,
317*4882a593Smuzhiyun 			     uint32_t iface_type, uint32_t payload_size,
318*4882a593Smuzhiyun 			     uint32_t pid, struct sockaddr *dst_addr)
319*4882a593Smuzhiyun {
320*4882a593Smuzhiyun 	struct scsi_qla_host *ha = to_qla_host(shost);
321*4882a593Smuzhiyun 	struct sockaddr_in *addr;
322*4882a593Smuzhiyun 	struct sockaddr_in6 *addr6;
323*4882a593Smuzhiyun 	uint32_t options = 0;
324*4882a593Smuzhiyun 	uint8_t ipaddr[IPv6_ADDR_LEN];
325*4882a593Smuzhiyun 	int rval;
326*4882a593Smuzhiyun 
327*4882a593Smuzhiyun 	memset(ipaddr, 0, IPv6_ADDR_LEN);
328*4882a593Smuzhiyun 	/* IPv4 to IPv4 */
329*4882a593Smuzhiyun 	if ((iface_type == ISCSI_IFACE_TYPE_IPV4) &&
330*4882a593Smuzhiyun 	    (dst_addr->sa_family == AF_INET)) {
331*4882a593Smuzhiyun 		addr = (struct sockaddr_in *)dst_addr;
332*4882a593Smuzhiyun 		memcpy(ipaddr, &addr->sin_addr.s_addr, IP_ADDR_LEN);
333*4882a593Smuzhiyun 		DEBUG2(ql4_printk(KERN_INFO, ha, "%s: IPv4 Ping src: %pI4 "
334*4882a593Smuzhiyun 				  "dest: %pI4\n", __func__,
335*4882a593Smuzhiyun 				  &ha->ip_config.ip_address, ipaddr));
336*4882a593Smuzhiyun 		rval = qla4xxx_ping_iocb(ha, options, payload_size, pid,
337*4882a593Smuzhiyun 					 ipaddr);
338*4882a593Smuzhiyun 		if (rval)
339*4882a593Smuzhiyun 			rval = -EINVAL;
340*4882a593Smuzhiyun 	} else if ((iface_type == ISCSI_IFACE_TYPE_IPV6) &&
341*4882a593Smuzhiyun 		   (dst_addr->sa_family == AF_INET6)) {
342*4882a593Smuzhiyun 		/* IPv6 to IPv6 */
343*4882a593Smuzhiyun 		addr6 = (struct sockaddr_in6 *)dst_addr;
344*4882a593Smuzhiyun 		memcpy(ipaddr, &addr6->sin6_addr.in6_u.u6_addr8, IPv6_ADDR_LEN);
345*4882a593Smuzhiyun 
346*4882a593Smuzhiyun 		options |= PING_IPV6_PROTOCOL_ENABLE;
347*4882a593Smuzhiyun 
348*4882a593Smuzhiyun 		/* Ping using LinkLocal address */
349*4882a593Smuzhiyun 		if ((iface_num == 0) || (iface_num == 1)) {
350*4882a593Smuzhiyun 			DEBUG2(ql4_printk(KERN_INFO, ha, "%s: LinkLocal Ping "
351*4882a593Smuzhiyun 					  "src: %pI6 dest: %pI6\n", __func__,
352*4882a593Smuzhiyun 					  &ha->ip_config.ipv6_link_local_addr,
353*4882a593Smuzhiyun 					  ipaddr));
354*4882a593Smuzhiyun 			options |= PING_IPV6_LINKLOCAL_ADDR;
355*4882a593Smuzhiyun 			rval = qla4xxx_ping_iocb(ha, options, payload_size,
356*4882a593Smuzhiyun 						 pid, ipaddr);
357*4882a593Smuzhiyun 		} else {
358*4882a593Smuzhiyun 			ql4_printk(KERN_WARNING, ha, "%s: iface num = %d "
359*4882a593Smuzhiyun 				   "not supported\n", __func__, iface_num);
360*4882a593Smuzhiyun 			rval = -ENOSYS;
361*4882a593Smuzhiyun 			goto exit_send_ping;
362*4882a593Smuzhiyun 		}
363*4882a593Smuzhiyun 
364*4882a593Smuzhiyun 		/*
365*4882a593Smuzhiyun 		 * If ping using LinkLocal address fails, try ping using
366*4882a593Smuzhiyun 		 * IPv6 address
367*4882a593Smuzhiyun 		 */
368*4882a593Smuzhiyun 		if (rval != QLA_SUCCESS) {
369*4882a593Smuzhiyun 			options &= ~PING_IPV6_LINKLOCAL_ADDR;
370*4882a593Smuzhiyun 			if (iface_num == 0) {
371*4882a593Smuzhiyun 				options |= PING_IPV6_ADDR0;
372*4882a593Smuzhiyun 				DEBUG2(ql4_printk(KERN_INFO, ha, "%s: IPv6 "
373*4882a593Smuzhiyun 						  "Ping src: %pI6 "
374*4882a593Smuzhiyun 						  "dest: %pI6\n", __func__,
375*4882a593Smuzhiyun 						  &ha->ip_config.ipv6_addr0,
376*4882a593Smuzhiyun 						  ipaddr));
377*4882a593Smuzhiyun 			} else if (iface_num == 1) {
378*4882a593Smuzhiyun 				options |= PING_IPV6_ADDR1;
379*4882a593Smuzhiyun 				DEBUG2(ql4_printk(KERN_INFO, ha, "%s: IPv6 "
380*4882a593Smuzhiyun 						  "Ping src: %pI6 "
381*4882a593Smuzhiyun 						  "dest: %pI6\n", __func__,
382*4882a593Smuzhiyun 						  &ha->ip_config.ipv6_addr1,
383*4882a593Smuzhiyun 						  ipaddr));
384*4882a593Smuzhiyun 			}
385*4882a593Smuzhiyun 			rval = qla4xxx_ping_iocb(ha, options, payload_size,
386*4882a593Smuzhiyun 						 pid, ipaddr);
387*4882a593Smuzhiyun 			if (rval)
388*4882a593Smuzhiyun 				rval = -EINVAL;
389*4882a593Smuzhiyun 		}
390*4882a593Smuzhiyun 	} else
391*4882a593Smuzhiyun 		rval = -ENOSYS;
392*4882a593Smuzhiyun exit_send_ping:
393*4882a593Smuzhiyun 	return rval;
394*4882a593Smuzhiyun }
395*4882a593Smuzhiyun 
qla4_attr_is_visible(int param_type,int param)396*4882a593Smuzhiyun static umode_t qla4_attr_is_visible(int param_type, int param)
397*4882a593Smuzhiyun {
398*4882a593Smuzhiyun 	switch (param_type) {
399*4882a593Smuzhiyun 	case ISCSI_HOST_PARAM:
400*4882a593Smuzhiyun 		switch (param) {
401*4882a593Smuzhiyun 		case ISCSI_HOST_PARAM_HWADDRESS:
402*4882a593Smuzhiyun 		case ISCSI_HOST_PARAM_IPADDRESS:
403*4882a593Smuzhiyun 		case ISCSI_HOST_PARAM_INITIATOR_NAME:
404*4882a593Smuzhiyun 		case ISCSI_HOST_PARAM_PORT_STATE:
405*4882a593Smuzhiyun 		case ISCSI_HOST_PARAM_PORT_SPEED:
406*4882a593Smuzhiyun 			return S_IRUGO;
407*4882a593Smuzhiyun 		default:
408*4882a593Smuzhiyun 			return 0;
409*4882a593Smuzhiyun 		}
410*4882a593Smuzhiyun 	case ISCSI_PARAM:
411*4882a593Smuzhiyun 		switch (param) {
412*4882a593Smuzhiyun 		case ISCSI_PARAM_PERSISTENT_ADDRESS:
413*4882a593Smuzhiyun 		case ISCSI_PARAM_PERSISTENT_PORT:
414*4882a593Smuzhiyun 		case ISCSI_PARAM_CONN_ADDRESS:
415*4882a593Smuzhiyun 		case ISCSI_PARAM_CONN_PORT:
416*4882a593Smuzhiyun 		case ISCSI_PARAM_TARGET_NAME:
417*4882a593Smuzhiyun 		case ISCSI_PARAM_TPGT:
418*4882a593Smuzhiyun 		case ISCSI_PARAM_TARGET_ALIAS:
419*4882a593Smuzhiyun 		case ISCSI_PARAM_MAX_BURST:
420*4882a593Smuzhiyun 		case ISCSI_PARAM_MAX_R2T:
421*4882a593Smuzhiyun 		case ISCSI_PARAM_FIRST_BURST:
422*4882a593Smuzhiyun 		case ISCSI_PARAM_MAX_RECV_DLENGTH:
423*4882a593Smuzhiyun 		case ISCSI_PARAM_MAX_XMIT_DLENGTH:
424*4882a593Smuzhiyun 		case ISCSI_PARAM_IFACE_NAME:
425*4882a593Smuzhiyun 		case ISCSI_PARAM_CHAP_OUT_IDX:
426*4882a593Smuzhiyun 		case ISCSI_PARAM_CHAP_IN_IDX:
427*4882a593Smuzhiyun 		case ISCSI_PARAM_USERNAME:
428*4882a593Smuzhiyun 		case ISCSI_PARAM_PASSWORD:
429*4882a593Smuzhiyun 		case ISCSI_PARAM_USERNAME_IN:
430*4882a593Smuzhiyun 		case ISCSI_PARAM_PASSWORD_IN:
431*4882a593Smuzhiyun 		case ISCSI_PARAM_AUTO_SND_TGT_DISABLE:
432*4882a593Smuzhiyun 		case ISCSI_PARAM_DISCOVERY_SESS:
433*4882a593Smuzhiyun 		case ISCSI_PARAM_PORTAL_TYPE:
434*4882a593Smuzhiyun 		case ISCSI_PARAM_CHAP_AUTH_EN:
435*4882a593Smuzhiyun 		case ISCSI_PARAM_DISCOVERY_LOGOUT_EN:
436*4882a593Smuzhiyun 		case ISCSI_PARAM_BIDI_CHAP_EN:
437*4882a593Smuzhiyun 		case ISCSI_PARAM_DISCOVERY_AUTH_OPTIONAL:
438*4882a593Smuzhiyun 		case ISCSI_PARAM_DEF_TIME2WAIT:
439*4882a593Smuzhiyun 		case ISCSI_PARAM_DEF_TIME2RETAIN:
440*4882a593Smuzhiyun 		case ISCSI_PARAM_HDRDGST_EN:
441*4882a593Smuzhiyun 		case ISCSI_PARAM_DATADGST_EN:
442*4882a593Smuzhiyun 		case ISCSI_PARAM_INITIAL_R2T_EN:
443*4882a593Smuzhiyun 		case ISCSI_PARAM_IMM_DATA_EN:
444*4882a593Smuzhiyun 		case ISCSI_PARAM_PDU_INORDER_EN:
445*4882a593Smuzhiyun 		case ISCSI_PARAM_DATASEQ_INORDER_EN:
446*4882a593Smuzhiyun 		case ISCSI_PARAM_MAX_SEGMENT_SIZE:
447*4882a593Smuzhiyun 		case ISCSI_PARAM_TCP_TIMESTAMP_STAT:
448*4882a593Smuzhiyun 		case ISCSI_PARAM_TCP_WSF_DISABLE:
449*4882a593Smuzhiyun 		case ISCSI_PARAM_TCP_NAGLE_DISABLE:
450*4882a593Smuzhiyun 		case ISCSI_PARAM_TCP_TIMER_SCALE:
451*4882a593Smuzhiyun 		case ISCSI_PARAM_TCP_TIMESTAMP_EN:
452*4882a593Smuzhiyun 		case ISCSI_PARAM_TCP_XMIT_WSF:
453*4882a593Smuzhiyun 		case ISCSI_PARAM_TCP_RECV_WSF:
454*4882a593Smuzhiyun 		case ISCSI_PARAM_IP_FRAGMENT_DISABLE:
455*4882a593Smuzhiyun 		case ISCSI_PARAM_IPV4_TOS:
456*4882a593Smuzhiyun 		case ISCSI_PARAM_IPV6_TC:
457*4882a593Smuzhiyun 		case ISCSI_PARAM_IPV6_FLOW_LABEL:
458*4882a593Smuzhiyun 		case ISCSI_PARAM_IS_FW_ASSIGNED_IPV6:
459*4882a593Smuzhiyun 		case ISCSI_PARAM_KEEPALIVE_TMO:
460*4882a593Smuzhiyun 		case ISCSI_PARAM_LOCAL_PORT:
461*4882a593Smuzhiyun 		case ISCSI_PARAM_ISID:
462*4882a593Smuzhiyun 		case ISCSI_PARAM_TSID:
463*4882a593Smuzhiyun 		case ISCSI_PARAM_DEF_TASKMGMT_TMO:
464*4882a593Smuzhiyun 		case ISCSI_PARAM_ERL:
465*4882a593Smuzhiyun 		case ISCSI_PARAM_STATSN:
466*4882a593Smuzhiyun 		case ISCSI_PARAM_EXP_STATSN:
467*4882a593Smuzhiyun 		case ISCSI_PARAM_DISCOVERY_PARENT_IDX:
468*4882a593Smuzhiyun 		case ISCSI_PARAM_DISCOVERY_PARENT_TYPE:
469*4882a593Smuzhiyun 		case ISCSI_PARAM_LOCAL_IPADDR:
470*4882a593Smuzhiyun 			return S_IRUGO;
471*4882a593Smuzhiyun 		default:
472*4882a593Smuzhiyun 			return 0;
473*4882a593Smuzhiyun 		}
474*4882a593Smuzhiyun 	case ISCSI_NET_PARAM:
475*4882a593Smuzhiyun 		switch (param) {
476*4882a593Smuzhiyun 		case ISCSI_NET_PARAM_IPV4_ADDR:
477*4882a593Smuzhiyun 		case ISCSI_NET_PARAM_IPV4_SUBNET:
478*4882a593Smuzhiyun 		case ISCSI_NET_PARAM_IPV4_GW:
479*4882a593Smuzhiyun 		case ISCSI_NET_PARAM_IPV4_BOOTPROTO:
480*4882a593Smuzhiyun 		case ISCSI_NET_PARAM_IFACE_ENABLE:
481*4882a593Smuzhiyun 		case ISCSI_NET_PARAM_IPV6_LINKLOCAL:
482*4882a593Smuzhiyun 		case ISCSI_NET_PARAM_IPV6_ADDR:
483*4882a593Smuzhiyun 		case ISCSI_NET_PARAM_IPV6_ROUTER:
484*4882a593Smuzhiyun 		case ISCSI_NET_PARAM_IPV6_ADDR_AUTOCFG:
485*4882a593Smuzhiyun 		case ISCSI_NET_PARAM_IPV6_LINKLOCAL_AUTOCFG:
486*4882a593Smuzhiyun 		case ISCSI_NET_PARAM_VLAN_ID:
487*4882a593Smuzhiyun 		case ISCSI_NET_PARAM_VLAN_PRIORITY:
488*4882a593Smuzhiyun 		case ISCSI_NET_PARAM_VLAN_ENABLED:
489*4882a593Smuzhiyun 		case ISCSI_NET_PARAM_MTU:
490*4882a593Smuzhiyun 		case ISCSI_NET_PARAM_PORT:
491*4882a593Smuzhiyun 		case ISCSI_NET_PARAM_IPADDR_STATE:
492*4882a593Smuzhiyun 		case ISCSI_NET_PARAM_IPV6_LINKLOCAL_STATE:
493*4882a593Smuzhiyun 		case ISCSI_NET_PARAM_IPV6_ROUTER_STATE:
494*4882a593Smuzhiyun 		case ISCSI_NET_PARAM_DELAYED_ACK_EN:
495*4882a593Smuzhiyun 		case ISCSI_NET_PARAM_TCP_NAGLE_DISABLE:
496*4882a593Smuzhiyun 		case ISCSI_NET_PARAM_TCP_WSF_DISABLE:
497*4882a593Smuzhiyun 		case ISCSI_NET_PARAM_TCP_WSF:
498*4882a593Smuzhiyun 		case ISCSI_NET_PARAM_TCP_TIMER_SCALE:
499*4882a593Smuzhiyun 		case ISCSI_NET_PARAM_TCP_TIMESTAMP_EN:
500*4882a593Smuzhiyun 		case ISCSI_NET_PARAM_CACHE_ID:
501*4882a593Smuzhiyun 		case ISCSI_NET_PARAM_IPV4_DHCP_DNS_ADDR_EN:
502*4882a593Smuzhiyun 		case ISCSI_NET_PARAM_IPV4_DHCP_SLP_DA_EN:
503*4882a593Smuzhiyun 		case ISCSI_NET_PARAM_IPV4_TOS_EN:
504*4882a593Smuzhiyun 		case ISCSI_NET_PARAM_IPV4_TOS:
505*4882a593Smuzhiyun 		case ISCSI_NET_PARAM_IPV4_GRAT_ARP_EN:
506*4882a593Smuzhiyun 		case ISCSI_NET_PARAM_IPV4_DHCP_ALT_CLIENT_ID_EN:
507*4882a593Smuzhiyun 		case ISCSI_NET_PARAM_IPV4_DHCP_ALT_CLIENT_ID:
508*4882a593Smuzhiyun 		case ISCSI_NET_PARAM_IPV4_DHCP_REQ_VENDOR_ID_EN:
509*4882a593Smuzhiyun 		case ISCSI_NET_PARAM_IPV4_DHCP_USE_VENDOR_ID_EN:
510*4882a593Smuzhiyun 		case ISCSI_NET_PARAM_IPV4_DHCP_VENDOR_ID:
511*4882a593Smuzhiyun 		case ISCSI_NET_PARAM_IPV4_DHCP_LEARN_IQN_EN:
512*4882a593Smuzhiyun 		case ISCSI_NET_PARAM_IPV4_FRAGMENT_DISABLE:
513*4882a593Smuzhiyun 		case ISCSI_NET_PARAM_IPV4_IN_FORWARD_EN:
514*4882a593Smuzhiyun 		case ISCSI_NET_PARAM_REDIRECT_EN:
515*4882a593Smuzhiyun 		case ISCSI_NET_PARAM_IPV4_TTL:
516*4882a593Smuzhiyun 		case ISCSI_NET_PARAM_IPV6_GRAT_NEIGHBOR_ADV_EN:
517*4882a593Smuzhiyun 		case ISCSI_NET_PARAM_IPV6_MLD_EN:
518*4882a593Smuzhiyun 		case ISCSI_NET_PARAM_IPV6_FLOW_LABEL:
519*4882a593Smuzhiyun 		case ISCSI_NET_PARAM_IPV6_TRAFFIC_CLASS:
520*4882a593Smuzhiyun 		case ISCSI_NET_PARAM_IPV6_HOP_LIMIT:
521*4882a593Smuzhiyun 		case ISCSI_NET_PARAM_IPV6_ND_REACHABLE_TMO:
522*4882a593Smuzhiyun 		case ISCSI_NET_PARAM_IPV6_ND_REXMIT_TIME:
523*4882a593Smuzhiyun 		case ISCSI_NET_PARAM_IPV6_ND_STALE_TMO:
524*4882a593Smuzhiyun 		case ISCSI_NET_PARAM_IPV6_DUP_ADDR_DETECT_CNT:
525*4882a593Smuzhiyun 		case ISCSI_NET_PARAM_IPV6_RTR_ADV_LINK_MTU:
526*4882a593Smuzhiyun 			return S_IRUGO;
527*4882a593Smuzhiyun 		default:
528*4882a593Smuzhiyun 			return 0;
529*4882a593Smuzhiyun 		}
530*4882a593Smuzhiyun 	case ISCSI_IFACE_PARAM:
531*4882a593Smuzhiyun 		switch (param) {
532*4882a593Smuzhiyun 		case ISCSI_IFACE_PARAM_DEF_TASKMGMT_TMO:
533*4882a593Smuzhiyun 		case ISCSI_IFACE_PARAM_HDRDGST_EN:
534*4882a593Smuzhiyun 		case ISCSI_IFACE_PARAM_DATADGST_EN:
535*4882a593Smuzhiyun 		case ISCSI_IFACE_PARAM_IMM_DATA_EN:
536*4882a593Smuzhiyun 		case ISCSI_IFACE_PARAM_INITIAL_R2T_EN:
537*4882a593Smuzhiyun 		case ISCSI_IFACE_PARAM_DATASEQ_INORDER_EN:
538*4882a593Smuzhiyun 		case ISCSI_IFACE_PARAM_PDU_INORDER_EN:
539*4882a593Smuzhiyun 		case ISCSI_IFACE_PARAM_ERL:
540*4882a593Smuzhiyun 		case ISCSI_IFACE_PARAM_MAX_RECV_DLENGTH:
541*4882a593Smuzhiyun 		case ISCSI_IFACE_PARAM_FIRST_BURST:
542*4882a593Smuzhiyun 		case ISCSI_IFACE_PARAM_MAX_R2T:
543*4882a593Smuzhiyun 		case ISCSI_IFACE_PARAM_MAX_BURST:
544*4882a593Smuzhiyun 		case ISCSI_IFACE_PARAM_CHAP_AUTH_EN:
545*4882a593Smuzhiyun 		case ISCSI_IFACE_PARAM_BIDI_CHAP_EN:
546*4882a593Smuzhiyun 		case ISCSI_IFACE_PARAM_DISCOVERY_AUTH_OPTIONAL:
547*4882a593Smuzhiyun 		case ISCSI_IFACE_PARAM_DISCOVERY_LOGOUT_EN:
548*4882a593Smuzhiyun 		case ISCSI_IFACE_PARAM_STRICT_LOGIN_COMP_EN:
549*4882a593Smuzhiyun 		case ISCSI_IFACE_PARAM_INITIATOR_NAME:
550*4882a593Smuzhiyun 			return S_IRUGO;
551*4882a593Smuzhiyun 		default:
552*4882a593Smuzhiyun 			return 0;
553*4882a593Smuzhiyun 		}
554*4882a593Smuzhiyun 	case ISCSI_FLASHNODE_PARAM:
555*4882a593Smuzhiyun 		switch (param) {
556*4882a593Smuzhiyun 		case ISCSI_FLASHNODE_IS_FW_ASSIGNED_IPV6:
557*4882a593Smuzhiyun 		case ISCSI_FLASHNODE_PORTAL_TYPE:
558*4882a593Smuzhiyun 		case ISCSI_FLASHNODE_AUTO_SND_TGT_DISABLE:
559*4882a593Smuzhiyun 		case ISCSI_FLASHNODE_DISCOVERY_SESS:
560*4882a593Smuzhiyun 		case ISCSI_FLASHNODE_ENTRY_EN:
561*4882a593Smuzhiyun 		case ISCSI_FLASHNODE_HDR_DGST_EN:
562*4882a593Smuzhiyun 		case ISCSI_FLASHNODE_DATA_DGST_EN:
563*4882a593Smuzhiyun 		case ISCSI_FLASHNODE_IMM_DATA_EN:
564*4882a593Smuzhiyun 		case ISCSI_FLASHNODE_INITIAL_R2T_EN:
565*4882a593Smuzhiyun 		case ISCSI_FLASHNODE_DATASEQ_INORDER:
566*4882a593Smuzhiyun 		case ISCSI_FLASHNODE_PDU_INORDER:
567*4882a593Smuzhiyun 		case ISCSI_FLASHNODE_CHAP_AUTH_EN:
568*4882a593Smuzhiyun 		case ISCSI_FLASHNODE_SNACK_REQ_EN:
569*4882a593Smuzhiyun 		case ISCSI_FLASHNODE_DISCOVERY_LOGOUT_EN:
570*4882a593Smuzhiyun 		case ISCSI_FLASHNODE_BIDI_CHAP_EN:
571*4882a593Smuzhiyun 		case ISCSI_FLASHNODE_DISCOVERY_AUTH_OPTIONAL:
572*4882a593Smuzhiyun 		case ISCSI_FLASHNODE_ERL:
573*4882a593Smuzhiyun 		case ISCSI_FLASHNODE_TCP_TIMESTAMP_STAT:
574*4882a593Smuzhiyun 		case ISCSI_FLASHNODE_TCP_NAGLE_DISABLE:
575*4882a593Smuzhiyun 		case ISCSI_FLASHNODE_TCP_WSF_DISABLE:
576*4882a593Smuzhiyun 		case ISCSI_FLASHNODE_TCP_TIMER_SCALE:
577*4882a593Smuzhiyun 		case ISCSI_FLASHNODE_TCP_TIMESTAMP_EN:
578*4882a593Smuzhiyun 		case ISCSI_FLASHNODE_IP_FRAG_DISABLE:
579*4882a593Smuzhiyun 		case ISCSI_FLASHNODE_MAX_RECV_DLENGTH:
580*4882a593Smuzhiyun 		case ISCSI_FLASHNODE_MAX_XMIT_DLENGTH:
581*4882a593Smuzhiyun 		case ISCSI_FLASHNODE_FIRST_BURST:
582*4882a593Smuzhiyun 		case ISCSI_FLASHNODE_DEF_TIME2WAIT:
583*4882a593Smuzhiyun 		case ISCSI_FLASHNODE_DEF_TIME2RETAIN:
584*4882a593Smuzhiyun 		case ISCSI_FLASHNODE_MAX_R2T:
585*4882a593Smuzhiyun 		case ISCSI_FLASHNODE_KEEPALIVE_TMO:
586*4882a593Smuzhiyun 		case ISCSI_FLASHNODE_ISID:
587*4882a593Smuzhiyun 		case ISCSI_FLASHNODE_TSID:
588*4882a593Smuzhiyun 		case ISCSI_FLASHNODE_PORT:
589*4882a593Smuzhiyun 		case ISCSI_FLASHNODE_MAX_BURST:
590*4882a593Smuzhiyun 		case ISCSI_FLASHNODE_DEF_TASKMGMT_TMO:
591*4882a593Smuzhiyun 		case ISCSI_FLASHNODE_IPADDR:
592*4882a593Smuzhiyun 		case ISCSI_FLASHNODE_ALIAS:
593*4882a593Smuzhiyun 		case ISCSI_FLASHNODE_REDIRECT_IPADDR:
594*4882a593Smuzhiyun 		case ISCSI_FLASHNODE_MAX_SEGMENT_SIZE:
595*4882a593Smuzhiyun 		case ISCSI_FLASHNODE_LOCAL_PORT:
596*4882a593Smuzhiyun 		case ISCSI_FLASHNODE_IPV4_TOS:
597*4882a593Smuzhiyun 		case ISCSI_FLASHNODE_IPV6_TC:
598*4882a593Smuzhiyun 		case ISCSI_FLASHNODE_IPV6_FLOW_LABEL:
599*4882a593Smuzhiyun 		case ISCSI_FLASHNODE_NAME:
600*4882a593Smuzhiyun 		case ISCSI_FLASHNODE_TPGT:
601*4882a593Smuzhiyun 		case ISCSI_FLASHNODE_LINK_LOCAL_IPV6:
602*4882a593Smuzhiyun 		case ISCSI_FLASHNODE_DISCOVERY_PARENT_IDX:
603*4882a593Smuzhiyun 		case ISCSI_FLASHNODE_DISCOVERY_PARENT_TYPE:
604*4882a593Smuzhiyun 		case ISCSI_FLASHNODE_TCP_XMIT_WSF:
605*4882a593Smuzhiyun 		case ISCSI_FLASHNODE_TCP_RECV_WSF:
606*4882a593Smuzhiyun 		case ISCSI_FLASHNODE_CHAP_OUT_IDX:
607*4882a593Smuzhiyun 		case ISCSI_FLASHNODE_USERNAME:
608*4882a593Smuzhiyun 		case ISCSI_FLASHNODE_PASSWORD:
609*4882a593Smuzhiyun 		case ISCSI_FLASHNODE_STATSN:
610*4882a593Smuzhiyun 		case ISCSI_FLASHNODE_EXP_STATSN:
611*4882a593Smuzhiyun 		case ISCSI_FLASHNODE_IS_BOOT_TGT:
612*4882a593Smuzhiyun 			return S_IRUGO;
613*4882a593Smuzhiyun 		default:
614*4882a593Smuzhiyun 			return 0;
615*4882a593Smuzhiyun 		}
616*4882a593Smuzhiyun 	}
617*4882a593Smuzhiyun 
618*4882a593Smuzhiyun 	return 0;
619*4882a593Smuzhiyun }
620*4882a593Smuzhiyun 
621*4882a593Smuzhiyun /**
622*4882a593Smuzhiyun  * qla4xxx_create chap_list - Create CHAP list from FLASH
623*4882a593Smuzhiyun  * @ha: pointer to adapter structure
624*4882a593Smuzhiyun  *
625*4882a593Smuzhiyun  * Read flash and make a list of CHAP entries, during login when a CHAP entry
626*4882a593Smuzhiyun  * is received, it will be checked in this list. If entry exist then the CHAP
627*4882a593Smuzhiyun  * entry index is set in the DDB. If CHAP entry does not exist in this list
628*4882a593Smuzhiyun  * then a new entry is added in FLASH in CHAP table and the index obtained is
629*4882a593Smuzhiyun  * used in the DDB.
630*4882a593Smuzhiyun  **/
qla4xxx_create_chap_list(struct scsi_qla_host * ha)631*4882a593Smuzhiyun static void qla4xxx_create_chap_list(struct scsi_qla_host *ha)
632*4882a593Smuzhiyun {
633*4882a593Smuzhiyun 	int rval = 0;
634*4882a593Smuzhiyun 	uint8_t *chap_flash_data = NULL;
635*4882a593Smuzhiyun 	uint32_t offset;
636*4882a593Smuzhiyun 	dma_addr_t chap_dma;
637*4882a593Smuzhiyun 	uint32_t chap_size = 0;
638*4882a593Smuzhiyun 
639*4882a593Smuzhiyun 	if (is_qla40XX(ha))
640*4882a593Smuzhiyun 		chap_size = MAX_CHAP_ENTRIES_40XX *
641*4882a593Smuzhiyun 			    sizeof(struct ql4_chap_table);
642*4882a593Smuzhiyun 	else	/* Single region contains CHAP info for both
643*4882a593Smuzhiyun 		 * ports which is divided into half for each port.
644*4882a593Smuzhiyun 		 */
645*4882a593Smuzhiyun 		chap_size = ha->hw.flt_chap_size / 2;
646*4882a593Smuzhiyun 
647*4882a593Smuzhiyun 	chap_flash_data = dma_alloc_coherent(&ha->pdev->dev, chap_size,
648*4882a593Smuzhiyun 					     &chap_dma, GFP_KERNEL);
649*4882a593Smuzhiyun 	if (!chap_flash_data) {
650*4882a593Smuzhiyun 		ql4_printk(KERN_ERR, ha, "No memory for chap_flash_data\n");
651*4882a593Smuzhiyun 		return;
652*4882a593Smuzhiyun 	}
653*4882a593Smuzhiyun 
654*4882a593Smuzhiyun 	if (is_qla40XX(ha)) {
655*4882a593Smuzhiyun 		offset = FLASH_CHAP_OFFSET;
656*4882a593Smuzhiyun 	} else {
657*4882a593Smuzhiyun 		offset = FLASH_RAW_ACCESS_ADDR + (ha->hw.flt_region_chap << 2);
658*4882a593Smuzhiyun 		if (ha->port_num == 1)
659*4882a593Smuzhiyun 			offset += chap_size;
660*4882a593Smuzhiyun 	}
661*4882a593Smuzhiyun 
662*4882a593Smuzhiyun 	rval = qla4xxx_get_flash(ha, chap_dma, offset, chap_size);
663*4882a593Smuzhiyun 	if (rval != QLA_SUCCESS)
664*4882a593Smuzhiyun 		goto exit_chap_list;
665*4882a593Smuzhiyun 
666*4882a593Smuzhiyun 	if (ha->chap_list == NULL)
667*4882a593Smuzhiyun 		ha->chap_list = vmalloc(chap_size);
668*4882a593Smuzhiyun 	if (ha->chap_list == NULL) {
669*4882a593Smuzhiyun 		ql4_printk(KERN_ERR, ha, "No memory for ha->chap_list\n");
670*4882a593Smuzhiyun 		goto exit_chap_list;
671*4882a593Smuzhiyun 	}
672*4882a593Smuzhiyun 
673*4882a593Smuzhiyun 	memset(ha->chap_list, 0, chap_size);
674*4882a593Smuzhiyun 	memcpy(ha->chap_list, chap_flash_data, chap_size);
675*4882a593Smuzhiyun 
676*4882a593Smuzhiyun exit_chap_list:
677*4882a593Smuzhiyun 	dma_free_coherent(&ha->pdev->dev, chap_size, chap_flash_data, chap_dma);
678*4882a593Smuzhiyun }
679*4882a593Smuzhiyun 
qla4xxx_get_chap_by_index(struct scsi_qla_host * ha,int16_t chap_index,struct ql4_chap_table ** chap_entry)680*4882a593Smuzhiyun static int qla4xxx_get_chap_by_index(struct scsi_qla_host *ha,
681*4882a593Smuzhiyun 				     int16_t chap_index,
682*4882a593Smuzhiyun 				     struct ql4_chap_table **chap_entry)
683*4882a593Smuzhiyun {
684*4882a593Smuzhiyun 	int rval = QLA_ERROR;
685*4882a593Smuzhiyun 	int max_chap_entries;
686*4882a593Smuzhiyun 
687*4882a593Smuzhiyun 	if (!ha->chap_list) {
688*4882a593Smuzhiyun 		ql4_printk(KERN_ERR, ha, "CHAP table cache is empty!\n");
689*4882a593Smuzhiyun 		rval = QLA_ERROR;
690*4882a593Smuzhiyun 		goto exit_get_chap;
691*4882a593Smuzhiyun 	}
692*4882a593Smuzhiyun 
693*4882a593Smuzhiyun 	if (is_qla80XX(ha))
694*4882a593Smuzhiyun 		max_chap_entries = (ha->hw.flt_chap_size / 2) /
695*4882a593Smuzhiyun 				   sizeof(struct ql4_chap_table);
696*4882a593Smuzhiyun 	else
697*4882a593Smuzhiyun 		max_chap_entries = MAX_CHAP_ENTRIES_40XX;
698*4882a593Smuzhiyun 
699*4882a593Smuzhiyun 	if (chap_index > max_chap_entries) {
700*4882a593Smuzhiyun 		ql4_printk(KERN_ERR, ha, "Invalid Chap index\n");
701*4882a593Smuzhiyun 		rval = QLA_ERROR;
702*4882a593Smuzhiyun 		goto exit_get_chap;
703*4882a593Smuzhiyun 	}
704*4882a593Smuzhiyun 
705*4882a593Smuzhiyun 	*chap_entry = (struct ql4_chap_table *)ha->chap_list + chap_index;
706*4882a593Smuzhiyun 	if ((*chap_entry)->cookie !=
707*4882a593Smuzhiyun 	     __constant_cpu_to_le16(CHAP_VALID_COOKIE)) {
708*4882a593Smuzhiyun 		rval = QLA_ERROR;
709*4882a593Smuzhiyun 		*chap_entry = NULL;
710*4882a593Smuzhiyun 	} else {
711*4882a593Smuzhiyun 		rval = QLA_SUCCESS;
712*4882a593Smuzhiyun 	}
713*4882a593Smuzhiyun 
714*4882a593Smuzhiyun exit_get_chap:
715*4882a593Smuzhiyun 	return rval;
716*4882a593Smuzhiyun }
717*4882a593Smuzhiyun 
718*4882a593Smuzhiyun /**
719*4882a593Smuzhiyun  * qla4xxx_find_free_chap_index - Find the first free chap index
720*4882a593Smuzhiyun  * @ha: pointer to adapter structure
721*4882a593Smuzhiyun  * @chap_index: CHAP index to be returned
722*4882a593Smuzhiyun  *
723*4882a593Smuzhiyun  * Find the first free chap index available in the chap table
724*4882a593Smuzhiyun  *
725*4882a593Smuzhiyun  * Note: Caller should acquire the chap lock before getting here.
726*4882a593Smuzhiyun  **/
qla4xxx_find_free_chap_index(struct scsi_qla_host * ha,uint16_t * chap_index)727*4882a593Smuzhiyun static int qla4xxx_find_free_chap_index(struct scsi_qla_host *ha,
728*4882a593Smuzhiyun 					uint16_t *chap_index)
729*4882a593Smuzhiyun {
730*4882a593Smuzhiyun 	int i, rval;
731*4882a593Smuzhiyun 	int free_index = -1;
732*4882a593Smuzhiyun 	int max_chap_entries = 0;
733*4882a593Smuzhiyun 	struct ql4_chap_table *chap_table;
734*4882a593Smuzhiyun 
735*4882a593Smuzhiyun 	if (is_qla80XX(ha))
736*4882a593Smuzhiyun 		max_chap_entries = (ha->hw.flt_chap_size / 2) /
737*4882a593Smuzhiyun 						sizeof(struct ql4_chap_table);
738*4882a593Smuzhiyun 	else
739*4882a593Smuzhiyun 		max_chap_entries = MAX_CHAP_ENTRIES_40XX;
740*4882a593Smuzhiyun 
741*4882a593Smuzhiyun 	if (!ha->chap_list) {
742*4882a593Smuzhiyun 		ql4_printk(KERN_ERR, ha, "CHAP table cache is empty!\n");
743*4882a593Smuzhiyun 		rval = QLA_ERROR;
744*4882a593Smuzhiyun 		goto exit_find_chap;
745*4882a593Smuzhiyun 	}
746*4882a593Smuzhiyun 
747*4882a593Smuzhiyun 	for (i = 0; i < max_chap_entries; i++) {
748*4882a593Smuzhiyun 		chap_table = (struct ql4_chap_table *)ha->chap_list + i;
749*4882a593Smuzhiyun 
750*4882a593Smuzhiyun 		if ((chap_table->cookie !=
751*4882a593Smuzhiyun 		    __constant_cpu_to_le16(CHAP_VALID_COOKIE)) &&
752*4882a593Smuzhiyun 		   (i > MAX_RESRV_CHAP_IDX)) {
753*4882a593Smuzhiyun 				free_index = i;
754*4882a593Smuzhiyun 				break;
755*4882a593Smuzhiyun 		}
756*4882a593Smuzhiyun 	}
757*4882a593Smuzhiyun 
758*4882a593Smuzhiyun 	if (free_index != -1) {
759*4882a593Smuzhiyun 		*chap_index = free_index;
760*4882a593Smuzhiyun 		rval = QLA_SUCCESS;
761*4882a593Smuzhiyun 	} else {
762*4882a593Smuzhiyun 		rval = QLA_ERROR;
763*4882a593Smuzhiyun 	}
764*4882a593Smuzhiyun 
765*4882a593Smuzhiyun exit_find_chap:
766*4882a593Smuzhiyun 	return rval;
767*4882a593Smuzhiyun }
768*4882a593Smuzhiyun 
qla4xxx_get_chap_list(struct Scsi_Host * shost,uint16_t chap_tbl_idx,uint32_t * num_entries,char * buf)769*4882a593Smuzhiyun static int qla4xxx_get_chap_list(struct Scsi_Host *shost, uint16_t chap_tbl_idx,
770*4882a593Smuzhiyun 				  uint32_t *num_entries, char *buf)
771*4882a593Smuzhiyun {
772*4882a593Smuzhiyun 	struct scsi_qla_host *ha = to_qla_host(shost);
773*4882a593Smuzhiyun 	struct ql4_chap_table *chap_table;
774*4882a593Smuzhiyun 	struct iscsi_chap_rec *chap_rec;
775*4882a593Smuzhiyun 	int max_chap_entries = 0;
776*4882a593Smuzhiyun 	int valid_chap_entries = 0;
777*4882a593Smuzhiyun 	int ret = 0, i;
778*4882a593Smuzhiyun 
779*4882a593Smuzhiyun 	if (is_qla80XX(ha))
780*4882a593Smuzhiyun 		max_chap_entries = (ha->hw.flt_chap_size / 2) /
781*4882a593Smuzhiyun 					sizeof(struct ql4_chap_table);
782*4882a593Smuzhiyun 	else
783*4882a593Smuzhiyun 		max_chap_entries = MAX_CHAP_ENTRIES_40XX;
784*4882a593Smuzhiyun 
785*4882a593Smuzhiyun 	ql4_printk(KERN_INFO, ha, "%s: num_entries = %d, CHAP idx = %d\n",
786*4882a593Smuzhiyun 			__func__, *num_entries, chap_tbl_idx);
787*4882a593Smuzhiyun 
788*4882a593Smuzhiyun 	if (!buf) {
789*4882a593Smuzhiyun 		ret = -ENOMEM;
790*4882a593Smuzhiyun 		goto exit_get_chap_list;
791*4882a593Smuzhiyun 	}
792*4882a593Smuzhiyun 
793*4882a593Smuzhiyun 	qla4xxx_create_chap_list(ha);
794*4882a593Smuzhiyun 
795*4882a593Smuzhiyun 	chap_rec = (struct iscsi_chap_rec *) buf;
796*4882a593Smuzhiyun 	mutex_lock(&ha->chap_sem);
797*4882a593Smuzhiyun 	for (i = chap_tbl_idx; i < max_chap_entries; i++) {
798*4882a593Smuzhiyun 		chap_table = (struct ql4_chap_table *)ha->chap_list + i;
799*4882a593Smuzhiyun 		if (chap_table->cookie !=
800*4882a593Smuzhiyun 		    __constant_cpu_to_le16(CHAP_VALID_COOKIE))
801*4882a593Smuzhiyun 			continue;
802*4882a593Smuzhiyun 
803*4882a593Smuzhiyun 		chap_rec->chap_tbl_idx = i;
804*4882a593Smuzhiyun 		strlcpy(chap_rec->username, chap_table->name,
805*4882a593Smuzhiyun 			ISCSI_CHAP_AUTH_NAME_MAX_LEN);
806*4882a593Smuzhiyun 		strlcpy(chap_rec->password, chap_table->secret,
807*4882a593Smuzhiyun 			QL4_CHAP_MAX_SECRET_LEN);
808*4882a593Smuzhiyun 		chap_rec->password_length = chap_table->secret_len;
809*4882a593Smuzhiyun 
810*4882a593Smuzhiyun 		if (chap_table->flags & BIT_7) /* local */
811*4882a593Smuzhiyun 			chap_rec->chap_type = CHAP_TYPE_OUT;
812*4882a593Smuzhiyun 
813*4882a593Smuzhiyun 		if (chap_table->flags & BIT_6) /* peer */
814*4882a593Smuzhiyun 			chap_rec->chap_type = CHAP_TYPE_IN;
815*4882a593Smuzhiyun 
816*4882a593Smuzhiyun 		chap_rec++;
817*4882a593Smuzhiyun 
818*4882a593Smuzhiyun 		valid_chap_entries++;
819*4882a593Smuzhiyun 		if (valid_chap_entries == *num_entries)
820*4882a593Smuzhiyun 			break;
821*4882a593Smuzhiyun 		else
822*4882a593Smuzhiyun 			continue;
823*4882a593Smuzhiyun 	}
824*4882a593Smuzhiyun 	mutex_unlock(&ha->chap_sem);
825*4882a593Smuzhiyun 
826*4882a593Smuzhiyun exit_get_chap_list:
827*4882a593Smuzhiyun 	ql4_printk(KERN_INFO, ha, "%s: Valid CHAP Entries = %d\n",
828*4882a593Smuzhiyun 			__func__,  valid_chap_entries);
829*4882a593Smuzhiyun 	*num_entries = valid_chap_entries;
830*4882a593Smuzhiyun 	return ret;
831*4882a593Smuzhiyun }
832*4882a593Smuzhiyun 
__qla4xxx_is_chap_active(struct device * dev,void * data)833*4882a593Smuzhiyun static int __qla4xxx_is_chap_active(struct device *dev, void *data)
834*4882a593Smuzhiyun {
835*4882a593Smuzhiyun 	int ret = 0;
836*4882a593Smuzhiyun 	uint16_t *chap_tbl_idx = (uint16_t *) data;
837*4882a593Smuzhiyun 	struct iscsi_cls_session *cls_session;
838*4882a593Smuzhiyun 	struct iscsi_session *sess;
839*4882a593Smuzhiyun 	struct ddb_entry *ddb_entry;
840*4882a593Smuzhiyun 
841*4882a593Smuzhiyun 	if (!iscsi_is_session_dev(dev))
842*4882a593Smuzhiyun 		goto exit_is_chap_active;
843*4882a593Smuzhiyun 
844*4882a593Smuzhiyun 	cls_session = iscsi_dev_to_session(dev);
845*4882a593Smuzhiyun 	sess = cls_session->dd_data;
846*4882a593Smuzhiyun 	ddb_entry = sess->dd_data;
847*4882a593Smuzhiyun 
848*4882a593Smuzhiyun 	if (iscsi_session_chkready(cls_session))
849*4882a593Smuzhiyun 		goto exit_is_chap_active;
850*4882a593Smuzhiyun 
851*4882a593Smuzhiyun 	if (ddb_entry->chap_tbl_idx == *chap_tbl_idx)
852*4882a593Smuzhiyun 		ret = 1;
853*4882a593Smuzhiyun 
854*4882a593Smuzhiyun exit_is_chap_active:
855*4882a593Smuzhiyun 	return ret;
856*4882a593Smuzhiyun }
857*4882a593Smuzhiyun 
qla4xxx_is_chap_active(struct Scsi_Host * shost,uint16_t chap_tbl_idx)858*4882a593Smuzhiyun static int qla4xxx_is_chap_active(struct Scsi_Host *shost,
859*4882a593Smuzhiyun 				  uint16_t chap_tbl_idx)
860*4882a593Smuzhiyun {
861*4882a593Smuzhiyun 	int ret = 0;
862*4882a593Smuzhiyun 
863*4882a593Smuzhiyun 	ret = device_for_each_child(&shost->shost_gendev, &chap_tbl_idx,
864*4882a593Smuzhiyun 				    __qla4xxx_is_chap_active);
865*4882a593Smuzhiyun 
866*4882a593Smuzhiyun 	return ret;
867*4882a593Smuzhiyun }
868*4882a593Smuzhiyun 
qla4xxx_delete_chap(struct Scsi_Host * shost,uint16_t chap_tbl_idx)869*4882a593Smuzhiyun static int qla4xxx_delete_chap(struct Scsi_Host *shost, uint16_t chap_tbl_idx)
870*4882a593Smuzhiyun {
871*4882a593Smuzhiyun 	struct scsi_qla_host *ha = to_qla_host(shost);
872*4882a593Smuzhiyun 	struct ql4_chap_table *chap_table;
873*4882a593Smuzhiyun 	dma_addr_t chap_dma;
874*4882a593Smuzhiyun 	int max_chap_entries = 0;
875*4882a593Smuzhiyun 	uint32_t offset = 0;
876*4882a593Smuzhiyun 	uint32_t chap_size;
877*4882a593Smuzhiyun 	int ret = 0;
878*4882a593Smuzhiyun 
879*4882a593Smuzhiyun 	chap_table = dma_pool_zalloc(ha->chap_dma_pool, GFP_KERNEL, &chap_dma);
880*4882a593Smuzhiyun 	if (chap_table == NULL)
881*4882a593Smuzhiyun 		return -ENOMEM;
882*4882a593Smuzhiyun 
883*4882a593Smuzhiyun 	if (is_qla80XX(ha))
884*4882a593Smuzhiyun 		max_chap_entries = (ha->hw.flt_chap_size / 2) /
885*4882a593Smuzhiyun 				   sizeof(struct ql4_chap_table);
886*4882a593Smuzhiyun 	else
887*4882a593Smuzhiyun 		max_chap_entries = MAX_CHAP_ENTRIES_40XX;
888*4882a593Smuzhiyun 
889*4882a593Smuzhiyun 	if (chap_tbl_idx > max_chap_entries) {
890*4882a593Smuzhiyun 		ret = -EINVAL;
891*4882a593Smuzhiyun 		goto exit_delete_chap;
892*4882a593Smuzhiyun 	}
893*4882a593Smuzhiyun 
894*4882a593Smuzhiyun 	/* Check if chap index is in use.
895*4882a593Smuzhiyun 	 * If chap is in use don't delet chap entry */
896*4882a593Smuzhiyun 	ret = qla4xxx_is_chap_active(shost, chap_tbl_idx);
897*4882a593Smuzhiyun 	if (ret) {
898*4882a593Smuzhiyun 		ql4_printk(KERN_INFO, ha, "CHAP entry %d is in use, cannot "
899*4882a593Smuzhiyun 			   "delete from flash\n", chap_tbl_idx);
900*4882a593Smuzhiyun 		ret = -EBUSY;
901*4882a593Smuzhiyun 		goto exit_delete_chap;
902*4882a593Smuzhiyun 	}
903*4882a593Smuzhiyun 
904*4882a593Smuzhiyun 	chap_size = sizeof(struct ql4_chap_table);
905*4882a593Smuzhiyun 	if (is_qla40XX(ha))
906*4882a593Smuzhiyun 		offset = FLASH_CHAP_OFFSET | (chap_tbl_idx * chap_size);
907*4882a593Smuzhiyun 	else {
908*4882a593Smuzhiyun 		offset = FLASH_RAW_ACCESS_ADDR + (ha->hw.flt_region_chap << 2);
909*4882a593Smuzhiyun 		/* flt_chap_size is CHAP table size for both ports
910*4882a593Smuzhiyun 		 * so divide it by 2 to calculate the offset for second port
911*4882a593Smuzhiyun 		 */
912*4882a593Smuzhiyun 		if (ha->port_num == 1)
913*4882a593Smuzhiyun 			offset += (ha->hw.flt_chap_size / 2);
914*4882a593Smuzhiyun 		offset += (chap_tbl_idx * chap_size);
915*4882a593Smuzhiyun 	}
916*4882a593Smuzhiyun 
917*4882a593Smuzhiyun 	ret = qla4xxx_get_flash(ha, chap_dma, offset, chap_size);
918*4882a593Smuzhiyun 	if (ret != QLA_SUCCESS) {
919*4882a593Smuzhiyun 		ret = -EINVAL;
920*4882a593Smuzhiyun 		goto exit_delete_chap;
921*4882a593Smuzhiyun 	}
922*4882a593Smuzhiyun 
923*4882a593Smuzhiyun 	DEBUG2(ql4_printk(KERN_INFO, ha, "Chap Cookie: x%x\n",
924*4882a593Smuzhiyun 			  __le16_to_cpu(chap_table->cookie)));
925*4882a593Smuzhiyun 
926*4882a593Smuzhiyun 	if (__le16_to_cpu(chap_table->cookie) != CHAP_VALID_COOKIE) {
927*4882a593Smuzhiyun 		ql4_printk(KERN_ERR, ha, "No valid chap entry found\n");
928*4882a593Smuzhiyun 		goto exit_delete_chap;
929*4882a593Smuzhiyun 	}
930*4882a593Smuzhiyun 
931*4882a593Smuzhiyun 	chap_table->cookie = __constant_cpu_to_le16(0xFFFF);
932*4882a593Smuzhiyun 
933*4882a593Smuzhiyun 	offset = FLASH_CHAP_OFFSET |
934*4882a593Smuzhiyun 			(chap_tbl_idx * sizeof(struct ql4_chap_table));
935*4882a593Smuzhiyun 	ret = qla4xxx_set_flash(ha, chap_dma, offset, chap_size,
936*4882a593Smuzhiyun 				FLASH_OPT_RMW_COMMIT);
937*4882a593Smuzhiyun 	if (ret == QLA_SUCCESS && ha->chap_list) {
938*4882a593Smuzhiyun 		mutex_lock(&ha->chap_sem);
939*4882a593Smuzhiyun 		/* Update ha chap_list cache */
940*4882a593Smuzhiyun 		memcpy((struct ql4_chap_table *)ha->chap_list + chap_tbl_idx,
941*4882a593Smuzhiyun 			chap_table, sizeof(struct ql4_chap_table));
942*4882a593Smuzhiyun 		mutex_unlock(&ha->chap_sem);
943*4882a593Smuzhiyun 	}
944*4882a593Smuzhiyun 	if (ret != QLA_SUCCESS)
945*4882a593Smuzhiyun 		ret =  -EINVAL;
946*4882a593Smuzhiyun 
947*4882a593Smuzhiyun exit_delete_chap:
948*4882a593Smuzhiyun 	dma_pool_free(ha->chap_dma_pool, chap_table, chap_dma);
949*4882a593Smuzhiyun 	return ret;
950*4882a593Smuzhiyun }
951*4882a593Smuzhiyun 
952*4882a593Smuzhiyun /**
953*4882a593Smuzhiyun  * qla4xxx_set_chap_entry - Make chap entry with given information
954*4882a593Smuzhiyun  * @shost: pointer to host
955*4882a593Smuzhiyun  * @data: chap info - credentials, index and type to make chap entry
956*4882a593Smuzhiyun  * @len: length of data
957*4882a593Smuzhiyun  *
958*4882a593Smuzhiyun  * Add or update chap entry with the given information
959*4882a593Smuzhiyun  **/
qla4xxx_set_chap_entry(struct Scsi_Host * shost,void * data,int len)960*4882a593Smuzhiyun static int qla4xxx_set_chap_entry(struct Scsi_Host *shost, void *data, int len)
961*4882a593Smuzhiyun {
962*4882a593Smuzhiyun 	struct scsi_qla_host *ha = to_qla_host(shost);
963*4882a593Smuzhiyun 	struct iscsi_chap_rec chap_rec;
964*4882a593Smuzhiyun 	struct ql4_chap_table *chap_entry = NULL;
965*4882a593Smuzhiyun 	struct iscsi_param_info *param_info;
966*4882a593Smuzhiyun 	struct nlattr *attr;
967*4882a593Smuzhiyun 	int max_chap_entries = 0;
968*4882a593Smuzhiyun 	int type;
969*4882a593Smuzhiyun 	int rem = len;
970*4882a593Smuzhiyun 	int rc = 0;
971*4882a593Smuzhiyun 	int size;
972*4882a593Smuzhiyun 
973*4882a593Smuzhiyun 	memset(&chap_rec, 0, sizeof(chap_rec));
974*4882a593Smuzhiyun 
975*4882a593Smuzhiyun 	nla_for_each_attr(attr, data, len, rem) {
976*4882a593Smuzhiyun 		param_info = nla_data(attr);
977*4882a593Smuzhiyun 
978*4882a593Smuzhiyun 		switch (param_info->param) {
979*4882a593Smuzhiyun 		case ISCSI_CHAP_PARAM_INDEX:
980*4882a593Smuzhiyun 			chap_rec.chap_tbl_idx = *(uint16_t *)param_info->value;
981*4882a593Smuzhiyun 			break;
982*4882a593Smuzhiyun 		case ISCSI_CHAP_PARAM_CHAP_TYPE:
983*4882a593Smuzhiyun 			chap_rec.chap_type = param_info->value[0];
984*4882a593Smuzhiyun 			break;
985*4882a593Smuzhiyun 		case ISCSI_CHAP_PARAM_USERNAME:
986*4882a593Smuzhiyun 			size = min_t(size_t, sizeof(chap_rec.username),
987*4882a593Smuzhiyun 				     param_info->len);
988*4882a593Smuzhiyun 			memcpy(chap_rec.username, param_info->value, size);
989*4882a593Smuzhiyun 			break;
990*4882a593Smuzhiyun 		case ISCSI_CHAP_PARAM_PASSWORD:
991*4882a593Smuzhiyun 			size = min_t(size_t, sizeof(chap_rec.password),
992*4882a593Smuzhiyun 				     param_info->len);
993*4882a593Smuzhiyun 			memcpy(chap_rec.password, param_info->value, size);
994*4882a593Smuzhiyun 			break;
995*4882a593Smuzhiyun 		case ISCSI_CHAP_PARAM_PASSWORD_LEN:
996*4882a593Smuzhiyun 			chap_rec.password_length = param_info->value[0];
997*4882a593Smuzhiyun 			break;
998*4882a593Smuzhiyun 		default:
999*4882a593Smuzhiyun 			ql4_printk(KERN_ERR, ha,
1000*4882a593Smuzhiyun 				   "%s: No such sysfs attribute\n", __func__);
1001*4882a593Smuzhiyun 			rc = -ENOSYS;
1002*4882a593Smuzhiyun 			goto exit_set_chap;
1003*4882a593Smuzhiyun 		}
1004*4882a593Smuzhiyun 	}
1005*4882a593Smuzhiyun 
1006*4882a593Smuzhiyun 	if (chap_rec.chap_type == CHAP_TYPE_IN)
1007*4882a593Smuzhiyun 		type = BIDI_CHAP;
1008*4882a593Smuzhiyun 	else
1009*4882a593Smuzhiyun 		type = LOCAL_CHAP;
1010*4882a593Smuzhiyun 
1011*4882a593Smuzhiyun 	if (is_qla80XX(ha))
1012*4882a593Smuzhiyun 		max_chap_entries = (ha->hw.flt_chap_size / 2) /
1013*4882a593Smuzhiyun 				   sizeof(struct ql4_chap_table);
1014*4882a593Smuzhiyun 	else
1015*4882a593Smuzhiyun 		max_chap_entries = MAX_CHAP_ENTRIES_40XX;
1016*4882a593Smuzhiyun 
1017*4882a593Smuzhiyun 	mutex_lock(&ha->chap_sem);
1018*4882a593Smuzhiyun 	if (chap_rec.chap_tbl_idx < max_chap_entries) {
1019*4882a593Smuzhiyun 		rc = qla4xxx_get_chap_by_index(ha, chap_rec.chap_tbl_idx,
1020*4882a593Smuzhiyun 					       &chap_entry);
1021*4882a593Smuzhiyun 		if (!rc) {
1022*4882a593Smuzhiyun 			if (!(type == qla4xxx_get_chap_type(chap_entry))) {
1023*4882a593Smuzhiyun 				ql4_printk(KERN_INFO, ha,
1024*4882a593Smuzhiyun 					   "Type mismatch for CHAP entry %d\n",
1025*4882a593Smuzhiyun 					   chap_rec.chap_tbl_idx);
1026*4882a593Smuzhiyun 				rc = -EINVAL;
1027*4882a593Smuzhiyun 				goto exit_unlock_chap;
1028*4882a593Smuzhiyun 			}
1029*4882a593Smuzhiyun 
1030*4882a593Smuzhiyun 			/* If chap index is in use then don't modify it */
1031*4882a593Smuzhiyun 			rc = qla4xxx_is_chap_active(shost,
1032*4882a593Smuzhiyun 						    chap_rec.chap_tbl_idx);
1033*4882a593Smuzhiyun 			if (rc) {
1034*4882a593Smuzhiyun 				ql4_printk(KERN_INFO, ha,
1035*4882a593Smuzhiyun 					   "CHAP entry %d is in use\n",
1036*4882a593Smuzhiyun 					   chap_rec.chap_tbl_idx);
1037*4882a593Smuzhiyun 				rc = -EBUSY;
1038*4882a593Smuzhiyun 				goto exit_unlock_chap;
1039*4882a593Smuzhiyun 			}
1040*4882a593Smuzhiyun 		}
1041*4882a593Smuzhiyun 	} else {
1042*4882a593Smuzhiyun 		rc = qla4xxx_find_free_chap_index(ha, &chap_rec.chap_tbl_idx);
1043*4882a593Smuzhiyun 		if (rc) {
1044*4882a593Smuzhiyun 			ql4_printk(KERN_INFO, ha, "CHAP entry not available\n");
1045*4882a593Smuzhiyun 			rc = -EBUSY;
1046*4882a593Smuzhiyun 			goto exit_unlock_chap;
1047*4882a593Smuzhiyun 		}
1048*4882a593Smuzhiyun 	}
1049*4882a593Smuzhiyun 
1050*4882a593Smuzhiyun 	rc = qla4xxx_set_chap(ha, chap_rec.username, chap_rec.password,
1051*4882a593Smuzhiyun 			      chap_rec.chap_tbl_idx, type);
1052*4882a593Smuzhiyun 
1053*4882a593Smuzhiyun exit_unlock_chap:
1054*4882a593Smuzhiyun 	mutex_unlock(&ha->chap_sem);
1055*4882a593Smuzhiyun 
1056*4882a593Smuzhiyun exit_set_chap:
1057*4882a593Smuzhiyun 	return rc;
1058*4882a593Smuzhiyun }
1059*4882a593Smuzhiyun 
1060*4882a593Smuzhiyun 
qla4xxx_get_host_stats(struct Scsi_Host * shost,char * buf,int len)1061*4882a593Smuzhiyun static int qla4xxx_get_host_stats(struct Scsi_Host *shost, char *buf, int len)
1062*4882a593Smuzhiyun {
1063*4882a593Smuzhiyun 	struct scsi_qla_host *ha = to_qla_host(shost);
1064*4882a593Smuzhiyun 	struct iscsi_offload_host_stats *host_stats = NULL;
1065*4882a593Smuzhiyun 	int host_stats_size;
1066*4882a593Smuzhiyun 	int ret = 0;
1067*4882a593Smuzhiyun 	int ddb_idx = 0;
1068*4882a593Smuzhiyun 	struct ql_iscsi_stats *ql_iscsi_stats = NULL;
1069*4882a593Smuzhiyun 	int stats_size;
1070*4882a593Smuzhiyun 	dma_addr_t iscsi_stats_dma;
1071*4882a593Smuzhiyun 
1072*4882a593Smuzhiyun 	DEBUG2(ql4_printk(KERN_INFO, ha, "Func: %s\n", __func__));
1073*4882a593Smuzhiyun 
1074*4882a593Smuzhiyun 	host_stats_size = sizeof(struct iscsi_offload_host_stats);
1075*4882a593Smuzhiyun 
1076*4882a593Smuzhiyun 	if (host_stats_size != len) {
1077*4882a593Smuzhiyun 		ql4_printk(KERN_INFO, ha, "%s: host_stats size mismatch expected = %d, is = %d\n",
1078*4882a593Smuzhiyun 			   __func__, len, host_stats_size);
1079*4882a593Smuzhiyun 		ret = -EINVAL;
1080*4882a593Smuzhiyun 		goto exit_host_stats;
1081*4882a593Smuzhiyun 	}
1082*4882a593Smuzhiyun 	host_stats = (struct iscsi_offload_host_stats *)buf;
1083*4882a593Smuzhiyun 
1084*4882a593Smuzhiyun 	if (!buf) {
1085*4882a593Smuzhiyun 		ret = -ENOMEM;
1086*4882a593Smuzhiyun 		goto exit_host_stats;
1087*4882a593Smuzhiyun 	}
1088*4882a593Smuzhiyun 
1089*4882a593Smuzhiyun 	stats_size = PAGE_ALIGN(sizeof(struct ql_iscsi_stats));
1090*4882a593Smuzhiyun 
1091*4882a593Smuzhiyun 	ql_iscsi_stats = dma_alloc_coherent(&ha->pdev->dev, stats_size,
1092*4882a593Smuzhiyun 					    &iscsi_stats_dma, GFP_KERNEL);
1093*4882a593Smuzhiyun 	if (!ql_iscsi_stats) {
1094*4882a593Smuzhiyun 		ql4_printk(KERN_ERR, ha,
1095*4882a593Smuzhiyun 			   "Unable to allocate memory for iscsi stats\n");
1096*4882a593Smuzhiyun 		ret = -ENOMEM;
1097*4882a593Smuzhiyun 		goto exit_host_stats;
1098*4882a593Smuzhiyun 	}
1099*4882a593Smuzhiyun 
1100*4882a593Smuzhiyun 	ret =  qla4xxx_get_mgmt_data(ha, ddb_idx, stats_size,
1101*4882a593Smuzhiyun 				     iscsi_stats_dma);
1102*4882a593Smuzhiyun 	if (ret != QLA_SUCCESS) {
1103*4882a593Smuzhiyun 		ql4_printk(KERN_ERR, ha,
1104*4882a593Smuzhiyun 			   "Unable to retrieve iscsi stats\n");
1105*4882a593Smuzhiyun 		ret = -EIO;
1106*4882a593Smuzhiyun 		goto exit_host_stats;
1107*4882a593Smuzhiyun 	}
1108*4882a593Smuzhiyun 	host_stats->mactx_frames = le64_to_cpu(ql_iscsi_stats->mac_tx_frames);
1109*4882a593Smuzhiyun 	host_stats->mactx_bytes = le64_to_cpu(ql_iscsi_stats->mac_tx_bytes);
1110*4882a593Smuzhiyun 	host_stats->mactx_multicast_frames =
1111*4882a593Smuzhiyun 			le64_to_cpu(ql_iscsi_stats->mac_tx_multicast_frames);
1112*4882a593Smuzhiyun 	host_stats->mactx_broadcast_frames =
1113*4882a593Smuzhiyun 			le64_to_cpu(ql_iscsi_stats->mac_tx_broadcast_frames);
1114*4882a593Smuzhiyun 	host_stats->mactx_pause_frames =
1115*4882a593Smuzhiyun 			le64_to_cpu(ql_iscsi_stats->mac_tx_pause_frames);
1116*4882a593Smuzhiyun 	host_stats->mactx_control_frames =
1117*4882a593Smuzhiyun 			le64_to_cpu(ql_iscsi_stats->mac_tx_control_frames);
1118*4882a593Smuzhiyun 	host_stats->mactx_deferral =
1119*4882a593Smuzhiyun 			le64_to_cpu(ql_iscsi_stats->mac_tx_deferral);
1120*4882a593Smuzhiyun 	host_stats->mactx_excess_deferral =
1121*4882a593Smuzhiyun 			le64_to_cpu(ql_iscsi_stats->mac_tx_excess_deferral);
1122*4882a593Smuzhiyun 	host_stats->mactx_late_collision =
1123*4882a593Smuzhiyun 			le64_to_cpu(ql_iscsi_stats->mac_tx_late_collision);
1124*4882a593Smuzhiyun 	host_stats->mactx_abort	= le64_to_cpu(ql_iscsi_stats->mac_tx_abort);
1125*4882a593Smuzhiyun 	host_stats->mactx_single_collision =
1126*4882a593Smuzhiyun 			le64_to_cpu(ql_iscsi_stats->mac_tx_single_collision);
1127*4882a593Smuzhiyun 	host_stats->mactx_multiple_collision =
1128*4882a593Smuzhiyun 			le64_to_cpu(ql_iscsi_stats->mac_tx_multiple_collision);
1129*4882a593Smuzhiyun 	host_stats->mactx_collision =
1130*4882a593Smuzhiyun 			le64_to_cpu(ql_iscsi_stats->mac_tx_collision);
1131*4882a593Smuzhiyun 	host_stats->mactx_frames_dropped =
1132*4882a593Smuzhiyun 			le64_to_cpu(ql_iscsi_stats->mac_tx_frames_dropped);
1133*4882a593Smuzhiyun 	host_stats->mactx_jumbo_frames =
1134*4882a593Smuzhiyun 			le64_to_cpu(ql_iscsi_stats->mac_tx_jumbo_frames);
1135*4882a593Smuzhiyun 	host_stats->macrx_frames = le64_to_cpu(ql_iscsi_stats->mac_rx_frames);
1136*4882a593Smuzhiyun 	host_stats->macrx_bytes = le64_to_cpu(ql_iscsi_stats->mac_rx_bytes);
1137*4882a593Smuzhiyun 	host_stats->macrx_unknown_control_frames =
1138*4882a593Smuzhiyun 		le64_to_cpu(ql_iscsi_stats->mac_rx_unknown_control_frames);
1139*4882a593Smuzhiyun 	host_stats->macrx_pause_frames =
1140*4882a593Smuzhiyun 			le64_to_cpu(ql_iscsi_stats->mac_rx_pause_frames);
1141*4882a593Smuzhiyun 	host_stats->macrx_control_frames =
1142*4882a593Smuzhiyun 			le64_to_cpu(ql_iscsi_stats->mac_rx_control_frames);
1143*4882a593Smuzhiyun 	host_stats->macrx_dribble =
1144*4882a593Smuzhiyun 			le64_to_cpu(ql_iscsi_stats->mac_rx_dribble);
1145*4882a593Smuzhiyun 	host_stats->macrx_frame_length_error =
1146*4882a593Smuzhiyun 			le64_to_cpu(ql_iscsi_stats->mac_rx_frame_length_error);
1147*4882a593Smuzhiyun 	host_stats->macrx_jabber = le64_to_cpu(ql_iscsi_stats->mac_rx_jabber);
1148*4882a593Smuzhiyun 	host_stats->macrx_carrier_sense_error =
1149*4882a593Smuzhiyun 		le64_to_cpu(ql_iscsi_stats->mac_rx_carrier_sense_error);
1150*4882a593Smuzhiyun 	host_stats->macrx_frame_discarded =
1151*4882a593Smuzhiyun 			le64_to_cpu(ql_iscsi_stats->mac_rx_frame_discarded);
1152*4882a593Smuzhiyun 	host_stats->macrx_frames_dropped =
1153*4882a593Smuzhiyun 			le64_to_cpu(ql_iscsi_stats->mac_rx_frames_dropped);
1154*4882a593Smuzhiyun 	host_stats->mac_crc_error = le64_to_cpu(ql_iscsi_stats->mac_crc_error);
1155*4882a593Smuzhiyun 	host_stats->mac_encoding_error =
1156*4882a593Smuzhiyun 			le64_to_cpu(ql_iscsi_stats->mac_encoding_error);
1157*4882a593Smuzhiyun 	host_stats->macrx_length_error_large =
1158*4882a593Smuzhiyun 			le64_to_cpu(ql_iscsi_stats->mac_rx_length_error_large);
1159*4882a593Smuzhiyun 	host_stats->macrx_length_error_small =
1160*4882a593Smuzhiyun 			le64_to_cpu(ql_iscsi_stats->mac_rx_length_error_small);
1161*4882a593Smuzhiyun 	host_stats->macrx_multicast_frames =
1162*4882a593Smuzhiyun 			le64_to_cpu(ql_iscsi_stats->mac_rx_multicast_frames);
1163*4882a593Smuzhiyun 	host_stats->macrx_broadcast_frames =
1164*4882a593Smuzhiyun 			le64_to_cpu(ql_iscsi_stats->mac_rx_broadcast_frames);
1165*4882a593Smuzhiyun 	host_stats->iptx_packets = le64_to_cpu(ql_iscsi_stats->ip_tx_packets);
1166*4882a593Smuzhiyun 	host_stats->iptx_bytes = le64_to_cpu(ql_iscsi_stats->ip_tx_bytes);
1167*4882a593Smuzhiyun 	host_stats->iptx_fragments =
1168*4882a593Smuzhiyun 			le64_to_cpu(ql_iscsi_stats->ip_tx_fragments);
1169*4882a593Smuzhiyun 	host_stats->iprx_packets = le64_to_cpu(ql_iscsi_stats->ip_rx_packets);
1170*4882a593Smuzhiyun 	host_stats->iprx_bytes = le64_to_cpu(ql_iscsi_stats->ip_rx_bytes);
1171*4882a593Smuzhiyun 	host_stats->iprx_fragments =
1172*4882a593Smuzhiyun 			le64_to_cpu(ql_iscsi_stats->ip_rx_fragments);
1173*4882a593Smuzhiyun 	host_stats->ip_datagram_reassembly =
1174*4882a593Smuzhiyun 			le64_to_cpu(ql_iscsi_stats->ip_datagram_reassembly);
1175*4882a593Smuzhiyun 	host_stats->ip_invalid_address_error =
1176*4882a593Smuzhiyun 			le64_to_cpu(ql_iscsi_stats->ip_invalid_address_error);
1177*4882a593Smuzhiyun 	host_stats->ip_error_packets =
1178*4882a593Smuzhiyun 			le64_to_cpu(ql_iscsi_stats->ip_error_packets);
1179*4882a593Smuzhiyun 	host_stats->ip_fragrx_overlap =
1180*4882a593Smuzhiyun 			le64_to_cpu(ql_iscsi_stats->ip_fragrx_overlap);
1181*4882a593Smuzhiyun 	host_stats->ip_fragrx_outoforder =
1182*4882a593Smuzhiyun 			le64_to_cpu(ql_iscsi_stats->ip_fragrx_outoforder);
1183*4882a593Smuzhiyun 	host_stats->ip_datagram_reassembly_timeout =
1184*4882a593Smuzhiyun 		le64_to_cpu(ql_iscsi_stats->ip_datagram_reassembly_timeout);
1185*4882a593Smuzhiyun 	host_stats->ipv6tx_packets =
1186*4882a593Smuzhiyun 			le64_to_cpu(ql_iscsi_stats->ipv6_tx_packets);
1187*4882a593Smuzhiyun 	host_stats->ipv6tx_bytes = le64_to_cpu(ql_iscsi_stats->ipv6_tx_bytes);
1188*4882a593Smuzhiyun 	host_stats->ipv6tx_fragments =
1189*4882a593Smuzhiyun 			le64_to_cpu(ql_iscsi_stats->ipv6_tx_fragments);
1190*4882a593Smuzhiyun 	host_stats->ipv6rx_packets =
1191*4882a593Smuzhiyun 			le64_to_cpu(ql_iscsi_stats->ipv6_rx_packets);
1192*4882a593Smuzhiyun 	host_stats->ipv6rx_bytes = le64_to_cpu(ql_iscsi_stats->ipv6_rx_bytes);
1193*4882a593Smuzhiyun 	host_stats->ipv6rx_fragments =
1194*4882a593Smuzhiyun 			le64_to_cpu(ql_iscsi_stats->ipv6_rx_fragments);
1195*4882a593Smuzhiyun 	host_stats->ipv6_datagram_reassembly =
1196*4882a593Smuzhiyun 			le64_to_cpu(ql_iscsi_stats->ipv6_datagram_reassembly);
1197*4882a593Smuzhiyun 	host_stats->ipv6_invalid_address_error =
1198*4882a593Smuzhiyun 		le64_to_cpu(ql_iscsi_stats->ipv6_invalid_address_error);
1199*4882a593Smuzhiyun 	host_stats->ipv6_error_packets =
1200*4882a593Smuzhiyun 			le64_to_cpu(ql_iscsi_stats->ipv6_error_packets);
1201*4882a593Smuzhiyun 	host_stats->ipv6_fragrx_overlap =
1202*4882a593Smuzhiyun 			le64_to_cpu(ql_iscsi_stats->ipv6_fragrx_overlap);
1203*4882a593Smuzhiyun 	host_stats->ipv6_fragrx_outoforder =
1204*4882a593Smuzhiyun 			le64_to_cpu(ql_iscsi_stats->ipv6_fragrx_outoforder);
1205*4882a593Smuzhiyun 	host_stats->ipv6_datagram_reassembly_timeout =
1206*4882a593Smuzhiyun 		le64_to_cpu(ql_iscsi_stats->ipv6_datagram_reassembly_timeout);
1207*4882a593Smuzhiyun 	host_stats->tcptx_segments =
1208*4882a593Smuzhiyun 			le64_to_cpu(ql_iscsi_stats->tcp_tx_segments);
1209*4882a593Smuzhiyun 	host_stats->tcptx_bytes	= le64_to_cpu(ql_iscsi_stats->tcp_tx_bytes);
1210*4882a593Smuzhiyun 	host_stats->tcprx_segments =
1211*4882a593Smuzhiyun 			le64_to_cpu(ql_iscsi_stats->tcp_rx_segments);
1212*4882a593Smuzhiyun 	host_stats->tcprx_byte = le64_to_cpu(ql_iscsi_stats->tcp_rx_byte);
1213*4882a593Smuzhiyun 	host_stats->tcp_duplicate_ack_retx =
1214*4882a593Smuzhiyun 			le64_to_cpu(ql_iscsi_stats->tcp_duplicate_ack_retx);
1215*4882a593Smuzhiyun 	host_stats->tcp_retx_timer_expired =
1216*4882a593Smuzhiyun 			le64_to_cpu(ql_iscsi_stats->tcp_retx_timer_expired);
1217*4882a593Smuzhiyun 	host_stats->tcprx_duplicate_ack	=
1218*4882a593Smuzhiyun 			le64_to_cpu(ql_iscsi_stats->tcp_rx_duplicate_ack);
1219*4882a593Smuzhiyun 	host_stats->tcprx_pure_ackr =
1220*4882a593Smuzhiyun 			le64_to_cpu(ql_iscsi_stats->tcp_rx_pure_ackr);
1221*4882a593Smuzhiyun 	host_stats->tcptx_delayed_ack =
1222*4882a593Smuzhiyun 			le64_to_cpu(ql_iscsi_stats->tcp_tx_delayed_ack);
1223*4882a593Smuzhiyun 	host_stats->tcptx_pure_ack =
1224*4882a593Smuzhiyun 			le64_to_cpu(ql_iscsi_stats->tcp_tx_pure_ack);
1225*4882a593Smuzhiyun 	host_stats->tcprx_segment_error =
1226*4882a593Smuzhiyun 			le64_to_cpu(ql_iscsi_stats->tcp_rx_segment_error);
1227*4882a593Smuzhiyun 	host_stats->tcprx_segment_outoforder =
1228*4882a593Smuzhiyun 			le64_to_cpu(ql_iscsi_stats->tcp_rx_segment_outoforder);
1229*4882a593Smuzhiyun 	host_stats->tcprx_window_probe =
1230*4882a593Smuzhiyun 			le64_to_cpu(ql_iscsi_stats->tcp_rx_window_probe);
1231*4882a593Smuzhiyun 	host_stats->tcprx_window_update =
1232*4882a593Smuzhiyun 			le64_to_cpu(ql_iscsi_stats->tcp_rx_window_update);
1233*4882a593Smuzhiyun 	host_stats->tcptx_window_probe_persist =
1234*4882a593Smuzhiyun 		le64_to_cpu(ql_iscsi_stats->tcp_tx_window_probe_persist);
1235*4882a593Smuzhiyun 	host_stats->ecc_error_correction =
1236*4882a593Smuzhiyun 			le64_to_cpu(ql_iscsi_stats->ecc_error_correction);
1237*4882a593Smuzhiyun 	host_stats->iscsi_pdu_tx = le64_to_cpu(ql_iscsi_stats->iscsi_pdu_tx);
1238*4882a593Smuzhiyun 	host_stats->iscsi_data_bytes_tx =
1239*4882a593Smuzhiyun 			le64_to_cpu(ql_iscsi_stats->iscsi_data_bytes_tx);
1240*4882a593Smuzhiyun 	host_stats->iscsi_pdu_rx = le64_to_cpu(ql_iscsi_stats->iscsi_pdu_rx);
1241*4882a593Smuzhiyun 	host_stats->iscsi_data_bytes_rx	=
1242*4882a593Smuzhiyun 			le64_to_cpu(ql_iscsi_stats->iscsi_data_bytes_rx);
1243*4882a593Smuzhiyun 	host_stats->iscsi_io_completed =
1244*4882a593Smuzhiyun 			le64_to_cpu(ql_iscsi_stats->iscsi_io_completed);
1245*4882a593Smuzhiyun 	host_stats->iscsi_unexpected_io_rx =
1246*4882a593Smuzhiyun 			le64_to_cpu(ql_iscsi_stats->iscsi_unexpected_io_rx);
1247*4882a593Smuzhiyun 	host_stats->iscsi_format_error =
1248*4882a593Smuzhiyun 			le64_to_cpu(ql_iscsi_stats->iscsi_format_error);
1249*4882a593Smuzhiyun 	host_stats->iscsi_hdr_digest_error =
1250*4882a593Smuzhiyun 			le64_to_cpu(ql_iscsi_stats->iscsi_hdr_digest_error);
1251*4882a593Smuzhiyun 	host_stats->iscsi_data_digest_error =
1252*4882a593Smuzhiyun 			le64_to_cpu(ql_iscsi_stats->iscsi_data_digest_error);
1253*4882a593Smuzhiyun 	host_stats->iscsi_sequence_error =
1254*4882a593Smuzhiyun 			le64_to_cpu(ql_iscsi_stats->iscsi_sequence_error);
1255*4882a593Smuzhiyun exit_host_stats:
1256*4882a593Smuzhiyun 	if (ql_iscsi_stats)
1257*4882a593Smuzhiyun 		dma_free_coherent(&ha->pdev->dev, stats_size,
1258*4882a593Smuzhiyun 				  ql_iscsi_stats, iscsi_stats_dma);
1259*4882a593Smuzhiyun 
1260*4882a593Smuzhiyun 	ql4_printk(KERN_INFO, ha, "%s: Get host stats done\n",
1261*4882a593Smuzhiyun 		   __func__);
1262*4882a593Smuzhiyun 	return ret;
1263*4882a593Smuzhiyun }
1264*4882a593Smuzhiyun 
qla4xxx_get_iface_param(struct iscsi_iface * iface,enum iscsi_param_type param_type,int param,char * buf)1265*4882a593Smuzhiyun static int qla4xxx_get_iface_param(struct iscsi_iface *iface,
1266*4882a593Smuzhiyun 				   enum iscsi_param_type param_type,
1267*4882a593Smuzhiyun 				   int param, char *buf)
1268*4882a593Smuzhiyun {
1269*4882a593Smuzhiyun 	struct Scsi_Host *shost = iscsi_iface_to_shost(iface);
1270*4882a593Smuzhiyun 	struct scsi_qla_host *ha = to_qla_host(shost);
1271*4882a593Smuzhiyun 	int ival;
1272*4882a593Smuzhiyun 	char *pval = NULL;
1273*4882a593Smuzhiyun 	int len = -ENOSYS;
1274*4882a593Smuzhiyun 
1275*4882a593Smuzhiyun 	if (param_type == ISCSI_NET_PARAM) {
1276*4882a593Smuzhiyun 		switch (param) {
1277*4882a593Smuzhiyun 		case ISCSI_NET_PARAM_IPV4_ADDR:
1278*4882a593Smuzhiyun 			len = sprintf(buf, "%pI4\n", &ha->ip_config.ip_address);
1279*4882a593Smuzhiyun 			break;
1280*4882a593Smuzhiyun 		case ISCSI_NET_PARAM_IPV4_SUBNET:
1281*4882a593Smuzhiyun 			len = sprintf(buf, "%pI4\n",
1282*4882a593Smuzhiyun 				      &ha->ip_config.subnet_mask);
1283*4882a593Smuzhiyun 			break;
1284*4882a593Smuzhiyun 		case ISCSI_NET_PARAM_IPV4_GW:
1285*4882a593Smuzhiyun 			len = sprintf(buf, "%pI4\n", &ha->ip_config.gateway);
1286*4882a593Smuzhiyun 			break;
1287*4882a593Smuzhiyun 		case ISCSI_NET_PARAM_IFACE_ENABLE:
1288*4882a593Smuzhiyun 			if (iface->iface_type == ISCSI_IFACE_TYPE_IPV4) {
1289*4882a593Smuzhiyun 				OP_STATE(ha->ip_config.ipv4_options,
1290*4882a593Smuzhiyun 					 IPOPT_IPV4_PROTOCOL_ENABLE, pval);
1291*4882a593Smuzhiyun 			} else {
1292*4882a593Smuzhiyun 				OP_STATE(ha->ip_config.ipv6_options,
1293*4882a593Smuzhiyun 					 IPV6_OPT_IPV6_PROTOCOL_ENABLE, pval);
1294*4882a593Smuzhiyun 			}
1295*4882a593Smuzhiyun 
1296*4882a593Smuzhiyun 			len = sprintf(buf, "%s\n", pval);
1297*4882a593Smuzhiyun 			break;
1298*4882a593Smuzhiyun 		case ISCSI_NET_PARAM_IPV4_BOOTPROTO:
1299*4882a593Smuzhiyun 			len = sprintf(buf, "%s\n",
1300*4882a593Smuzhiyun 				      (ha->ip_config.tcp_options &
1301*4882a593Smuzhiyun 				       TCPOPT_DHCP_ENABLE) ?
1302*4882a593Smuzhiyun 				      "dhcp" : "static");
1303*4882a593Smuzhiyun 			break;
1304*4882a593Smuzhiyun 		case ISCSI_NET_PARAM_IPV6_ADDR:
1305*4882a593Smuzhiyun 			if (iface->iface_num == 0)
1306*4882a593Smuzhiyun 				len = sprintf(buf, "%pI6\n",
1307*4882a593Smuzhiyun 					      &ha->ip_config.ipv6_addr0);
1308*4882a593Smuzhiyun 			if (iface->iface_num == 1)
1309*4882a593Smuzhiyun 				len = sprintf(buf, "%pI6\n",
1310*4882a593Smuzhiyun 					      &ha->ip_config.ipv6_addr1);
1311*4882a593Smuzhiyun 			break;
1312*4882a593Smuzhiyun 		case ISCSI_NET_PARAM_IPV6_LINKLOCAL:
1313*4882a593Smuzhiyun 			len = sprintf(buf, "%pI6\n",
1314*4882a593Smuzhiyun 				      &ha->ip_config.ipv6_link_local_addr);
1315*4882a593Smuzhiyun 			break;
1316*4882a593Smuzhiyun 		case ISCSI_NET_PARAM_IPV6_ROUTER:
1317*4882a593Smuzhiyun 			len = sprintf(buf, "%pI6\n",
1318*4882a593Smuzhiyun 				      &ha->ip_config.ipv6_default_router_addr);
1319*4882a593Smuzhiyun 			break;
1320*4882a593Smuzhiyun 		case ISCSI_NET_PARAM_IPV6_ADDR_AUTOCFG:
1321*4882a593Smuzhiyun 			pval = (ha->ip_config.ipv6_addl_options &
1322*4882a593Smuzhiyun 				IPV6_ADDOPT_NEIGHBOR_DISCOVERY_ADDR_ENABLE) ?
1323*4882a593Smuzhiyun 				"nd" : "static";
1324*4882a593Smuzhiyun 
1325*4882a593Smuzhiyun 			len = sprintf(buf, "%s\n", pval);
1326*4882a593Smuzhiyun 			break;
1327*4882a593Smuzhiyun 		case ISCSI_NET_PARAM_IPV6_LINKLOCAL_AUTOCFG:
1328*4882a593Smuzhiyun 			pval = (ha->ip_config.ipv6_addl_options &
1329*4882a593Smuzhiyun 				IPV6_ADDOPT_AUTOCONFIG_LINK_LOCAL_ADDR) ?
1330*4882a593Smuzhiyun 				"auto" : "static";
1331*4882a593Smuzhiyun 
1332*4882a593Smuzhiyun 			len = sprintf(buf, "%s\n", pval);
1333*4882a593Smuzhiyun 			break;
1334*4882a593Smuzhiyun 		case ISCSI_NET_PARAM_VLAN_ID:
1335*4882a593Smuzhiyun 			if (iface->iface_type == ISCSI_IFACE_TYPE_IPV4)
1336*4882a593Smuzhiyun 				ival = ha->ip_config.ipv4_vlan_tag &
1337*4882a593Smuzhiyun 				       ISCSI_MAX_VLAN_ID;
1338*4882a593Smuzhiyun 			else
1339*4882a593Smuzhiyun 				ival = ha->ip_config.ipv6_vlan_tag &
1340*4882a593Smuzhiyun 				       ISCSI_MAX_VLAN_ID;
1341*4882a593Smuzhiyun 
1342*4882a593Smuzhiyun 			len = sprintf(buf, "%d\n", ival);
1343*4882a593Smuzhiyun 			break;
1344*4882a593Smuzhiyun 		case ISCSI_NET_PARAM_VLAN_PRIORITY:
1345*4882a593Smuzhiyun 			if (iface->iface_type == ISCSI_IFACE_TYPE_IPV4)
1346*4882a593Smuzhiyun 				ival = (ha->ip_config.ipv4_vlan_tag >> 13) &
1347*4882a593Smuzhiyun 				       ISCSI_MAX_VLAN_PRIORITY;
1348*4882a593Smuzhiyun 			else
1349*4882a593Smuzhiyun 				ival = (ha->ip_config.ipv6_vlan_tag >> 13) &
1350*4882a593Smuzhiyun 				       ISCSI_MAX_VLAN_PRIORITY;
1351*4882a593Smuzhiyun 
1352*4882a593Smuzhiyun 			len = sprintf(buf, "%d\n", ival);
1353*4882a593Smuzhiyun 			break;
1354*4882a593Smuzhiyun 		case ISCSI_NET_PARAM_VLAN_ENABLED:
1355*4882a593Smuzhiyun 			if (iface->iface_type == ISCSI_IFACE_TYPE_IPV4) {
1356*4882a593Smuzhiyun 				OP_STATE(ha->ip_config.ipv4_options,
1357*4882a593Smuzhiyun 					 IPOPT_VLAN_TAGGING_ENABLE, pval);
1358*4882a593Smuzhiyun 			} else {
1359*4882a593Smuzhiyun 				OP_STATE(ha->ip_config.ipv6_options,
1360*4882a593Smuzhiyun 					 IPV6_OPT_VLAN_TAGGING_ENABLE, pval);
1361*4882a593Smuzhiyun 			}
1362*4882a593Smuzhiyun 			len = sprintf(buf, "%s\n", pval);
1363*4882a593Smuzhiyun 			break;
1364*4882a593Smuzhiyun 		case ISCSI_NET_PARAM_MTU:
1365*4882a593Smuzhiyun 			len = sprintf(buf, "%d\n", ha->ip_config.eth_mtu_size);
1366*4882a593Smuzhiyun 			break;
1367*4882a593Smuzhiyun 		case ISCSI_NET_PARAM_PORT:
1368*4882a593Smuzhiyun 			if (iface->iface_type == ISCSI_IFACE_TYPE_IPV4)
1369*4882a593Smuzhiyun 				len = sprintf(buf, "%d\n",
1370*4882a593Smuzhiyun 					      ha->ip_config.ipv4_port);
1371*4882a593Smuzhiyun 			else
1372*4882a593Smuzhiyun 				len = sprintf(buf, "%d\n",
1373*4882a593Smuzhiyun 					      ha->ip_config.ipv6_port);
1374*4882a593Smuzhiyun 			break;
1375*4882a593Smuzhiyun 		case ISCSI_NET_PARAM_IPADDR_STATE:
1376*4882a593Smuzhiyun 			if (iface->iface_type == ISCSI_IFACE_TYPE_IPV4) {
1377*4882a593Smuzhiyun 				pval = iscsi_get_ipaddress_state_name(
1378*4882a593Smuzhiyun 						ha->ip_config.ipv4_addr_state);
1379*4882a593Smuzhiyun 			} else {
1380*4882a593Smuzhiyun 				if (iface->iface_num == 0)
1381*4882a593Smuzhiyun 					pval = iscsi_get_ipaddress_state_name(
1382*4882a593Smuzhiyun 						ha->ip_config.ipv6_addr0_state);
1383*4882a593Smuzhiyun 				else if (iface->iface_num == 1)
1384*4882a593Smuzhiyun 					pval = iscsi_get_ipaddress_state_name(
1385*4882a593Smuzhiyun 						ha->ip_config.ipv6_addr1_state);
1386*4882a593Smuzhiyun 			}
1387*4882a593Smuzhiyun 
1388*4882a593Smuzhiyun 			len = sprintf(buf, "%s\n", pval);
1389*4882a593Smuzhiyun 			break;
1390*4882a593Smuzhiyun 		case ISCSI_NET_PARAM_IPV6_LINKLOCAL_STATE:
1391*4882a593Smuzhiyun 			pval = iscsi_get_ipaddress_state_name(
1392*4882a593Smuzhiyun 					ha->ip_config.ipv6_link_local_state);
1393*4882a593Smuzhiyun 			len = sprintf(buf, "%s\n", pval);
1394*4882a593Smuzhiyun 			break;
1395*4882a593Smuzhiyun 		case ISCSI_NET_PARAM_IPV6_ROUTER_STATE:
1396*4882a593Smuzhiyun 			pval = iscsi_get_router_state_name(
1397*4882a593Smuzhiyun 				      ha->ip_config.ipv6_default_router_state);
1398*4882a593Smuzhiyun 			len = sprintf(buf, "%s\n", pval);
1399*4882a593Smuzhiyun 			break;
1400*4882a593Smuzhiyun 		case ISCSI_NET_PARAM_DELAYED_ACK_EN:
1401*4882a593Smuzhiyun 			if (iface->iface_type == ISCSI_IFACE_TYPE_IPV4) {
1402*4882a593Smuzhiyun 				OP_STATE(~ha->ip_config.tcp_options,
1403*4882a593Smuzhiyun 					 TCPOPT_DELAYED_ACK_DISABLE, pval);
1404*4882a593Smuzhiyun 			} else {
1405*4882a593Smuzhiyun 				OP_STATE(~ha->ip_config.ipv6_tcp_options,
1406*4882a593Smuzhiyun 					 IPV6_TCPOPT_DELAYED_ACK_DISABLE, pval);
1407*4882a593Smuzhiyun 			}
1408*4882a593Smuzhiyun 			len = sprintf(buf, "%s\n", pval);
1409*4882a593Smuzhiyun 			break;
1410*4882a593Smuzhiyun 		case ISCSI_NET_PARAM_TCP_NAGLE_DISABLE:
1411*4882a593Smuzhiyun 			if (iface->iface_type == ISCSI_IFACE_TYPE_IPV4) {
1412*4882a593Smuzhiyun 				OP_STATE(~ha->ip_config.tcp_options,
1413*4882a593Smuzhiyun 					 TCPOPT_NAGLE_ALGO_DISABLE, pval);
1414*4882a593Smuzhiyun 			} else {
1415*4882a593Smuzhiyun 				OP_STATE(~ha->ip_config.ipv6_tcp_options,
1416*4882a593Smuzhiyun 					 IPV6_TCPOPT_NAGLE_ALGO_DISABLE, pval);
1417*4882a593Smuzhiyun 			}
1418*4882a593Smuzhiyun 			len = sprintf(buf, "%s\n", pval);
1419*4882a593Smuzhiyun 			break;
1420*4882a593Smuzhiyun 		case ISCSI_NET_PARAM_TCP_WSF_DISABLE:
1421*4882a593Smuzhiyun 			if (iface->iface_type == ISCSI_IFACE_TYPE_IPV4) {
1422*4882a593Smuzhiyun 				OP_STATE(~ha->ip_config.tcp_options,
1423*4882a593Smuzhiyun 					 TCPOPT_WINDOW_SCALE_DISABLE, pval);
1424*4882a593Smuzhiyun 			} else {
1425*4882a593Smuzhiyun 				OP_STATE(~ha->ip_config.ipv6_tcp_options,
1426*4882a593Smuzhiyun 					 IPV6_TCPOPT_WINDOW_SCALE_DISABLE,
1427*4882a593Smuzhiyun 					 pval);
1428*4882a593Smuzhiyun 			}
1429*4882a593Smuzhiyun 			len = sprintf(buf, "%s\n", pval);
1430*4882a593Smuzhiyun 			break;
1431*4882a593Smuzhiyun 		case ISCSI_NET_PARAM_TCP_WSF:
1432*4882a593Smuzhiyun 			if (iface->iface_type == ISCSI_IFACE_TYPE_IPV4)
1433*4882a593Smuzhiyun 				len = sprintf(buf, "%d\n",
1434*4882a593Smuzhiyun 					      ha->ip_config.tcp_wsf);
1435*4882a593Smuzhiyun 			else
1436*4882a593Smuzhiyun 				len = sprintf(buf, "%d\n",
1437*4882a593Smuzhiyun 					      ha->ip_config.ipv6_tcp_wsf);
1438*4882a593Smuzhiyun 			break;
1439*4882a593Smuzhiyun 		case ISCSI_NET_PARAM_TCP_TIMER_SCALE:
1440*4882a593Smuzhiyun 			if (iface->iface_type == ISCSI_IFACE_TYPE_IPV4)
1441*4882a593Smuzhiyun 				ival = (ha->ip_config.tcp_options &
1442*4882a593Smuzhiyun 					TCPOPT_TIMER_SCALE) >> 1;
1443*4882a593Smuzhiyun 			else
1444*4882a593Smuzhiyun 				ival = (ha->ip_config.ipv6_tcp_options &
1445*4882a593Smuzhiyun 					IPV6_TCPOPT_TIMER_SCALE) >> 1;
1446*4882a593Smuzhiyun 
1447*4882a593Smuzhiyun 			len = sprintf(buf, "%d\n", ival);
1448*4882a593Smuzhiyun 			break;
1449*4882a593Smuzhiyun 		case ISCSI_NET_PARAM_TCP_TIMESTAMP_EN:
1450*4882a593Smuzhiyun 			if (iface->iface_type == ISCSI_IFACE_TYPE_IPV4) {
1451*4882a593Smuzhiyun 				OP_STATE(ha->ip_config.tcp_options,
1452*4882a593Smuzhiyun 					 TCPOPT_TIMESTAMP_ENABLE, pval);
1453*4882a593Smuzhiyun 			} else {
1454*4882a593Smuzhiyun 				OP_STATE(ha->ip_config.ipv6_tcp_options,
1455*4882a593Smuzhiyun 					 IPV6_TCPOPT_TIMESTAMP_EN, pval);
1456*4882a593Smuzhiyun 			}
1457*4882a593Smuzhiyun 			len = sprintf(buf, "%s\n", pval);
1458*4882a593Smuzhiyun 			break;
1459*4882a593Smuzhiyun 		case ISCSI_NET_PARAM_CACHE_ID:
1460*4882a593Smuzhiyun 			if (iface->iface_type == ISCSI_IFACE_TYPE_IPV4)
1461*4882a593Smuzhiyun 				len = sprintf(buf, "%d\n",
1462*4882a593Smuzhiyun 					      ha->ip_config.ipv4_cache_id);
1463*4882a593Smuzhiyun 			else
1464*4882a593Smuzhiyun 				len = sprintf(buf, "%d\n",
1465*4882a593Smuzhiyun 					      ha->ip_config.ipv6_cache_id);
1466*4882a593Smuzhiyun 			break;
1467*4882a593Smuzhiyun 		case ISCSI_NET_PARAM_IPV4_DHCP_DNS_ADDR_EN:
1468*4882a593Smuzhiyun 			OP_STATE(ha->ip_config.tcp_options,
1469*4882a593Smuzhiyun 				 TCPOPT_DNS_SERVER_IP_EN, pval);
1470*4882a593Smuzhiyun 
1471*4882a593Smuzhiyun 			len = sprintf(buf, "%s\n", pval);
1472*4882a593Smuzhiyun 			break;
1473*4882a593Smuzhiyun 		case ISCSI_NET_PARAM_IPV4_DHCP_SLP_DA_EN:
1474*4882a593Smuzhiyun 			OP_STATE(ha->ip_config.tcp_options,
1475*4882a593Smuzhiyun 				 TCPOPT_SLP_DA_INFO_EN, pval);
1476*4882a593Smuzhiyun 
1477*4882a593Smuzhiyun 			len = sprintf(buf, "%s\n", pval);
1478*4882a593Smuzhiyun 			break;
1479*4882a593Smuzhiyun 		case ISCSI_NET_PARAM_IPV4_TOS_EN:
1480*4882a593Smuzhiyun 			OP_STATE(ha->ip_config.ipv4_options,
1481*4882a593Smuzhiyun 				 IPOPT_IPV4_TOS_EN, pval);
1482*4882a593Smuzhiyun 
1483*4882a593Smuzhiyun 			len = sprintf(buf, "%s\n", pval);
1484*4882a593Smuzhiyun 			break;
1485*4882a593Smuzhiyun 		case ISCSI_NET_PARAM_IPV4_TOS:
1486*4882a593Smuzhiyun 			len = sprintf(buf, "%d\n", ha->ip_config.ipv4_tos);
1487*4882a593Smuzhiyun 			break;
1488*4882a593Smuzhiyun 		case ISCSI_NET_PARAM_IPV4_GRAT_ARP_EN:
1489*4882a593Smuzhiyun 			OP_STATE(ha->ip_config.ipv4_options,
1490*4882a593Smuzhiyun 				 IPOPT_GRAT_ARP_EN, pval);
1491*4882a593Smuzhiyun 
1492*4882a593Smuzhiyun 			len = sprintf(buf, "%s\n", pval);
1493*4882a593Smuzhiyun 			break;
1494*4882a593Smuzhiyun 		case ISCSI_NET_PARAM_IPV4_DHCP_ALT_CLIENT_ID_EN:
1495*4882a593Smuzhiyun 			OP_STATE(ha->ip_config.ipv4_options, IPOPT_ALT_CID_EN,
1496*4882a593Smuzhiyun 				 pval);
1497*4882a593Smuzhiyun 
1498*4882a593Smuzhiyun 			len = sprintf(buf, "%s\n", pval);
1499*4882a593Smuzhiyun 			break;
1500*4882a593Smuzhiyun 		case ISCSI_NET_PARAM_IPV4_DHCP_ALT_CLIENT_ID:
1501*4882a593Smuzhiyun 			pval = (ha->ip_config.ipv4_alt_cid_len) ?
1502*4882a593Smuzhiyun 			       (char *)ha->ip_config.ipv4_alt_cid : "";
1503*4882a593Smuzhiyun 
1504*4882a593Smuzhiyun 			len = sprintf(buf, "%s\n", pval);
1505*4882a593Smuzhiyun 			break;
1506*4882a593Smuzhiyun 		case ISCSI_NET_PARAM_IPV4_DHCP_REQ_VENDOR_ID_EN:
1507*4882a593Smuzhiyun 			OP_STATE(ha->ip_config.ipv4_options,
1508*4882a593Smuzhiyun 				 IPOPT_REQ_VID_EN, pval);
1509*4882a593Smuzhiyun 
1510*4882a593Smuzhiyun 			len = sprintf(buf, "%s\n", pval);
1511*4882a593Smuzhiyun 			break;
1512*4882a593Smuzhiyun 		case ISCSI_NET_PARAM_IPV4_DHCP_USE_VENDOR_ID_EN:
1513*4882a593Smuzhiyun 			OP_STATE(ha->ip_config.ipv4_options,
1514*4882a593Smuzhiyun 				 IPOPT_USE_VID_EN, pval);
1515*4882a593Smuzhiyun 
1516*4882a593Smuzhiyun 			len = sprintf(buf, "%s\n", pval);
1517*4882a593Smuzhiyun 			break;
1518*4882a593Smuzhiyun 		case ISCSI_NET_PARAM_IPV4_DHCP_VENDOR_ID:
1519*4882a593Smuzhiyun 			pval = (ha->ip_config.ipv4_vid_len) ?
1520*4882a593Smuzhiyun 			       (char *)ha->ip_config.ipv4_vid : "";
1521*4882a593Smuzhiyun 
1522*4882a593Smuzhiyun 			len = sprintf(buf, "%s\n", pval);
1523*4882a593Smuzhiyun 			break;
1524*4882a593Smuzhiyun 		case ISCSI_NET_PARAM_IPV4_DHCP_LEARN_IQN_EN:
1525*4882a593Smuzhiyun 			OP_STATE(ha->ip_config.ipv4_options,
1526*4882a593Smuzhiyun 				 IPOPT_LEARN_IQN_EN, pval);
1527*4882a593Smuzhiyun 
1528*4882a593Smuzhiyun 			len = sprintf(buf, "%s\n", pval);
1529*4882a593Smuzhiyun 			break;
1530*4882a593Smuzhiyun 		case ISCSI_NET_PARAM_IPV4_FRAGMENT_DISABLE:
1531*4882a593Smuzhiyun 			OP_STATE(~ha->ip_config.ipv4_options,
1532*4882a593Smuzhiyun 				 IPOPT_FRAGMENTATION_DISABLE, pval);
1533*4882a593Smuzhiyun 
1534*4882a593Smuzhiyun 			len = sprintf(buf, "%s\n", pval);
1535*4882a593Smuzhiyun 			break;
1536*4882a593Smuzhiyun 		case ISCSI_NET_PARAM_IPV4_IN_FORWARD_EN:
1537*4882a593Smuzhiyun 			OP_STATE(ha->ip_config.ipv4_options,
1538*4882a593Smuzhiyun 				 IPOPT_IN_FORWARD_EN, pval);
1539*4882a593Smuzhiyun 
1540*4882a593Smuzhiyun 			len = sprintf(buf, "%s\n", pval);
1541*4882a593Smuzhiyun 			break;
1542*4882a593Smuzhiyun 		case ISCSI_NET_PARAM_REDIRECT_EN:
1543*4882a593Smuzhiyun 			if (iface->iface_type == ISCSI_IFACE_TYPE_IPV4) {
1544*4882a593Smuzhiyun 				OP_STATE(ha->ip_config.ipv4_options,
1545*4882a593Smuzhiyun 					 IPOPT_ARP_REDIRECT_EN, pval);
1546*4882a593Smuzhiyun 			} else {
1547*4882a593Smuzhiyun 				OP_STATE(ha->ip_config.ipv6_options,
1548*4882a593Smuzhiyun 					 IPV6_OPT_REDIRECT_EN, pval);
1549*4882a593Smuzhiyun 			}
1550*4882a593Smuzhiyun 			len = sprintf(buf, "%s\n", pval);
1551*4882a593Smuzhiyun 			break;
1552*4882a593Smuzhiyun 		case ISCSI_NET_PARAM_IPV4_TTL:
1553*4882a593Smuzhiyun 			len = sprintf(buf, "%d\n", ha->ip_config.ipv4_ttl);
1554*4882a593Smuzhiyun 			break;
1555*4882a593Smuzhiyun 		case ISCSI_NET_PARAM_IPV6_GRAT_NEIGHBOR_ADV_EN:
1556*4882a593Smuzhiyun 			OP_STATE(ha->ip_config.ipv6_options,
1557*4882a593Smuzhiyun 				 IPV6_OPT_GRAT_NEIGHBOR_ADV_EN, pval);
1558*4882a593Smuzhiyun 
1559*4882a593Smuzhiyun 			len = sprintf(buf, "%s\n", pval);
1560*4882a593Smuzhiyun 			break;
1561*4882a593Smuzhiyun 		case ISCSI_NET_PARAM_IPV6_MLD_EN:
1562*4882a593Smuzhiyun 			OP_STATE(ha->ip_config.ipv6_addl_options,
1563*4882a593Smuzhiyun 				 IPV6_ADDOPT_MLD_EN, pval);
1564*4882a593Smuzhiyun 
1565*4882a593Smuzhiyun 			len = sprintf(buf, "%s\n", pval);
1566*4882a593Smuzhiyun 			break;
1567*4882a593Smuzhiyun 		case ISCSI_NET_PARAM_IPV6_FLOW_LABEL:
1568*4882a593Smuzhiyun 			len = sprintf(buf, "%u\n", ha->ip_config.ipv6_flow_lbl);
1569*4882a593Smuzhiyun 			break;
1570*4882a593Smuzhiyun 		case ISCSI_NET_PARAM_IPV6_TRAFFIC_CLASS:
1571*4882a593Smuzhiyun 			len = sprintf(buf, "%d\n",
1572*4882a593Smuzhiyun 				      ha->ip_config.ipv6_traffic_class);
1573*4882a593Smuzhiyun 			break;
1574*4882a593Smuzhiyun 		case ISCSI_NET_PARAM_IPV6_HOP_LIMIT:
1575*4882a593Smuzhiyun 			len = sprintf(buf, "%d\n",
1576*4882a593Smuzhiyun 				      ha->ip_config.ipv6_hop_limit);
1577*4882a593Smuzhiyun 			break;
1578*4882a593Smuzhiyun 		case ISCSI_NET_PARAM_IPV6_ND_REACHABLE_TMO:
1579*4882a593Smuzhiyun 			len = sprintf(buf, "%d\n",
1580*4882a593Smuzhiyun 				      ha->ip_config.ipv6_nd_reach_time);
1581*4882a593Smuzhiyun 			break;
1582*4882a593Smuzhiyun 		case ISCSI_NET_PARAM_IPV6_ND_REXMIT_TIME:
1583*4882a593Smuzhiyun 			len = sprintf(buf, "%d\n",
1584*4882a593Smuzhiyun 				      ha->ip_config.ipv6_nd_rexmit_timer);
1585*4882a593Smuzhiyun 			break;
1586*4882a593Smuzhiyun 		case ISCSI_NET_PARAM_IPV6_ND_STALE_TMO:
1587*4882a593Smuzhiyun 			len = sprintf(buf, "%d\n",
1588*4882a593Smuzhiyun 				      ha->ip_config.ipv6_nd_stale_timeout);
1589*4882a593Smuzhiyun 			break;
1590*4882a593Smuzhiyun 		case ISCSI_NET_PARAM_IPV6_DUP_ADDR_DETECT_CNT:
1591*4882a593Smuzhiyun 			len = sprintf(buf, "%d\n",
1592*4882a593Smuzhiyun 				      ha->ip_config.ipv6_dup_addr_detect_count);
1593*4882a593Smuzhiyun 			break;
1594*4882a593Smuzhiyun 		case ISCSI_NET_PARAM_IPV6_RTR_ADV_LINK_MTU:
1595*4882a593Smuzhiyun 			len = sprintf(buf, "%d\n",
1596*4882a593Smuzhiyun 				      ha->ip_config.ipv6_gw_advrt_mtu);
1597*4882a593Smuzhiyun 			break;
1598*4882a593Smuzhiyun 		default:
1599*4882a593Smuzhiyun 			len = -ENOSYS;
1600*4882a593Smuzhiyun 		}
1601*4882a593Smuzhiyun 	} else if (param_type == ISCSI_IFACE_PARAM) {
1602*4882a593Smuzhiyun 		switch (param) {
1603*4882a593Smuzhiyun 		case ISCSI_IFACE_PARAM_DEF_TASKMGMT_TMO:
1604*4882a593Smuzhiyun 			len = sprintf(buf, "%d\n", ha->ip_config.def_timeout);
1605*4882a593Smuzhiyun 			break;
1606*4882a593Smuzhiyun 		case ISCSI_IFACE_PARAM_HDRDGST_EN:
1607*4882a593Smuzhiyun 			OP_STATE(ha->ip_config.iscsi_options,
1608*4882a593Smuzhiyun 				 ISCSIOPTS_HEADER_DIGEST_EN, pval);
1609*4882a593Smuzhiyun 
1610*4882a593Smuzhiyun 			len = sprintf(buf, "%s\n", pval);
1611*4882a593Smuzhiyun 			break;
1612*4882a593Smuzhiyun 		case ISCSI_IFACE_PARAM_DATADGST_EN:
1613*4882a593Smuzhiyun 			OP_STATE(ha->ip_config.iscsi_options,
1614*4882a593Smuzhiyun 				 ISCSIOPTS_DATA_DIGEST_EN, pval);
1615*4882a593Smuzhiyun 
1616*4882a593Smuzhiyun 			len = sprintf(buf, "%s\n", pval);
1617*4882a593Smuzhiyun 			break;
1618*4882a593Smuzhiyun 		case ISCSI_IFACE_PARAM_IMM_DATA_EN:
1619*4882a593Smuzhiyun 			OP_STATE(ha->ip_config.iscsi_options,
1620*4882a593Smuzhiyun 				 ISCSIOPTS_IMMEDIATE_DATA_EN, pval);
1621*4882a593Smuzhiyun 
1622*4882a593Smuzhiyun 			len = sprintf(buf, "%s\n", pval);
1623*4882a593Smuzhiyun 			break;
1624*4882a593Smuzhiyun 		case ISCSI_IFACE_PARAM_INITIAL_R2T_EN:
1625*4882a593Smuzhiyun 			OP_STATE(ha->ip_config.iscsi_options,
1626*4882a593Smuzhiyun 				 ISCSIOPTS_INITIAL_R2T_EN, pval);
1627*4882a593Smuzhiyun 
1628*4882a593Smuzhiyun 			len = sprintf(buf, "%s\n", pval);
1629*4882a593Smuzhiyun 			break;
1630*4882a593Smuzhiyun 		case ISCSI_IFACE_PARAM_DATASEQ_INORDER_EN:
1631*4882a593Smuzhiyun 			OP_STATE(ha->ip_config.iscsi_options,
1632*4882a593Smuzhiyun 				 ISCSIOPTS_DATA_SEQ_INORDER_EN, pval);
1633*4882a593Smuzhiyun 
1634*4882a593Smuzhiyun 			len = sprintf(buf, "%s\n", pval);
1635*4882a593Smuzhiyun 			break;
1636*4882a593Smuzhiyun 		case ISCSI_IFACE_PARAM_PDU_INORDER_EN:
1637*4882a593Smuzhiyun 			OP_STATE(ha->ip_config.iscsi_options,
1638*4882a593Smuzhiyun 				 ISCSIOPTS_DATA_PDU_INORDER_EN, pval);
1639*4882a593Smuzhiyun 
1640*4882a593Smuzhiyun 			len = sprintf(buf, "%s\n", pval);
1641*4882a593Smuzhiyun 			break;
1642*4882a593Smuzhiyun 		case ISCSI_IFACE_PARAM_ERL:
1643*4882a593Smuzhiyun 			len = sprintf(buf, "%d\n",
1644*4882a593Smuzhiyun 				      (ha->ip_config.iscsi_options &
1645*4882a593Smuzhiyun 				       ISCSIOPTS_ERL));
1646*4882a593Smuzhiyun 			break;
1647*4882a593Smuzhiyun 		case ISCSI_IFACE_PARAM_MAX_RECV_DLENGTH:
1648*4882a593Smuzhiyun 			len = sprintf(buf, "%u\n",
1649*4882a593Smuzhiyun 				      ha->ip_config.iscsi_max_pdu_size *
1650*4882a593Smuzhiyun 				      BYTE_UNITS);
1651*4882a593Smuzhiyun 			break;
1652*4882a593Smuzhiyun 		case ISCSI_IFACE_PARAM_FIRST_BURST:
1653*4882a593Smuzhiyun 			len = sprintf(buf, "%u\n",
1654*4882a593Smuzhiyun 				      ha->ip_config.iscsi_first_burst_len *
1655*4882a593Smuzhiyun 				      BYTE_UNITS);
1656*4882a593Smuzhiyun 			break;
1657*4882a593Smuzhiyun 		case ISCSI_IFACE_PARAM_MAX_R2T:
1658*4882a593Smuzhiyun 			len = sprintf(buf, "%d\n",
1659*4882a593Smuzhiyun 				      ha->ip_config.iscsi_max_outstnd_r2t);
1660*4882a593Smuzhiyun 			break;
1661*4882a593Smuzhiyun 		case ISCSI_IFACE_PARAM_MAX_BURST:
1662*4882a593Smuzhiyun 			len = sprintf(buf, "%u\n",
1663*4882a593Smuzhiyun 				      ha->ip_config.iscsi_max_burst_len *
1664*4882a593Smuzhiyun 				      BYTE_UNITS);
1665*4882a593Smuzhiyun 			break;
1666*4882a593Smuzhiyun 		case ISCSI_IFACE_PARAM_CHAP_AUTH_EN:
1667*4882a593Smuzhiyun 			OP_STATE(ha->ip_config.iscsi_options,
1668*4882a593Smuzhiyun 				 ISCSIOPTS_CHAP_AUTH_EN, pval);
1669*4882a593Smuzhiyun 
1670*4882a593Smuzhiyun 			len = sprintf(buf, "%s\n", pval);
1671*4882a593Smuzhiyun 			break;
1672*4882a593Smuzhiyun 		case ISCSI_IFACE_PARAM_BIDI_CHAP_EN:
1673*4882a593Smuzhiyun 			OP_STATE(ha->ip_config.iscsi_options,
1674*4882a593Smuzhiyun 				 ISCSIOPTS_BIDI_CHAP_EN, pval);
1675*4882a593Smuzhiyun 
1676*4882a593Smuzhiyun 			len = sprintf(buf, "%s\n", pval);
1677*4882a593Smuzhiyun 			break;
1678*4882a593Smuzhiyun 		case ISCSI_IFACE_PARAM_DISCOVERY_AUTH_OPTIONAL:
1679*4882a593Smuzhiyun 			OP_STATE(ha->ip_config.iscsi_options,
1680*4882a593Smuzhiyun 				 ISCSIOPTS_DISCOVERY_AUTH_EN, pval);
1681*4882a593Smuzhiyun 
1682*4882a593Smuzhiyun 			len = sprintf(buf, "%s\n", pval);
1683*4882a593Smuzhiyun 			break;
1684*4882a593Smuzhiyun 		case ISCSI_IFACE_PARAM_DISCOVERY_LOGOUT_EN:
1685*4882a593Smuzhiyun 			OP_STATE(ha->ip_config.iscsi_options,
1686*4882a593Smuzhiyun 				 ISCSIOPTS_DISCOVERY_LOGOUT_EN, pval);
1687*4882a593Smuzhiyun 
1688*4882a593Smuzhiyun 			len = sprintf(buf, "%s\n", pval);
1689*4882a593Smuzhiyun 			break;
1690*4882a593Smuzhiyun 		case ISCSI_IFACE_PARAM_STRICT_LOGIN_COMP_EN:
1691*4882a593Smuzhiyun 			OP_STATE(ha->ip_config.iscsi_options,
1692*4882a593Smuzhiyun 				 ISCSIOPTS_STRICT_LOGIN_COMP_EN, pval);
1693*4882a593Smuzhiyun 
1694*4882a593Smuzhiyun 			len = sprintf(buf, "%s\n", pval);
1695*4882a593Smuzhiyun 			break;
1696*4882a593Smuzhiyun 		case ISCSI_IFACE_PARAM_INITIATOR_NAME:
1697*4882a593Smuzhiyun 			len = sprintf(buf, "%s\n", ha->ip_config.iscsi_name);
1698*4882a593Smuzhiyun 			break;
1699*4882a593Smuzhiyun 		default:
1700*4882a593Smuzhiyun 			len = -ENOSYS;
1701*4882a593Smuzhiyun 		}
1702*4882a593Smuzhiyun 	}
1703*4882a593Smuzhiyun 
1704*4882a593Smuzhiyun 	return len;
1705*4882a593Smuzhiyun }
1706*4882a593Smuzhiyun 
1707*4882a593Smuzhiyun static struct iscsi_endpoint *
qla4xxx_ep_connect(struct Scsi_Host * shost,struct sockaddr * dst_addr,int non_blocking)1708*4882a593Smuzhiyun qla4xxx_ep_connect(struct Scsi_Host *shost, struct sockaddr *dst_addr,
1709*4882a593Smuzhiyun 		   int non_blocking)
1710*4882a593Smuzhiyun {
1711*4882a593Smuzhiyun 	int ret;
1712*4882a593Smuzhiyun 	struct iscsi_endpoint *ep;
1713*4882a593Smuzhiyun 	struct qla_endpoint *qla_ep;
1714*4882a593Smuzhiyun 	struct scsi_qla_host *ha;
1715*4882a593Smuzhiyun 	struct sockaddr_in *addr;
1716*4882a593Smuzhiyun 	struct sockaddr_in6 *addr6;
1717*4882a593Smuzhiyun 
1718*4882a593Smuzhiyun 	if (!shost) {
1719*4882a593Smuzhiyun 		ret = -ENXIO;
1720*4882a593Smuzhiyun 		pr_err("%s: shost is NULL\n", __func__);
1721*4882a593Smuzhiyun 		return ERR_PTR(ret);
1722*4882a593Smuzhiyun 	}
1723*4882a593Smuzhiyun 
1724*4882a593Smuzhiyun 	ha = iscsi_host_priv(shost);
1725*4882a593Smuzhiyun 	ep = iscsi_create_endpoint(sizeof(struct qla_endpoint));
1726*4882a593Smuzhiyun 	if (!ep) {
1727*4882a593Smuzhiyun 		ret = -ENOMEM;
1728*4882a593Smuzhiyun 		return ERR_PTR(ret);
1729*4882a593Smuzhiyun 	}
1730*4882a593Smuzhiyun 
1731*4882a593Smuzhiyun 	qla_ep = ep->dd_data;
1732*4882a593Smuzhiyun 	memset(qla_ep, 0, sizeof(struct qla_endpoint));
1733*4882a593Smuzhiyun 	if (dst_addr->sa_family == AF_INET) {
1734*4882a593Smuzhiyun 		memcpy(&qla_ep->dst_addr, dst_addr, sizeof(struct sockaddr_in));
1735*4882a593Smuzhiyun 		addr = (struct sockaddr_in *)&qla_ep->dst_addr;
1736*4882a593Smuzhiyun 		DEBUG2(ql4_printk(KERN_INFO, ha, "%s: %pI4\n", __func__,
1737*4882a593Smuzhiyun 				  (char *)&addr->sin_addr));
1738*4882a593Smuzhiyun 	} else if (dst_addr->sa_family == AF_INET6) {
1739*4882a593Smuzhiyun 		memcpy(&qla_ep->dst_addr, dst_addr,
1740*4882a593Smuzhiyun 		       sizeof(struct sockaddr_in6));
1741*4882a593Smuzhiyun 		addr6 = (struct sockaddr_in6 *)&qla_ep->dst_addr;
1742*4882a593Smuzhiyun 		DEBUG2(ql4_printk(KERN_INFO, ha, "%s: %pI6\n", __func__,
1743*4882a593Smuzhiyun 				  (char *)&addr6->sin6_addr));
1744*4882a593Smuzhiyun 	} else {
1745*4882a593Smuzhiyun 		ql4_printk(KERN_WARNING, ha, "%s: Invalid endpoint\n",
1746*4882a593Smuzhiyun 			   __func__);
1747*4882a593Smuzhiyun 	}
1748*4882a593Smuzhiyun 
1749*4882a593Smuzhiyun 	qla_ep->host = shost;
1750*4882a593Smuzhiyun 
1751*4882a593Smuzhiyun 	return ep;
1752*4882a593Smuzhiyun }
1753*4882a593Smuzhiyun 
qla4xxx_ep_poll(struct iscsi_endpoint * ep,int timeout_ms)1754*4882a593Smuzhiyun static int qla4xxx_ep_poll(struct iscsi_endpoint *ep, int timeout_ms)
1755*4882a593Smuzhiyun {
1756*4882a593Smuzhiyun 	struct qla_endpoint *qla_ep;
1757*4882a593Smuzhiyun 	struct scsi_qla_host *ha;
1758*4882a593Smuzhiyun 	int ret = 0;
1759*4882a593Smuzhiyun 
1760*4882a593Smuzhiyun 	qla_ep = ep->dd_data;
1761*4882a593Smuzhiyun 	ha = to_qla_host(qla_ep->host);
1762*4882a593Smuzhiyun 	DEBUG2(pr_info_ratelimited("%s: host: %ld\n", __func__, ha->host_no));
1763*4882a593Smuzhiyun 
1764*4882a593Smuzhiyun 	if (adapter_up(ha) && !test_bit(AF_BUILD_DDB_LIST, &ha->flags))
1765*4882a593Smuzhiyun 		ret = 1;
1766*4882a593Smuzhiyun 
1767*4882a593Smuzhiyun 	return ret;
1768*4882a593Smuzhiyun }
1769*4882a593Smuzhiyun 
qla4xxx_ep_disconnect(struct iscsi_endpoint * ep)1770*4882a593Smuzhiyun static void qla4xxx_ep_disconnect(struct iscsi_endpoint *ep)
1771*4882a593Smuzhiyun {
1772*4882a593Smuzhiyun 	struct qla_endpoint *qla_ep;
1773*4882a593Smuzhiyun 	struct scsi_qla_host *ha;
1774*4882a593Smuzhiyun 
1775*4882a593Smuzhiyun 	qla_ep = ep->dd_data;
1776*4882a593Smuzhiyun 	ha = to_qla_host(qla_ep->host);
1777*4882a593Smuzhiyun 	DEBUG2(ql4_printk(KERN_INFO, ha, "%s: host: %ld\n", __func__,
1778*4882a593Smuzhiyun 			  ha->host_no));
1779*4882a593Smuzhiyun 	iscsi_destroy_endpoint(ep);
1780*4882a593Smuzhiyun }
1781*4882a593Smuzhiyun 
qla4xxx_get_ep_param(struct iscsi_endpoint * ep,enum iscsi_param param,char * buf)1782*4882a593Smuzhiyun static int qla4xxx_get_ep_param(struct iscsi_endpoint *ep,
1783*4882a593Smuzhiyun 				enum iscsi_param param,
1784*4882a593Smuzhiyun 				char *buf)
1785*4882a593Smuzhiyun {
1786*4882a593Smuzhiyun 	struct qla_endpoint *qla_ep = ep->dd_data;
1787*4882a593Smuzhiyun 	struct sockaddr *dst_addr;
1788*4882a593Smuzhiyun 	struct scsi_qla_host *ha;
1789*4882a593Smuzhiyun 
1790*4882a593Smuzhiyun 	if (!qla_ep)
1791*4882a593Smuzhiyun 		return -ENOTCONN;
1792*4882a593Smuzhiyun 
1793*4882a593Smuzhiyun 	ha = to_qla_host(qla_ep->host);
1794*4882a593Smuzhiyun 	DEBUG2(ql4_printk(KERN_INFO, ha, "%s: host: %ld\n", __func__,
1795*4882a593Smuzhiyun 			  ha->host_no));
1796*4882a593Smuzhiyun 
1797*4882a593Smuzhiyun 	switch (param) {
1798*4882a593Smuzhiyun 	case ISCSI_PARAM_CONN_PORT:
1799*4882a593Smuzhiyun 	case ISCSI_PARAM_CONN_ADDRESS:
1800*4882a593Smuzhiyun 		dst_addr = (struct sockaddr *)&qla_ep->dst_addr;
1801*4882a593Smuzhiyun 		if (!dst_addr)
1802*4882a593Smuzhiyun 			return -ENOTCONN;
1803*4882a593Smuzhiyun 
1804*4882a593Smuzhiyun 		return iscsi_conn_get_addr_param((struct sockaddr_storage *)
1805*4882a593Smuzhiyun 						 &qla_ep->dst_addr, param, buf);
1806*4882a593Smuzhiyun 	default:
1807*4882a593Smuzhiyun 		return -ENOSYS;
1808*4882a593Smuzhiyun 	}
1809*4882a593Smuzhiyun }
1810*4882a593Smuzhiyun 
qla4xxx_conn_get_stats(struct iscsi_cls_conn * cls_conn,struct iscsi_stats * stats)1811*4882a593Smuzhiyun static void qla4xxx_conn_get_stats(struct iscsi_cls_conn *cls_conn,
1812*4882a593Smuzhiyun 				   struct iscsi_stats *stats)
1813*4882a593Smuzhiyun {
1814*4882a593Smuzhiyun 	struct iscsi_session *sess;
1815*4882a593Smuzhiyun 	struct iscsi_cls_session *cls_sess;
1816*4882a593Smuzhiyun 	struct ddb_entry *ddb_entry;
1817*4882a593Smuzhiyun 	struct scsi_qla_host *ha;
1818*4882a593Smuzhiyun 	struct ql_iscsi_stats *ql_iscsi_stats;
1819*4882a593Smuzhiyun 	int stats_size;
1820*4882a593Smuzhiyun 	int ret;
1821*4882a593Smuzhiyun 	dma_addr_t iscsi_stats_dma;
1822*4882a593Smuzhiyun 
1823*4882a593Smuzhiyun 	cls_sess = iscsi_conn_to_session(cls_conn);
1824*4882a593Smuzhiyun 	sess = cls_sess->dd_data;
1825*4882a593Smuzhiyun 	ddb_entry = sess->dd_data;
1826*4882a593Smuzhiyun 	ha = ddb_entry->ha;
1827*4882a593Smuzhiyun 
1828*4882a593Smuzhiyun 	DEBUG2(ql4_printk(KERN_INFO, ha, "%s: host: %ld\n", __func__,
1829*4882a593Smuzhiyun 			  ha->host_no));
1830*4882a593Smuzhiyun 	stats_size = PAGE_ALIGN(sizeof(struct ql_iscsi_stats));
1831*4882a593Smuzhiyun 	/* Allocate memory */
1832*4882a593Smuzhiyun 	ql_iscsi_stats = dma_alloc_coherent(&ha->pdev->dev, stats_size,
1833*4882a593Smuzhiyun 					    &iscsi_stats_dma, GFP_KERNEL);
1834*4882a593Smuzhiyun 	if (!ql_iscsi_stats) {
1835*4882a593Smuzhiyun 		ql4_printk(KERN_ERR, ha,
1836*4882a593Smuzhiyun 			   "Unable to allocate memory for iscsi stats\n");
1837*4882a593Smuzhiyun 		goto exit_get_stats;
1838*4882a593Smuzhiyun 	}
1839*4882a593Smuzhiyun 
1840*4882a593Smuzhiyun 	ret =  qla4xxx_get_mgmt_data(ha, ddb_entry->fw_ddb_index, stats_size,
1841*4882a593Smuzhiyun 				     iscsi_stats_dma);
1842*4882a593Smuzhiyun 	if (ret != QLA_SUCCESS) {
1843*4882a593Smuzhiyun 		ql4_printk(KERN_ERR, ha,
1844*4882a593Smuzhiyun 			   "Unable to retrieve iscsi stats\n");
1845*4882a593Smuzhiyun 		goto free_stats;
1846*4882a593Smuzhiyun 	}
1847*4882a593Smuzhiyun 
1848*4882a593Smuzhiyun 	/* octets */
1849*4882a593Smuzhiyun 	stats->txdata_octets = le64_to_cpu(ql_iscsi_stats->tx_data_octets);
1850*4882a593Smuzhiyun 	stats->rxdata_octets = le64_to_cpu(ql_iscsi_stats->rx_data_octets);
1851*4882a593Smuzhiyun 	/* xmit pdus */
1852*4882a593Smuzhiyun 	stats->noptx_pdus = le32_to_cpu(ql_iscsi_stats->tx_nopout_pdus);
1853*4882a593Smuzhiyun 	stats->scsicmd_pdus = le32_to_cpu(ql_iscsi_stats->tx_scsi_cmd_pdus);
1854*4882a593Smuzhiyun 	stats->tmfcmd_pdus = le32_to_cpu(ql_iscsi_stats->tx_tmf_cmd_pdus);
1855*4882a593Smuzhiyun 	stats->login_pdus = le32_to_cpu(ql_iscsi_stats->tx_login_cmd_pdus);
1856*4882a593Smuzhiyun 	stats->text_pdus = le32_to_cpu(ql_iscsi_stats->tx_text_cmd_pdus);
1857*4882a593Smuzhiyun 	stats->dataout_pdus = le32_to_cpu(ql_iscsi_stats->tx_scsi_write_pdus);
1858*4882a593Smuzhiyun 	stats->logout_pdus = le32_to_cpu(ql_iscsi_stats->tx_logout_cmd_pdus);
1859*4882a593Smuzhiyun 	stats->snack_pdus = le32_to_cpu(ql_iscsi_stats->tx_snack_req_pdus);
1860*4882a593Smuzhiyun 	/* recv pdus */
1861*4882a593Smuzhiyun 	stats->noprx_pdus = le32_to_cpu(ql_iscsi_stats->rx_nopin_pdus);
1862*4882a593Smuzhiyun 	stats->scsirsp_pdus = le32_to_cpu(ql_iscsi_stats->rx_scsi_resp_pdus);
1863*4882a593Smuzhiyun 	stats->tmfrsp_pdus = le32_to_cpu(ql_iscsi_stats->rx_tmf_resp_pdus);
1864*4882a593Smuzhiyun 	stats->textrsp_pdus = le32_to_cpu(ql_iscsi_stats->rx_text_resp_pdus);
1865*4882a593Smuzhiyun 	stats->datain_pdus = le32_to_cpu(ql_iscsi_stats->rx_scsi_read_pdus);
1866*4882a593Smuzhiyun 	stats->logoutrsp_pdus =
1867*4882a593Smuzhiyun 			le32_to_cpu(ql_iscsi_stats->rx_logout_resp_pdus);
1868*4882a593Smuzhiyun 	stats->r2t_pdus = le32_to_cpu(ql_iscsi_stats->rx_r2t_pdus);
1869*4882a593Smuzhiyun 	stats->async_pdus = le32_to_cpu(ql_iscsi_stats->rx_async_pdus);
1870*4882a593Smuzhiyun 	stats->rjt_pdus = le32_to_cpu(ql_iscsi_stats->rx_reject_pdus);
1871*4882a593Smuzhiyun 
1872*4882a593Smuzhiyun free_stats:
1873*4882a593Smuzhiyun 	dma_free_coherent(&ha->pdev->dev, stats_size, ql_iscsi_stats,
1874*4882a593Smuzhiyun 			  iscsi_stats_dma);
1875*4882a593Smuzhiyun exit_get_stats:
1876*4882a593Smuzhiyun 	return;
1877*4882a593Smuzhiyun }
1878*4882a593Smuzhiyun 
qla4xxx_eh_cmd_timed_out(struct scsi_cmnd * sc)1879*4882a593Smuzhiyun static enum blk_eh_timer_return qla4xxx_eh_cmd_timed_out(struct scsi_cmnd *sc)
1880*4882a593Smuzhiyun {
1881*4882a593Smuzhiyun 	struct iscsi_cls_session *session;
1882*4882a593Smuzhiyun 	unsigned long flags;
1883*4882a593Smuzhiyun 	enum blk_eh_timer_return ret = BLK_EH_DONE;
1884*4882a593Smuzhiyun 
1885*4882a593Smuzhiyun 	session = starget_to_session(scsi_target(sc->device));
1886*4882a593Smuzhiyun 
1887*4882a593Smuzhiyun 	spin_lock_irqsave(&session->lock, flags);
1888*4882a593Smuzhiyun 	if (session->state == ISCSI_SESSION_FAILED)
1889*4882a593Smuzhiyun 		ret = BLK_EH_RESET_TIMER;
1890*4882a593Smuzhiyun 	spin_unlock_irqrestore(&session->lock, flags);
1891*4882a593Smuzhiyun 
1892*4882a593Smuzhiyun 	return ret;
1893*4882a593Smuzhiyun }
1894*4882a593Smuzhiyun 
qla4xxx_set_port_speed(struct Scsi_Host * shost)1895*4882a593Smuzhiyun static void qla4xxx_set_port_speed(struct Scsi_Host *shost)
1896*4882a593Smuzhiyun {
1897*4882a593Smuzhiyun 	struct scsi_qla_host *ha = to_qla_host(shost);
1898*4882a593Smuzhiyun 	struct iscsi_cls_host *ihost = shost->shost_data;
1899*4882a593Smuzhiyun 	uint32_t speed = ISCSI_PORT_SPEED_UNKNOWN;
1900*4882a593Smuzhiyun 
1901*4882a593Smuzhiyun 	qla4xxx_get_firmware_state(ha);
1902*4882a593Smuzhiyun 
1903*4882a593Smuzhiyun 	switch (ha->addl_fw_state & 0x0F00) {
1904*4882a593Smuzhiyun 	case FW_ADDSTATE_LINK_SPEED_10MBPS:
1905*4882a593Smuzhiyun 		speed = ISCSI_PORT_SPEED_10MBPS;
1906*4882a593Smuzhiyun 		break;
1907*4882a593Smuzhiyun 	case FW_ADDSTATE_LINK_SPEED_100MBPS:
1908*4882a593Smuzhiyun 		speed = ISCSI_PORT_SPEED_100MBPS;
1909*4882a593Smuzhiyun 		break;
1910*4882a593Smuzhiyun 	case FW_ADDSTATE_LINK_SPEED_1GBPS:
1911*4882a593Smuzhiyun 		speed = ISCSI_PORT_SPEED_1GBPS;
1912*4882a593Smuzhiyun 		break;
1913*4882a593Smuzhiyun 	case FW_ADDSTATE_LINK_SPEED_10GBPS:
1914*4882a593Smuzhiyun 		speed = ISCSI_PORT_SPEED_10GBPS;
1915*4882a593Smuzhiyun 		break;
1916*4882a593Smuzhiyun 	}
1917*4882a593Smuzhiyun 	ihost->port_speed = speed;
1918*4882a593Smuzhiyun }
1919*4882a593Smuzhiyun 
qla4xxx_set_port_state(struct Scsi_Host * shost)1920*4882a593Smuzhiyun static void qla4xxx_set_port_state(struct Scsi_Host *shost)
1921*4882a593Smuzhiyun {
1922*4882a593Smuzhiyun 	struct scsi_qla_host *ha = to_qla_host(shost);
1923*4882a593Smuzhiyun 	struct iscsi_cls_host *ihost = shost->shost_data;
1924*4882a593Smuzhiyun 	uint32_t state = ISCSI_PORT_STATE_DOWN;
1925*4882a593Smuzhiyun 
1926*4882a593Smuzhiyun 	if (test_bit(AF_LINK_UP, &ha->flags))
1927*4882a593Smuzhiyun 		state = ISCSI_PORT_STATE_UP;
1928*4882a593Smuzhiyun 
1929*4882a593Smuzhiyun 	ihost->port_state = state;
1930*4882a593Smuzhiyun }
1931*4882a593Smuzhiyun 
qla4xxx_host_get_param(struct Scsi_Host * shost,enum iscsi_host_param param,char * buf)1932*4882a593Smuzhiyun static int qla4xxx_host_get_param(struct Scsi_Host *shost,
1933*4882a593Smuzhiyun 				  enum iscsi_host_param param, char *buf)
1934*4882a593Smuzhiyun {
1935*4882a593Smuzhiyun 	struct scsi_qla_host *ha = to_qla_host(shost);
1936*4882a593Smuzhiyun 	int len;
1937*4882a593Smuzhiyun 
1938*4882a593Smuzhiyun 	switch (param) {
1939*4882a593Smuzhiyun 	case ISCSI_HOST_PARAM_HWADDRESS:
1940*4882a593Smuzhiyun 		len = sysfs_format_mac(buf, ha->my_mac, MAC_ADDR_LEN);
1941*4882a593Smuzhiyun 		break;
1942*4882a593Smuzhiyun 	case ISCSI_HOST_PARAM_IPADDRESS:
1943*4882a593Smuzhiyun 		len = sprintf(buf, "%pI4\n", &ha->ip_config.ip_address);
1944*4882a593Smuzhiyun 		break;
1945*4882a593Smuzhiyun 	case ISCSI_HOST_PARAM_INITIATOR_NAME:
1946*4882a593Smuzhiyun 		len = sprintf(buf, "%s\n", ha->name_string);
1947*4882a593Smuzhiyun 		break;
1948*4882a593Smuzhiyun 	case ISCSI_HOST_PARAM_PORT_STATE:
1949*4882a593Smuzhiyun 		qla4xxx_set_port_state(shost);
1950*4882a593Smuzhiyun 		len = sprintf(buf, "%s\n", iscsi_get_port_state_name(shost));
1951*4882a593Smuzhiyun 		break;
1952*4882a593Smuzhiyun 	case ISCSI_HOST_PARAM_PORT_SPEED:
1953*4882a593Smuzhiyun 		qla4xxx_set_port_speed(shost);
1954*4882a593Smuzhiyun 		len = sprintf(buf, "%s\n", iscsi_get_port_speed_name(shost));
1955*4882a593Smuzhiyun 		break;
1956*4882a593Smuzhiyun 	default:
1957*4882a593Smuzhiyun 		return -ENOSYS;
1958*4882a593Smuzhiyun 	}
1959*4882a593Smuzhiyun 
1960*4882a593Smuzhiyun 	return len;
1961*4882a593Smuzhiyun }
1962*4882a593Smuzhiyun 
qla4xxx_create_ipv4_iface(struct scsi_qla_host * ha)1963*4882a593Smuzhiyun static void qla4xxx_create_ipv4_iface(struct scsi_qla_host *ha)
1964*4882a593Smuzhiyun {
1965*4882a593Smuzhiyun 	if (ha->iface_ipv4)
1966*4882a593Smuzhiyun 		return;
1967*4882a593Smuzhiyun 
1968*4882a593Smuzhiyun 	/* IPv4 */
1969*4882a593Smuzhiyun 	ha->iface_ipv4 = iscsi_create_iface(ha->host,
1970*4882a593Smuzhiyun 					    &qla4xxx_iscsi_transport,
1971*4882a593Smuzhiyun 					    ISCSI_IFACE_TYPE_IPV4, 0, 0);
1972*4882a593Smuzhiyun 	if (!ha->iface_ipv4)
1973*4882a593Smuzhiyun 		ql4_printk(KERN_ERR, ha, "Could not create IPv4 iSCSI "
1974*4882a593Smuzhiyun 			   "iface0.\n");
1975*4882a593Smuzhiyun }
1976*4882a593Smuzhiyun 
qla4xxx_create_ipv6_iface(struct scsi_qla_host * ha)1977*4882a593Smuzhiyun static void qla4xxx_create_ipv6_iface(struct scsi_qla_host *ha)
1978*4882a593Smuzhiyun {
1979*4882a593Smuzhiyun 	if (!ha->iface_ipv6_0)
1980*4882a593Smuzhiyun 		/* IPv6 iface-0 */
1981*4882a593Smuzhiyun 		ha->iface_ipv6_0 = iscsi_create_iface(ha->host,
1982*4882a593Smuzhiyun 						      &qla4xxx_iscsi_transport,
1983*4882a593Smuzhiyun 						      ISCSI_IFACE_TYPE_IPV6, 0,
1984*4882a593Smuzhiyun 						      0);
1985*4882a593Smuzhiyun 	if (!ha->iface_ipv6_0)
1986*4882a593Smuzhiyun 		ql4_printk(KERN_ERR, ha, "Could not create IPv6 iSCSI "
1987*4882a593Smuzhiyun 			   "iface0.\n");
1988*4882a593Smuzhiyun 
1989*4882a593Smuzhiyun 	if (!ha->iface_ipv6_1)
1990*4882a593Smuzhiyun 		/* IPv6 iface-1 */
1991*4882a593Smuzhiyun 		ha->iface_ipv6_1 = iscsi_create_iface(ha->host,
1992*4882a593Smuzhiyun 						      &qla4xxx_iscsi_transport,
1993*4882a593Smuzhiyun 						      ISCSI_IFACE_TYPE_IPV6, 1,
1994*4882a593Smuzhiyun 						      0);
1995*4882a593Smuzhiyun 	if (!ha->iface_ipv6_1)
1996*4882a593Smuzhiyun 		ql4_printk(KERN_ERR, ha, "Could not create IPv6 iSCSI "
1997*4882a593Smuzhiyun 			   "iface1.\n");
1998*4882a593Smuzhiyun }
1999*4882a593Smuzhiyun 
qla4xxx_create_ifaces(struct scsi_qla_host * ha)2000*4882a593Smuzhiyun static void qla4xxx_create_ifaces(struct scsi_qla_host *ha)
2001*4882a593Smuzhiyun {
2002*4882a593Smuzhiyun 	if (ha->ip_config.ipv4_options & IPOPT_IPV4_PROTOCOL_ENABLE)
2003*4882a593Smuzhiyun 		qla4xxx_create_ipv4_iface(ha);
2004*4882a593Smuzhiyun 
2005*4882a593Smuzhiyun 	if (ha->ip_config.ipv6_options & IPV6_OPT_IPV6_PROTOCOL_ENABLE)
2006*4882a593Smuzhiyun 		qla4xxx_create_ipv6_iface(ha);
2007*4882a593Smuzhiyun }
2008*4882a593Smuzhiyun 
qla4xxx_destroy_ipv4_iface(struct scsi_qla_host * ha)2009*4882a593Smuzhiyun static void qla4xxx_destroy_ipv4_iface(struct scsi_qla_host *ha)
2010*4882a593Smuzhiyun {
2011*4882a593Smuzhiyun 	if (ha->iface_ipv4) {
2012*4882a593Smuzhiyun 		iscsi_destroy_iface(ha->iface_ipv4);
2013*4882a593Smuzhiyun 		ha->iface_ipv4 = NULL;
2014*4882a593Smuzhiyun 	}
2015*4882a593Smuzhiyun }
2016*4882a593Smuzhiyun 
qla4xxx_destroy_ipv6_iface(struct scsi_qla_host * ha)2017*4882a593Smuzhiyun static void qla4xxx_destroy_ipv6_iface(struct scsi_qla_host *ha)
2018*4882a593Smuzhiyun {
2019*4882a593Smuzhiyun 	if (ha->iface_ipv6_0) {
2020*4882a593Smuzhiyun 		iscsi_destroy_iface(ha->iface_ipv6_0);
2021*4882a593Smuzhiyun 		ha->iface_ipv6_0 = NULL;
2022*4882a593Smuzhiyun 	}
2023*4882a593Smuzhiyun 	if (ha->iface_ipv6_1) {
2024*4882a593Smuzhiyun 		iscsi_destroy_iface(ha->iface_ipv6_1);
2025*4882a593Smuzhiyun 		ha->iface_ipv6_1 = NULL;
2026*4882a593Smuzhiyun 	}
2027*4882a593Smuzhiyun }
2028*4882a593Smuzhiyun 
qla4xxx_destroy_ifaces(struct scsi_qla_host * ha)2029*4882a593Smuzhiyun static void qla4xxx_destroy_ifaces(struct scsi_qla_host *ha)
2030*4882a593Smuzhiyun {
2031*4882a593Smuzhiyun 	qla4xxx_destroy_ipv4_iface(ha);
2032*4882a593Smuzhiyun 	qla4xxx_destroy_ipv6_iface(ha);
2033*4882a593Smuzhiyun }
2034*4882a593Smuzhiyun 
qla4xxx_set_ipv6(struct scsi_qla_host * ha,struct iscsi_iface_param_info * iface_param,struct addr_ctrl_blk * init_fw_cb)2035*4882a593Smuzhiyun static void qla4xxx_set_ipv6(struct scsi_qla_host *ha,
2036*4882a593Smuzhiyun 			     struct iscsi_iface_param_info *iface_param,
2037*4882a593Smuzhiyun 			     struct addr_ctrl_blk *init_fw_cb)
2038*4882a593Smuzhiyun {
2039*4882a593Smuzhiyun 	/*
2040*4882a593Smuzhiyun 	 * iface_num 0 is valid for IPv6 Addr, linklocal, router, autocfg.
2041*4882a593Smuzhiyun 	 * iface_num 1 is valid only for IPv6 Addr.
2042*4882a593Smuzhiyun 	 */
2043*4882a593Smuzhiyun 	switch (iface_param->param) {
2044*4882a593Smuzhiyun 	case ISCSI_NET_PARAM_IPV6_ADDR:
2045*4882a593Smuzhiyun 		if (iface_param->iface_num & 0x1)
2046*4882a593Smuzhiyun 			/* IPv6 Addr 1 */
2047*4882a593Smuzhiyun 			memcpy(init_fw_cb->ipv6_addr1, iface_param->value,
2048*4882a593Smuzhiyun 			       sizeof(init_fw_cb->ipv6_addr1));
2049*4882a593Smuzhiyun 		else
2050*4882a593Smuzhiyun 			/* IPv6 Addr 0 */
2051*4882a593Smuzhiyun 			memcpy(init_fw_cb->ipv6_addr0, iface_param->value,
2052*4882a593Smuzhiyun 			       sizeof(init_fw_cb->ipv6_addr0));
2053*4882a593Smuzhiyun 		break;
2054*4882a593Smuzhiyun 	case ISCSI_NET_PARAM_IPV6_LINKLOCAL:
2055*4882a593Smuzhiyun 		if (iface_param->iface_num & 0x1)
2056*4882a593Smuzhiyun 			break;
2057*4882a593Smuzhiyun 		memcpy(init_fw_cb->ipv6_if_id, &iface_param->value[8],
2058*4882a593Smuzhiyun 		       sizeof(init_fw_cb->ipv6_if_id));
2059*4882a593Smuzhiyun 		break;
2060*4882a593Smuzhiyun 	case ISCSI_NET_PARAM_IPV6_ROUTER:
2061*4882a593Smuzhiyun 		if (iface_param->iface_num & 0x1)
2062*4882a593Smuzhiyun 			break;
2063*4882a593Smuzhiyun 		memcpy(init_fw_cb->ipv6_dflt_rtr_addr, iface_param->value,
2064*4882a593Smuzhiyun 		       sizeof(init_fw_cb->ipv6_dflt_rtr_addr));
2065*4882a593Smuzhiyun 		break;
2066*4882a593Smuzhiyun 	case ISCSI_NET_PARAM_IPV6_ADDR_AUTOCFG:
2067*4882a593Smuzhiyun 		/* Autocfg applies to even interface */
2068*4882a593Smuzhiyun 		if (iface_param->iface_num & 0x1)
2069*4882a593Smuzhiyun 			break;
2070*4882a593Smuzhiyun 
2071*4882a593Smuzhiyun 		if (iface_param->value[0] == ISCSI_IPV6_AUTOCFG_DISABLE)
2072*4882a593Smuzhiyun 			init_fw_cb->ipv6_addtl_opts &=
2073*4882a593Smuzhiyun 				cpu_to_le16(
2074*4882a593Smuzhiyun 				  ~IPV6_ADDOPT_NEIGHBOR_DISCOVERY_ADDR_ENABLE);
2075*4882a593Smuzhiyun 		else if (iface_param->value[0] == ISCSI_IPV6_AUTOCFG_ND_ENABLE)
2076*4882a593Smuzhiyun 			init_fw_cb->ipv6_addtl_opts |=
2077*4882a593Smuzhiyun 				cpu_to_le16(
2078*4882a593Smuzhiyun 				  IPV6_ADDOPT_NEIGHBOR_DISCOVERY_ADDR_ENABLE);
2079*4882a593Smuzhiyun 		else
2080*4882a593Smuzhiyun 			ql4_printk(KERN_ERR, ha,
2081*4882a593Smuzhiyun 				   "Invalid autocfg setting for IPv6 addr\n");
2082*4882a593Smuzhiyun 		break;
2083*4882a593Smuzhiyun 	case ISCSI_NET_PARAM_IPV6_LINKLOCAL_AUTOCFG:
2084*4882a593Smuzhiyun 		/* Autocfg applies to even interface */
2085*4882a593Smuzhiyun 		if (iface_param->iface_num & 0x1)
2086*4882a593Smuzhiyun 			break;
2087*4882a593Smuzhiyun 
2088*4882a593Smuzhiyun 		if (iface_param->value[0] ==
2089*4882a593Smuzhiyun 		    ISCSI_IPV6_LINKLOCAL_AUTOCFG_ENABLE)
2090*4882a593Smuzhiyun 			init_fw_cb->ipv6_addtl_opts |= cpu_to_le16(
2091*4882a593Smuzhiyun 					IPV6_ADDOPT_AUTOCONFIG_LINK_LOCAL_ADDR);
2092*4882a593Smuzhiyun 		else if (iface_param->value[0] ==
2093*4882a593Smuzhiyun 			 ISCSI_IPV6_LINKLOCAL_AUTOCFG_DISABLE)
2094*4882a593Smuzhiyun 			init_fw_cb->ipv6_addtl_opts &= cpu_to_le16(
2095*4882a593Smuzhiyun 				       ~IPV6_ADDOPT_AUTOCONFIG_LINK_LOCAL_ADDR);
2096*4882a593Smuzhiyun 		else
2097*4882a593Smuzhiyun 			ql4_printk(KERN_ERR, ha,
2098*4882a593Smuzhiyun 				   "Invalid autocfg setting for IPv6 linklocal addr\n");
2099*4882a593Smuzhiyun 		break;
2100*4882a593Smuzhiyun 	case ISCSI_NET_PARAM_IPV6_ROUTER_AUTOCFG:
2101*4882a593Smuzhiyun 		/* Autocfg applies to even interface */
2102*4882a593Smuzhiyun 		if (iface_param->iface_num & 0x1)
2103*4882a593Smuzhiyun 			break;
2104*4882a593Smuzhiyun 
2105*4882a593Smuzhiyun 		if (iface_param->value[0] == ISCSI_IPV6_ROUTER_AUTOCFG_ENABLE)
2106*4882a593Smuzhiyun 			memset(init_fw_cb->ipv6_dflt_rtr_addr, 0,
2107*4882a593Smuzhiyun 			       sizeof(init_fw_cb->ipv6_dflt_rtr_addr));
2108*4882a593Smuzhiyun 		break;
2109*4882a593Smuzhiyun 	case ISCSI_NET_PARAM_IFACE_ENABLE:
2110*4882a593Smuzhiyun 		if (iface_param->value[0] == ISCSI_IFACE_ENABLE) {
2111*4882a593Smuzhiyun 			init_fw_cb->ipv6_opts |=
2112*4882a593Smuzhiyun 				cpu_to_le16(IPV6_OPT_IPV6_PROTOCOL_ENABLE);
2113*4882a593Smuzhiyun 			qla4xxx_create_ipv6_iface(ha);
2114*4882a593Smuzhiyun 		} else {
2115*4882a593Smuzhiyun 			init_fw_cb->ipv6_opts &=
2116*4882a593Smuzhiyun 				cpu_to_le16(~IPV6_OPT_IPV6_PROTOCOL_ENABLE &
2117*4882a593Smuzhiyun 					    0xFFFF);
2118*4882a593Smuzhiyun 			qla4xxx_destroy_ipv6_iface(ha);
2119*4882a593Smuzhiyun 		}
2120*4882a593Smuzhiyun 		break;
2121*4882a593Smuzhiyun 	case ISCSI_NET_PARAM_VLAN_TAG:
2122*4882a593Smuzhiyun 		if (iface_param->len != sizeof(init_fw_cb->ipv6_vlan_tag))
2123*4882a593Smuzhiyun 			break;
2124*4882a593Smuzhiyun 		init_fw_cb->ipv6_vlan_tag =
2125*4882a593Smuzhiyun 				cpu_to_be16(*(uint16_t *)iface_param->value);
2126*4882a593Smuzhiyun 		break;
2127*4882a593Smuzhiyun 	case ISCSI_NET_PARAM_VLAN_ENABLED:
2128*4882a593Smuzhiyun 		if (iface_param->value[0] == ISCSI_VLAN_ENABLE)
2129*4882a593Smuzhiyun 			init_fw_cb->ipv6_opts |=
2130*4882a593Smuzhiyun 				cpu_to_le16(IPV6_OPT_VLAN_TAGGING_ENABLE);
2131*4882a593Smuzhiyun 		else
2132*4882a593Smuzhiyun 			init_fw_cb->ipv6_opts &=
2133*4882a593Smuzhiyun 				cpu_to_le16(~IPV6_OPT_VLAN_TAGGING_ENABLE);
2134*4882a593Smuzhiyun 		break;
2135*4882a593Smuzhiyun 	case ISCSI_NET_PARAM_MTU:
2136*4882a593Smuzhiyun 		init_fw_cb->eth_mtu_size =
2137*4882a593Smuzhiyun 				cpu_to_le16(*(uint16_t *)iface_param->value);
2138*4882a593Smuzhiyun 		break;
2139*4882a593Smuzhiyun 	case ISCSI_NET_PARAM_PORT:
2140*4882a593Smuzhiyun 		/* Autocfg applies to even interface */
2141*4882a593Smuzhiyun 		if (iface_param->iface_num & 0x1)
2142*4882a593Smuzhiyun 			break;
2143*4882a593Smuzhiyun 
2144*4882a593Smuzhiyun 		init_fw_cb->ipv6_port =
2145*4882a593Smuzhiyun 				cpu_to_le16(*(uint16_t *)iface_param->value);
2146*4882a593Smuzhiyun 		break;
2147*4882a593Smuzhiyun 	case ISCSI_NET_PARAM_DELAYED_ACK_EN:
2148*4882a593Smuzhiyun 		if (iface_param->iface_num & 0x1)
2149*4882a593Smuzhiyun 			break;
2150*4882a593Smuzhiyun 		if (iface_param->value[0] == ISCSI_NET_PARAM_DISABLE)
2151*4882a593Smuzhiyun 			init_fw_cb->ipv6_tcp_opts |=
2152*4882a593Smuzhiyun 				cpu_to_le16(IPV6_TCPOPT_DELAYED_ACK_DISABLE);
2153*4882a593Smuzhiyun 		else
2154*4882a593Smuzhiyun 			init_fw_cb->ipv6_tcp_opts &=
2155*4882a593Smuzhiyun 				cpu_to_le16(~IPV6_TCPOPT_DELAYED_ACK_DISABLE &
2156*4882a593Smuzhiyun 					    0xFFFF);
2157*4882a593Smuzhiyun 		break;
2158*4882a593Smuzhiyun 	case ISCSI_NET_PARAM_TCP_NAGLE_DISABLE:
2159*4882a593Smuzhiyun 		if (iface_param->iface_num & 0x1)
2160*4882a593Smuzhiyun 			break;
2161*4882a593Smuzhiyun 		if (iface_param->value[0] == ISCSI_NET_PARAM_DISABLE)
2162*4882a593Smuzhiyun 			init_fw_cb->ipv6_tcp_opts |=
2163*4882a593Smuzhiyun 				cpu_to_le16(IPV6_TCPOPT_NAGLE_ALGO_DISABLE);
2164*4882a593Smuzhiyun 		else
2165*4882a593Smuzhiyun 			init_fw_cb->ipv6_tcp_opts &=
2166*4882a593Smuzhiyun 				cpu_to_le16(~IPV6_TCPOPT_NAGLE_ALGO_DISABLE);
2167*4882a593Smuzhiyun 		break;
2168*4882a593Smuzhiyun 	case ISCSI_NET_PARAM_TCP_WSF_DISABLE:
2169*4882a593Smuzhiyun 		if (iface_param->iface_num & 0x1)
2170*4882a593Smuzhiyun 			break;
2171*4882a593Smuzhiyun 		if (iface_param->value[0] == ISCSI_NET_PARAM_DISABLE)
2172*4882a593Smuzhiyun 			init_fw_cb->ipv6_tcp_opts |=
2173*4882a593Smuzhiyun 				cpu_to_le16(IPV6_TCPOPT_WINDOW_SCALE_DISABLE);
2174*4882a593Smuzhiyun 		else
2175*4882a593Smuzhiyun 			init_fw_cb->ipv6_tcp_opts &=
2176*4882a593Smuzhiyun 				cpu_to_le16(~IPV6_TCPOPT_WINDOW_SCALE_DISABLE);
2177*4882a593Smuzhiyun 		break;
2178*4882a593Smuzhiyun 	case ISCSI_NET_PARAM_TCP_WSF:
2179*4882a593Smuzhiyun 		if (iface_param->iface_num & 0x1)
2180*4882a593Smuzhiyun 			break;
2181*4882a593Smuzhiyun 		init_fw_cb->ipv6_tcp_wsf = iface_param->value[0];
2182*4882a593Smuzhiyun 		break;
2183*4882a593Smuzhiyun 	case ISCSI_NET_PARAM_TCP_TIMER_SCALE:
2184*4882a593Smuzhiyun 		if (iface_param->iface_num & 0x1)
2185*4882a593Smuzhiyun 			break;
2186*4882a593Smuzhiyun 		init_fw_cb->ipv6_tcp_opts &=
2187*4882a593Smuzhiyun 					cpu_to_le16(~IPV6_TCPOPT_TIMER_SCALE);
2188*4882a593Smuzhiyun 		init_fw_cb->ipv6_tcp_opts |=
2189*4882a593Smuzhiyun 				cpu_to_le16((iface_param->value[0] << 1) &
2190*4882a593Smuzhiyun 					    IPV6_TCPOPT_TIMER_SCALE);
2191*4882a593Smuzhiyun 		break;
2192*4882a593Smuzhiyun 	case ISCSI_NET_PARAM_TCP_TIMESTAMP_EN:
2193*4882a593Smuzhiyun 		if (iface_param->iface_num & 0x1)
2194*4882a593Smuzhiyun 			break;
2195*4882a593Smuzhiyun 		if (iface_param->value[0] == ISCSI_NET_PARAM_ENABLE)
2196*4882a593Smuzhiyun 			init_fw_cb->ipv6_tcp_opts |=
2197*4882a593Smuzhiyun 				cpu_to_le16(IPV6_TCPOPT_TIMESTAMP_EN);
2198*4882a593Smuzhiyun 		else
2199*4882a593Smuzhiyun 			init_fw_cb->ipv6_tcp_opts &=
2200*4882a593Smuzhiyun 				cpu_to_le16(~IPV6_TCPOPT_TIMESTAMP_EN);
2201*4882a593Smuzhiyun 		break;
2202*4882a593Smuzhiyun 	case ISCSI_NET_PARAM_IPV6_GRAT_NEIGHBOR_ADV_EN:
2203*4882a593Smuzhiyun 		if (iface_param->iface_num & 0x1)
2204*4882a593Smuzhiyun 			break;
2205*4882a593Smuzhiyun 		if (iface_param->value[0] == ISCSI_NET_PARAM_ENABLE)
2206*4882a593Smuzhiyun 			init_fw_cb->ipv6_opts |=
2207*4882a593Smuzhiyun 				cpu_to_le16(IPV6_OPT_GRAT_NEIGHBOR_ADV_EN);
2208*4882a593Smuzhiyun 		else
2209*4882a593Smuzhiyun 			init_fw_cb->ipv6_opts &=
2210*4882a593Smuzhiyun 				cpu_to_le16(~IPV6_OPT_GRAT_NEIGHBOR_ADV_EN);
2211*4882a593Smuzhiyun 		break;
2212*4882a593Smuzhiyun 	case ISCSI_NET_PARAM_REDIRECT_EN:
2213*4882a593Smuzhiyun 		if (iface_param->iface_num & 0x1)
2214*4882a593Smuzhiyun 			break;
2215*4882a593Smuzhiyun 		if (iface_param->value[0] == ISCSI_NET_PARAM_ENABLE)
2216*4882a593Smuzhiyun 			init_fw_cb->ipv6_opts |=
2217*4882a593Smuzhiyun 				cpu_to_le16(IPV6_OPT_REDIRECT_EN);
2218*4882a593Smuzhiyun 		else
2219*4882a593Smuzhiyun 			init_fw_cb->ipv6_opts &=
2220*4882a593Smuzhiyun 				cpu_to_le16(~IPV6_OPT_REDIRECT_EN);
2221*4882a593Smuzhiyun 		break;
2222*4882a593Smuzhiyun 	case ISCSI_NET_PARAM_IPV6_MLD_EN:
2223*4882a593Smuzhiyun 		if (iface_param->iface_num & 0x1)
2224*4882a593Smuzhiyun 			break;
2225*4882a593Smuzhiyun 		if (iface_param->value[0] == ISCSI_NET_PARAM_ENABLE)
2226*4882a593Smuzhiyun 			init_fw_cb->ipv6_addtl_opts |=
2227*4882a593Smuzhiyun 				cpu_to_le16(IPV6_ADDOPT_MLD_EN);
2228*4882a593Smuzhiyun 		else
2229*4882a593Smuzhiyun 			init_fw_cb->ipv6_addtl_opts &=
2230*4882a593Smuzhiyun 				cpu_to_le16(~IPV6_ADDOPT_MLD_EN);
2231*4882a593Smuzhiyun 		break;
2232*4882a593Smuzhiyun 	case ISCSI_NET_PARAM_IPV6_FLOW_LABEL:
2233*4882a593Smuzhiyun 		if (iface_param->iface_num & 0x1)
2234*4882a593Smuzhiyun 			break;
2235*4882a593Smuzhiyun 		init_fw_cb->ipv6_flow_lbl =
2236*4882a593Smuzhiyun 				cpu_to_le16(*(uint16_t *)iface_param->value);
2237*4882a593Smuzhiyun 		break;
2238*4882a593Smuzhiyun 	case ISCSI_NET_PARAM_IPV6_TRAFFIC_CLASS:
2239*4882a593Smuzhiyun 		if (iface_param->iface_num & 0x1)
2240*4882a593Smuzhiyun 			break;
2241*4882a593Smuzhiyun 		init_fw_cb->ipv6_traffic_class = iface_param->value[0];
2242*4882a593Smuzhiyun 		break;
2243*4882a593Smuzhiyun 	case ISCSI_NET_PARAM_IPV6_HOP_LIMIT:
2244*4882a593Smuzhiyun 		if (iface_param->iface_num & 0x1)
2245*4882a593Smuzhiyun 			break;
2246*4882a593Smuzhiyun 		init_fw_cb->ipv6_hop_limit = iface_param->value[0];
2247*4882a593Smuzhiyun 		break;
2248*4882a593Smuzhiyun 	case ISCSI_NET_PARAM_IPV6_ND_REACHABLE_TMO:
2249*4882a593Smuzhiyun 		if (iface_param->iface_num & 0x1)
2250*4882a593Smuzhiyun 			break;
2251*4882a593Smuzhiyun 		init_fw_cb->ipv6_nd_reach_time =
2252*4882a593Smuzhiyun 				cpu_to_le32(*(uint32_t *)iface_param->value);
2253*4882a593Smuzhiyun 		break;
2254*4882a593Smuzhiyun 	case ISCSI_NET_PARAM_IPV6_ND_REXMIT_TIME:
2255*4882a593Smuzhiyun 		if (iface_param->iface_num & 0x1)
2256*4882a593Smuzhiyun 			break;
2257*4882a593Smuzhiyun 		init_fw_cb->ipv6_nd_rexmit_timer =
2258*4882a593Smuzhiyun 				cpu_to_le32(*(uint32_t *)iface_param->value);
2259*4882a593Smuzhiyun 		break;
2260*4882a593Smuzhiyun 	case ISCSI_NET_PARAM_IPV6_ND_STALE_TMO:
2261*4882a593Smuzhiyun 		if (iface_param->iface_num & 0x1)
2262*4882a593Smuzhiyun 			break;
2263*4882a593Smuzhiyun 		init_fw_cb->ipv6_nd_stale_timeout =
2264*4882a593Smuzhiyun 				cpu_to_le32(*(uint32_t *)iface_param->value);
2265*4882a593Smuzhiyun 		break;
2266*4882a593Smuzhiyun 	case ISCSI_NET_PARAM_IPV6_DUP_ADDR_DETECT_CNT:
2267*4882a593Smuzhiyun 		if (iface_param->iface_num & 0x1)
2268*4882a593Smuzhiyun 			break;
2269*4882a593Smuzhiyun 		init_fw_cb->ipv6_dup_addr_detect_count = iface_param->value[0];
2270*4882a593Smuzhiyun 		break;
2271*4882a593Smuzhiyun 	case ISCSI_NET_PARAM_IPV6_RTR_ADV_LINK_MTU:
2272*4882a593Smuzhiyun 		if (iface_param->iface_num & 0x1)
2273*4882a593Smuzhiyun 			break;
2274*4882a593Smuzhiyun 		init_fw_cb->ipv6_gw_advrt_mtu =
2275*4882a593Smuzhiyun 				cpu_to_le32(*(uint32_t *)iface_param->value);
2276*4882a593Smuzhiyun 		break;
2277*4882a593Smuzhiyun 	default:
2278*4882a593Smuzhiyun 		ql4_printk(KERN_ERR, ha, "Unknown IPv6 param = %d\n",
2279*4882a593Smuzhiyun 			   iface_param->param);
2280*4882a593Smuzhiyun 		break;
2281*4882a593Smuzhiyun 	}
2282*4882a593Smuzhiyun }
2283*4882a593Smuzhiyun 
qla4xxx_set_ipv4(struct scsi_qla_host * ha,struct iscsi_iface_param_info * iface_param,struct addr_ctrl_blk * init_fw_cb)2284*4882a593Smuzhiyun static void qla4xxx_set_ipv4(struct scsi_qla_host *ha,
2285*4882a593Smuzhiyun 			     struct iscsi_iface_param_info *iface_param,
2286*4882a593Smuzhiyun 			     struct addr_ctrl_blk *init_fw_cb)
2287*4882a593Smuzhiyun {
2288*4882a593Smuzhiyun 	switch (iface_param->param) {
2289*4882a593Smuzhiyun 	case ISCSI_NET_PARAM_IPV4_ADDR:
2290*4882a593Smuzhiyun 		memcpy(init_fw_cb->ipv4_addr, iface_param->value,
2291*4882a593Smuzhiyun 		       sizeof(init_fw_cb->ipv4_addr));
2292*4882a593Smuzhiyun 		break;
2293*4882a593Smuzhiyun 	case ISCSI_NET_PARAM_IPV4_SUBNET:
2294*4882a593Smuzhiyun 		memcpy(init_fw_cb->ipv4_subnet,	iface_param->value,
2295*4882a593Smuzhiyun 		       sizeof(init_fw_cb->ipv4_subnet));
2296*4882a593Smuzhiyun 		break;
2297*4882a593Smuzhiyun 	case ISCSI_NET_PARAM_IPV4_GW:
2298*4882a593Smuzhiyun 		memcpy(init_fw_cb->ipv4_gw_addr, iface_param->value,
2299*4882a593Smuzhiyun 		       sizeof(init_fw_cb->ipv4_gw_addr));
2300*4882a593Smuzhiyun 		break;
2301*4882a593Smuzhiyun 	case ISCSI_NET_PARAM_IPV4_BOOTPROTO:
2302*4882a593Smuzhiyun 		if (iface_param->value[0] == ISCSI_BOOTPROTO_DHCP)
2303*4882a593Smuzhiyun 			init_fw_cb->ipv4_tcp_opts |=
2304*4882a593Smuzhiyun 					cpu_to_le16(TCPOPT_DHCP_ENABLE);
2305*4882a593Smuzhiyun 		else if (iface_param->value[0] == ISCSI_BOOTPROTO_STATIC)
2306*4882a593Smuzhiyun 			init_fw_cb->ipv4_tcp_opts &=
2307*4882a593Smuzhiyun 					cpu_to_le16(~TCPOPT_DHCP_ENABLE);
2308*4882a593Smuzhiyun 		else
2309*4882a593Smuzhiyun 			ql4_printk(KERN_ERR, ha, "Invalid IPv4 bootproto\n");
2310*4882a593Smuzhiyun 		break;
2311*4882a593Smuzhiyun 	case ISCSI_NET_PARAM_IFACE_ENABLE:
2312*4882a593Smuzhiyun 		if (iface_param->value[0] == ISCSI_IFACE_ENABLE) {
2313*4882a593Smuzhiyun 			init_fw_cb->ipv4_ip_opts |=
2314*4882a593Smuzhiyun 				cpu_to_le16(IPOPT_IPV4_PROTOCOL_ENABLE);
2315*4882a593Smuzhiyun 			qla4xxx_create_ipv4_iface(ha);
2316*4882a593Smuzhiyun 		} else {
2317*4882a593Smuzhiyun 			init_fw_cb->ipv4_ip_opts &=
2318*4882a593Smuzhiyun 				cpu_to_le16(~IPOPT_IPV4_PROTOCOL_ENABLE &
2319*4882a593Smuzhiyun 					    0xFFFF);
2320*4882a593Smuzhiyun 			qla4xxx_destroy_ipv4_iface(ha);
2321*4882a593Smuzhiyun 		}
2322*4882a593Smuzhiyun 		break;
2323*4882a593Smuzhiyun 	case ISCSI_NET_PARAM_VLAN_TAG:
2324*4882a593Smuzhiyun 		if (iface_param->len != sizeof(init_fw_cb->ipv4_vlan_tag))
2325*4882a593Smuzhiyun 			break;
2326*4882a593Smuzhiyun 		init_fw_cb->ipv4_vlan_tag =
2327*4882a593Smuzhiyun 				cpu_to_be16(*(uint16_t *)iface_param->value);
2328*4882a593Smuzhiyun 		break;
2329*4882a593Smuzhiyun 	case ISCSI_NET_PARAM_VLAN_ENABLED:
2330*4882a593Smuzhiyun 		if (iface_param->value[0] == ISCSI_VLAN_ENABLE)
2331*4882a593Smuzhiyun 			init_fw_cb->ipv4_ip_opts |=
2332*4882a593Smuzhiyun 					cpu_to_le16(IPOPT_VLAN_TAGGING_ENABLE);
2333*4882a593Smuzhiyun 		else
2334*4882a593Smuzhiyun 			init_fw_cb->ipv4_ip_opts &=
2335*4882a593Smuzhiyun 					cpu_to_le16(~IPOPT_VLAN_TAGGING_ENABLE);
2336*4882a593Smuzhiyun 		break;
2337*4882a593Smuzhiyun 	case ISCSI_NET_PARAM_MTU:
2338*4882a593Smuzhiyun 		init_fw_cb->eth_mtu_size =
2339*4882a593Smuzhiyun 				cpu_to_le16(*(uint16_t *)iface_param->value);
2340*4882a593Smuzhiyun 		break;
2341*4882a593Smuzhiyun 	case ISCSI_NET_PARAM_PORT:
2342*4882a593Smuzhiyun 		init_fw_cb->ipv4_port =
2343*4882a593Smuzhiyun 				cpu_to_le16(*(uint16_t *)iface_param->value);
2344*4882a593Smuzhiyun 		break;
2345*4882a593Smuzhiyun 	case ISCSI_NET_PARAM_DELAYED_ACK_EN:
2346*4882a593Smuzhiyun 		if (iface_param->iface_num & 0x1)
2347*4882a593Smuzhiyun 			break;
2348*4882a593Smuzhiyun 		if (iface_param->value[0] == ISCSI_NET_PARAM_DISABLE)
2349*4882a593Smuzhiyun 			init_fw_cb->ipv4_tcp_opts |=
2350*4882a593Smuzhiyun 				cpu_to_le16(TCPOPT_DELAYED_ACK_DISABLE);
2351*4882a593Smuzhiyun 		else
2352*4882a593Smuzhiyun 			init_fw_cb->ipv4_tcp_opts &=
2353*4882a593Smuzhiyun 				cpu_to_le16(~TCPOPT_DELAYED_ACK_DISABLE &
2354*4882a593Smuzhiyun 					    0xFFFF);
2355*4882a593Smuzhiyun 		break;
2356*4882a593Smuzhiyun 	case ISCSI_NET_PARAM_TCP_NAGLE_DISABLE:
2357*4882a593Smuzhiyun 		if (iface_param->iface_num & 0x1)
2358*4882a593Smuzhiyun 			break;
2359*4882a593Smuzhiyun 		if (iface_param->value[0] == ISCSI_NET_PARAM_DISABLE)
2360*4882a593Smuzhiyun 			init_fw_cb->ipv4_tcp_opts |=
2361*4882a593Smuzhiyun 				cpu_to_le16(TCPOPT_NAGLE_ALGO_DISABLE);
2362*4882a593Smuzhiyun 		else
2363*4882a593Smuzhiyun 			init_fw_cb->ipv4_tcp_opts &=
2364*4882a593Smuzhiyun 				cpu_to_le16(~TCPOPT_NAGLE_ALGO_DISABLE);
2365*4882a593Smuzhiyun 		break;
2366*4882a593Smuzhiyun 	case ISCSI_NET_PARAM_TCP_WSF_DISABLE:
2367*4882a593Smuzhiyun 		if (iface_param->iface_num & 0x1)
2368*4882a593Smuzhiyun 			break;
2369*4882a593Smuzhiyun 		if (iface_param->value[0] == ISCSI_NET_PARAM_DISABLE)
2370*4882a593Smuzhiyun 			init_fw_cb->ipv4_tcp_opts |=
2371*4882a593Smuzhiyun 				cpu_to_le16(TCPOPT_WINDOW_SCALE_DISABLE);
2372*4882a593Smuzhiyun 		else
2373*4882a593Smuzhiyun 			init_fw_cb->ipv4_tcp_opts &=
2374*4882a593Smuzhiyun 				cpu_to_le16(~TCPOPT_WINDOW_SCALE_DISABLE);
2375*4882a593Smuzhiyun 		break;
2376*4882a593Smuzhiyun 	case ISCSI_NET_PARAM_TCP_WSF:
2377*4882a593Smuzhiyun 		if (iface_param->iface_num & 0x1)
2378*4882a593Smuzhiyun 			break;
2379*4882a593Smuzhiyun 		init_fw_cb->ipv4_tcp_wsf = iface_param->value[0];
2380*4882a593Smuzhiyun 		break;
2381*4882a593Smuzhiyun 	case ISCSI_NET_PARAM_TCP_TIMER_SCALE:
2382*4882a593Smuzhiyun 		if (iface_param->iface_num & 0x1)
2383*4882a593Smuzhiyun 			break;
2384*4882a593Smuzhiyun 		init_fw_cb->ipv4_tcp_opts &= cpu_to_le16(~TCPOPT_TIMER_SCALE);
2385*4882a593Smuzhiyun 		init_fw_cb->ipv4_tcp_opts |=
2386*4882a593Smuzhiyun 				cpu_to_le16((iface_param->value[0] << 1) &
2387*4882a593Smuzhiyun 					    TCPOPT_TIMER_SCALE);
2388*4882a593Smuzhiyun 		break;
2389*4882a593Smuzhiyun 	case ISCSI_NET_PARAM_TCP_TIMESTAMP_EN:
2390*4882a593Smuzhiyun 		if (iface_param->iface_num & 0x1)
2391*4882a593Smuzhiyun 			break;
2392*4882a593Smuzhiyun 		if (iface_param->value[0] == ISCSI_NET_PARAM_ENABLE)
2393*4882a593Smuzhiyun 			init_fw_cb->ipv4_tcp_opts |=
2394*4882a593Smuzhiyun 				cpu_to_le16(TCPOPT_TIMESTAMP_ENABLE);
2395*4882a593Smuzhiyun 		else
2396*4882a593Smuzhiyun 			init_fw_cb->ipv4_tcp_opts &=
2397*4882a593Smuzhiyun 				cpu_to_le16(~TCPOPT_TIMESTAMP_ENABLE);
2398*4882a593Smuzhiyun 		break;
2399*4882a593Smuzhiyun 	case ISCSI_NET_PARAM_IPV4_DHCP_DNS_ADDR_EN:
2400*4882a593Smuzhiyun 		if (iface_param->iface_num & 0x1)
2401*4882a593Smuzhiyun 			break;
2402*4882a593Smuzhiyun 		if (iface_param->value[0] == ISCSI_NET_PARAM_ENABLE)
2403*4882a593Smuzhiyun 			init_fw_cb->ipv4_tcp_opts |=
2404*4882a593Smuzhiyun 				cpu_to_le16(TCPOPT_DNS_SERVER_IP_EN);
2405*4882a593Smuzhiyun 		else
2406*4882a593Smuzhiyun 			init_fw_cb->ipv4_tcp_opts &=
2407*4882a593Smuzhiyun 				cpu_to_le16(~TCPOPT_DNS_SERVER_IP_EN);
2408*4882a593Smuzhiyun 		break;
2409*4882a593Smuzhiyun 	case ISCSI_NET_PARAM_IPV4_DHCP_SLP_DA_EN:
2410*4882a593Smuzhiyun 		if (iface_param->iface_num & 0x1)
2411*4882a593Smuzhiyun 			break;
2412*4882a593Smuzhiyun 		if (iface_param->value[0] == ISCSI_NET_PARAM_ENABLE)
2413*4882a593Smuzhiyun 			init_fw_cb->ipv4_tcp_opts |=
2414*4882a593Smuzhiyun 				cpu_to_le16(TCPOPT_SLP_DA_INFO_EN);
2415*4882a593Smuzhiyun 		else
2416*4882a593Smuzhiyun 			init_fw_cb->ipv4_tcp_opts &=
2417*4882a593Smuzhiyun 				cpu_to_le16(~TCPOPT_SLP_DA_INFO_EN);
2418*4882a593Smuzhiyun 		break;
2419*4882a593Smuzhiyun 	case ISCSI_NET_PARAM_IPV4_TOS_EN:
2420*4882a593Smuzhiyun 		if (iface_param->iface_num & 0x1)
2421*4882a593Smuzhiyun 			break;
2422*4882a593Smuzhiyun 		if (iface_param->value[0] == ISCSI_NET_PARAM_ENABLE)
2423*4882a593Smuzhiyun 			init_fw_cb->ipv4_ip_opts |=
2424*4882a593Smuzhiyun 				cpu_to_le16(IPOPT_IPV4_TOS_EN);
2425*4882a593Smuzhiyun 		else
2426*4882a593Smuzhiyun 			init_fw_cb->ipv4_ip_opts &=
2427*4882a593Smuzhiyun 				cpu_to_le16(~IPOPT_IPV4_TOS_EN);
2428*4882a593Smuzhiyun 		break;
2429*4882a593Smuzhiyun 	case ISCSI_NET_PARAM_IPV4_TOS:
2430*4882a593Smuzhiyun 		if (iface_param->iface_num & 0x1)
2431*4882a593Smuzhiyun 			break;
2432*4882a593Smuzhiyun 		init_fw_cb->ipv4_tos = iface_param->value[0];
2433*4882a593Smuzhiyun 		break;
2434*4882a593Smuzhiyun 	case ISCSI_NET_PARAM_IPV4_GRAT_ARP_EN:
2435*4882a593Smuzhiyun 		if (iface_param->iface_num & 0x1)
2436*4882a593Smuzhiyun 			break;
2437*4882a593Smuzhiyun 		if (iface_param->value[0] == ISCSI_NET_PARAM_ENABLE)
2438*4882a593Smuzhiyun 			init_fw_cb->ipv4_ip_opts |=
2439*4882a593Smuzhiyun 					cpu_to_le16(IPOPT_GRAT_ARP_EN);
2440*4882a593Smuzhiyun 		else
2441*4882a593Smuzhiyun 			init_fw_cb->ipv4_ip_opts &=
2442*4882a593Smuzhiyun 					cpu_to_le16(~IPOPT_GRAT_ARP_EN);
2443*4882a593Smuzhiyun 		break;
2444*4882a593Smuzhiyun 	case ISCSI_NET_PARAM_IPV4_DHCP_ALT_CLIENT_ID_EN:
2445*4882a593Smuzhiyun 		if (iface_param->iface_num & 0x1)
2446*4882a593Smuzhiyun 			break;
2447*4882a593Smuzhiyun 		if (iface_param->value[0] == ISCSI_NET_PARAM_ENABLE)
2448*4882a593Smuzhiyun 			init_fw_cb->ipv4_ip_opts |=
2449*4882a593Smuzhiyun 				cpu_to_le16(IPOPT_ALT_CID_EN);
2450*4882a593Smuzhiyun 		else
2451*4882a593Smuzhiyun 			init_fw_cb->ipv4_ip_opts &=
2452*4882a593Smuzhiyun 				cpu_to_le16(~IPOPT_ALT_CID_EN);
2453*4882a593Smuzhiyun 		break;
2454*4882a593Smuzhiyun 	case ISCSI_NET_PARAM_IPV4_DHCP_ALT_CLIENT_ID:
2455*4882a593Smuzhiyun 		if (iface_param->iface_num & 0x1)
2456*4882a593Smuzhiyun 			break;
2457*4882a593Smuzhiyun 		memcpy(init_fw_cb->ipv4_dhcp_alt_cid, iface_param->value,
2458*4882a593Smuzhiyun 		       (sizeof(init_fw_cb->ipv4_dhcp_alt_cid) - 1));
2459*4882a593Smuzhiyun 		init_fw_cb->ipv4_dhcp_alt_cid_len =
2460*4882a593Smuzhiyun 					strlen(init_fw_cb->ipv4_dhcp_alt_cid);
2461*4882a593Smuzhiyun 		break;
2462*4882a593Smuzhiyun 	case ISCSI_NET_PARAM_IPV4_DHCP_REQ_VENDOR_ID_EN:
2463*4882a593Smuzhiyun 		if (iface_param->iface_num & 0x1)
2464*4882a593Smuzhiyun 			break;
2465*4882a593Smuzhiyun 		if (iface_param->value[0] == ISCSI_NET_PARAM_ENABLE)
2466*4882a593Smuzhiyun 			init_fw_cb->ipv4_ip_opts |=
2467*4882a593Smuzhiyun 					cpu_to_le16(IPOPT_REQ_VID_EN);
2468*4882a593Smuzhiyun 		else
2469*4882a593Smuzhiyun 			init_fw_cb->ipv4_ip_opts &=
2470*4882a593Smuzhiyun 					cpu_to_le16(~IPOPT_REQ_VID_EN);
2471*4882a593Smuzhiyun 		break;
2472*4882a593Smuzhiyun 	case ISCSI_NET_PARAM_IPV4_DHCP_USE_VENDOR_ID_EN:
2473*4882a593Smuzhiyun 		if (iface_param->iface_num & 0x1)
2474*4882a593Smuzhiyun 			break;
2475*4882a593Smuzhiyun 		if (iface_param->value[0] == ISCSI_NET_PARAM_ENABLE)
2476*4882a593Smuzhiyun 			init_fw_cb->ipv4_ip_opts |=
2477*4882a593Smuzhiyun 					cpu_to_le16(IPOPT_USE_VID_EN);
2478*4882a593Smuzhiyun 		else
2479*4882a593Smuzhiyun 			init_fw_cb->ipv4_ip_opts &=
2480*4882a593Smuzhiyun 					cpu_to_le16(~IPOPT_USE_VID_EN);
2481*4882a593Smuzhiyun 		break;
2482*4882a593Smuzhiyun 	case ISCSI_NET_PARAM_IPV4_DHCP_VENDOR_ID:
2483*4882a593Smuzhiyun 		if (iface_param->iface_num & 0x1)
2484*4882a593Smuzhiyun 			break;
2485*4882a593Smuzhiyun 		memcpy(init_fw_cb->ipv4_dhcp_vid, iface_param->value,
2486*4882a593Smuzhiyun 		       (sizeof(init_fw_cb->ipv4_dhcp_vid) - 1));
2487*4882a593Smuzhiyun 		init_fw_cb->ipv4_dhcp_vid_len =
2488*4882a593Smuzhiyun 					strlen(init_fw_cb->ipv4_dhcp_vid);
2489*4882a593Smuzhiyun 		break;
2490*4882a593Smuzhiyun 	case ISCSI_NET_PARAM_IPV4_DHCP_LEARN_IQN_EN:
2491*4882a593Smuzhiyun 		if (iface_param->iface_num & 0x1)
2492*4882a593Smuzhiyun 			break;
2493*4882a593Smuzhiyun 		if (iface_param->value[0] == ISCSI_NET_PARAM_ENABLE)
2494*4882a593Smuzhiyun 			init_fw_cb->ipv4_ip_opts |=
2495*4882a593Smuzhiyun 					cpu_to_le16(IPOPT_LEARN_IQN_EN);
2496*4882a593Smuzhiyun 		else
2497*4882a593Smuzhiyun 			init_fw_cb->ipv4_ip_opts &=
2498*4882a593Smuzhiyun 					cpu_to_le16(~IPOPT_LEARN_IQN_EN);
2499*4882a593Smuzhiyun 		break;
2500*4882a593Smuzhiyun 	case ISCSI_NET_PARAM_IPV4_FRAGMENT_DISABLE:
2501*4882a593Smuzhiyun 		if (iface_param->iface_num & 0x1)
2502*4882a593Smuzhiyun 			break;
2503*4882a593Smuzhiyun 		if (iface_param->value[0] == ISCSI_NET_PARAM_DISABLE)
2504*4882a593Smuzhiyun 			init_fw_cb->ipv4_ip_opts |=
2505*4882a593Smuzhiyun 				cpu_to_le16(IPOPT_FRAGMENTATION_DISABLE);
2506*4882a593Smuzhiyun 		else
2507*4882a593Smuzhiyun 			init_fw_cb->ipv4_ip_opts &=
2508*4882a593Smuzhiyun 				cpu_to_le16(~IPOPT_FRAGMENTATION_DISABLE);
2509*4882a593Smuzhiyun 		break;
2510*4882a593Smuzhiyun 	case ISCSI_NET_PARAM_IPV4_IN_FORWARD_EN:
2511*4882a593Smuzhiyun 		if (iface_param->iface_num & 0x1)
2512*4882a593Smuzhiyun 			break;
2513*4882a593Smuzhiyun 		if (iface_param->value[0] == ISCSI_NET_PARAM_ENABLE)
2514*4882a593Smuzhiyun 			init_fw_cb->ipv4_ip_opts |=
2515*4882a593Smuzhiyun 				cpu_to_le16(IPOPT_IN_FORWARD_EN);
2516*4882a593Smuzhiyun 		else
2517*4882a593Smuzhiyun 			init_fw_cb->ipv4_ip_opts &=
2518*4882a593Smuzhiyun 				cpu_to_le16(~IPOPT_IN_FORWARD_EN);
2519*4882a593Smuzhiyun 		break;
2520*4882a593Smuzhiyun 	case ISCSI_NET_PARAM_REDIRECT_EN:
2521*4882a593Smuzhiyun 		if (iface_param->iface_num & 0x1)
2522*4882a593Smuzhiyun 			break;
2523*4882a593Smuzhiyun 		if (iface_param->value[0] == ISCSI_NET_PARAM_ENABLE)
2524*4882a593Smuzhiyun 			init_fw_cb->ipv4_ip_opts |=
2525*4882a593Smuzhiyun 				cpu_to_le16(IPOPT_ARP_REDIRECT_EN);
2526*4882a593Smuzhiyun 		else
2527*4882a593Smuzhiyun 			init_fw_cb->ipv4_ip_opts &=
2528*4882a593Smuzhiyun 				cpu_to_le16(~IPOPT_ARP_REDIRECT_EN);
2529*4882a593Smuzhiyun 		break;
2530*4882a593Smuzhiyun 	case ISCSI_NET_PARAM_IPV4_TTL:
2531*4882a593Smuzhiyun 		if (iface_param->iface_num & 0x1)
2532*4882a593Smuzhiyun 			break;
2533*4882a593Smuzhiyun 		init_fw_cb->ipv4_ttl = iface_param->value[0];
2534*4882a593Smuzhiyun 		break;
2535*4882a593Smuzhiyun 	default:
2536*4882a593Smuzhiyun 		ql4_printk(KERN_ERR, ha, "Unknown IPv4 param = %d\n",
2537*4882a593Smuzhiyun 			   iface_param->param);
2538*4882a593Smuzhiyun 		break;
2539*4882a593Smuzhiyun 	}
2540*4882a593Smuzhiyun }
2541*4882a593Smuzhiyun 
qla4xxx_set_iscsi_param(struct scsi_qla_host * ha,struct iscsi_iface_param_info * iface_param,struct addr_ctrl_blk * init_fw_cb)2542*4882a593Smuzhiyun static void qla4xxx_set_iscsi_param(struct scsi_qla_host *ha,
2543*4882a593Smuzhiyun 				    struct iscsi_iface_param_info *iface_param,
2544*4882a593Smuzhiyun 				    struct addr_ctrl_blk *init_fw_cb)
2545*4882a593Smuzhiyun {
2546*4882a593Smuzhiyun 	switch (iface_param->param) {
2547*4882a593Smuzhiyun 	case ISCSI_IFACE_PARAM_DEF_TASKMGMT_TMO:
2548*4882a593Smuzhiyun 		if (iface_param->iface_num & 0x1)
2549*4882a593Smuzhiyun 			break;
2550*4882a593Smuzhiyun 		init_fw_cb->def_timeout =
2551*4882a593Smuzhiyun 				cpu_to_le16(*(uint16_t *)iface_param->value);
2552*4882a593Smuzhiyun 		break;
2553*4882a593Smuzhiyun 	case ISCSI_IFACE_PARAM_HDRDGST_EN:
2554*4882a593Smuzhiyun 		if (iface_param->iface_num & 0x1)
2555*4882a593Smuzhiyun 			break;
2556*4882a593Smuzhiyun 		if (iface_param->value[0] == ISCSI_NET_PARAM_ENABLE)
2557*4882a593Smuzhiyun 			init_fw_cb->iscsi_opts |=
2558*4882a593Smuzhiyun 				cpu_to_le16(ISCSIOPTS_HEADER_DIGEST_EN);
2559*4882a593Smuzhiyun 		else
2560*4882a593Smuzhiyun 			init_fw_cb->iscsi_opts &=
2561*4882a593Smuzhiyun 				cpu_to_le16(~ISCSIOPTS_HEADER_DIGEST_EN);
2562*4882a593Smuzhiyun 		break;
2563*4882a593Smuzhiyun 	case ISCSI_IFACE_PARAM_DATADGST_EN:
2564*4882a593Smuzhiyun 		if (iface_param->iface_num & 0x1)
2565*4882a593Smuzhiyun 			break;
2566*4882a593Smuzhiyun 		if (iface_param->value[0] == ISCSI_NET_PARAM_ENABLE)
2567*4882a593Smuzhiyun 			init_fw_cb->iscsi_opts |=
2568*4882a593Smuzhiyun 				cpu_to_le16(ISCSIOPTS_DATA_DIGEST_EN);
2569*4882a593Smuzhiyun 		else
2570*4882a593Smuzhiyun 			init_fw_cb->iscsi_opts &=
2571*4882a593Smuzhiyun 				cpu_to_le16(~ISCSIOPTS_DATA_DIGEST_EN);
2572*4882a593Smuzhiyun 		break;
2573*4882a593Smuzhiyun 	case ISCSI_IFACE_PARAM_IMM_DATA_EN:
2574*4882a593Smuzhiyun 		if (iface_param->iface_num & 0x1)
2575*4882a593Smuzhiyun 			break;
2576*4882a593Smuzhiyun 		if (iface_param->value[0] == ISCSI_NET_PARAM_ENABLE)
2577*4882a593Smuzhiyun 			init_fw_cb->iscsi_opts |=
2578*4882a593Smuzhiyun 				cpu_to_le16(ISCSIOPTS_IMMEDIATE_DATA_EN);
2579*4882a593Smuzhiyun 		else
2580*4882a593Smuzhiyun 			init_fw_cb->iscsi_opts &=
2581*4882a593Smuzhiyun 				cpu_to_le16(~ISCSIOPTS_IMMEDIATE_DATA_EN);
2582*4882a593Smuzhiyun 		break;
2583*4882a593Smuzhiyun 	case ISCSI_IFACE_PARAM_INITIAL_R2T_EN:
2584*4882a593Smuzhiyun 		if (iface_param->iface_num & 0x1)
2585*4882a593Smuzhiyun 			break;
2586*4882a593Smuzhiyun 		if (iface_param->value[0] == ISCSI_NET_PARAM_ENABLE)
2587*4882a593Smuzhiyun 			init_fw_cb->iscsi_opts |=
2588*4882a593Smuzhiyun 				cpu_to_le16(ISCSIOPTS_INITIAL_R2T_EN);
2589*4882a593Smuzhiyun 		else
2590*4882a593Smuzhiyun 			init_fw_cb->iscsi_opts &=
2591*4882a593Smuzhiyun 				cpu_to_le16(~ISCSIOPTS_INITIAL_R2T_EN);
2592*4882a593Smuzhiyun 		break;
2593*4882a593Smuzhiyun 	case ISCSI_IFACE_PARAM_DATASEQ_INORDER_EN:
2594*4882a593Smuzhiyun 		if (iface_param->iface_num & 0x1)
2595*4882a593Smuzhiyun 			break;
2596*4882a593Smuzhiyun 		if (iface_param->value[0] == ISCSI_NET_PARAM_ENABLE)
2597*4882a593Smuzhiyun 			init_fw_cb->iscsi_opts |=
2598*4882a593Smuzhiyun 				cpu_to_le16(ISCSIOPTS_DATA_SEQ_INORDER_EN);
2599*4882a593Smuzhiyun 		else
2600*4882a593Smuzhiyun 			init_fw_cb->iscsi_opts &=
2601*4882a593Smuzhiyun 				cpu_to_le16(~ISCSIOPTS_DATA_SEQ_INORDER_EN);
2602*4882a593Smuzhiyun 		break;
2603*4882a593Smuzhiyun 	case ISCSI_IFACE_PARAM_PDU_INORDER_EN:
2604*4882a593Smuzhiyun 		if (iface_param->iface_num & 0x1)
2605*4882a593Smuzhiyun 			break;
2606*4882a593Smuzhiyun 		if (iface_param->value[0] == ISCSI_NET_PARAM_ENABLE)
2607*4882a593Smuzhiyun 			init_fw_cb->iscsi_opts |=
2608*4882a593Smuzhiyun 				cpu_to_le16(ISCSIOPTS_DATA_PDU_INORDER_EN);
2609*4882a593Smuzhiyun 		else
2610*4882a593Smuzhiyun 			init_fw_cb->iscsi_opts &=
2611*4882a593Smuzhiyun 				cpu_to_le16(~ISCSIOPTS_DATA_PDU_INORDER_EN);
2612*4882a593Smuzhiyun 		break;
2613*4882a593Smuzhiyun 	case ISCSI_IFACE_PARAM_ERL:
2614*4882a593Smuzhiyun 		if (iface_param->iface_num & 0x1)
2615*4882a593Smuzhiyun 			break;
2616*4882a593Smuzhiyun 		init_fw_cb->iscsi_opts &= cpu_to_le16(~ISCSIOPTS_ERL);
2617*4882a593Smuzhiyun 		init_fw_cb->iscsi_opts |= cpu_to_le16(iface_param->value[0] &
2618*4882a593Smuzhiyun 						      ISCSIOPTS_ERL);
2619*4882a593Smuzhiyun 		break;
2620*4882a593Smuzhiyun 	case ISCSI_IFACE_PARAM_MAX_RECV_DLENGTH:
2621*4882a593Smuzhiyun 		if (iface_param->iface_num & 0x1)
2622*4882a593Smuzhiyun 			break;
2623*4882a593Smuzhiyun 		init_fw_cb->iscsi_max_pdu_size =
2624*4882a593Smuzhiyun 				cpu_to_le32(*(uint32_t *)iface_param->value) /
2625*4882a593Smuzhiyun 				BYTE_UNITS;
2626*4882a593Smuzhiyun 		break;
2627*4882a593Smuzhiyun 	case ISCSI_IFACE_PARAM_FIRST_BURST:
2628*4882a593Smuzhiyun 		if (iface_param->iface_num & 0x1)
2629*4882a593Smuzhiyun 			break;
2630*4882a593Smuzhiyun 		init_fw_cb->iscsi_fburst_len =
2631*4882a593Smuzhiyun 				cpu_to_le32(*(uint32_t *)iface_param->value) /
2632*4882a593Smuzhiyun 				BYTE_UNITS;
2633*4882a593Smuzhiyun 		break;
2634*4882a593Smuzhiyun 	case ISCSI_IFACE_PARAM_MAX_R2T:
2635*4882a593Smuzhiyun 		if (iface_param->iface_num & 0x1)
2636*4882a593Smuzhiyun 			break;
2637*4882a593Smuzhiyun 		init_fw_cb->iscsi_max_outstnd_r2t =
2638*4882a593Smuzhiyun 				cpu_to_le16(*(uint16_t *)iface_param->value);
2639*4882a593Smuzhiyun 		break;
2640*4882a593Smuzhiyun 	case ISCSI_IFACE_PARAM_MAX_BURST:
2641*4882a593Smuzhiyun 		if (iface_param->iface_num & 0x1)
2642*4882a593Smuzhiyun 			break;
2643*4882a593Smuzhiyun 		init_fw_cb->iscsi_max_burst_len =
2644*4882a593Smuzhiyun 				cpu_to_le32(*(uint32_t *)iface_param->value) /
2645*4882a593Smuzhiyun 				BYTE_UNITS;
2646*4882a593Smuzhiyun 		break;
2647*4882a593Smuzhiyun 	case ISCSI_IFACE_PARAM_CHAP_AUTH_EN:
2648*4882a593Smuzhiyun 		if (iface_param->iface_num & 0x1)
2649*4882a593Smuzhiyun 			break;
2650*4882a593Smuzhiyun 		if (iface_param->value[0] == ISCSI_NET_PARAM_ENABLE)
2651*4882a593Smuzhiyun 			init_fw_cb->iscsi_opts |=
2652*4882a593Smuzhiyun 				cpu_to_le16(ISCSIOPTS_CHAP_AUTH_EN);
2653*4882a593Smuzhiyun 		else
2654*4882a593Smuzhiyun 			init_fw_cb->iscsi_opts &=
2655*4882a593Smuzhiyun 				cpu_to_le16(~ISCSIOPTS_CHAP_AUTH_EN);
2656*4882a593Smuzhiyun 		break;
2657*4882a593Smuzhiyun 	case ISCSI_IFACE_PARAM_BIDI_CHAP_EN:
2658*4882a593Smuzhiyun 		if (iface_param->iface_num & 0x1)
2659*4882a593Smuzhiyun 			break;
2660*4882a593Smuzhiyun 		if (iface_param->value[0] == ISCSI_NET_PARAM_ENABLE)
2661*4882a593Smuzhiyun 			init_fw_cb->iscsi_opts |=
2662*4882a593Smuzhiyun 				cpu_to_le16(ISCSIOPTS_BIDI_CHAP_EN);
2663*4882a593Smuzhiyun 		else
2664*4882a593Smuzhiyun 			init_fw_cb->iscsi_opts &=
2665*4882a593Smuzhiyun 				cpu_to_le16(~ISCSIOPTS_BIDI_CHAP_EN);
2666*4882a593Smuzhiyun 		break;
2667*4882a593Smuzhiyun 	case ISCSI_IFACE_PARAM_DISCOVERY_AUTH_OPTIONAL:
2668*4882a593Smuzhiyun 		if (iface_param->iface_num & 0x1)
2669*4882a593Smuzhiyun 			break;
2670*4882a593Smuzhiyun 		if (iface_param->value[0] == ISCSI_NET_PARAM_ENABLE)
2671*4882a593Smuzhiyun 			init_fw_cb->iscsi_opts |=
2672*4882a593Smuzhiyun 				cpu_to_le16(ISCSIOPTS_DISCOVERY_AUTH_EN);
2673*4882a593Smuzhiyun 		else
2674*4882a593Smuzhiyun 			init_fw_cb->iscsi_opts &=
2675*4882a593Smuzhiyun 				cpu_to_le16(~ISCSIOPTS_DISCOVERY_AUTH_EN);
2676*4882a593Smuzhiyun 		break;
2677*4882a593Smuzhiyun 	case ISCSI_IFACE_PARAM_DISCOVERY_LOGOUT_EN:
2678*4882a593Smuzhiyun 		if (iface_param->iface_num & 0x1)
2679*4882a593Smuzhiyun 			break;
2680*4882a593Smuzhiyun 		if (iface_param->value[0] == ISCSI_NET_PARAM_ENABLE)
2681*4882a593Smuzhiyun 			init_fw_cb->iscsi_opts |=
2682*4882a593Smuzhiyun 				cpu_to_le16(ISCSIOPTS_DISCOVERY_LOGOUT_EN);
2683*4882a593Smuzhiyun 		else
2684*4882a593Smuzhiyun 			init_fw_cb->iscsi_opts &=
2685*4882a593Smuzhiyun 				cpu_to_le16(~ISCSIOPTS_DISCOVERY_LOGOUT_EN);
2686*4882a593Smuzhiyun 		break;
2687*4882a593Smuzhiyun 	case ISCSI_IFACE_PARAM_STRICT_LOGIN_COMP_EN:
2688*4882a593Smuzhiyun 		if (iface_param->iface_num & 0x1)
2689*4882a593Smuzhiyun 			break;
2690*4882a593Smuzhiyun 		if (iface_param->value[0] == ISCSI_NET_PARAM_ENABLE)
2691*4882a593Smuzhiyun 			init_fw_cb->iscsi_opts |=
2692*4882a593Smuzhiyun 				cpu_to_le16(ISCSIOPTS_STRICT_LOGIN_COMP_EN);
2693*4882a593Smuzhiyun 		else
2694*4882a593Smuzhiyun 			init_fw_cb->iscsi_opts &=
2695*4882a593Smuzhiyun 				cpu_to_le16(~ISCSIOPTS_STRICT_LOGIN_COMP_EN);
2696*4882a593Smuzhiyun 		break;
2697*4882a593Smuzhiyun 	default:
2698*4882a593Smuzhiyun 		ql4_printk(KERN_ERR, ha, "Unknown iscsi param = %d\n",
2699*4882a593Smuzhiyun 			   iface_param->param);
2700*4882a593Smuzhiyun 		break;
2701*4882a593Smuzhiyun 	}
2702*4882a593Smuzhiyun }
2703*4882a593Smuzhiyun 
2704*4882a593Smuzhiyun static void
qla4xxx_initcb_to_acb(struct addr_ctrl_blk * init_fw_cb)2705*4882a593Smuzhiyun qla4xxx_initcb_to_acb(struct addr_ctrl_blk *init_fw_cb)
2706*4882a593Smuzhiyun {
2707*4882a593Smuzhiyun 	struct addr_ctrl_blk_def *acb;
2708*4882a593Smuzhiyun 	acb = (struct addr_ctrl_blk_def *)init_fw_cb;
2709*4882a593Smuzhiyun 	memset(acb->reserved1, 0, sizeof(acb->reserved1));
2710*4882a593Smuzhiyun 	memset(acb->reserved2, 0, sizeof(acb->reserved2));
2711*4882a593Smuzhiyun 	memset(acb->reserved3, 0, sizeof(acb->reserved3));
2712*4882a593Smuzhiyun 	memset(acb->reserved4, 0, sizeof(acb->reserved4));
2713*4882a593Smuzhiyun 	memset(acb->reserved5, 0, sizeof(acb->reserved5));
2714*4882a593Smuzhiyun 	memset(acb->reserved6, 0, sizeof(acb->reserved6));
2715*4882a593Smuzhiyun 	memset(acb->reserved7, 0, sizeof(acb->reserved7));
2716*4882a593Smuzhiyun 	memset(acb->reserved8, 0, sizeof(acb->reserved8));
2717*4882a593Smuzhiyun 	memset(acb->reserved9, 0, sizeof(acb->reserved9));
2718*4882a593Smuzhiyun 	memset(acb->reserved10, 0, sizeof(acb->reserved10));
2719*4882a593Smuzhiyun 	memset(acb->reserved11, 0, sizeof(acb->reserved11));
2720*4882a593Smuzhiyun 	memset(acb->reserved12, 0, sizeof(acb->reserved12));
2721*4882a593Smuzhiyun 	memset(acb->reserved13, 0, sizeof(acb->reserved13));
2722*4882a593Smuzhiyun 	memset(acb->reserved14, 0, sizeof(acb->reserved14));
2723*4882a593Smuzhiyun 	memset(acb->reserved15, 0, sizeof(acb->reserved15));
2724*4882a593Smuzhiyun }
2725*4882a593Smuzhiyun 
2726*4882a593Smuzhiyun static int
qla4xxx_iface_set_param(struct Scsi_Host * shost,void * data,uint32_t len)2727*4882a593Smuzhiyun qla4xxx_iface_set_param(struct Scsi_Host *shost, void *data, uint32_t len)
2728*4882a593Smuzhiyun {
2729*4882a593Smuzhiyun 	struct scsi_qla_host *ha = to_qla_host(shost);
2730*4882a593Smuzhiyun 	int rval = 0;
2731*4882a593Smuzhiyun 	struct iscsi_iface_param_info *iface_param = NULL;
2732*4882a593Smuzhiyun 	struct addr_ctrl_blk *init_fw_cb = NULL;
2733*4882a593Smuzhiyun 	dma_addr_t init_fw_cb_dma;
2734*4882a593Smuzhiyun 	uint32_t mbox_cmd[MBOX_REG_COUNT];
2735*4882a593Smuzhiyun 	uint32_t mbox_sts[MBOX_REG_COUNT];
2736*4882a593Smuzhiyun 	uint32_t rem = len;
2737*4882a593Smuzhiyun 	struct nlattr *attr;
2738*4882a593Smuzhiyun 
2739*4882a593Smuzhiyun 	init_fw_cb = dma_alloc_coherent(&ha->pdev->dev,
2740*4882a593Smuzhiyun 					sizeof(struct addr_ctrl_blk),
2741*4882a593Smuzhiyun 					&init_fw_cb_dma, GFP_KERNEL);
2742*4882a593Smuzhiyun 	if (!init_fw_cb) {
2743*4882a593Smuzhiyun 		ql4_printk(KERN_ERR, ha, "%s: Unable to alloc init_cb\n",
2744*4882a593Smuzhiyun 			   __func__);
2745*4882a593Smuzhiyun 		return -ENOMEM;
2746*4882a593Smuzhiyun 	}
2747*4882a593Smuzhiyun 
2748*4882a593Smuzhiyun 	memset(&mbox_cmd, 0, sizeof(mbox_cmd));
2749*4882a593Smuzhiyun 	memset(&mbox_sts, 0, sizeof(mbox_sts));
2750*4882a593Smuzhiyun 
2751*4882a593Smuzhiyun 	if (qla4xxx_get_ifcb(ha, &mbox_cmd[0], &mbox_sts[0], init_fw_cb_dma)) {
2752*4882a593Smuzhiyun 		ql4_printk(KERN_ERR, ha, "%s: get ifcb failed\n", __func__);
2753*4882a593Smuzhiyun 		rval = -EIO;
2754*4882a593Smuzhiyun 		goto exit_init_fw_cb;
2755*4882a593Smuzhiyun 	}
2756*4882a593Smuzhiyun 
2757*4882a593Smuzhiyun 	nla_for_each_attr(attr, data, len, rem) {
2758*4882a593Smuzhiyun 		iface_param = nla_data(attr);
2759*4882a593Smuzhiyun 
2760*4882a593Smuzhiyun 		if (iface_param->param_type == ISCSI_NET_PARAM) {
2761*4882a593Smuzhiyun 			switch (iface_param->iface_type) {
2762*4882a593Smuzhiyun 			case ISCSI_IFACE_TYPE_IPV4:
2763*4882a593Smuzhiyun 				switch (iface_param->iface_num) {
2764*4882a593Smuzhiyun 				case 0:
2765*4882a593Smuzhiyun 					qla4xxx_set_ipv4(ha, iface_param,
2766*4882a593Smuzhiyun 							 init_fw_cb);
2767*4882a593Smuzhiyun 					break;
2768*4882a593Smuzhiyun 				default:
2769*4882a593Smuzhiyun 				/* Cannot have more than one IPv4 interface */
2770*4882a593Smuzhiyun 					ql4_printk(KERN_ERR, ha,
2771*4882a593Smuzhiyun 						   "Invalid IPv4 iface number = %d\n",
2772*4882a593Smuzhiyun 						   iface_param->iface_num);
2773*4882a593Smuzhiyun 					break;
2774*4882a593Smuzhiyun 				}
2775*4882a593Smuzhiyun 				break;
2776*4882a593Smuzhiyun 			case ISCSI_IFACE_TYPE_IPV6:
2777*4882a593Smuzhiyun 				switch (iface_param->iface_num) {
2778*4882a593Smuzhiyun 				case 0:
2779*4882a593Smuzhiyun 				case 1:
2780*4882a593Smuzhiyun 					qla4xxx_set_ipv6(ha, iface_param,
2781*4882a593Smuzhiyun 							 init_fw_cb);
2782*4882a593Smuzhiyun 					break;
2783*4882a593Smuzhiyun 				default:
2784*4882a593Smuzhiyun 				/* Cannot have more than two IPv6 interface */
2785*4882a593Smuzhiyun 					ql4_printk(KERN_ERR, ha,
2786*4882a593Smuzhiyun 						   "Invalid IPv6 iface number = %d\n",
2787*4882a593Smuzhiyun 						   iface_param->iface_num);
2788*4882a593Smuzhiyun 					break;
2789*4882a593Smuzhiyun 				}
2790*4882a593Smuzhiyun 				break;
2791*4882a593Smuzhiyun 			default:
2792*4882a593Smuzhiyun 				ql4_printk(KERN_ERR, ha,
2793*4882a593Smuzhiyun 					   "Invalid iface type\n");
2794*4882a593Smuzhiyun 				break;
2795*4882a593Smuzhiyun 			}
2796*4882a593Smuzhiyun 		} else if (iface_param->param_type == ISCSI_IFACE_PARAM) {
2797*4882a593Smuzhiyun 				qla4xxx_set_iscsi_param(ha, iface_param,
2798*4882a593Smuzhiyun 							init_fw_cb);
2799*4882a593Smuzhiyun 		} else {
2800*4882a593Smuzhiyun 			continue;
2801*4882a593Smuzhiyun 		}
2802*4882a593Smuzhiyun 	}
2803*4882a593Smuzhiyun 
2804*4882a593Smuzhiyun 	init_fw_cb->cookie = cpu_to_le32(0x11BEAD5A);
2805*4882a593Smuzhiyun 
2806*4882a593Smuzhiyun 	rval = qla4xxx_set_flash(ha, init_fw_cb_dma, FLASH_SEGMENT_IFCB,
2807*4882a593Smuzhiyun 				 sizeof(struct addr_ctrl_blk),
2808*4882a593Smuzhiyun 				 FLASH_OPT_RMW_COMMIT);
2809*4882a593Smuzhiyun 	if (rval != QLA_SUCCESS) {
2810*4882a593Smuzhiyun 		ql4_printk(KERN_ERR, ha, "%s: set flash mbx failed\n",
2811*4882a593Smuzhiyun 			   __func__);
2812*4882a593Smuzhiyun 		rval = -EIO;
2813*4882a593Smuzhiyun 		goto exit_init_fw_cb;
2814*4882a593Smuzhiyun 	}
2815*4882a593Smuzhiyun 
2816*4882a593Smuzhiyun 	rval = qla4xxx_disable_acb(ha);
2817*4882a593Smuzhiyun 	if (rval != QLA_SUCCESS) {
2818*4882a593Smuzhiyun 		ql4_printk(KERN_ERR, ha, "%s: disable acb mbx failed\n",
2819*4882a593Smuzhiyun 			   __func__);
2820*4882a593Smuzhiyun 		rval = -EIO;
2821*4882a593Smuzhiyun 		goto exit_init_fw_cb;
2822*4882a593Smuzhiyun 	}
2823*4882a593Smuzhiyun 
2824*4882a593Smuzhiyun 	wait_for_completion_timeout(&ha->disable_acb_comp,
2825*4882a593Smuzhiyun 				    DISABLE_ACB_TOV * HZ);
2826*4882a593Smuzhiyun 
2827*4882a593Smuzhiyun 	qla4xxx_initcb_to_acb(init_fw_cb);
2828*4882a593Smuzhiyun 
2829*4882a593Smuzhiyun 	rval = qla4xxx_set_acb(ha, &mbox_cmd[0], &mbox_sts[0], init_fw_cb_dma);
2830*4882a593Smuzhiyun 	if (rval != QLA_SUCCESS) {
2831*4882a593Smuzhiyun 		ql4_printk(KERN_ERR, ha, "%s: set acb mbx failed\n",
2832*4882a593Smuzhiyun 			   __func__);
2833*4882a593Smuzhiyun 		rval = -EIO;
2834*4882a593Smuzhiyun 		goto exit_init_fw_cb;
2835*4882a593Smuzhiyun 	}
2836*4882a593Smuzhiyun 
2837*4882a593Smuzhiyun 	memset(init_fw_cb, 0, sizeof(struct addr_ctrl_blk));
2838*4882a593Smuzhiyun 	qla4xxx_update_local_ifcb(ha, &mbox_cmd[0], &mbox_sts[0], init_fw_cb,
2839*4882a593Smuzhiyun 				  init_fw_cb_dma);
2840*4882a593Smuzhiyun 
2841*4882a593Smuzhiyun exit_init_fw_cb:
2842*4882a593Smuzhiyun 	dma_free_coherent(&ha->pdev->dev, sizeof(struct addr_ctrl_blk),
2843*4882a593Smuzhiyun 			  init_fw_cb, init_fw_cb_dma);
2844*4882a593Smuzhiyun 
2845*4882a593Smuzhiyun 	return rval;
2846*4882a593Smuzhiyun }
2847*4882a593Smuzhiyun 
qla4xxx_session_get_param(struct iscsi_cls_session * cls_sess,enum iscsi_param param,char * buf)2848*4882a593Smuzhiyun static int qla4xxx_session_get_param(struct iscsi_cls_session *cls_sess,
2849*4882a593Smuzhiyun 				     enum iscsi_param param, char *buf)
2850*4882a593Smuzhiyun {
2851*4882a593Smuzhiyun 	struct iscsi_session *sess = cls_sess->dd_data;
2852*4882a593Smuzhiyun 	struct ddb_entry *ddb_entry = sess->dd_data;
2853*4882a593Smuzhiyun 	struct scsi_qla_host *ha = ddb_entry->ha;
2854*4882a593Smuzhiyun 	struct iscsi_cls_conn *cls_conn = ddb_entry->conn;
2855*4882a593Smuzhiyun 	struct ql4_chap_table chap_tbl;
2856*4882a593Smuzhiyun 	int rval, len;
2857*4882a593Smuzhiyun 	uint16_t idx;
2858*4882a593Smuzhiyun 
2859*4882a593Smuzhiyun 	memset(&chap_tbl, 0, sizeof(chap_tbl));
2860*4882a593Smuzhiyun 	switch (param) {
2861*4882a593Smuzhiyun 	case ISCSI_PARAM_CHAP_IN_IDX:
2862*4882a593Smuzhiyun 		rval = qla4xxx_get_chap_index(ha, sess->username_in,
2863*4882a593Smuzhiyun 					      sess->password_in, BIDI_CHAP,
2864*4882a593Smuzhiyun 					      &idx);
2865*4882a593Smuzhiyun 		if (rval)
2866*4882a593Smuzhiyun 			len = sprintf(buf, "\n");
2867*4882a593Smuzhiyun 		else
2868*4882a593Smuzhiyun 			len = sprintf(buf, "%hu\n", idx);
2869*4882a593Smuzhiyun 		break;
2870*4882a593Smuzhiyun 	case ISCSI_PARAM_CHAP_OUT_IDX:
2871*4882a593Smuzhiyun 		if (ddb_entry->ddb_type == FLASH_DDB) {
2872*4882a593Smuzhiyun 			if (ddb_entry->chap_tbl_idx != INVALID_ENTRY) {
2873*4882a593Smuzhiyun 				idx = ddb_entry->chap_tbl_idx;
2874*4882a593Smuzhiyun 				rval = QLA_SUCCESS;
2875*4882a593Smuzhiyun 			} else {
2876*4882a593Smuzhiyun 				rval = QLA_ERROR;
2877*4882a593Smuzhiyun 			}
2878*4882a593Smuzhiyun 		} else {
2879*4882a593Smuzhiyun 			rval = qla4xxx_get_chap_index(ha, sess->username,
2880*4882a593Smuzhiyun 						      sess->password,
2881*4882a593Smuzhiyun 						      LOCAL_CHAP, &idx);
2882*4882a593Smuzhiyun 		}
2883*4882a593Smuzhiyun 		if (rval)
2884*4882a593Smuzhiyun 			len = sprintf(buf, "\n");
2885*4882a593Smuzhiyun 		else
2886*4882a593Smuzhiyun 			len = sprintf(buf, "%hu\n", idx);
2887*4882a593Smuzhiyun 		break;
2888*4882a593Smuzhiyun 	case ISCSI_PARAM_USERNAME:
2889*4882a593Smuzhiyun 	case ISCSI_PARAM_PASSWORD:
2890*4882a593Smuzhiyun 		/* First, populate session username and password for FLASH DDB,
2891*4882a593Smuzhiyun 		 * if not already done. This happens when session login fails
2892*4882a593Smuzhiyun 		 * for a FLASH DDB.
2893*4882a593Smuzhiyun 		 */
2894*4882a593Smuzhiyun 		if (ddb_entry->ddb_type == FLASH_DDB &&
2895*4882a593Smuzhiyun 		    ddb_entry->chap_tbl_idx != INVALID_ENTRY &&
2896*4882a593Smuzhiyun 		    !sess->username && !sess->password) {
2897*4882a593Smuzhiyun 			idx = ddb_entry->chap_tbl_idx;
2898*4882a593Smuzhiyun 			rval = qla4xxx_get_uni_chap_at_index(ha, chap_tbl.name,
2899*4882a593Smuzhiyun 							    chap_tbl.secret,
2900*4882a593Smuzhiyun 							    idx);
2901*4882a593Smuzhiyun 			if (!rval) {
2902*4882a593Smuzhiyun 				iscsi_set_param(cls_conn, ISCSI_PARAM_USERNAME,
2903*4882a593Smuzhiyun 						(char *)chap_tbl.name,
2904*4882a593Smuzhiyun 						strlen((char *)chap_tbl.name));
2905*4882a593Smuzhiyun 				iscsi_set_param(cls_conn, ISCSI_PARAM_PASSWORD,
2906*4882a593Smuzhiyun 						(char *)chap_tbl.secret,
2907*4882a593Smuzhiyun 						chap_tbl.secret_len);
2908*4882a593Smuzhiyun 			}
2909*4882a593Smuzhiyun 		}
2910*4882a593Smuzhiyun 		fallthrough;
2911*4882a593Smuzhiyun 	default:
2912*4882a593Smuzhiyun 		return iscsi_session_get_param(cls_sess, param, buf);
2913*4882a593Smuzhiyun 	}
2914*4882a593Smuzhiyun 
2915*4882a593Smuzhiyun 	return len;
2916*4882a593Smuzhiyun }
2917*4882a593Smuzhiyun 
qla4xxx_conn_get_param(struct iscsi_cls_conn * cls_conn,enum iscsi_param param,char * buf)2918*4882a593Smuzhiyun static int qla4xxx_conn_get_param(struct iscsi_cls_conn *cls_conn,
2919*4882a593Smuzhiyun 				  enum iscsi_param param, char *buf)
2920*4882a593Smuzhiyun {
2921*4882a593Smuzhiyun 	struct iscsi_conn *conn;
2922*4882a593Smuzhiyun 	struct qla_conn *qla_conn;
2923*4882a593Smuzhiyun 	struct sockaddr *dst_addr;
2924*4882a593Smuzhiyun 
2925*4882a593Smuzhiyun 	conn = cls_conn->dd_data;
2926*4882a593Smuzhiyun 	qla_conn = conn->dd_data;
2927*4882a593Smuzhiyun 	dst_addr = (struct sockaddr *)&qla_conn->qla_ep->dst_addr;
2928*4882a593Smuzhiyun 
2929*4882a593Smuzhiyun 	switch (param) {
2930*4882a593Smuzhiyun 	case ISCSI_PARAM_CONN_PORT:
2931*4882a593Smuzhiyun 	case ISCSI_PARAM_CONN_ADDRESS:
2932*4882a593Smuzhiyun 		return iscsi_conn_get_addr_param((struct sockaddr_storage *)
2933*4882a593Smuzhiyun 						 dst_addr, param, buf);
2934*4882a593Smuzhiyun 	default:
2935*4882a593Smuzhiyun 		return iscsi_conn_get_param(cls_conn, param, buf);
2936*4882a593Smuzhiyun 	}
2937*4882a593Smuzhiyun }
2938*4882a593Smuzhiyun 
qla4xxx_get_ddb_index(struct scsi_qla_host * ha,uint16_t * ddb_index)2939*4882a593Smuzhiyun int qla4xxx_get_ddb_index(struct scsi_qla_host *ha, uint16_t *ddb_index)
2940*4882a593Smuzhiyun {
2941*4882a593Smuzhiyun 	uint32_t mbx_sts = 0;
2942*4882a593Smuzhiyun 	uint16_t tmp_ddb_index;
2943*4882a593Smuzhiyun 	int ret;
2944*4882a593Smuzhiyun 
2945*4882a593Smuzhiyun get_ddb_index:
2946*4882a593Smuzhiyun 	tmp_ddb_index = find_first_zero_bit(ha->ddb_idx_map, MAX_DDB_ENTRIES);
2947*4882a593Smuzhiyun 
2948*4882a593Smuzhiyun 	if (tmp_ddb_index >= MAX_DDB_ENTRIES) {
2949*4882a593Smuzhiyun 		DEBUG2(ql4_printk(KERN_INFO, ha,
2950*4882a593Smuzhiyun 				  "Free DDB index not available\n"));
2951*4882a593Smuzhiyun 		ret = QLA_ERROR;
2952*4882a593Smuzhiyun 		goto exit_get_ddb_index;
2953*4882a593Smuzhiyun 	}
2954*4882a593Smuzhiyun 
2955*4882a593Smuzhiyun 	if (test_and_set_bit(tmp_ddb_index, ha->ddb_idx_map))
2956*4882a593Smuzhiyun 		goto get_ddb_index;
2957*4882a593Smuzhiyun 
2958*4882a593Smuzhiyun 	DEBUG2(ql4_printk(KERN_INFO, ha,
2959*4882a593Smuzhiyun 			  "Found a free DDB index at %d\n", tmp_ddb_index));
2960*4882a593Smuzhiyun 	ret = qla4xxx_req_ddb_entry(ha, tmp_ddb_index, &mbx_sts);
2961*4882a593Smuzhiyun 	if (ret == QLA_ERROR) {
2962*4882a593Smuzhiyun 		if (mbx_sts == MBOX_STS_COMMAND_ERROR) {
2963*4882a593Smuzhiyun 			ql4_printk(KERN_INFO, ha,
2964*4882a593Smuzhiyun 				   "DDB index = %d not available trying next\n",
2965*4882a593Smuzhiyun 				   tmp_ddb_index);
2966*4882a593Smuzhiyun 			goto get_ddb_index;
2967*4882a593Smuzhiyun 		}
2968*4882a593Smuzhiyun 		DEBUG2(ql4_printk(KERN_INFO, ha,
2969*4882a593Smuzhiyun 				  "Free FW DDB not available\n"));
2970*4882a593Smuzhiyun 	}
2971*4882a593Smuzhiyun 
2972*4882a593Smuzhiyun 	*ddb_index = tmp_ddb_index;
2973*4882a593Smuzhiyun 
2974*4882a593Smuzhiyun exit_get_ddb_index:
2975*4882a593Smuzhiyun 	return ret;
2976*4882a593Smuzhiyun }
2977*4882a593Smuzhiyun 
qla4xxx_match_ipaddress(struct scsi_qla_host * ha,struct ddb_entry * ddb_entry,char * existing_ipaddr,char * user_ipaddr)2978*4882a593Smuzhiyun static int qla4xxx_match_ipaddress(struct scsi_qla_host *ha,
2979*4882a593Smuzhiyun 				   struct ddb_entry *ddb_entry,
2980*4882a593Smuzhiyun 				   char *existing_ipaddr,
2981*4882a593Smuzhiyun 				   char *user_ipaddr)
2982*4882a593Smuzhiyun {
2983*4882a593Smuzhiyun 	uint8_t dst_ipaddr[IPv6_ADDR_LEN];
2984*4882a593Smuzhiyun 	char formatted_ipaddr[DDB_IPADDR_LEN];
2985*4882a593Smuzhiyun 	int status = QLA_SUCCESS, ret = 0;
2986*4882a593Smuzhiyun 
2987*4882a593Smuzhiyun 	if (ddb_entry->fw_ddb_entry.options & DDB_OPT_IPV6_DEVICE) {
2988*4882a593Smuzhiyun 		ret = in6_pton(user_ipaddr, strlen(user_ipaddr), dst_ipaddr,
2989*4882a593Smuzhiyun 			       '\0', NULL);
2990*4882a593Smuzhiyun 		if (ret == 0) {
2991*4882a593Smuzhiyun 			status = QLA_ERROR;
2992*4882a593Smuzhiyun 			goto out_match;
2993*4882a593Smuzhiyun 		}
2994*4882a593Smuzhiyun 		ret = sprintf(formatted_ipaddr, "%pI6", dst_ipaddr);
2995*4882a593Smuzhiyun 	} else {
2996*4882a593Smuzhiyun 		ret = in4_pton(user_ipaddr, strlen(user_ipaddr), dst_ipaddr,
2997*4882a593Smuzhiyun 			       '\0', NULL);
2998*4882a593Smuzhiyun 		if (ret == 0) {
2999*4882a593Smuzhiyun 			status = QLA_ERROR;
3000*4882a593Smuzhiyun 			goto out_match;
3001*4882a593Smuzhiyun 		}
3002*4882a593Smuzhiyun 		ret = sprintf(formatted_ipaddr, "%pI4", dst_ipaddr);
3003*4882a593Smuzhiyun 	}
3004*4882a593Smuzhiyun 
3005*4882a593Smuzhiyun 	if (strcmp(existing_ipaddr, formatted_ipaddr))
3006*4882a593Smuzhiyun 		status = QLA_ERROR;
3007*4882a593Smuzhiyun 
3008*4882a593Smuzhiyun out_match:
3009*4882a593Smuzhiyun 	return status;
3010*4882a593Smuzhiyun }
3011*4882a593Smuzhiyun 
qla4xxx_match_fwdb_session(struct scsi_qla_host * ha,struct iscsi_cls_conn * cls_conn)3012*4882a593Smuzhiyun static int qla4xxx_match_fwdb_session(struct scsi_qla_host *ha,
3013*4882a593Smuzhiyun 				      struct iscsi_cls_conn *cls_conn)
3014*4882a593Smuzhiyun {
3015*4882a593Smuzhiyun 	int idx = 0, max_ddbs, rval;
3016*4882a593Smuzhiyun 	struct iscsi_cls_session *cls_sess = iscsi_conn_to_session(cls_conn);
3017*4882a593Smuzhiyun 	struct iscsi_session *sess, *existing_sess;
3018*4882a593Smuzhiyun 	struct iscsi_conn *conn, *existing_conn;
3019*4882a593Smuzhiyun 	struct ddb_entry *ddb_entry;
3020*4882a593Smuzhiyun 
3021*4882a593Smuzhiyun 	sess = cls_sess->dd_data;
3022*4882a593Smuzhiyun 	conn = cls_conn->dd_data;
3023*4882a593Smuzhiyun 
3024*4882a593Smuzhiyun 	if (sess->targetname == NULL ||
3025*4882a593Smuzhiyun 	    conn->persistent_address == NULL ||
3026*4882a593Smuzhiyun 	    conn->persistent_port == 0)
3027*4882a593Smuzhiyun 		return QLA_ERROR;
3028*4882a593Smuzhiyun 
3029*4882a593Smuzhiyun 	max_ddbs =  is_qla40XX(ha) ? MAX_DEV_DB_ENTRIES_40XX :
3030*4882a593Smuzhiyun 				     MAX_DEV_DB_ENTRIES;
3031*4882a593Smuzhiyun 
3032*4882a593Smuzhiyun 	for (idx = 0; idx < max_ddbs; idx++) {
3033*4882a593Smuzhiyun 		ddb_entry = qla4xxx_lookup_ddb_by_fw_index(ha, idx);
3034*4882a593Smuzhiyun 		if (ddb_entry == NULL)
3035*4882a593Smuzhiyun 			continue;
3036*4882a593Smuzhiyun 
3037*4882a593Smuzhiyun 		if (ddb_entry->ddb_type != FLASH_DDB)
3038*4882a593Smuzhiyun 			continue;
3039*4882a593Smuzhiyun 
3040*4882a593Smuzhiyun 		existing_sess = ddb_entry->sess->dd_data;
3041*4882a593Smuzhiyun 		existing_conn = ddb_entry->conn->dd_data;
3042*4882a593Smuzhiyun 
3043*4882a593Smuzhiyun 		if (existing_sess->targetname == NULL ||
3044*4882a593Smuzhiyun 		    existing_conn->persistent_address == NULL ||
3045*4882a593Smuzhiyun 		    existing_conn->persistent_port == 0)
3046*4882a593Smuzhiyun 			continue;
3047*4882a593Smuzhiyun 
3048*4882a593Smuzhiyun 		DEBUG2(ql4_printk(KERN_INFO, ha,
3049*4882a593Smuzhiyun 				  "IQN = %s User IQN = %s\n",
3050*4882a593Smuzhiyun 				  existing_sess->targetname,
3051*4882a593Smuzhiyun 				  sess->targetname));
3052*4882a593Smuzhiyun 
3053*4882a593Smuzhiyun 		DEBUG2(ql4_printk(KERN_INFO, ha,
3054*4882a593Smuzhiyun 				  "IP = %s User IP = %s\n",
3055*4882a593Smuzhiyun 				  existing_conn->persistent_address,
3056*4882a593Smuzhiyun 				  conn->persistent_address));
3057*4882a593Smuzhiyun 
3058*4882a593Smuzhiyun 		DEBUG2(ql4_printk(KERN_INFO, ha,
3059*4882a593Smuzhiyun 				  "Port = %d User Port = %d\n",
3060*4882a593Smuzhiyun 				  existing_conn->persistent_port,
3061*4882a593Smuzhiyun 				  conn->persistent_port));
3062*4882a593Smuzhiyun 
3063*4882a593Smuzhiyun 		if (strcmp(existing_sess->targetname, sess->targetname))
3064*4882a593Smuzhiyun 			continue;
3065*4882a593Smuzhiyun 		rval = qla4xxx_match_ipaddress(ha, ddb_entry,
3066*4882a593Smuzhiyun 					existing_conn->persistent_address,
3067*4882a593Smuzhiyun 					conn->persistent_address);
3068*4882a593Smuzhiyun 		if (rval == QLA_ERROR)
3069*4882a593Smuzhiyun 			continue;
3070*4882a593Smuzhiyun 		if (existing_conn->persistent_port != conn->persistent_port)
3071*4882a593Smuzhiyun 			continue;
3072*4882a593Smuzhiyun 		break;
3073*4882a593Smuzhiyun 	}
3074*4882a593Smuzhiyun 
3075*4882a593Smuzhiyun 	if (idx == max_ddbs)
3076*4882a593Smuzhiyun 		return QLA_ERROR;
3077*4882a593Smuzhiyun 
3078*4882a593Smuzhiyun 	DEBUG2(ql4_printk(KERN_INFO, ha,
3079*4882a593Smuzhiyun 			  "Match found in fwdb sessions\n"));
3080*4882a593Smuzhiyun 	return QLA_SUCCESS;
3081*4882a593Smuzhiyun }
3082*4882a593Smuzhiyun 
3083*4882a593Smuzhiyun static struct iscsi_cls_session *
qla4xxx_session_create(struct iscsi_endpoint * ep,uint16_t cmds_max,uint16_t qdepth,uint32_t initial_cmdsn)3084*4882a593Smuzhiyun qla4xxx_session_create(struct iscsi_endpoint *ep,
3085*4882a593Smuzhiyun 			uint16_t cmds_max, uint16_t qdepth,
3086*4882a593Smuzhiyun 			uint32_t initial_cmdsn)
3087*4882a593Smuzhiyun {
3088*4882a593Smuzhiyun 	struct iscsi_cls_session *cls_sess;
3089*4882a593Smuzhiyun 	struct scsi_qla_host *ha;
3090*4882a593Smuzhiyun 	struct qla_endpoint *qla_ep;
3091*4882a593Smuzhiyun 	struct ddb_entry *ddb_entry;
3092*4882a593Smuzhiyun 	uint16_t ddb_index;
3093*4882a593Smuzhiyun 	struct iscsi_session *sess;
3094*4882a593Smuzhiyun 	int ret;
3095*4882a593Smuzhiyun 
3096*4882a593Smuzhiyun 	if (!ep) {
3097*4882a593Smuzhiyun 		printk(KERN_ERR "qla4xxx: missing ep.\n");
3098*4882a593Smuzhiyun 		return NULL;
3099*4882a593Smuzhiyun 	}
3100*4882a593Smuzhiyun 
3101*4882a593Smuzhiyun 	qla_ep = ep->dd_data;
3102*4882a593Smuzhiyun 	ha = to_qla_host(qla_ep->host);
3103*4882a593Smuzhiyun 	DEBUG2(ql4_printk(KERN_INFO, ha, "%s: host: %ld\n", __func__,
3104*4882a593Smuzhiyun 			  ha->host_no));
3105*4882a593Smuzhiyun 
3106*4882a593Smuzhiyun 	ret = qla4xxx_get_ddb_index(ha, &ddb_index);
3107*4882a593Smuzhiyun 	if (ret == QLA_ERROR)
3108*4882a593Smuzhiyun 		return NULL;
3109*4882a593Smuzhiyun 
3110*4882a593Smuzhiyun 	cls_sess = iscsi_session_setup(&qla4xxx_iscsi_transport, qla_ep->host,
3111*4882a593Smuzhiyun 				       cmds_max, sizeof(struct ddb_entry),
3112*4882a593Smuzhiyun 				       sizeof(struct ql4_task_data),
3113*4882a593Smuzhiyun 				       initial_cmdsn, ddb_index);
3114*4882a593Smuzhiyun 	if (!cls_sess)
3115*4882a593Smuzhiyun 		return NULL;
3116*4882a593Smuzhiyun 
3117*4882a593Smuzhiyun 	sess = cls_sess->dd_data;
3118*4882a593Smuzhiyun 	ddb_entry = sess->dd_data;
3119*4882a593Smuzhiyun 	ddb_entry->fw_ddb_index = ddb_index;
3120*4882a593Smuzhiyun 	ddb_entry->fw_ddb_device_state = DDB_DS_NO_CONNECTION_ACTIVE;
3121*4882a593Smuzhiyun 	ddb_entry->ha = ha;
3122*4882a593Smuzhiyun 	ddb_entry->sess = cls_sess;
3123*4882a593Smuzhiyun 	ddb_entry->unblock_sess = qla4xxx_unblock_ddb;
3124*4882a593Smuzhiyun 	ddb_entry->ddb_change = qla4xxx_ddb_change;
3125*4882a593Smuzhiyun 	clear_bit(DDB_CONN_CLOSE_FAILURE, &ddb_entry->flags);
3126*4882a593Smuzhiyun 	cls_sess->recovery_tmo = ql4xsess_recovery_tmo;
3127*4882a593Smuzhiyun 	ha->fw_ddb_index_map[ddb_entry->fw_ddb_index] = ddb_entry;
3128*4882a593Smuzhiyun 	ha->tot_ddbs++;
3129*4882a593Smuzhiyun 
3130*4882a593Smuzhiyun 	return cls_sess;
3131*4882a593Smuzhiyun }
3132*4882a593Smuzhiyun 
qla4xxx_session_destroy(struct iscsi_cls_session * cls_sess)3133*4882a593Smuzhiyun static void qla4xxx_session_destroy(struct iscsi_cls_session *cls_sess)
3134*4882a593Smuzhiyun {
3135*4882a593Smuzhiyun 	struct iscsi_session *sess;
3136*4882a593Smuzhiyun 	struct ddb_entry *ddb_entry;
3137*4882a593Smuzhiyun 	struct scsi_qla_host *ha;
3138*4882a593Smuzhiyun 	unsigned long flags, wtime;
3139*4882a593Smuzhiyun 	struct dev_db_entry *fw_ddb_entry = NULL;
3140*4882a593Smuzhiyun 	dma_addr_t fw_ddb_entry_dma;
3141*4882a593Smuzhiyun 	uint32_t ddb_state;
3142*4882a593Smuzhiyun 	int ret;
3143*4882a593Smuzhiyun 
3144*4882a593Smuzhiyun 	sess = cls_sess->dd_data;
3145*4882a593Smuzhiyun 	ddb_entry = sess->dd_data;
3146*4882a593Smuzhiyun 	ha = ddb_entry->ha;
3147*4882a593Smuzhiyun 	DEBUG2(ql4_printk(KERN_INFO, ha, "%s: host: %ld\n", __func__,
3148*4882a593Smuzhiyun 			  ha->host_no));
3149*4882a593Smuzhiyun 
3150*4882a593Smuzhiyun 	fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
3151*4882a593Smuzhiyun 					  &fw_ddb_entry_dma, GFP_KERNEL);
3152*4882a593Smuzhiyun 	if (!fw_ddb_entry) {
3153*4882a593Smuzhiyun 		ql4_printk(KERN_ERR, ha,
3154*4882a593Smuzhiyun 			   "%s: Unable to allocate dma buffer\n", __func__);
3155*4882a593Smuzhiyun 		goto destroy_session;
3156*4882a593Smuzhiyun 	}
3157*4882a593Smuzhiyun 
3158*4882a593Smuzhiyun 	wtime = jiffies + (HZ * LOGOUT_TOV);
3159*4882a593Smuzhiyun 	do {
3160*4882a593Smuzhiyun 		ret = qla4xxx_get_fwddb_entry(ha, ddb_entry->fw_ddb_index,
3161*4882a593Smuzhiyun 					      fw_ddb_entry, fw_ddb_entry_dma,
3162*4882a593Smuzhiyun 					      NULL, NULL, &ddb_state, NULL,
3163*4882a593Smuzhiyun 					      NULL, NULL);
3164*4882a593Smuzhiyun 		if (ret == QLA_ERROR)
3165*4882a593Smuzhiyun 			goto destroy_session;
3166*4882a593Smuzhiyun 
3167*4882a593Smuzhiyun 		if ((ddb_state == DDB_DS_NO_CONNECTION_ACTIVE) ||
3168*4882a593Smuzhiyun 		    (ddb_state == DDB_DS_SESSION_FAILED))
3169*4882a593Smuzhiyun 			goto destroy_session;
3170*4882a593Smuzhiyun 
3171*4882a593Smuzhiyun 		schedule_timeout_uninterruptible(HZ);
3172*4882a593Smuzhiyun 	} while ((time_after(wtime, jiffies)));
3173*4882a593Smuzhiyun 
3174*4882a593Smuzhiyun destroy_session:
3175*4882a593Smuzhiyun 	qla4xxx_clear_ddb_entry(ha, ddb_entry->fw_ddb_index);
3176*4882a593Smuzhiyun 	if (test_and_clear_bit(DDB_CONN_CLOSE_FAILURE, &ddb_entry->flags))
3177*4882a593Smuzhiyun 		clear_bit(ddb_entry->fw_ddb_index, ha->ddb_idx_map);
3178*4882a593Smuzhiyun 	spin_lock_irqsave(&ha->hardware_lock, flags);
3179*4882a593Smuzhiyun 	qla4xxx_free_ddb(ha, ddb_entry);
3180*4882a593Smuzhiyun 	spin_unlock_irqrestore(&ha->hardware_lock, flags);
3181*4882a593Smuzhiyun 
3182*4882a593Smuzhiyun 	iscsi_session_teardown(cls_sess);
3183*4882a593Smuzhiyun 
3184*4882a593Smuzhiyun 	if (fw_ddb_entry)
3185*4882a593Smuzhiyun 		dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
3186*4882a593Smuzhiyun 				  fw_ddb_entry, fw_ddb_entry_dma);
3187*4882a593Smuzhiyun }
3188*4882a593Smuzhiyun 
3189*4882a593Smuzhiyun static struct iscsi_cls_conn *
qla4xxx_conn_create(struct iscsi_cls_session * cls_sess,uint32_t conn_idx)3190*4882a593Smuzhiyun qla4xxx_conn_create(struct iscsi_cls_session *cls_sess, uint32_t conn_idx)
3191*4882a593Smuzhiyun {
3192*4882a593Smuzhiyun 	struct iscsi_cls_conn *cls_conn;
3193*4882a593Smuzhiyun 	struct iscsi_session *sess;
3194*4882a593Smuzhiyun 	struct ddb_entry *ddb_entry;
3195*4882a593Smuzhiyun 	struct scsi_qla_host *ha;
3196*4882a593Smuzhiyun 
3197*4882a593Smuzhiyun 	cls_conn = iscsi_conn_setup(cls_sess, sizeof(struct qla_conn),
3198*4882a593Smuzhiyun 				    conn_idx);
3199*4882a593Smuzhiyun 	if (!cls_conn) {
3200*4882a593Smuzhiyun 		pr_info("%s: Can not create connection for conn_idx = %u\n",
3201*4882a593Smuzhiyun 			__func__, conn_idx);
3202*4882a593Smuzhiyun 		return NULL;
3203*4882a593Smuzhiyun 	}
3204*4882a593Smuzhiyun 
3205*4882a593Smuzhiyun 	sess = cls_sess->dd_data;
3206*4882a593Smuzhiyun 	ddb_entry = sess->dd_data;
3207*4882a593Smuzhiyun 	ddb_entry->conn = cls_conn;
3208*4882a593Smuzhiyun 
3209*4882a593Smuzhiyun 	ha = ddb_entry->ha;
3210*4882a593Smuzhiyun 	DEBUG2(ql4_printk(KERN_INFO, ha, "%s: conn_idx = %u\n", __func__,
3211*4882a593Smuzhiyun 			  conn_idx));
3212*4882a593Smuzhiyun 	return cls_conn;
3213*4882a593Smuzhiyun }
3214*4882a593Smuzhiyun 
qla4xxx_conn_bind(struct iscsi_cls_session * cls_session,struct iscsi_cls_conn * cls_conn,uint64_t transport_fd,int is_leading)3215*4882a593Smuzhiyun static int qla4xxx_conn_bind(struct iscsi_cls_session *cls_session,
3216*4882a593Smuzhiyun 			     struct iscsi_cls_conn *cls_conn,
3217*4882a593Smuzhiyun 			     uint64_t transport_fd, int is_leading)
3218*4882a593Smuzhiyun {
3219*4882a593Smuzhiyun 	struct iscsi_conn *conn;
3220*4882a593Smuzhiyun 	struct qla_conn *qla_conn;
3221*4882a593Smuzhiyun 	struct iscsi_endpoint *ep;
3222*4882a593Smuzhiyun 	struct ddb_entry *ddb_entry;
3223*4882a593Smuzhiyun 	struct scsi_qla_host *ha;
3224*4882a593Smuzhiyun 	struct iscsi_session *sess;
3225*4882a593Smuzhiyun 
3226*4882a593Smuzhiyun 	sess = cls_session->dd_data;
3227*4882a593Smuzhiyun 	ddb_entry = sess->dd_data;
3228*4882a593Smuzhiyun 	ha = ddb_entry->ha;
3229*4882a593Smuzhiyun 
3230*4882a593Smuzhiyun 	DEBUG2(ql4_printk(KERN_INFO, ha, "%s: sid = %d, cid = %d\n", __func__,
3231*4882a593Smuzhiyun 			  cls_session->sid, cls_conn->cid));
3232*4882a593Smuzhiyun 
3233*4882a593Smuzhiyun 	if (iscsi_conn_bind(cls_session, cls_conn, is_leading))
3234*4882a593Smuzhiyun 		return -EINVAL;
3235*4882a593Smuzhiyun 	ep = iscsi_lookup_endpoint(transport_fd);
3236*4882a593Smuzhiyun 	if (!ep)
3237*4882a593Smuzhiyun 		return -EINVAL;
3238*4882a593Smuzhiyun 	conn = cls_conn->dd_data;
3239*4882a593Smuzhiyun 	qla_conn = conn->dd_data;
3240*4882a593Smuzhiyun 	qla_conn->qla_ep = ep->dd_data;
3241*4882a593Smuzhiyun 	iscsi_put_endpoint(ep);
3242*4882a593Smuzhiyun 	return 0;
3243*4882a593Smuzhiyun }
3244*4882a593Smuzhiyun 
qla4xxx_conn_start(struct iscsi_cls_conn * cls_conn)3245*4882a593Smuzhiyun static int qla4xxx_conn_start(struct iscsi_cls_conn *cls_conn)
3246*4882a593Smuzhiyun {
3247*4882a593Smuzhiyun 	struct iscsi_cls_session *cls_sess = iscsi_conn_to_session(cls_conn);
3248*4882a593Smuzhiyun 	struct iscsi_session *sess;
3249*4882a593Smuzhiyun 	struct ddb_entry *ddb_entry;
3250*4882a593Smuzhiyun 	struct scsi_qla_host *ha;
3251*4882a593Smuzhiyun 	struct dev_db_entry *fw_ddb_entry = NULL;
3252*4882a593Smuzhiyun 	dma_addr_t fw_ddb_entry_dma;
3253*4882a593Smuzhiyun 	uint32_t mbx_sts = 0;
3254*4882a593Smuzhiyun 	int ret = 0;
3255*4882a593Smuzhiyun 	int status = QLA_SUCCESS;
3256*4882a593Smuzhiyun 
3257*4882a593Smuzhiyun 	sess = cls_sess->dd_data;
3258*4882a593Smuzhiyun 	ddb_entry = sess->dd_data;
3259*4882a593Smuzhiyun 	ha = ddb_entry->ha;
3260*4882a593Smuzhiyun 	DEBUG2(ql4_printk(KERN_INFO, ha, "%s: sid = %d, cid = %d\n", __func__,
3261*4882a593Smuzhiyun 			  cls_sess->sid, cls_conn->cid));
3262*4882a593Smuzhiyun 
3263*4882a593Smuzhiyun 	/* Check if we have  matching FW DDB, if yes then do not
3264*4882a593Smuzhiyun 	 * login to this target. This could cause target to logout previous
3265*4882a593Smuzhiyun 	 * connection
3266*4882a593Smuzhiyun 	 */
3267*4882a593Smuzhiyun 	ret = qla4xxx_match_fwdb_session(ha, cls_conn);
3268*4882a593Smuzhiyun 	if (ret == QLA_SUCCESS) {
3269*4882a593Smuzhiyun 		ql4_printk(KERN_INFO, ha,
3270*4882a593Smuzhiyun 			   "Session already exist in FW.\n");
3271*4882a593Smuzhiyun 		ret = -EEXIST;
3272*4882a593Smuzhiyun 		goto exit_conn_start;
3273*4882a593Smuzhiyun 	}
3274*4882a593Smuzhiyun 
3275*4882a593Smuzhiyun 	fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
3276*4882a593Smuzhiyun 					  &fw_ddb_entry_dma, GFP_KERNEL);
3277*4882a593Smuzhiyun 	if (!fw_ddb_entry) {
3278*4882a593Smuzhiyun 		ql4_printk(KERN_ERR, ha,
3279*4882a593Smuzhiyun 			   "%s: Unable to allocate dma buffer\n", __func__);
3280*4882a593Smuzhiyun 		ret = -ENOMEM;
3281*4882a593Smuzhiyun 		goto exit_conn_start;
3282*4882a593Smuzhiyun 	}
3283*4882a593Smuzhiyun 
3284*4882a593Smuzhiyun 	ret = qla4xxx_set_param_ddbentry(ha, ddb_entry, cls_conn, &mbx_sts);
3285*4882a593Smuzhiyun 	if (ret) {
3286*4882a593Smuzhiyun 		/* If iscsid is stopped and started then no need to do
3287*4882a593Smuzhiyun 		* set param again since ddb state will be already
3288*4882a593Smuzhiyun 		* active and FW does not allow set ddb to an
3289*4882a593Smuzhiyun 		* active session.
3290*4882a593Smuzhiyun 		*/
3291*4882a593Smuzhiyun 		if (mbx_sts)
3292*4882a593Smuzhiyun 			if (ddb_entry->fw_ddb_device_state ==
3293*4882a593Smuzhiyun 						DDB_DS_SESSION_ACTIVE) {
3294*4882a593Smuzhiyun 				ddb_entry->unblock_sess(ddb_entry->sess);
3295*4882a593Smuzhiyun 				goto exit_set_param;
3296*4882a593Smuzhiyun 			}
3297*4882a593Smuzhiyun 
3298*4882a593Smuzhiyun 		ql4_printk(KERN_ERR, ha, "%s: Failed set param for index[%d]\n",
3299*4882a593Smuzhiyun 			   __func__, ddb_entry->fw_ddb_index);
3300*4882a593Smuzhiyun 		goto exit_conn_start;
3301*4882a593Smuzhiyun 	}
3302*4882a593Smuzhiyun 
3303*4882a593Smuzhiyun 	status = qla4xxx_conn_open(ha, ddb_entry->fw_ddb_index);
3304*4882a593Smuzhiyun 	if (status == QLA_ERROR) {
3305*4882a593Smuzhiyun 		ql4_printk(KERN_ERR, ha, "%s: Login failed: %s\n", __func__,
3306*4882a593Smuzhiyun 			   sess->targetname);
3307*4882a593Smuzhiyun 		ret = -EINVAL;
3308*4882a593Smuzhiyun 		goto exit_conn_start;
3309*4882a593Smuzhiyun 	}
3310*4882a593Smuzhiyun 
3311*4882a593Smuzhiyun 	if (ddb_entry->fw_ddb_device_state == DDB_DS_NO_CONNECTION_ACTIVE)
3312*4882a593Smuzhiyun 		ddb_entry->fw_ddb_device_state = DDB_DS_LOGIN_IN_PROCESS;
3313*4882a593Smuzhiyun 
3314*4882a593Smuzhiyun 	DEBUG2(printk(KERN_INFO "%s: DDB state [%d]\n", __func__,
3315*4882a593Smuzhiyun 		      ddb_entry->fw_ddb_device_state));
3316*4882a593Smuzhiyun 
3317*4882a593Smuzhiyun exit_set_param:
3318*4882a593Smuzhiyun 	ret = 0;
3319*4882a593Smuzhiyun 
3320*4882a593Smuzhiyun exit_conn_start:
3321*4882a593Smuzhiyun 	if (fw_ddb_entry)
3322*4882a593Smuzhiyun 		dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
3323*4882a593Smuzhiyun 				  fw_ddb_entry, fw_ddb_entry_dma);
3324*4882a593Smuzhiyun 	return ret;
3325*4882a593Smuzhiyun }
3326*4882a593Smuzhiyun 
qla4xxx_conn_destroy(struct iscsi_cls_conn * cls_conn)3327*4882a593Smuzhiyun static void qla4xxx_conn_destroy(struct iscsi_cls_conn *cls_conn)
3328*4882a593Smuzhiyun {
3329*4882a593Smuzhiyun 	struct iscsi_cls_session *cls_sess = iscsi_conn_to_session(cls_conn);
3330*4882a593Smuzhiyun 	struct iscsi_session *sess;
3331*4882a593Smuzhiyun 	struct scsi_qla_host *ha;
3332*4882a593Smuzhiyun 	struct ddb_entry *ddb_entry;
3333*4882a593Smuzhiyun 	int options;
3334*4882a593Smuzhiyun 
3335*4882a593Smuzhiyun 	sess = cls_sess->dd_data;
3336*4882a593Smuzhiyun 	ddb_entry = sess->dd_data;
3337*4882a593Smuzhiyun 	ha = ddb_entry->ha;
3338*4882a593Smuzhiyun 	DEBUG2(ql4_printk(KERN_INFO, ha, "%s: cid = %d\n", __func__,
3339*4882a593Smuzhiyun 			  cls_conn->cid));
3340*4882a593Smuzhiyun 
3341*4882a593Smuzhiyun 	options = LOGOUT_OPTION_CLOSE_SESSION;
3342*4882a593Smuzhiyun 	if (qla4xxx_session_logout_ddb(ha, ddb_entry, options) == QLA_ERROR)
3343*4882a593Smuzhiyun 		ql4_printk(KERN_ERR, ha, "%s: Logout failed\n", __func__);
3344*4882a593Smuzhiyun }
3345*4882a593Smuzhiyun 
qla4xxx_task_work(struct work_struct * wdata)3346*4882a593Smuzhiyun static void qla4xxx_task_work(struct work_struct *wdata)
3347*4882a593Smuzhiyun {
3348*4882a593Smuzhiyun 	struct ql4_task_data *task_data;
3349*4882a593Smuzhiyun 	struct scsi_qla_host *ha;
3350*4882a593Smuzhiyun 	struct passthru_status *sts;
3351*4882a593Smuzhiyun 	struct iscsi_task *task;
3352*4882a593Smuzhiyun 	struct iscsi_hdr *hdr;
3353*4882a593Smuzhiyun 	uint8_t *data;
3354*4882a593Smuzhiyun 	uint32_t data_len;
3355*4882a593Smuzhiyun 	struct iscsi_conn *conn;
3356*4882a593Smuzhiyun 	int hdr_len;
3357*4882a593Smuzhiyun 	itt_t itt;
3358*4882a593Smuzhiyun 
3359*4882a593Smuzhiyun 	task_data = container_of(wdata, struct ql4_task_data, task_work);
3360*4882a593Smuzhiyun 	ha = task_data->ha;
3361*4882a593Smuzhiyun 	task = task_data->task;
3362*4882a593Smuzhiyun 	sts = &task_data->sts;
3363*4882a593Smuzhiyun 	hdr_len = sizeof(struct iscsi_hdr);
3364*4882a593Smuzhiyun 
3365*4882a593Smuzhiyun 	DEBUG3(printk(KERN_INFO "Status returned\n"));
3366*4882a593Smuzhiyun 	DEBUG3(qla4xxx_dump_buffer(sts, 64));
3367*4882a593Smuzhiyun 	DEBUG3(printk(KERN_INFO "Response buffer"));
3368*4882a593Smuzhiyun 	DEBUG3(qla4xxx_dump_buffer(task_data->resp_buffer, 64));
3369*4882a593Smuzhiyun 
3370*4882a593Smuzhiyun 	conn = task->conn;
3371*4882a593Smuzhiyun 
3372*4882a593Smuzhiyun 	switch (sts->completionStatus) {
3373*4882a593Smuzhiyun 	case PASSTHRU_STATUS_COMPLETE:
3374*4882a593Smuzhiyun 		hdr = (struct iscsi_hdr *)task_data->resp_buffer;
3375*4882a593Smuzhiyun 		/* Assign back the itt in hdr, until we use the PREASSIGN_TAG */
3376*4882a593Smuzhiyun 		itt = sts->handle;
3377*4882a593Smuzhiyun 		hdr->itt = itt;
3378*4882a593Smuzhiyun 		data = task_data->resp_buffer + hdr_len;
3379*4882a593Smuzhiyun 		data_len = task_data->resp_len - hdr_len;
3380*4882a593Smuzhiyun 		iscsi_complete_pdu(conn, hdr, data, data_len);
3381*4882a593Smuzhiyun 		break;
3382*4882a593Smuzhiyun 	default:
3383*4882a593Smuzhiyun 		ql4_printk(KERN_ERR, ha, "Passthru failed status = 0x%x\n",
3384*4882a593Smuzhiyun 			   sts->completionStatus);
3385*4882a593Smuzhiyun 		break;
3386*4882a593Smuzhiyun 	}
3387*4882a593Smuzhiyun 	return;
3388*4882a593Smuzhiyun }
3389*4882a593Smuzhiyun 
qla4xxx_alloc_pdu(struct iscsi_task * task,uint8_t opcode)3390*4882a593Smuzhiyun static int qla4xxx_alloc_pdu(struct iscsi_task *task, uint8_t opcode)
3391*4882a593Smuzhiyun {
3392*4882a593Smuzhiyun 	struct ql4_task_data *task_data;
3393*4882a593Smuzhiyun 	struct iscsi_session *sess;
3394*4882a593Smuzhiyun 	struct ddb_entry *ddb_entry;
3395*4882a593Smuzhiyun 	struct scsi_qla_host *ha;
3396*4882a593Smuzhiyun 	int hdr_len;
3397*4882a593Smuzhiyun 
3398*4882a593Smuzhiyun 	sess = task->conn->session;
3399*4882a593Smuzhiyun 	ddb_entry = sess->dd_data;
3400*4882a593Smuzhiyun 	ha = ddb_entry->ha;
3401*4882a593Smuzhiyun 	task_data = task->dd_data;
3402*4882a593Smuzhiyun 	memset(task_data, 0, sizeof(struct ql4_task_data));
3403*4882a593Smuzhiyun 
3404*4882a593Smuzhiyun 	if (task->sc) {
3405*4882a593Smuzhiyun 		ql4_printk(KERN_INFO, ha,
3406*4882a593Smuzhiyun 			   "%s: SCSI Commands not implemented\n", __func__);
3407*4882a593Smuzhiyun 		return -EINVAL;
3408*4882a593Smuzhiyun 	}
3409*4882a593Smuzhiyun 
3410*4882a593Smuzhiyun 	hdr_len = sizeof(struct iscsi_hdr);
3411*4882a593Smuzhiyun 	task_data->ha = ha;
3412*4882a593Smuzhiyun 	task_data->task = task;
3413*4882a593Smuzhiyun 
3414*4882a593Smuzhiyun 	if (task->data_count) {
3415*4882a593Smuzhiyun 		task_data->data_dma = dma_map_single(&ha->pdev->dev, task->data,
3416*4882a593Smuzhiyun 						     task->data_count,
3417*4882a593Smuzhiyun 						     DMA_TO_DEVICE);
3418*4882a593Smuzhiyun 	}
3419*4882a593Smuzhiyun 
3420*4882a593Smuzhiyun 	DEBUG2(ql4_printk(KERN_INFO, ha, "%s: MaxRecvLen %u, iscsi hrd %d\n",
3421*4882a593Smuzhiyun 		      __func__, task->conn->max_recv_dlength, hdr_len));
3422*4882a593Smuzhiyun 
3423*4882a593Smuzhiyun 	task_data->resp_len = task->conn->max_recv_dlength + hdr_len;
3424*4882a593Smuzhiyun 	task_data->resp_buffer = dma_alloc_coherent(&ha->pdev->dev,
3425*4882a593Smuzhiyun 						    task_data->resp_len,
3426*4882a593Smuzhiyun 						    &task_data->resp_dma,
3427*4882a593Smuzhiyun 						    GFP_ATOMIC);
3428*4882a593Smuzhiyun 	if (!task_data->resp_buffer)
3429*4882a593Smuzhiyun 		goto exit_alloc_pdu;
3430*4882a593Smuzhiyun 
3431*4882a593Smuzhiyun 	task_data->req_len = task->data_count + hdr_len;
3432*4882a593Smuzhiyun 	task_data->req_buffer = dma_alloc_coherent(&ha->pdev->dev,
3433*4882a593Smuzhiyun 						   task_data->req_len,
3434*4882a593Smuzhiyun 						   &task_data->req_dma,
3435*4882a593Smuzhiyun 						   GFP_ATOMIC);
3436*4882a593Smuzhiyun 	if (!task_data->req_buffer)
3437*4882a593Smuzhiyun 		goto exit_alloc_pdu;
3438*4882a593Smuzhiyun 
3439*4882a593Smuzhiyun 	task->hdr = task_data->req_buffer;
3440*4882a593Smuzhiyun 
3441*4882a593Smuzhiyun 	INIT_WORK(&task_data->task_work, qla4xxx_task_work);
3442*4882a593Smuzhiyun 
3443*4882a593Smuzhiyun 	return 0;
3444*4882a593Smuzhiyun 
3445*4882a593Smuzhiyun exit_alloc_pdu:
3446*4882a593Smuzhiyun 	if (task_data->resp_buffer)
3447*4882a593Smuzhiyun 		dma_free_coherent(&ha->pdev->dev, task_data->resp_len,
3448*4882a593Smuzhiyun 				  task_data->resp_buffer, task_data->resp_dma);
3449*4882a593Smuzhiyun 
3450*4882a593Smuzhiyun 	if (task_data->req_buffer)
3451*4882a593Smuzhiyun 		dma_free_coherent(&ha->pdev->dev, task_data->req_len,
3452*4882a593Smuzhiyun 				  task_data->req_buffer, task_data->req_dma);
3453*4882a593Smuzhiyun 	return -ENOMEM;
3454*4882a593Smuzhiyun }
3455*4882a593Smuzhiyun 
qla4xxx_task_cleanup(struct iscsi_task * task)3456*4882a593Smuzhiyun static void qla4xxx_task_cleanup(struct iscsi_task *task)
3457*4882a593Smuzhiyun {
3458*4882a593Smuzhiyun 	struct ql4_task_data *task_data;
3459*4882a593Smuzhiyun 	struct iscsi_session *sess;
3460*4882a593Smuzhiyun 	struct ddb_entry *ddb_entry;
3461*4882a593Smuzhiyun 	struct scsi_qla_host *ha;
3462*4882a593Smuzhiyun 	int hdr_len;
3463*4882a593Smuzhiyun 
3464*4882a593Smuzhiyun 	hdr_len = sizeof(struct iscsi_hdr);
3465*4882a593Smuzhiyun 	sess = task->conn->session;
3466*4882a593Smuzhiyun 	ddb_entry = sess->dd_data;
3467*4882a593Smuzhiyun 	ha = ddb_entry->ha;
3468*4882a593Smuzhiyun 	task_data = task->dd_data;
3469*4882a593Smuzhiyun 
3470*4882a593Smuzhiyun 	if (task->data_count) {
3471*4882a593Smuzhiyun 		dma_unmap_single(&ha->pdev->dev, task_data->data_dma,
3472*4882a593Smuzhiyun 				 task->data_count, DMA_TO_DEVICE);
3473*4882a593Smuzhiyun 	}
3474*4882a593Smuzhiyun 
3475*4882a593Smuzhiyun 	DEBUG2(ql4_printk(KERN_INFO, ha, "%s: MaxRecvLen %u, iscsi hrd %d\n",
3476*4882a593Smuzhiyun 		      __func__, task->conn->max_recv_dlength, hdr_len));
3477*4882a593Smuzhiyun 
3478*4882a593Smuzhiyun 	dma_free_coherent(&ha->pdev->dev, task_data->resp_len,
3479*4882a593Smuzhiyun 			  task_data->resp_buffer, task_data->resp_dma);
3480*4882a593Smuzhiyun 	dma_free_coherent(&ha->pdev->dev, task_data->req_len,
3481*4882a593Smuzhiyun 			  task_data->req_buffer, task_data->req_dma);
3482*4882a593Smuzhiyun 	return;
3483*4882a593Smuzhiyun }
3484*4882a593Smuzhiyun 
qla4xxx_task_xmit(struct iscsi_task * task)3485*4882a593Smuzhiyun static int qla4xxx_task_xmit(struct iscsi_task *task)
3486*4882a593Smuzhiyun {
3487*4882a593Smuzhiyun 	struct scsi_cmnd *sc = task->sc;
3488*4882a593Smuzhiyun 	struct iscsi_session *sess = task->conn->session;
3489*4882a593Smuzhiyun 	struct ddb_entry *ddb_entry = sess->dd_data;
3490*4882a593Smuzhiyun 	struct scsi_qla_host *ha = ddb_entry->ha;
3491*4882a593Smuzhiyun 
3492*4882a593Smuzhiyun 	if (!sc)
3493*4882a593Smuzhiyun 		return qla4xxx_send_passthru0(task);
3494*4882a593Smuzhiyun 
3495*4882a593Smuzhiyun 	ql4_printk(KERN_INFO, ha, "%s: scsi cmd xmit not implemented\n",
3496*4882a593Smuzhiyun 		   __func__);
3497*4882a593Smuzhiyun 	return -ENOSYS;
3498*4882a593Smuzhiyun }
3499*4882a593Smuzhiyun 
qla4xxx_copy_from_fwddb_param(struct iscsi_bus_flash_session * sess,struct iscsi_bus_flash_conn * conn,struct dev_db_entry * fw_ddb_entry)3500*4882a593Smuzhiyun static int qla4xxx_copy_from_fwddb_param(struct iscsi_bus_flash_session *sess,
3501*4882a593Smuzhiyun 					 struct iscsi_bus_flash_conn *conn,
3502*4882a593Smuzhiyun 					 struct dev_db_entry *fw_ddb_entry)
3503*4882a593Smuzhiyun {
3504*4882a593Smuzhiyun 	unsigned long options = 0;
3505*4882a593Smuzhiyun 	int rc = 0;
3506*4882a593Smuzhiyun 
3507*4882a593Smuzhiyun 	options = le16_to_cpu(fw_ddb_entry->options);
3508*4882a593Smuzhiyun 	conn->is_fw_assigned_ipv6 = test_bit(OPT_IS_FW_ASSIGNED_IPV6, &options);
3509*4882a593Smuzhiyun 	if (test_bit(OPT_IPV6_DEVICE, &options)) {
3510*4882a593Smuzhiyun 		rc = iscsi_switch_str_param(&sess->portal_type,
3511*4882a593Smuzhiyun 					    PORTAL_TYPE_IPV6);
3512*4882a593Smuzhiyun 		if (rc)
3513*4882a593Smuzhiyun 			goto exit_copy;
3514*4882a593Smuzhiyun 	} else {
3515*4882a593Smuzhiyun 		rc = iscsi_switch_str_param(&sess->portal_type,
3516*4882a593Smuzhiyun 					    PORTAL_TYPE_IPV4);
3517*4882a593Smuzhiyun 		if (rc)
3518*4882a593Smuzhiyun 			goto exit_copy;
3519*4882a593Smuzhiyun 	}
3520*4882a593Smuzhiyun 
3521*4882a593Smuzhiyun 	sess->auto_snd_tgt_disable = test_bit(OPT_AUTO_SENDTGTS_DISABLE,
3522*4882a593Smuzhiyun 					      &options);
3523*4882a593Smuzhiyun 	sess->discovery_sess = test_bit(OPT_DISC_SESSION, &options);
3524*4882a593Smuzhiyun 	sess->entry_state = test_bit(OPT_ENTRY_STATE, &options);
3525*4882a593Smuzhiyun 
3526*4882a593Smuzhiyun 	options = le16_to_cpu(fw_ddb_entry->iscsi_options);
3527*4882a593Smuzhiyun 	conn->hdrdgst_en = test_bit(ISCSIOPT_HEADER_DIGEST_EN, &options);
3528*4882a593Smuzhiyun 	conn->datadgst_en = test_bit(ISCSIOPT_DATA_DIGEST_EN, &options);
3529*4882a593Smuzhiyun 	sess->imm_data_en = test_bit(ISCSIOPT_IMMEDIATE_DATA_EN, &options);
3530*4882a593Smuzhiyun 	sess->initial_r2t_en = test_bit(ISCSIOPT_INITIAL_R2T_EN, &options);
3531*4882a593Smuzhiyun 	sess->dataseq_inorder_en = test_bit(ISCSIOPT_DATA_SEQ_IN_ORDER,
3532*4882a593Smuzhiyun 					    &options);
3533*4882a593Smuzhiyun 	sess->pdu_inorder_en = test_bit(ISCSIOPT_DATA_PDU_IN_ORDER, &options);
3534*4882a593Smuzhiyun 	sess->chap_auth_en = test_bit(ISCSIOPT_CHAP_AUTH_EN, &options);
3535*4882a593Smuzhiyun 	conn->snack_req_en = test_bit(ISCSIOPT_SNACK_REQ_EN, &options);
3536*4882a593Smuzhiyun 	sess->discovery_logout_en = test_bit(ISCSIOPT_DISCOVERY_LOGOUT_EN,
3537*4882a593Smuzhiyun 					     &options);
3538*4882a593Smuzhiyun 	sess->bidi_chap_en = test_bit(ISCSIOPT_BIDI_CHAP_EN, &options);
3539*4882a593Smuzhiyun 	sess->discovery_auth_optional =
3540*4882a593Smuzhiyun 			test_bit(ISCSIOPT_DISCOVERY_AUTH_OPTIONAL, &options);
3541*4882a593Smuzhiyun 	if (test_bit(ISCSIOPT_ERL1, &options))
3542*4882a593Smuzhiyun 		sess->erl |= BIT_1;
3543*4882a593Smuzhiyun 	if (test_bit(ISCSIOPT_ERL0, &options))
3544*4882a593Smuzhiyun 		sess->erl |= BIT_0;
3545*4882a593Smuzhiyun 
3546*4882a593Smuzhiyun 	options = le16_to_cpu(fw_ddb_entry->tcp_options);
3547*4882a593Smuzhiyun 	conn->tcp_timestamp_stat = test_bit(TCPOPT_TIMESTAMP_STAT, &options);
3548*4882a593Smuzhiyun 	conn->tcp_nagle_disable = test_bit(TCPOPT_NAGLE_DISABLE, &options);
3549*4882a593Smuzhiyun 	conn->tcp_wsf_disable = test_bit(TCPOPT_WSF_DISABLE, &options);
3550*4882a593Smuzhiyun 	if (test_bit(TCPOPT_TIMER_SCALE3, &options))
3551*4882a593Smuzhiyun 		conn->tcp_timer_scale |= BIT_3;
3552*4882a593Smuzhiyun 	if (test_bit(TCPOPT_TIMER_SCALE2, &options))
3553*4882a593Smuzhiyun 		conn->tcp_timer_scale |= BIT_2;
3554*4882a593Smuzhiyun 	if (test_bit(TCPOPT_TIMER_SCALE1, &options))
3555*4882a593Smuzhiyun 		conn->tcp_timer_scale |= BIT_1;
3556*4882a593Smuzhiyun 
3557*4882a593Smuzhiyun 	conn->tcp_timer_scale >>= 1;
3558*4882a593Smuzhiyun 	conn->tcp_timestamp_en = test_bit(TCPOPT_TIMESTAMP_EN, &options);
3559*4882a593Smuzhiyun 
3560*4882a593Smuzhiyun 	options = le16_to_cpu(fw_ddb_entry->ip_options);
3561*4882a593Smuzhiyun 	conn->fragment_disable = test_bit(IPOPT_FRAGMENT_DISABLE, &options);
3562*4882a593Smuzhiyun 
3563*4882a593Smuzhiyun 	conn->max_recv_dlength = BYTE_UNITS *
3564*4882a593Smuzhiyun 			  le16_to_cpu(fw_ddb_entry->iscsi_max_rcv_data_seg_len);
3565*4882a593Smuzhiyun 	conn->max_xmit_dlength = BYTE_UNITS *
3566*4882a593Smuzhiyun 			  le16_to_cpu(fw_ddb_entry->iscsi_max_snd_data_seg_len);
3567*4882a593Smuzhiyun 	sess->first_burst = BYTE_UNITS *
3568*4882a593Smuzhiyun 			       le16_to_cpu(fw_ddb_entry->iscsi_first_burst_len);
3569*4882a593Smuzhiyun 	sess->max_burst = BYTE_UNITS *
3570*4882a593Smuzhiyun 				 le16_to_cpu(fw_ddb_entry->iscsi_max_burst_len);
3571*4882a593Smuzhiyun 	sess->max_r2t = le16_to_cpu(fw_ddb_entry->iscsi_max_outsnd_r2t);
3572*4882a593Smuzhiyun 	sess->time2wait = le16_to_cpu(fw_ddb_entry->iscsi_def_time2wait);
3573*4882a593Smuzhiyun 	sess->time2retain = le16_to_cpu(fw_ddb_entry->iscsi_def_time2retain);
3574*4882a593Smuzhiyun 	sess->tpgt = le32_to_cpu(fw_ddb_entry->tgt_portal_grp);
3575*4882a593Smuzhiyun 	conn->max_segment_size = le16_to_cpu(fw_ddb_entry->mss);
3576*4882a593Smuzhiyun 	conn->tcp_xmit_wsf = fw_ddb_entry->tcp_xmt_wsf;
3577*4882a593Smuzhiyun 	conn->tcp_recv_wsf = fw_ddb_entry->tcp_rcv_wsf;
3578*4882a593Smuzhiyun 	conn->ipv6_flow_label = le16_to_cpu(fw_ddb_entry->ipv6_flow_lbl);
3579*4882a593Smuzhiyun 	conn->keepalive_timeout = le16_to_cpu(fw_ddb_entry->ka_timeout);
3580*4882a593Smuzhiyun 	conn->local_port = le16_to_cpu(fw_ddb_entry->lcl_port);
3581*4882a593Smuzhiyun 	conn->statsn = le32_to_cpu(fw_ddb_entry->stat_sn);
3582*4882a593Smuzhiyun 	conn->exp_statsn = le32_to_cpu(fw_ddb_entry->exp_stat_sn);
3583*4882a593Smuzhiyun 	sess->discovery_parent_idx = le16_to_cpu(fw_ddb_entry->ddb_link);
3584*4882a593Smuzhiyun 	sess->discovery_parent_type = le16_to_cpu(fw_ddb_entry->ddb_link);
3585*4882a593Smuzhiyun 	sess->chap_out_idx = le16_to_cpu(fw_ddb_entry->chap_tbl_idx);
3586*4882a593Smuzhiyun 	sess->tsid = le16_to_cpu(fw_ddb_entry->tsid);
3587*4882a593Smuzhiyun 
3588*4882a593Smuzhiyun 	sess->default_taskmgmt_timeout =
3589*4882a593Smuzhiyun 				le16_to_cpu(fw_ddb_entry->def_timeout);
3590*4882a593Smuzhiyun 	conn->port = le16_to_cpu(fw_ddb_entry->port);
3591*4882a593Smuzhiyun 
3592*4882a593Smuzhiyun 	options = le16_to_cpu(fw_ddb_entry->options);
3593*4882a593Smuzhiyun 	conn->ipaddress = kzalloc(IPv6_ADDR_LEN, GFP_KERNEL);
3594*4882a593Smuzhiyun 	if (!conn->ipaddress) {
3595*4882a593Smuzhiyun 		rc = -ENOMEM;
3596*4882a593Smuzhiyun 		goto exit_copy;
3597*4882a593Smuzhiyun 	}
3598*4882a593Smuzhiyun 
3599*4882a593Smuzhiyun 	conn->redirect_ipaddr = kzalloc(IPv6_ADDR_LEN, GFP_KERNEL);
3600*4882a593Smuzhiyun 	if (!conn->redirect_ipaddr) {
3601*4882a593Smuzhiyun 		rc = -ENOMEM;
3602*4882a593Smuzhiyun 		goto exit_copy;
3603*4882a593Smuzhiyun 	}
3604*4882a593Smuzhiyun 
3605*4882a593Smuzhiyun 	memcpy(conn->ipaddress, fw_ddb_entry->ip_addr, IPv6_ADDR_LEN);
3606*4882a593Smuzhiyun 	memcpy(conn->redirect_ipaddr, fw_ddb_entry->tgt_addr, IPv6_ADDR_LEN);
3607*4882a593Smuzhiyun 
3608*4882a593Smuzhiyun 	if (test_bit(OPT_IPV6_DEVICE, &options)) {
3609*4882a593Smuzhiyun 		conn->ipv6_traffic_class = fw_ddb_entry->ipv4_tos;
3610*4882a593Smuzhiyun 
3611*4882a593Smuzhiyun 		conn->link_local_ipv6_addr = kmemdup(
3612*4882a593Smuzhiyun 					fw_ddb_entry->link_local_ipv6_addr,
3613*4882a593Smuzhiyun 					IPv6_ADDR_LEN, GFP_KERNEL);
3614*4882a593Smuzhiyun 		if (!conn->link_local_ipv6_addr) {
3615*4882a593Smuzhiyun 			rc = -ENOMEM;
3616*4882a593Smuzhiyun 			goto exit_copy;
3617*4882a593Smuzhiyun 		}
3618*4882a593Smuzhiyun 	} else {
3619*4882a593Smuzhiyun 		conn->ipv4_tos = fw_ddb_entry->ipv4_tos;
3620*4882a593Smuzhiyun 	}
3621*4882a593Smuzhiyun 
3622*4882a593Smuzhiyun 	if (fw_ddb_entry->iscsi_name[0]) {
3623*4882a593Smuzhiyun 		rc = iscsi_switch_str_param(&sess->targetname,
3624*4882a593Smuzhiyun 					    (char *)fw_ddb_entry->iscsi_name);
3625*4882a593Smuzhiyun 		if (rc)
3626*4882a593Smuzhiyun 			goto exit_copy;
3627*4882a593Smuzhiyun 	}
3628*4882a593Smuzhiyun 
3629*4882a593Smuzhiyun 	if (fw_ddb_entry->iscsi_alias[0]) {
3630*4882a593Smuzhiyun 		rc = iscsi_switch_str_param(&sess->targetalias,
3631*4882a593Smuzhiyun 					    (char *)fw_ddb_entry->iscsi_alias);
3632*4882a593Smuzhiyun 		if (rc)
3633*4882a593Smuzhiyun 			goto exit_copy;
3634*4882a593Smuzhiyun 	}
3635*4882a593Smuzhiyun 
3636*4882a593Smuzhiyun 	COPY_ISID(sess->isid, fw_ddb_entry->isid);
3637*4882a593Smuzhiyun 
3638*4882a593Smuzhiyun exit_copy:
3639*4882a593Smuzhiyun 	return rc;
3640*4882a593Smuzhiyun }
3641*4882a593Smuzhiyun 
qla4xxx_copy_to_fwddb_param(struct iscsi_bus_flash_session * sess,struct iscsi_bus_flash_conn * conn,struct dev_db_entry * fw_ddb_entry)3642*4882a593Smuzhiyun static int qla4xxx_copy_to_fwddb_param(struct iscsi_bus_flash_session *sess,
3643*4882a593Smuzhiyun 				       struct iscsi_bus_flash_conn *conn,
3644*4882a593Smuzhiyun 				       struct dev_db_entry *fw_ddb_entry)
3645*4882a593Smuzhiyun {
3646*4882a593Smuzhiyun 	uint16_t options;
3647*4882a593Smuzhiyun 	int rc = 0;
3648*4882a593Smuzhiyun 
3649*4882a593Smuzhiyun 	options = le16_to_cpu(fw_ddb_entry->options);
3650*4882a593Smuzhiyun 	SET_BITVAL(conn->is_fw_assigned_ipv6,  options, BIT_11);
3651*4882a593Smuzhiyun 	if (!strncmp(sess->portal_type, PORTAL_TYPE_IPV6, 4))
3652*4882a593Smuzhiyun 		options |= BIT_8;
3653*4882a593Smuzhiyun 	else
3654*4882a593Smuzhiyun 		options &= ~BIT_8;
3655*4882a593Smuzhiyun 
3656*4882a593Smuzhiyun 	SET_BITVAL(sess->auto_snd_tgt_disable, options, BIT_6);
3657*4882a593Smuzhiyun 	SET_BITVAL(sess->discovery_sess, options, BIT_4);
3658*4882a593Smuzhiyun 	SET_BITVAL(sess->entry_state, options, BIT_3);
3659*4882a593Smuzhiyun 	fw_ddb_entry->options = cpu_to_le16(options);
3660*4882a593Smuzhiyun 
3661*4882a593Smuzhiyun 	options = le16_to_cpu(fw_ddb_entry->iscsi_options);
3662*4882a593Smuzhiyun 	SET_BITVAL(conn->hdrdgst_en, options, BIT_13);
3663*4882a593Smuzhiyun 	SET_BITVAL(conn->datadgst_en, options, BIT_12);
3664*4882a593Smuzhiyun 	SET_BITVAL(sess->imm_data_en, options, BIT_11);
3665*4882a593Smuzhiyun 	SET_BITVAL(sess->initial_r2t_en, options, BIT_10);
3666*4882a593Smuzhiyun 	SET_BITVAL(sess->dataseq_inorder_en, options, BIT_9);
3667*4882a593Smuzhiyun 	SET_BITVAL(sess->pdu_inorder_en, options, BIT_8);
3668*4882a593Smuzhiyun 	SET_BITVAL(sess->chap_auth_en, options, BIT_7);
3669*4882a593Smuzhiyun 	SET_BITVAL(conn->snack_req_en, options, BIT_6);
3670*4882a593Smuzhiyun 	SET_BITVAL(sess->discovery_logout_en, options, BIT_5);
3671*4882a593Smuzhiyun 	SET_BITVAL(sess->bidi_chap_en, options, BIT_4);
3672*4882a593Smuzhiyun 	SET_BITVAL(sess->discovery_auth_optional, options, BIT_3);
3673*4882a593Smuzhiyun 	SET_BITVAL(sess->erl & BIT_1, options, BIT_1);
3674*4882a593Smuzhiyun 	SET_BITVAL(sess->erl & BIT_0, options, BIT_0);
3675*4882a593Smuzhiyun 	fw_ddb_entry->iscsi_options = cpu_to_le16(options);
3676*4882a593Smuzhiyun 
3677*4882a593Smuzhiyun 	options = le16_to_cpu(fw_ddb_entry->tcp_options);
3678*4882a593Smuzhiyun 	SET_BITVAL(conn->tcp_timestamp_stat, options, BIT_6);
3679*4882a593Smuzhiyun 	SET_BITVAL(conn->tcp_nagle_disable, options, BIT_5);
3680*4882a593Smuzhiyun 	SET_BITVAL(conn->tcp_wsf_disable, options, BIT_4);
3681*4882a593Smuzhiyun 	SET_BITVAL(conn->tcp_timer_scale & BIT_2, options, BIT_3);
3682*4882a593Smuzhiyun 	SET_BITVAL(conn->tcp_timer_scale & BIT_1, options, BIT_2);
3683*4882a593Smuzhiyun 	SET_BITVAL(conn->tcp_timer_scale & BIT_0, options, BIT_1);
3684*4882a593Smuzhiyun 	SET_BITVAL(conn->tcp_timestamp_en, options, BIT_0);
3685*4882a593Smuzhiyun 	fw_ddb_entry->tcp_options = cpu_to_le16(options);
3686*4882a593Smuzhiyun 
3687*4882a593Smuzhiyun 	options = le16_to_cpu(fw_ddb_entry->ip_options);
3688*4882a593Smuzhiyun 	SET_BITVAL(conn->fragment_disable, options, BIT_4);
3689*4882a593Smuzhiyun 	fw_ddb_entry->ip_options = cpu_to_le16(options);
3690*4882a593Smuzhiyun 
3691*4882a593Smuzhiyun 	fw_ddb_entry->iscsi_max_outsnd_r2t = cpu_to_le16(sess->max_r2t);
3692*4882a593Smuzhiyun 	fw_ddb_entry->iscsi_max_rcv_data_seg_len =
3693*4882a593Smuzhiyun 			       cpu_to_le16(conn->max_recv_dlength / BYTE_UNITS);
3694*4882a593Smuzhiyun 	fw_ddb_entry->iscsi_max_snd_data_seg_len =
3695*4882a593Smuzhiyun 			       cpu_to_le16(conn->max_xmit_dlength / BYTE_UNITS);
3696*4882a593Smuzhiyun 	fw_ddb_entry->iscsi_first_burst_len =
3697*4882a593Smuzhiyun 				cpu_to_le16(sess->first_burst / BYTE_UNITS);
3698*4882a593Smuzhiyun 	fw_ddb_entry->iscsi_max_burst_len = cpu_to_le16(sess->max_burst /
3699*4882a593Smuzhiyun 					    BYTE_UNITS);
3700*4882a593Smuzhiyun 	fw_ddb_entry->iscsi_def_time2wait = cpu_to_le16(sess->time2wait);
3701*4882a593Smuzhiyun 	fw_ddb_entry->iscsi_def_time2retain = cpu_to_le16(sess->time2retain);
3702*4882a593Smuzhiyun 	fw_ddb_entry->tgt_portal_grp = cpu_to_le16(sess->tpgt);
3703*4882a593Smuzhiyun 	fw_ddb_entry->mss = cpu_to_le16(conn->max_segment_size);
3704*4882a593Smuzhiyun 	fw_ddb_entry->tcp_xmt_wsf = (uint8_t) cpu_to_le32(conn->tcp_xmit_wsf);
3705*4882a593Smuzhiyun 	fw_ddb_entry->tcp_rcv_wsf = (uint8_t) cpu_to_le32(conn->tcp_recv_wsf);
3706*4882a593Smuzhiyun 	fw_ddb_entry->ipv6_flow_lbl = cpu_to_le16(conn->ipv6_flow_label);
3707*4882a593Smuzhiyun 	fw_ddb_entry->ka_timeout = cpu_to_le16(conn->keepalive_timeout);
3708*4882a593Smuzhiyun 	fw_ddb_entry->lcl_port = cpu_to_le16(conn->local_port);
3709*4882a593Smuzhiyun 	fw_ddb_entry->stat_sn = cpu_to_le32(conn->statsn);
3710*4882a593Smuzhiyun 	fw_ddb_entry->exp_stat_sn = cpu_to_le32(conn->exp_statsn);
3711*4882a593Smuzhiyun 	fw_ddb_entry->ddb_link = cpu_to_le16(sess->discovery_parent_idx);
3712*4882a593Smuzhiyun 	fw_ddb_entry->chap_tbl_idx = cpu_to_le16(sess->chap_out_idx);
3713*4882a593Smuzhiyun 	fw_ddb_entry->tsid = cpu_to_le16(sess->tsid);
3714*4882a593Smuzhiyun 	fw_ddb_entry->port = cpu_to_le16(conn->port);
3715*4882a593Smuzhiyun 	fw_ddb_entry->def_timeout =
3716*4882a593Smuzhiyun 				cpu_to_le16(sess->default_taskmgmt_timeout);
3717*4882a593Smuzhiyun 
3718*4882a593Smuzhiyun 	if (!strncmp(sess->portal_type, PORTAL_TYPE_IPV6, 4))
3719*4882a593Smuzhiyun 		fw_ddb_entry->ipv4_tos = conn->ipv6_traffic_class;
3720*4882a593Smuzhiyun 	else
3721*4882a593Smuzhiyun 		fw_ddb_entry->ipv4_tos = conn->ipv4_tos;
3722*4882a593Smuzhiyun 
3723*4882a593Smuzhiyun 	if (conn->ipaddress)
3724*4882a593Smuzhiyun 		memcpy(fw_ddb_entry->ip_addr, conn->ipaddress,
3725*4882a593Smuzhiyun 		       sizeof(fw_ddb_entry->ip_addr));
3726*4882a593Smuzhiyun 
3727*4882a593Smuzhiyun 	if (conn->redirect_ipaddr)
3728*4882a593Smuzhiyun 		memcpy(fw_ddb_entry->tgt_addr, conn->redirect_ipaddr,
3729*4882a593Smuzhiyun 		       sizeof(fw_ddb_entry->tgt_addr));
3730*4882a593Smuzhiyun 
3731*4882a593Smuzhiyun 	if (conn->link_local_ipv6_addr)
3732*4882a593Smuzhiyun 		memcpy(fw_ddb_entry->link_local_ipv6_addr,
3733*4882a593Smuzhiyun 		       conn->link_local_ipv6_addr,
3734*4882a593Smuzhiyun 		       sizeof(fw_ddb_entry->link_local_ipv6_addr));
3735*4882a593Smuzhiyun 
3736*4882a593Smuzhiyun 	if (sess->targetname)
3737*4882a593Smuzhiyun 		memcpy(fw_ddb_entry->iscsi_name, sess->targetname,
3738*4882a593Smuzhiyun 		       sizeof(fw_ddb_entry->iscsi_name));
3739*4882a593Smuzhiyun 
3740*4882a593Smuzhiyun 	if (sess->targetalias)
3741*4882a593Smuzhiyun 		memcpy(fw_ddb_entry->iscsi_alias, sess->targetalias,
3742*4882a593Smuzhiyun 		       sizeof(fw_ddb_entry->iscsi_alias));
3743*4882a593Smuzhiyun 
3744*4882a593Smuzhiyun 	COPY_ISID(fw_ddb_entry->isid, sess->isid);
3745*4882a593Smuzhiyun 
3746*4882a593Smuzhiyun 	return rc;
3747*4882a593Smuzhiyun }
3748*4882a593Smuzhiyun 
qla4xxx_copy_to_sess_conn_params(struct iscsi_conn * conn,struct iscsi_session * sess,struct dev_db_entry * fw_ddb_entry)3749*4882a593Smuzhiyun static void qla4xxx_copy_to_sess_conn_params(struct iscsi_conn *conn,
3750*4882a593Smuzhiyun 					     struct iscsi_session *sess,
3751*4882a593Smuzhiyun 					     struct dev_db_entry *fw_ddb_entry)
3752*4882a593Smuzhiyun {
3753*4882a593Smuzhiyun 	unsigned long options = 0;
3754*4882a593Smuzhiyun 	uint16_t ddb_link;
3755*4882a593Smuzhiyun 	uint16_t disc_parent;
3756*4882a593Smuzhiyun 	char ip_addr[DDB_IPADDR_LEN];
3757*4882a593Smuzhiyun 
3758*4882a593Smuzhiyun 	options = le16_to_cpu(fw_ddb_entry->options);
3759*4882a593Smuzhiyun 	conn->is_fw_assigned_ipv6 = test_bit(OPT_IS_FW_ASSIGNED_IPV6, &options);
3760*4882a593Smuzhiyun 	sess->auto_snd_tgt_disable = test_bit(OPT_AUTO_SENDTGTS_DISABLE,
3761*4882a593Smuzhiyun 					      &options);
3762*4882a593Smuzhiyun 	sess->discovery_sess = test_bit(OPT_DISC_SESSION, &options);
3763*4882a593Smuzhiyun 
3764*4882a593Smuzhiyun 	options = le16_to_cpu(fw_ddb_entry->iscsi_options);
3765*4882a593Smuzhiyun 	conn->hdrdgst_en = test_bit(ISCSIOPT_HEADER_DIGEST_EN, &options);
3766*4882a593Smuzhiyun 	conn->datadgst_en = test_bit(ISCSIOPT_DATA_DIGEST_EN, &options);
3767*4882a593Smuzhiyun 	sess->imm_data_en = test_bit(ISCSIOPT_IMMEDIATE_DATA_EN, &options);
3768*4882a593Smuzhiyun 	sess->initial_r2t_en = test_bit(ISCSIOPT_INITIAL_R2T_EN, &options);
3769*4882a593Smuzhiyun 	sess->dataseq_inorder_en = test_bit(ISCSIOPT_DATA_SEQ_IN_ORDER,
3770*4882a593Smuzhiyun 					    &options);
3771*4882a593Smuzhiyun 	sess->pdu_inorder_en = test_bit(ISCSIOPT_DATA_PDU_IN_ORDER, &options);
3772*4882a593Smuzhiyun 	sess->chap_auth_en = test_bit(ISCSIOPT_CHAP_AUTH_EN, &options);
3773*4882a593Smuzhiyun 	sess->discovery_logout_en = test_bit(ISCSIOPT_DISCOVERY_LOGOUT_EN,
3774*4882a593Smuzhiyun 					     &options);
3775*4882a593Smuzhiyun 	sess->bidi_chap_en = test_bit(ISCSIOPT_BIDI_CHAP_EN, &options);
3776*4882a593Smuzhiyun 	sess->discovery_auth_optional =
3777*4882a593Smuzhiyun 			test_bit(ISCSIOPT_DISCOVERY_AUTH_OPTIONAL, &options);
3778*4882a593Smuzhiyun 	if (test_bit(ISCSIOPT_ERL1, &options))
3779*4882a593Smuzhiyun 		sess->erl |= BIT_1;
3780*4882a593Smuzhiyun 	if (test_bit(ISCSIOPT_ERL0, &options))
3781*4882a593Smuzhiyun 		sess->erl |= BIT_0;
3782*4882a593Smuzhiyun 
3783*4882a593Smuzhiyun 	options = le16_to_cpu(fw_ddb_entry->tcp_options);
3784*4882a593Smuzhiyun 	conn->tcp_timestamp_stat = test_bit(TCPOPT_TIMESTAMP_STAT, &options);
3785*4882a593Smuzhiyun 	conn->tcp_nagle_disable = test_bit(TCPOPT_NAGLE_DISABLE, &options);
3786*4882a593Smuzhiyun 	conn->tcp_wsf_disable = test_bit(TCPOPT_WSF_DISABLE, &options);
3787*4882a593Smuzhiyun 	if (test_bit(TCPOPT_TIMER_SCALE3, &options))
3788*4882a593Smuzhiyun 		conn->tcp_timer_scale |= BIT_3;
3789*4882a593Smuzhiyun 	if (test_bit(TCPOPT_TIMER_SCALE2, &options))
3790*4882a593Smuzhiyun 		conn->tcp_timer_scale |= BIT_2;
3791*4882a593Smuzhiyun 	if (test_bit(TCPOPT_TIMER_SCALE1, &options))
3792*4882a593Smuzhiyun 		conn->tcp_timer_scale |= BIT_1;
3793*4882a593Smuzhiyun 
3794*4882a593Smuzhiyun 	conn->tcp_timer_scale >>= 1;
3795*4882a593Smuzhiyun 	conn->tcp_timestamp_en = test_bit(TCPOPT_TIMESTAMP_EN, &options);
3796*4882a593Smuzhiyun 
3797*4882a593Smuzhiyun 	options = le16_to_cpu(fw_ddb_entry->ip_options);
3798*4882a593Smuzhiyun 	conn->fragment_disable = test_bit(IPOPT_FRAGMENT_DISABLE, &options);
3799*4882a593Smuzhiyun 
3800*4882a593Smuzhiyun 	conn->max_recv_dlength = BYTE_UNITS *
3801*4882a593Smuzhiyun 			  le16_to_cpu(fw_ddb_entry->iscsi_max_rcv_data_seg_len);
3802*4882a593Smuzhiyun 	conn->max_xmit_dlength = BYTE_UNITS *
3803*4882a593Smuzhiyun 			  le16_to_cpu(fw_ddb_entry->iscsi_max_snd_data_seg_len);
3804*4882a593Smuzhiyun 	sess->max_r2t = le16_to_cpu(fw_ddb_entry->iscsi_max_outsnd_r2t);
3805*4882a593Smuzhiyun 	sess->first_burst = BYTE_UNITS *
3806*4882a593Smuzhiyun 			       le16_to_cpu(fw_ddb_entry->iscsi_first_burst_len);
3807*4882a593Smuzhiyun 	sess->max_burst = BYTE_UNITS *
3808*4882a593Smuzhiyun 				 le16_to_cpu(fw_ddb_entry->iscsi_max_burst_len);
3809*4882a593Smuzhiyun 	sess->time2wait = le16_to_cpu(fw_ddb_entry->iscsi_def_time2wait);
3810*4882a593Smuzhiyun 	sess->time2retain = le16_to_cpu(fw_ddb_entry->iscsi_def_time2retain);
3811*4882a593Smuzhiyun 	sess->tpgt = le32_to_cpu(fw_ddb_entry->tgt_portal_grp);
3812*4882a593Smuzhiyun 	conn->max_segment_size = le16_to_cpu(fw_ddb_entry->mss);
3813*4882a593Smuzhiyun 	conn->tcp_xmit_wsf = fw_ddb_entry->tcp_xmt_wsf;
3814*4882a593Smuzhiyun 	conn->tcp_recv_wsf = fw_ddb_entry->tcp_rcv_wsf;
3815*4882a593Smuzhiyun 	conn->ipv4_tos = fw_ddb_entry->ipv4_tos;
3816*4882a593Smuzhiyun 	conn->keepalive_tmo = le16_to_cpu(fw_ddb_entry->ka_timeout);
3817*4882a593Smuzhiyun 	conn->local_port = le16_to_cpu(fw_ddb_entry->lcl_port);
3818*4882a593Smuzhiyun 	conn->statsn = le32_to_cpu(fw_ddb_entry->stat_sn);
3819*4882a593Smuzhiyun 	conn->exp_statsn = le32_to_cpu(fw_ddb_entry->exp_stat_sn);
3820*4882a593Smuzhiyun 	sess->tsid = le16_to_cpu(fw_ddb_entry->tsid);
3821*4882a593Smuzhiyun 	COPY_ISID(sess->isid, fw_ddb_entry->isid);
3822*4882a593Smuzhiyun 
3823*4882a593Smuzhiyun 	ddb_link = le16_to_cpu(fw_ddb_entry->ddb_link);
3824*4882a593Smuzhiyun 	if (ddb_link == DDB_ISNS)
3825*4882a593Smuzhiyun 		disc_parent = ISCSI_DISC_PARENT_ISNS;
3826*4882a593Smuzhiyun 	else if (ddb_link == DDB_NO_LINK)
3827*4882a593Smuzhiyun 		disc_parent = ISCSI_DISC_PARENT_UNKNOWN;
3828*4882a593Smuzhiyun 	else if (ddb_link < MAX_DDB_ENTRIES)
3829*4882a593Smuzhiyun 		disc_parent = ISCSI_DISC_PARENT_SENDTGT;
3830*4882a593Smuzhiyun 	else
3831*4882a593Smuzhiyun 		disc_parent = ISCSI_DISC_PARENT_UNKNOWN;
3832*4882a593Smuzhiyun 
3833*4882a593Smuzhiyun 	iscsi_set_param(conn->cls_conn, ISCSI_PARAM_DISCOVERY_PARENT_TYPE,
3834*4882a593Smuzhiyun 			iscsi_get_discovery_parent_name(disc_parent), 0);
3835*4882a593Smuzhiyun 
3836*4882a593Smuzhiyun 	iscsi_set_param(conn->cls_conn, ISCSI_PARAM_TARGET_ALIAS,
3837*4882a593Smuzhiyun 			(char *)fw_ddb_entry->iscsi_alias, 0);
3838*4882a593Smuzhiyun 
3839*4882a593Smuzhiyun 	options = le16_to_cpu(fw_ddb_entry->options);
3840*4882a593Smuzhiyun 	if (options & DDB_OPT_IPV6_DEVICE) {
3841*4882a593Smuzhiyun 		memset(ip_addr, 0, sizeof(ip_addr));
3842*4882a593Smuzhiyun 		sprintf(ip_addr, "%pI6", fw_ddb_entry->link_local_ipv6_addr);
3843*4882a593Smuzhiyun 		iscsi_set_param(conn->cls_conn, ISCSI_PARAM_LOCAL_IPADDR,
3844*4882a593Smuzhiyun 				(char *)ip_addr, 0);
3845*4882a593Smuzhiyun 	}
3846*4882a593Smuzhiyun }
3847*4882a593Smuzhiyun 
qla4xxx_copy_fwddb_param(struct scsi_qla_host * ha,struct dev_db_entry * fw_ddb_entry,struct iscsi_cls_session * cls_sess,struct iscsi_cls_conn * cls_conn)3848*4882a593Smuzhiyun static void qla4xxx_copy_fwddb_param(struct scsi_qla_host *ha,
3849*4882a593Smuzhiyun 				     struct dev_db_entry *fw_ddb_entry,
3850*4882a593Smuzhiyun 				     struct iscsi_cls_session *cls_sess,
3851*4882a593Smuzhiyun 				     struct iscsi_cls_conn *cls_conn)
3852*4882a593Smuzhiyun {
3853*4882a593Smuzhiyun 	int buflen = 0;
3854*4882a593Smuzhiyun 	struct iscsi_session *sess;
3855*4882a593Smuzhiyun 	struct ddb_entry *ddb_entry;
3856*4882a593Smuzhiyun 	struct ql4_chap_table chap_tbl;
3857*4882a593Smuzhiyun 	struct iscsi_conn *conn;
3858*4882a593Smuzhiyun 	char ip_addr[DDB_IPADDR_LEN];
3859*4882a593Smuzhiyun 	uint16_t options = 0;
3860*4882a593Smuzhiyun 
3861*4882a593Smuzhiyun 	sess = cls_sess->dd_data;
3862*4882a593Smuzhiyun 	ddb_entry = sess->dd_data;
3863*4882a593Smuzhiyun 	conn = cls_conn->dd_data;
3864*4882a593Smuzhiyun 	memset(&chap_tbl, 0, sizeof(chap_tbl));
3865*4882a593Smuzhiyun 
3866*4882a593Smuzhiyun 	ddb_entry->chap_tbl_idx = le16_to_cpu(fw_ddb_entry->chap_tbl_idx);
3867*4882a593Smuzhiyun 
3868*4882a593Smuzhiyun 	qla4xxx_copy_to_sess_conn_params(conn, sess, fw_ddb_entry);
3869*4882a593Smuzhiyun 
3870*4882a593Smuzhiyun 	sess->def_taskmgmt_tmo = le16_to_cpu(fw_ddb_entry->def_timeout);
3871*4882a593Smuzhiyun 	conn->persistent_port = le16_to_cpu(fw_ddb_entry->port);
3872*4882a593Smuzhiyun 
3873*4882a593Smuzhiyun 	memset(ip_addr, 0, sizeof(ip_addr));
3874*4882a593Smuzhiyun 	options = le16_to_cpu(fw_ddb_entry->options);
3875*4882a593Smuzhiyun 	if (options & DDB_OPT_IPV6_DEVICE) {
3876*4882a593Smuzhiyun 		iscsi_set_param(cls_conn, ISCSI_PARAM_PORTAL_TYPE, "ipv6", 4);
3877*4882a593Smuzhiyun 
3878*4882a593Smuzhiyun 		memset(ip_addr, 0, sizeof(ip_addr));
3879*4882a593Smuzhiyun 		sprintf(ip_addr, "%pI6", fw_ddb_entry->ip_addr);
3880*4882a593Smuzhiyun 	} else {
3881*4882a593Smuzhiyun 		iscsi_set_param(cls_conn, ISCSI_PARAM_PORTAL_TYPE, "ipv4", 4);
3882*4882a593Smuzhiyun 		sprintf(ip_addr, "%pI4", fw_ddb_entry->ip_addr);
3883*4882a593Smuzhiyun 	}
3884*4882a593Smuzhiyun 
3885*4882a593Smuzhiyun 	iscsi_set_param(cls_conn, ISCSI_PARAM_PERSISTENT_ADDRESS,
3886*4882a593Smuzhiyun 			(char *)ip_addr, buflen);
3887*4882a593Smuzhiyun 	iscsi_set_param(cls_conn, ISCSI_PARAM_TARGET_NAME,
3888*4882a593Smuzhiyun 			(char *)fw_ddb_entry->iscsi_name, buflen);
3889*4882a593Smuzhiyun 	iscsi_set_param(cls_conn, ISCSI_PARAM_INITIATOR_NAME,
3890*4882a593Smuzhiyun 			(char *)ha->name_string, buflen);
3891*4882a593Smuzhiyun 
3892*4882a593Smuzhiyun 	if (ddb_entry->chap_tbl_idx != INVALID_ENTRY) {
3893*4882a593Smuzhiyun 		if (!qla4xxx_get_uni_chap_at_index(ha, chap_tbl.name,
3894*4882a593Smuzhiyun 						   chap_tbl.secret,
3895*4882a593Smuzhiyun 						   ddb_entry->chap_tbl_idx)) {
3896*4882a593Smuzhiyun 			iscsi_set_param(cls_conn, ISCSI_PARAM_USERNAME,
3897*4882a593Smuzhiyun 					(char *)chap_tbl.name,
3898*4882a593Smuzhiyun 					strlen((char *)chap_tbl.name));
3899*4882a593Smuzhiyun 			iscsi_set_param(cls_conn, ISCSI_PARAM_PASSWORD,
3900*4882a593Smuzhiyun 					(char *)chap_tbl.secret,
3901*4882a593Smuzhiyun 					chap_tbl.secret_len);
3902*4882a593Smuzhiyun 		}
3903*4882a593Smuzhiyun 	}
3904*4882a593Smuzhiyun }
3905*4882a593Smuzhiyun 
qla4xxx_update_session_conn_fwddb_param(struct scsi_qla_host * ha,struct ddb_entry * ddb_entry)3906*4882a593Smuzhiyun void qla4xxx_update_session_conn_fwddb_param(struct scsi_qla_host *ha,
3907*4882a593Smuzhiyun 					     struct ddb_entry *ddb_entry)
3908*4882a593Smuzhiyun {
3909*4882a593Smuzhiyun 	struct iscsi_cls_session *cls_sess;
3910*4882a593Smuzhiyun 	struct iscsi_cls_conn *cls_conn;
3911*4882a593Smuzhiyun 	uint32_t ddb_state;
3912*4882a593Smuzhiyun 	dma_addr_t fw_ddb_entry_dma;
3913*4882a593Smuzhiyun 	struct dev_db_entry *fw_ddb_entry;
3914*4882a593Smuzhiyun 
3915*4882a593Smuzhiyun 	fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
3916*4882a593Smuzhiyun 					  &fw_ddb_entry_dma, GFP_KERNEL);
3917*4882a593Smuzhiyun 	if (!fw_ddb_entry) {
3918*4882a593Smuzhiyun 		ql4_printk(KERN_ERR, ha,
3919*4882a593Smuzhiyun 			   "%s: Unable to allocate dma buffer\n", __func__);
3920*4882a593Smuzhiyun 		goto exit_session_conn_fwddb_param;
3921*4882a593Smuzhiyun 	}
3922*4882a593Smuzhiyun 
3923*4882a593Smuzhiyun 	if (qla4xxx_get_fwddb_entry(ha, ddb_entry->fw_ddb_index, fw_ddb_entry,
3924*4882a593Smuzhiyun 				    fw_ddb_entry_dma, NULL, NULL, &ddb_state,
3925*4882a593Smuzhiyun 				    NULL, NULL, NULL) == QLA_ERROR) {
3926*4882a593Smuzhiyun 		DEBUG2(ql4_printk(KERN_ERR, ha, "scsi%ld: %s: failed "
3927*4882a593Smuzhiyun 				  "get_ddb_entry for fw_ddb_index %d\n",
3928*4882a593Smuzhiyun 				  ha->host_no, __func__,
3929*4882a593Smuzhiyun 				  ddb_entry->fw_ddb_index));
3930*4882a593Smuzhiyun 		goto exit_session_conn_fwddb_param;
3931*4882a593Smuzhiyun 	}
3932*4882a593Smuzhiyun 
3933*4882a593Smuzhiyun 	cls_sess = ddb_entry->sess;
3934*4882a593Smuzhiyun 
3935*4882a593Smuzhiyun 	cls_conn = ddb_entry->conn;
3936*4882a593Smuzhiyun 
3937*4882a593Smuzhiyun 	/* Update params */
3938*4882a593Smuzhiyun 	qla4xxx_copy_fwddb_param(ha, fw_ddb_entry, cls_sess, cls_conn);
3939*4882a593Smuzhiyun 
3940*4882a593Smuzhiyun exit_session_conn_fwddb_param:
3941*4882a593Smuzhiyun 	if (fw_ddb_entry)
3942*4882a593Smuzhiyun 		dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
3943*4882a593Smuzhiyun 				  fw_ddb_entry, fw_ddb_entry_dma);
3944*4882a593Smuzhiyun }
3945*4882a593Smuzhiyun 
qla4xxx_update_session_conn_param(struct scsi_qla_host * ha,struct ddb_entry * ddb_entry)3946*4882a593Smuzhiyun void qla4xxx_update_session_conn_param(struct scsi_qla_host *ha,
3947*4882a593Smuzhiyun 				       struct ddb_entry *ddb_entry)
3948*4882a593Smuzhiyun {
3949*4882a593Smuzhiyun 	struct iscsi_cls_session *cls_sess;
3950*4882a593Smuzhiyun 	struct iscsi_cls_conn *cls_conn;
3951*4882a593Smuzhiyun 	struct iscsi_session *sess;
3952*4882a593Smuzhiyun 	struct iscsi_conn *conn;
3953*4882a593Smuzhiyun 	uint32_t ddb_state;
3954*4882a593Smuzhiyun 	dma_addr_t fw_ddb_entry_dma;
3955*4882a593Smuzhiyun 	struct dev_db_entry *fw_ddb_entry;
3956*4882a593Smuzhiyun 
3957*4882a593Smuzhiyun 	fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
3958*4882a593Smuzhiyun 					  &fw_ddb_entry_dma, GFP_KERNEL);
3959*4882a593Smuzhiyun 	if (!fw_ddb_entry) {
3960*4882a593Smuzhiyun 		ql4_printk(KERN_ERR, ha,
3961*4882a593Smuzhiyun 			   "%s: Unable to allocate dma buffer\n", __func__);
3962*4882a593Smuzhiyun 		goto exit_session_conn_param;
3963*4882a593Smuzhiyun 	}
3964*4882a593Smuzhiyun 
3965*4882a593Smuzhiyun 	if (qla4xxx_get_fwddb_entry(ha, ddb_entry->fw_ddb_index, fw_ddb_entry,
3966*4882a593Smuzhiyun 				    fw_ddb_entry_dma, NULL, NULL, &ddb_state,
3967*4882a593Smuzhiyun 				    NULL, NULL, NULL) == QLA_ERROR) {
3968*4882a593Smuzhiyun 		DEBUG2(ql4_printk(KERN_ERR, ha, "scsi%ld: %s: failed "
3969*4882a593Smuzhiyun 				  "get_ddb_entry for fw_ddb_index %d\n",
3970*4882a593Smuzhiyun 				  ha->host_no, __func__,
3971*4882a593Smuzhiyun 				  ddb_entry->fw_ddb_index));
3972*4882a593Smuzhiyun 		goto exit_session_conn_param;
3973*4882a593Smuzhiyun 	}
3974*4882a593Smuzhiyun 
3975*4882a593Smuzhiyun 	cls_sess = ddb_entry->sess;
3976*4882a593Smuzhiyun 	sess = cls_sess->dd_data;
3977*4882a593Smuzhiyun 
3978*4882a593Smuzhiyun 	cls_conn = ddb_entry->conn;
3979*4882a593Smuzhiyun 	conn = cls_conn->dd_data;
3980*4882a593Smuzhiyun 
3981*4882a593Smuzhiyun 	/* Update timers after login */
3982*4882a593Smuzhiyun 	ddb_entry->default_relogin_timeout =
3983*4882a593Smuzhiyun 		(le16_to_cpu(fw_ddb_entry->def_timeout) > LOGIN_TOV) &&
3984*4882a593Smuzhiyun 		 (le16_to_cpu(fw_ddb_entry->def_timeout) < LOGIN_TOV * 10) ?
3985*4882a593Smuzhiyun 		 le16_to_cpu(fw_ddb_entry->def_timeout) : LOGIN_TOV;
3986*4882a593Smuzhiyun 	ddb_entry->default_time2wait =
3987*4882a593Smuzhiyun 				le16_to_cpu(fw_ddb_entry->iscsi_def_time2wait);
3988*4882a593Smuzhiyun 
3989*4882a593Smuzhiyun 	/* Update params */
3990*4882a593Smuzhiyun 	ddb_entry->chap_tbl_idx = le16_to_cpu(fw_ddb_entry->chap_tbl_idx);
3991*4882a593Smuzhiyun 	qla4xxx_copy_to_sess_conn_params(conn, sess, fw_ddb_entry);
3992*4882a593Smuzhiyun 
3993*4882a593Smuzhiyun 	memcpy(sess->initiatorname, ha->name_string,
3994*4882a593Smuzhiyun 	       min(sizeof(ha->name_string), sizeof(sess->initiatorname)));
3995*4882a593Smuzhiyun 
3996*4882a593Smuzhiyun exit_session_conn_param:
3997*4882a593Smuzhiyun 	if (fw_ddb_entry)
3998*4882a593Smuzhiyun 		dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
3999*4882a593Smuzhiyun 				  fw_ddb_entry, fw_ddb_entry_dma);
4000*4882a593Smuzhiyun }
4001*4882a593Smuzhiyun 
4002*4882a593Smuzhiyun /*
4003*4882a593Smuzhiyun  * Timer routines
4004*4882a593Smuzhiyun  */
4005*4882a593Smuzhiyun static void qla4xxx_timer(struct timer_list *t);
4006*4882a593Smuzhiyun 
qla4xxx_start_timer(struct scsi_qla_host * ha,unsigned long interval)4007*4882a593Smuzhiyun static void qla4xxx_start_timer(struct scsi_qla_host *ha,
4008*4882a593Smuzhiyun 				unsigned long interval)
4009*4882a593Smuzhiyun {
4010*4882a593Smuzhiyun 	DEBUG(printk("scsi: %s: Starting timer thread for adapter %d\n",
4011*4882a593Smuzhiyun 		     __func__, ha->host->host_no));
4012*4882a593Smuzhiyun 	timer_setup(&ha->timer, qla4xxx_timer, 0);
4013*4882a593Smuzhiyun 	ha->timer.expires = jiffies + interval * HZ;
4014*4882a593Smuzhiyun 	add_timer(&ha->timer);
4015*4882a593Smuzhiyun 	ha->timer_active = 1;
4016*4882a593Smuzhiyun }
4017*4882a593Smuzhiyun 
qla4xxx_stop_timer(struct scsi_qla_host * ha)4018*4882a593Smuzhiyun static void qla4xxx_stop_timer(struct scsi_qla_host *ha)
4019*4882a593Smuzhiyun {
4020*4882a593Smuzhiyun 	del_timer_sync(&ha->timer);
4021*4882a593Smuzhiyun 	ha->timer_active = 0;
4022*4882a593Smuzhiyun }
4023*4882a593Smuzhiyun 
4024*4882a593Smuzhiyun /***
4025*4882a593Smuzhiyun  * qla4xxx_mark_device_missing - blocks the session
4026*4882a593Smuzhiyun  * @cls_session: Pointer to the session to be blocked
4027*4882a593Smuzhiyun  * @ddb_entry: Pointer to device database entry
4028*4882a593Smuzhiyun  *
4029*4882a593Smuzhiyun  * This routine marks a device missing and close connection.
4030*4882a593Smuzhiyun  **/
qla4xxx_mark_device_missing(struct iscsi_cls_session * cls_session)4031*4882a593Smuzhiyun void qla4xxx_mark_device_missing(struct iscsi_cls_session *cls_session)
4032*4882a593Smuzhiyun {
4033*4882a593Smuzhiyun 	iscsi_block_session(cls_session);
4034*4882a593Smuzhiyun }
4035*4882a593Smuzhiyun 
4036*4882a593Smuzhiyun /**
4037*4882a593Smuzhiyun  * qla4xxx_mark_all_devices_missing - mark all devices as missing.
4038*4882a593Smuzhiyun  * @ha: Pointer to host adapter structure.
4039*4882a593Smuzhiyun  *
4040*4882a593Smuzhiyun  * This routine marks a device missing and resets the relogin retry count.
4041*4882a593Smuzhiyun  **/
qla4xxx_mark_all_devices_missing(struct scsi_qla_host * ha)4042*4882a593Smuzhiyun void qla4xxx_mark_all_devices_missing(struct scsi_qla_host *ha)
4043*4882a593Smuzhiyun {
4044*4882a593Smuzhiyun 	iscsi_host_for_each_session(ha->host, qla4xxx_mark_device_missing);
4045*4882a593Smuzhiyun }
4046*4882a593Smuzhiyun 
qla4xxx_get_new_srb(struct scsi_qla_host * ha,struct ddb_entry * ddb_entry,struct scsi_cmnd * cmd)4047*4882a593Smuzhiyun static struct srb* qla4xxx_get_new_srb(struct scsi_qla_host *ha,
4048*4882a593Smuzhiyun 				       struct ddb_entry *ddb_entry,
4049*4882a593Smuzhiyun 				       struct scsi_cmnd *cmd)
4050*4882a593Smuzhiyun {
4051*4882a593Smuzhiyun 	struct srb *srb;
4052*4882a593Smuzhiyun 
4053*4882a593Smuzhiyun 	srb = mempool_alloc(ha->srb_mempool, GFP_ATOMIC);
4054*4882a593Smuzhiyun 	if (!srb)
4055*4882a593Smuzhiyun 		return srb;
4056*4882a593Smuzhiyun 
4057*4882a593Smuzhiyun 	kref_init(&srb->srb_ref);
4058*4882a593Smuzhiyun 	srb->ha = ha;
4059*4882a593Smuzhiyun 	srb->ddb = ddb_entry;
4060*4882a593Smuzhiyun 	srb->cmd = cmd;
4061*4882a593Smuzhiyun 	srb->flags = 0;
4062*4882a593Smuzhiyun 	CMD_SP(cmd) = (void *)srb;
4063*4882a593Smuzhiyun 
4064*4882a593Smuzhiyun 	return srb;
4065*4882a593Smuzhiyun }
4066*4882a593Smuzhiyun 
qla4xxx_srb_free_dma(struct scsi_qla_host * ha,struct srb * srb)4067*4882a593Smuzhiyun static void qla4xxx_srb_free_dma(struct scsi_qla_host *ha, struct srb *srb)
4068*4882a593Smuzhiyun {
4069*4882a593Smuzhiyun 	struct scsi_cmnd *cmd = srb->cmd;
4070*4882a593Smuzhiyun 
4071*4882a593Smuzhiyun 	if (srb->flags & SRB_DMA_VALID) {
4072*4882a593Smuzhiyun 		scsi_dma_unmap(cmd);
4073*4882a593Smuzhiyun 		srb->flags &= ~SRB_DMA_VALID;
4074*4882a593Smuzhiyun 	}
4075*4882a593Smuzhiyun 	CMD_SP(cmd) = NULL;
4076*4882a593Smuzhiyun }
4077*4882a593Smuzhiyun 
qla4xxx_srb_compl(struct kref * ref)4078*4882a593Smuzhiyun void qla4xxx_srb_compl(struct kref *ref)
4079*4882a593Smuzhiyun {
4080*4882a593Smuzhiyun 	struct srb *srb = container_of(ref, struct srb, srb_ref);
4081*4882a593Smuzhiyun 	struct scsi_cmnd *cmd = srb->cmd;
4082*4882a593Smuzhiyun 	struct scsi_qla_host *ha = srb->ha;
4083*4882a593Smuzhiyun 
4084*4882a593Smuzhiyun 	qla4xxx_srb_free_dma(ha, srb);
4085*4882a593Smuzhiyun 
4086*4882a593Smuzhiyun 	mempool_free(srb, ha->srb_mempool);
4087*4882a593Smuzhiyun 
4088*4882a593Smuzhiyun 	cmd->scsi_done(cmd);
4089*4882a593Smuzhiyun }
4090*4882a593Smuzhiyun 
4091*4882a593Smuzhiyun /**
4092*4882a593Smuzhiyun  * qla4xxx_queuecommand - scsi layer issues scsi command to driver.
4093*4882a593Smuzhiyun  * @host: scsi host
4094*4882a593Smuzhiyun  * @cmd: Pointer to Linux's SCSI command structure
4095*4882a593Smuzhiyun  *
4096*4882a593Smuzhiyun  * Remarks:
4097*4882a593Smuzhiyun  * This routine is invoked by Linux to send a SCSI command to the driver.
4098*4882a593Smuzhiyun  * The mid-level driver tries to ensure that queuecommand never gets
4099*4882a593Smuzhiyun  * invoked concurrently with itself or the interrupt handler (although
4100*4882a593Smuzhiyun  * the interrupt handler may call this routine as part of request-
4101*4882a593Smuzhiyun  * completion handling).   Unfortunely, it sometimes calls the scheduler
4102*4882a593Smuzhiyun  * in interrupt context which is a big NO! NO!.
4103*4882a593Smuzhiyun  **/
qla4xxx_queuecommand(struct Scsi_Host * host,struct scsi_cmnd * cmd)4104*4882a593Smuzhiyun static int qla4xxx_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd)
4105*4882a593Smuzhiyun {
4106*4882a593Smuzhiyun 	struct scsi_qla_host *ha = to_qla_host(host);
4107*4882a593Smuzhiyun 	struct ddb_entry *ddb_entry = cmd->device->hostdata;
4108*4882a593Smuzhiyun 	struct iscsi_cls_session *sess = ddb_entry->sess;
4109*4882a593Smuzhiyun 	struct srb *srb;
4110*4882a593Smuzhiyun 	int rval;
4111*4882a593Smuzhiyun 
4112*4882a593Smuzhiyun 	if (test_bit(AF_EEH_BUSY, &ha->flags)) {
4113*4882a593Smuzhiyun 		if (test_bit(AF_PCI_CHANNEL_IO_PERM_FAILURE, &ha->flags))
4114*4882a593Smuzhiyun 			cmd->result = DID_NO_CONNECT << 16;
4115*4882a593Smuzhiyun 		else
4116*4882a593Smuzhiyun 			cmd->result = DID_REQUEUE << 16;
4117*4882a593Smuzhiyun 		goto qc_fail_command;
4118*4882a593Smuzhiyun 	}
4119*4882a593Smuzhiyun 
4120*4882a593Smuzhiyun 	if (!sess) {
4121*4882a593Smuzhiyun 		cmd->result = DID_IMM_RETRY << 16;
4122*4882a593Smuzhiyun 		goto qc_fail_command;
4123*4882a593Smuzhiyun 	}
4124*4882a593Smuzhiyun 
4125*4882a593Smuzhiyun 	rval = iscsi_session_chkready(sess);
4126*4882a593Smuzhiyun 	if (rval) {
4127*4882a593Smuzhiyun 		cmd->result = rval;
4128*4882a593Smuzhiyun 		goto qc_fail_command;
4129*4882a593Smuzhiyun 	}
4130*4882a593Smuzhiyun 
4131*4882a593Smuzhiyun 	if (test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags) ||
4132*4882a593Smuzhiyun 	    test_bit(DPC_RESET_ACTIVE, &ha->dpc_flags) ||
4133*4882a593Smuzhiyun 	    test_bit(DPC_RESET_HA, &ha->dpc_flags) ||
4134*4882a593Smuzhiyun 	    test_bit(DPC_HA_UNRECOVERABLE, &ha->dpc_flags) ||
4135*4882a593Smuzhiyun 	    test_bit(DPC_HA_NEED_QUIESCENT, &ha->dpc_flags) ||
4136*4882a593Smuzhiyun 	    !test_bit(AF_ONLINE, &ha->flags) ||
4137*4882a593Smuzhiyun 	    !test_bit(AF_LINK_UP, &ha->flags) ||
4138*4882a593Smuzhiyun 	    test_bit(AF_LOOPBACK, &ha->flags) ||
4139*4882a593Smuzhiyun 	    test_bit(DPC_POST_IDC_ACK, &ha->dpc_flags) ||
4140*4882a593Smuzhiyun 	    test_bit(DPC_RESTORE_ACB, &ha->dpc_flags) ||
4141*4882a593Smuzhiyun 	    test_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags))
4142*4882a593Smuzhiyun 		goto qc_host_busy;
4143*4882a593Smuzhiyun 
4144*4882a593Smuzhiyun 	srb = qla4xxx_get_new_srb(ha, ddb_entry, cmd);
4145*4882a593Smuzhiyun 	if (!srb)
4146*4882a593Smuzhiyun 		goto qc_host_busy;
4147*4882a593Smuzhiyun 
4148*4882a593Smuzhiyun 	rval = qla4xxx_send_command_to_isp(ha, srb);
4149*4882a593Smuzhiyun 	if (rval != QLA_SUCCESS)
4150*4882a593Smuzhiyun 		goto qc_host_busy_free_sp;
4151*4882a593Smuzhiyun 
4152*4882a593Smuzhiyun 	return 0;
4153*4882a593Smuzhiyun 
4154*4882a593Smuzhiyun qc_host_busy_free_sp:
4155*4882a593Smuzhiyun 	qla4xxx_srb_free_dma(ha, srb);
4156*4882a593Smuzhiyun 	mempool_free(srb, ha->srb_mempool);
4157*4882a593Smuzhiyun 
4158*4882a593Smuzhiyun qc_host_busy:
4159*4882a593Smuzhiyun 	return SCSI_MLQUEUE_HOST_BUSY;
4160*4882a593Smuzhiyun 
4161*4882a593Smuzhiyun qc_fail_command:
4162*4882a593Smuzhiyun 	cmd->scsi_done(cmd);
4163*4882a593Smuzhiyun 
4164*4882a593Smuzhiyun 	return 0;
4165*4882a593Smuzhiyun }
4166*4882a593Smuzhiyun 
4167*4882a593Smuzhiyun /**
4168*4882a593Smuzhiyun  * qla4xxx_mem_free - frees memory allocated to adapter
4169*4882a593Smuzhiyun  * @ha: Pointer to host adapter structure.
4170*4882a593Smuzhiyun  *
4171*4882a593Smuzhiyun  * Frees memory previously allocated by qla4xxx_mem_alloc
4172*4882a593Smuzhiyun  **/
qla4xxx_mem_free(struct scsi_qla_host * ha)4173*4882a593Smuzhiyun static void qla4xxx_mem_free(struct scsi_qla_host *ha)
4174*4882a593Smuzhiyun {
4175*4882a593Smuzhiyun 	if (ha->queues)
4176*4882a593Smuzhiyun 		dma_free_coherent(&ha->pdev->dev, ha->queues_len, ha->queues,
4177*4882a593Smuzhiyun 				  ha->queues_dma);
4178*4882a593Smuzhiyun 
4179*4882a593Smuzhiyun 	if (ha->fw_dump)
4180*4882a593Smuzhiyun 		vfree(ha->fw_dump);
4181*4882a593Smuzhiyun 
4182*4882a593Smuzhiyun 	ha->queues_len = 0;
4183*4882a593Smuzhiyun 	ha->queues = NULL;
4184*4882a593Smuzhiyun 	ha->queues_dma = 0;
4185*4882a593Smuzhiyun 	ha->request_ring = NULL;
4186*4882a593Smuzhiyun 	ha->request_dma = 0;
4187*4882a593Smuzhiyun 	ha->response_ring = NULL;
4188*4882a593Smuzhiyun 	ha->response_dma = 0;
4189*4882a593Smuzhiyun 	ha->shadow_regs = NULL;
4190*4882a593Smuzhiyun 	ha->shadow_regs_dma = 0;
4191*4882a593Smuzhiyun 	ha->fw_dump = NULL;
4192*4882a593Smuzhiyun 	ha->fw_dump_size = 0;
4193*4882a593Smuzhiyun 
4194*4882a593Smuzhiyun 	/* Free srb pool. */
4195*4882a593Smuzhiyun 	mempool_destroy(ha->srb_mempool);
4196*4882a593Smuzhiyun 	ha->srb_mempool = NULL;
4197*4882a593Smuzhiyun 
4198*4882a593Smuzhiyun 	dma_pool_destroy(ha->chap_dma_pool);
4199*4882a593Smuzhiyun 
4200*4882a593Smuzhiyun 	if (ha->chap_list)
4201*4882a593Smuzhiyun 		vfree(ha->chap_list);
4202*4882a593Smuzhiyun 	ha->chap_list = NULL;
4203*4882a593Smuzhiyun 
4204*4882a593Smuzhiyun 	dma_pool_destroy(ha->fw_ddb_dma_pool);
4205*4882a593Smuzhiyun 
4206*4882a593Smuzhiyun 	/* release io space registers  */
4207*4882a593Smuzhiyun 	if (is_qla8022(ha)) {
4208*4882a593Smuzhiyun 		if (ha->nx_pcibase)
4209*4882a593Smuzhiyun 			iounmap(
4210*4882a593Smuzhiyun 			    (struct device_reg_82xx __iomem *)ha->nx_pcibase);
4211*4882a593Smuzhiyun 	} else if (is_qla8032(ha) || is_qla8042(ha)) {
4212*4882a593Smuzhiyun 		if (ha->nx_pcibase)
4213*4882a593Smuzhiyun 			iounmap(
4214*4882a593Smuzhiyun 			    (struct device_reg_83xx __iomem *)ha->nx_pcibase);
4215*4882a593Smuzhiyun 	} else if (ha->reg) {
4216*4882a593Smuzhiyun 		iounmap(ha->reg);
4217*4882a593Smuzhiyun 	}
4218*4882a593Smuzhiyun 
4219*4882a593Smuzhiyun 	if (ha->reset_tmplt.buff)
4220*4882a593Smuzhiyun 		vfree(ha->reset_tmplt.buff);
4221*4882a593Smuzhiyun 
4222*4882a593Smuzhiyun 	pci_release_regions(ha->pdev);
4223*4882a593Smuzhiyun }
4224*4882a593Smuzhiyun 
4225*4882a593Smuzhiyun /**
4226*4882a593Smuzhiyun  * qla4xxx_mem_alloc - allocates memory for use by adapter.
4227*4882a593Smuzhiyun  * @ha: Pointer to host adapter structure
4228*4882a593Smuzhiyun  *
4229*4882a593Smuzhiyun  * Allocates DMA memory for request and response queues. Also allocates memory
4230*4882a593Smuzhiyun  * for srbs.
4231*4882a593Smuzhiyun  **/
qla4xxx_mem_alloc(struct scsi_qla_host * ha)4232*4882a593Smuzhiyun static int qla4xxx_mem_alloc(struct scsi_qla_host *ha)
4233*4882a593Smuzhiyun {
4234*4882a593Smuzhiyun 	unsigned long align;
4235*4882a593Smuzhiyun 
4236*4882a593Smuzhiyun 	/* Allocate contiguous block of DMA memory for queues. */
4237*4882a593Smuzhiyun 	ha->queues_len = ((REQUEST_QUEUE_DEPTH * QUEUE_SIZE) +
4238*4882a593Smuzhiyun 			  (RESPONSE_QUEUE_DEPTH * QUEUE_SIZE) +
4239*4882a593Smuzhiyun 			  sizeof(struct shadow_regs) +
4240*4882a593Smuzhiyun 			  MEM_ALIGN_VALUE +
4241*4882a593Smuzhiyun 			  (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1);
4242*4882a593Smuzhiyun 	ha->queues = dma_alloc_coherent(&ha->pdev->dev, ha->queues_len,
4243*4882a593Smuzhiyun 					&ha->queues_dma, GFP_KERNEL);
4244*4882a593Smuzhiyun 	if (ha->queues == NULL) {
4245*4882a593Smuzhiyun 		ql4_printk(KERN_WARNING, ha,
4246*4882a593Smuzhiyun 		    "Memory Allocation failed - queues.\n");
4247*4882a593Smuzhiyun 
4248*4882a593Smuzhiyun 		goto mem_alloc_error_exit;
4249*4882a593Smuzhiyun 	}
4250*4882a593Smuzhiyun 
4251*4882a593Smuzhiyun 	/*
4252*4882a593Smuzhiyun 	 * As per RISC alignment requirements -- the bus-address must be a
4253*4882a593Smuzhiyun 	 * multiple of the request-ring size (in bytes).
4254*4882a593Smuzhiyun 	 */
4255*4882a593Smuzhiyun 	align = 0;
4256*4882a593Smuzhiyun 	if ((unsigned long)ha->queues_dma & (MEM_ALIGN_VALUE - 1))
4257*4882a593Smuzhiyun 		align = MEM_ALIGN_VALUE - ((unsigned long)ha->queues_dma &
4258*4882a593Smuzhiyun 					   (MEM_ALIGN_VALUE - 1));
4259*4882a593Smuzhiyun 
4260*4882a593Smuzhiyun 	/* Update request and response queue pointers. */
4261*4882a593Smuzhiyun 	ha->request_dma = ha->queues_dma + align;
4262*4882a593Smuzhiyun 	ha->request_ring = (struct queue_entry *) (ha->queues + align);
4263*4882a593Smuzhiyun 	ha->response_dma = ha->queues_dma + align +
4264*4882a593Smuzhiyun 		(REQUEST_QUEUE_DEPTH * QUEUE_SIZE);
4265*4882a593Smuzhiyun 	ha->response_ring = (struct queue_entry *) (ha->queues + align +
4266*4882a593Smuzhiyun 						    (REQUEST_QUEUE_DEPTH *
4267*4882a593Smuzhiyun 						     QUEUE_SIZE));
4268*4882a593Smuzhiyun 	ha->shadow_regs_dma = ha->queues_dma + align +
4269*4882a593Smuzhiyun 		(REQUEST_QUEUE_DEPTH * QUEUE_SIZE) +
4270*4882a593Smuzhiyun 		(RESPONSE_QUEUE_DEPTH * QUEUE_SIZE);
4271*4882a593Smuzhiyun 	ha->shadow_regs = (struct shadow_regs *) (ha->queues + align +
4272*4882a593Smuzhiyun 						  (REQUEST_QUEUE_DEPTH *
4273*4882a593Smuzhiyun 						   QUEUE_SIZE) +
4274*4882a593Smuzhiyun 						  (RESPONSE_QUEUE_DEPTH *
4275*4882a593Smuzhiyun 						   QUEUE_SIZE));
4276*4882a593Smuzhiyun 
4277*4882a593Smuzhiyun 	/* Allocate memory for srb pool. */
4278*4882a593Smuzhiyun 	ha->srb_mempool = mempool_create(SRB_MIN_REQ, mempool_alloc_slab,
4279*4882a593Smuzhiyun 					 mempool_free_slab, srb_cachep);
4280*4882a593Smuzhiyun 	if (ha->srb_mempool == NULL) {
4281*4882a593Smuzhiyun 		ql4_printk(KERN_WARNING, ha,
4282*4882a593Smuzhiyun 		    "Memory Allocation failed - SRB Pool.\n");
4283*4882a593Smuzhiyun 
4284*4882a593Smuzhiyun 		goto mem_alloc_error_exit;
4285*4882a593Smuzhiyun 	}
4286*4882a593Smuzhiyun 
4287*4882a593Smuzhiyun 	ha->chap_dma_pool = dma_pool_create("ql4_chap", &ha->pdev->dev,
4288*4882a593Smuzhiyun 					    CHAP_DMA_BLOCK_SIZE, 8, 0);
4289*4882a593Smuzhiyun 
4290*4882a593Smuzhiyun 	if (ha->chap_dma_pool == NULL) {
4291*4882a593Smuzhiyun 		ql4_printk(KERN_WARNING, ha,
4292*4882a593Smuzhiyun 		    "%s: chap_dma_pool allocation failed..\n", __func__);
4293*4882a593Smuzhiyun 		goto mem_alloc_error_exit;
4294*4882a593Smuzhiyun 	}
4295*4882a593Smuzhiyun 
4296*4882a593Smuzhiyun 	ha->fw_ddb_dma_pool = dma_pool_create("ql4_fw_ddb", &ha->pdev->dev,
4297*4882a593Smuzhiyun 					      DDB_DMA_BLOCK_SIZE, 8, 0);
4298*4882a593Smuzhiyun 
4299*4882a593Smuzhiyun 	if (ha->fw_ddb_dma_pool == NULL) {
4300*4882a593Smuzhiyun 		ql4_printk(KERN_WARNING, ha,
4301*4882a593Smuzhiyun 			   "%s: fw_ddb_dma_pool allocation failed..\n",
4302*4882a593Smuzhiyun 			   __func__);
4303*4882a593Smuzhiyun 		goto mem_alloc_error_exit;
4304*4882a593Smuzhiyun 	}
4305*4882a593Smuzhiyun 
4306*4882a593Smuzhiyun 	return QLA_SUCCESS;
4307*4882a593Smuzhiyun 
4308*4882a593Smuzhiyun mem_alloc_error_exit:
4309*4882a593Smuzhiyun 	return QLA_ERROR;
4310*4882a593Smuzhiyun }
4311*4882a593Smuzhiyun 
4312*4882a593Smuzhiyun /**
4313*4882a593Smuzhiyun  * qla4_8xxx_check_temp - Check the ISP82XX temperature.
4314*4882a593Smuzhiyun  * @ha: adapter block pointer.
4315*4882a593Smuzhiyun  *
4316*4882a593Smuzhiyun  * Note: The caller should not hold the idc lock.
4317*4882a593Smuzhiyun  **/
qla4_8xxx_check_temp(struct scsi_qla_host * ha)4318*4882a593Smuzhiyun static int qla4_8xxx_check_temp(struct scsi_qla_host *ha)
4319*4882a593Smuzhiyun {
4320*4882a593Smuzhiyun 	uint32_t temp, temp_state, temp_val;
4321*4882a593Smuzhiyun 	int status = QLA_SUCCESS;
4322*4882a593Smuzhiyun 
4323*4882a593Smuzhiyun 	temp = qla4_8xxx_rd_direct(ha, QLA8XXX_CRB_TEMP_STATE);
4324*4882a593Smuzhiyun 
4325*4882a593Smuzhiyun 	temp_state = qla82xx_get_temp_state(temp);
4326*4882a593Smuzhiyun 	temp_val = qla82xx_get_temp_val(temp);
4327*4882a593Smuzhiyun 
4328*4882a593Smuzhiyun 	if (temp_state == QLA82XX_TEMP_PANIC) {
4329*4882a593Smuzhiyun 		ql4_printk(KERN_WARNING, ha, "Device temperature %d degrees C"
4330*4882a593Smuzhiyun 			   " exceeds maximum allowed. Hardware has been shut"
4331*4882a593Smuzhiyun 			   " down.\n", temp_val);
4332*4882a593Smuzhiyun 		status = QLA_ERROR;
4333*4882a593Smuzhiyun 	} else if (temp_state == QLA82XX_TEMP_WARN) {
4334*4882a593Smuzhiyun 		if (ha->temperature == QLA82XX_TEMP_NORMAL)
4335*4882a593Smuzhiyun 			ql4_printk(KERN_WARNING, ha, "Device temperature %d"
4336*4882a593Smuzhiyun 				   " degrees C exceeds operating range."
4337*4882a593Smuzhiyun 				   " Immediate action needed.\n", temp_val);
4338*4882a593Smuzhiyun 	} else {
4339*4882a593Smuzhiyun 		if (ha->temperature == QLA82XX_TEMP_WARN)
4340*4882a593Smuzhiyun 			ql4_printk(KERN_INFO, ha, "Device temperature is"
4341*4882a593Smuzhiyun 				   " now %d degrees C in normal range.\n",
4342*4882a593Smuzhiyun 				   temp_val);
4343*4882a593Smuzhiyun 	}
4344*4882a593Smuzhiyun 	ha->temperature = temp_state;
4345*4882a593Smuzhiyun 	return status;
4346*4882a593Smuzhiyun }
4347*4882a593Smuzhiyun 
4348*4882a593Smuzhiyun /**
4349*4882a593Smuzhiyun  * qla4_8xxx_check_fw_alive  - Check firmware health
4350*4882a593Smuzhiyun  * @ha: Pointer to host adapter structure.
4351*4882a593Smuzhiyun  *
4352*4882a593Smuzhiyun  * Context: Interrupt
4353*4882a593Smuzhiyun  **/
qla4_8xxx_check_fw_alive(struct scsi_qla_host * ha)4354*4882a593Smuzhiyun static int qla4_8xxx_check_fw_alive(struct scsi_qla_host *ha)
4355*4882a593Smuzhiyun {
4356*4882a593Smuzhiyun 	uint32_t fw_heartbeat_counter;
4357*4882a593Smuzhiyun 	int status = QLA_SUCCESS;
4358*4882a593Smuzhiyun 
4359*4882a593Smuzhiyun 	fw_heartbeat_counter = qla4_8xxx_rd_direct(ha,
4360*4882a593Smuzhiyun 						   QLA8XXX_PEG_ALIVE_COUNTER);
4361*4882a593Smuzhiyun 	/* If PEG_ALIVE_COUNTER is 0xffffffff, AER/EEH is in progress, ignore */
4362*4882a593Smuzhiyun 	if (fw_heartbeat_counter == 0xffffffff) {
4363*4882a593Smuzhiyun 		DEBUG2(printk(KERN_WARNING "scsi%ld: %s: Device in frozen "
4364*4882a593Smuzhiyun 		    "state, QLA82XX_PEG_ALIVE_COUNTER is 0xffffffff\n",
4365*4882a593Smuzhiyun 		    ha->host_no, __func__));
4366*4882a593Smuzhiyun 		return status;
4367*4882a593Smuzhiyun 	}
4368*4882a593Smuzhiyun 
4369*4882a593Smuzhiyun 	if (ha->fw_heartbeat_counter == fw_heartbeat_counter) {
4370*4882a593Smuzhiyun 		ha->seconds_since_last_heartbeat++;
4371*4882a593Smuzhiyun 		/* FW not alive after 2 seconds */
4372*4882a593Smuzhiyun 		if (ha->seconds_since_last_heartbeat == 2) {
4373*4882a593Smuzhiyun 			ha->seconds_since_last_heartbeat = 0;
4374*4882a593Smuzhiyun 			qla4_8xxx_dump_peg_reg(ha);
4375*4882a593Smuzhiyun 			status = QLA_ERROR;
4376*4882a593Smuzhiyun 		}
4377*4882a593Smuzhiyun 	} else
4378*4882a593Smuzhiyun 		ha->seconds_since_last_heartbeat = 0;
4379*4882a593Smuzhiyun 
4380*4882a593Smuzhiyun 	ha->fw_heartbeat_counter = fw_heartbeat_counter;
4381*4882a593Smuzhiyun 	return status;
4382*4882a593Smuzhiyun }
4383*4882a593Smuzhiyun 
qla4_8xxx_process_fw_error(struct scsi_qla_host * ha)4384*4882a593Smuzhiyun static void qla4_8xxx_process_fw_error(struct scsi_qla_host *ha)
4385*4882a593Smuzhiyun {
4386*4882a593Smuzhiyun 	uint32_t halt_status;
4387*4882a593Smuzhiyun 	int halt_status_unrecoverable = 0;
4388*4882a593Smuzhiyun 
4389*4882a593Smuzhiyun 	halt_status = qla4_8xxx_rd_direct(ha, QLA8XXX_PEG_HALT_STATUS1);
4390*4882a593Smuzhiyun 
4391*4882a593Smuzhiyun 	if (is_qla8022(ha)) {
4392*4882a593Smuzhiyun 		ql4_printk(KERN_INFO, ha, "%s: disabling pause transmit on port 0 & 1.\n",
4393*4882a593Smuzhiyun 			   __func__);
4394*4882a593Smuzhiyun 		qla4_82xx_wr_32(ha, QLA82XX_CRB_NIU + 0x98,
4395*4882a593Smuzhiyun 				CRB_NIU_XG_PAUSE_CTL_P0 |
4396*4882a593Smuzhiyun 				CRB_NIU_XG_PAUSE_CTL_P1);
4397*4882a593Smuzhiyun 
4398*4882a593Smuzhiyun 		if (QLA82XX_FWERROR_CODE(halt_status) == 0x67)
4399*4882a593Smuzhiyun 			ql4_printk(KERN_ERR, ha, "%s: Firmware aborted with error code 0x00006700. Device is being reset\n",
4400*4882a593Smuzhiyun 				   __func__);
4401*4882a593Smuzhiyun 		if (halt_status & HALT_STATUS_UNRECOVERABLE)
4402*4882a593Smuzhiyun 			halt_status_unrecoverable = 1;
4403*4882a593Smuzhiyun 	} else if (is_qla8032(ha) || is_qla8042(ha)) {
4404*4882a593Smuzhiyun 		if (halt_status & QLA83XX_HALT_STATUS_FW_RESET)
4405*4882a593Smuzhiyun 			ql4_printk(KERN_ERR, ha, "%s: Firmware error detected device is being reset\n",
4406*4882a593Smuzhiyun 				   __func__);
4407*4882a593Smuzhiyun 		else if (halt_status & QLA83XX_HALT_STATUS_UNRECOVERABLE)
4408*4882a593Smuzhiyun 			halt_status_unrecoverable = 1;
4409*4882a593Smuzhiyun 	}
4410*4882a593Smuzhiyun 
4411*4882a593Smuzhiyun 	/*
4412*4882a593Smuzhiyun 	 * Since we cannot change dev_state in interrupt context,
4413*4882a593Smuzhiyun 	 * set appropriate DPC flag then wakeup DPC
4414*4882a593Smuzhiyun 	 */
4415*4882a593Smuzhiyun 	if (halt_status_unrecoverable) {
4416*4882a593Smuzhiyun 		set_bit(DPC_HA_UNRECOVERABLE, &ha->dpc_flags);
4417*4882a593Smuzhiyun 	} else {
4418*4882a593Smuzhiyun 		ql4_printk(KERN_INFO, ha, "%s: detect abort needed!\n",
4419*4882a593Smuzhiyun 			   __func__);
4420*4882a593Smuzhiyun 		set_bit(DPC_RESET_HA, &ha->dpc_flags);
4421*4882a593Smuzhiyun 	}
4422*4882a593Smuzhiyun 	qla4xxx_mailbox_premature_completion(ha);
4423*4882a593Smuzhiyun 	qla4xxx_wake_dpc(ha);
4424*4882a593Smuzhiyun }
4425*4882a593Smuzhiyun 
4426*4882a593Smuzhiyun /**
4427*4882a593Smuzhiyun  * qla4_8xxx_watchdog - Poll dev state
4428*4882a593Smuzhiyun  * @ha: Pointer to host adapter structure.
4429*4882a593Smuzhiyun  *
4430*4882a593Smuzhiyun  * Context: Interrupt
4431*4882a593Smuzhiyun  **/
qla4_8xxx_watchdog(struct scsi_qla_host * ha)4432*4882a593Smuzhiyun void qla4_8xxx_watchdog(struct scsi_qla_host *ha)
4433*4882a593Smuzhiyun {
4434*4882a593Smuzhiyun 	uint32_t dev_state;
4435*4882a593Smuzhiyun 	uint32_t idc_ctrl;
4436*4882a593Smuzhiyun 
4437*4882a593Smuzhiyun 	if (is_qla8032(ha) &&
4438*4882a593Smuzhiyun 	    (qla4_83xx_is_detached(ha) == QLA_SUCCESS))
4439*4882a593Smuzhiyun 		WARN_ONCE(1, "%s: iSCSI function %d marked invisible\n",
4440*4882a593Smuzhiyun 			  __func__, ha->func_num);
4441*4882a593Smuzhiyun 
4442*4882a593Smuzhiyun 	/* don't poll if reset is going on */
4443*4882a593Smuzhiyun 	if (!(test_bit(DPC_RESET_ACTIVE, &ha->dpc_flags) ||
4444*4882a593Smuzhiyun 	    test_bit(DPC_RESET_HA, &ha->dpc_flags) ||
4445*4882a593Smuzhiyun 	    test_bit(DPC_RETRY_RESET_HA, &ha->dpc_flags))) {
4446*4882a593Smuzhiyun 		dev_state = qla4_8xxx_rd_direct(ha, QLA8XXX_CRB_DEV_STATE);
4447*4882a593Smuzhiyun 
4448*4882a593Smuzhiyun 		if (qla4_8xxx_check_temp(ha)) {
4449*4882a593Smuzhiyun 			if (is_qla8022(ha)) {
4450*4882a593Smuzhiyun 				ql4_printk(KERN_INFO, ha, "disabling pause transmit on port 0 & 1.\n");
4451*4882a593Smuzhiyun 				qla4_82xx_wr_32(ha, QLA82XX_CRB_NIU + 0x98,
4452*4882a593Smuzhiyun 						CRB_NIU_XG_PAUSE_CTL_P0 |
4453*4882a593Smuzhiyun 						CRB_NIU_XG_PAUSE_CTL_P1);
4454*4882a593Smuzhiyun 			}
4455*4882a593Smuzhiyun 			set_bit(DPC_HA_UNRECOVERABLE, &ha->dpc_flags);
4456*4882a593Smuzhiyun 			qla4xxx_wake_dpc(ha);
4457*4882a593Smuzhiyun 		} else if (dev_state == QLA8XXX_DEV_NEED_RESET &&
4458*4882a593Smuzhiyun 			   !test_bit(DPC_RESET_HA, &ha->dpc_flags)) {
4459*4882a593Smuzhiyun 
4460*4882a593Smuzhiyun 			ql4_printk(KERN_INFO, ha, "%s: HW State: NEED RESET!\n",
4461*4882a593Smuzhiyun 				   __func__);
4462*4882a593Smuzhiyun 
4463*4882a593Smuzhiyun 			if (is_qla8032(ha) || is_qla8042(ha)) {
4464*4882a593Smuzhiyun 				idc_ctrl = qla4_83xx_rd_reg(ha,
4465*4882a593Smuzhiyun 							QLA83XX_IDC_DRV_CTRL);
4466*4882a593Smuzhiyun 				if (!(idc_ctrl & GRACEFUL_RESET_BIT1)) {
4467*4882a593Smuzhiyun 					ql4_printk(KERN_INFO, ha, "%s: Graceful reset bit is not set\n",
4468*4882a593Smuzhiyun 						   __func__);
4469*4882a593Smuzhiyun 					qla4xxx_mailbox_premature_completion(
4470*4882a593Smuzhiyun 									    ha);
4471*4882a593Smuzhiyun 				}
4472*4882a593Smuzhiyun 			}
4473*4882a593Smuzhiyun 
4474*4882a593Smuzhiyun 			if ((is_qla8032(ha) || is_qla8042(ha)) ||
4475*4882a593Smuzhiyun 			    (is_qla8022(ha) && !ql4xdontresethba)) {
4476*4882a593Smuzhiyun 				set_bit(DPC_RESET_HA, &ha->dpc_flags);
4477*4882a593Smuzhiyun 				qla4xxx_wake_dpc(ha);
4478*4882a593Smuzhiyun 			}
4479*4882a593Smuzhiyun 		} else if (dev_state == QLA8XXX_DEV_NEED_QUIESCENT &&
4480*4882a593Smuzhiyun 		    !test_bit(DPC_HA_NEED_QUIESCENT, &ha->dpc_flags)) {
4481*4882a593Smuzhiyun 			ql4_printk(KERN_INFO, ha, "%s: HW State: NEED QUIES!\n",
4482*4882a593Smuzhiyun 			    __func__);
4483*4882a593Smuzhiyun 			set_bit(DPC_HA_NEED_QUIESCENT, &ha->dpc_flags);
4484*4882a593Smuzhiyun 			qla4xxx_wake_dpc(ha);
4485*4882a593Smuzhiyun 		} else  {
4486*4882a593Smuzhiyun 			/* Check firmware health */
4487*4882a593Smuzhiyun 			if (qla4_8xxx_check_fw_alive(ha))
4488*4882a593Smuzhiyun 				qla4_8xxx_process_fw_error(ha);
4489*4882a593Smuzhiyun 		}
4490*4882a593Smuzhiyun 	}
4491*4882a593Smuzhiyun }
4492*4882a593Smuzhiyun 
qla4xxx_check_relogin_flash_ddb(struct iscsi_cls_session * cls_sess)4493*4882a593Smuzhiyun static void qla4xxx_check_relogin_flash_ddb(struct iscsi_cls_session *cls_sess)
4494*4882a593Smuzhiyun {
4495*4882a593Smuzhiyun 	struct iscsi_session *sess;
4496*4882a593Smuzhiyun 	struct ddb_entry *ddb_entry;
4497*4882a593Smuzhiyun 	struct scsi_qla_host *ha;
4498*4882a593Smuzhiyun 
4499*4882a593Smuzhiyun 	sess = cls_sess->dd_data;
4500*4882a593Smuzhiyun 	ddb_entry = sess->dd_data;
4501*4882a593Smuzhiyun 	ha = ddb_entry->ha;
4502*4882a593Smuzhiyun 
4503*4882a593Smuzhiyun 	if (!(ddb_entry->ddb_type == FLASH_DDB))
4504*4882a593Smuzhiyun 		return;
4505*4882a593Smuzhiyun 
4506*4882a593Smuzhiyun 	if (adapter_up(ha) && !test_bit(DF_RELOGIN, &ddb_entry->flags) &&
4507*4882a593Smuzhiyun 	    !iscsi_is_session_online(cls_sess)) {
4508*4882a593Smuzhiyun 		if (atomic_read(&ddb_entry->retry_relogin_timer) !=
4509*4882a593Smuzhiyun 		    INVALID_ENTRY) {
4510*4882a593Smuzhiyun 			if (atomic_read(&ddb_entry->retry_relogin_timer) ==
4511*4882a593Smuzhiyun 					0) {
4512*4882a593Smuzhiyun 				atomic_set(&ddb_entry->retry_relogin_timer,
4513*4882a593Smuzhiyun 					   INVALID_ENTRY);
4514*4882a593Smuzhiyun 				set_bit(DPC_RELOGIN_DEVICE, &ha->dpc_flags);
4515*4882a593Smuzhiyun 				set_bit(DF_RELOGIN, &ddb_entry->flags);
4516*4882a593Smuzhiyun 				DEBUG2(ql4_printk(KERN_INFO, ha,
4517*4882a593Smuzhiyun 				       "%s: index [%d] login device\n",
4518*4882a593Smuzhiyun 					__func__, ddb_entry->fw_ddb_index));
4519*4882a593Smuzhiyun 			} else
4520*4882a593Smuzhiyun 				atomic_dec(&ddb_entry->retry_relogin_timer);
4521*4882a593Smuzhiyun 		}
4522*4882a593Smuzhiyun 	}
4523*4882a593Smuzhiyun 
4524*4882a593Smuzhiyun 	/* Wait for relogin to timeout */
4525*4882a593Smuzhiyun 	if (atomic_read(&ddb_entry->relogin_timer) &&
4526*4882a593Smuzhiyun 	    (atomic_dec_and_test(&ddb_entry->relogin_timer) != 0)) {
4527*4882a593Smuzhiyun 		/*
4528*4882a593Smuzhiyun 		 * If the relogin times out and the device is
4529*4882a593Smuzhiyun 		 * still NOT ONLINE then try and relogin again.
4530*4882a593Smuzhiyun 		 */
4531*4882a593Smuzhiyun 		if (!iscsi_is_session_online(cls_sess)) {
4532*4882a593Smuzhiyun 			/* Reset retry relogin timer */
4533*4882a593Smuzhiyun 			atomic_inc(&ddb_entry->relogin_retry_count);
4534*4882a593Smuzhiyun 			DEBUG2(ql4_printk(KERN_INFO, ha,
4535*4882a593Smuzhiyun 				"%s: index[%d] relogin timed out-retrying"
4536*4882a593Smuzhiyun 				" relogin (%d), retry (%d)\n", __func__,
4537*4882a593Smuzhiyun 				ddb_entry->fw_ddb_index,
4538*4882a593Smuzhiyun 				atomic_read(&ddb_entry->relogin_retry_count),
4539*4882a593Smuzhiyun 				ddb_entry->default_time2wait + 4));
4540*4882a593Smuzhiyun 			set_bit(DPC_RELOGIN_DEVICE, &ha->dpc_flags);
4541*4882a593Smuzhiyun 			atomic_set(&ddb_entry->retry_relogin_timer,
4542*4882a593Smuzhiyun 				   ddb_entry->default_time2wait + 4);
4543*4882a593Smuzhiyun 		}
4544*4882a593Smuzhiyun 	}
4545*4882a593Smuzhiyun }
4546*4882a593Smuzhiyun 
4547*4882a593Smuzhiyun /**
4548*4882a593Smuzhiyun  * qla4xxx_timer - checks every second for work to do.
4549*4882a593Smuzhiyun  * @t: Context to obtain pointer to host adapter structure.
4550*4882a593Smuzhiyun  **/
qla4xxx_timer(struct timer_list * t)4551*4882a593Smuzhiyun static void qla4xxx_timer(struct timer_list *t)
4552*4882a593Smuzhiyun {
4553*4882a593Smuzhiyun 	struct scsi_qla_host *ha = from_timer(ha, t, timer);
4554*4882a593Smuzhiyun 	int start_dpc = 0;
4555*4882a593Smuzhiyun 	uint16_t w;
4556*4882a593Smuzhiyun 
4557*4882a593Smuzhiyun 	iscsi_host_for_each_session(ha->host, qla4xxx_check_relogin_flash_ddb);
4558*4882a593Smuzhiyun 
4559*4882a593Smuzhiyun 	/* If we are in the middle of AER/EEH processing
4560*4882a593Smuzhiyun 	 * skip any processing and reschedule the timer
4561*4882a593Smuzhiyun 	 */
4562*4882a593Smuzhiyun 	if (test_bit(AF_EEH_BUSY, &ha->flags)) {
4563*4882a593Smuzhiyun 		mod_timer(&ha->timer, jiffies + HZ);
4564*4882a593Smuzhiyun 		return;
4565*4882a593Smuzhiyun 	}
4566*4882a593Smuzhiyun 
4567*4882a593Smuzhiyun 	/* Hardware read to trigger an EEH error during mailbox waits. */
4568*4882a593Smuzhiyun 	if (!pci_channel_offline(ha->pdev))
4569*4882a593Smuzhiyun 		pci_read_config_word(ha->pdev, PCI_VENDOR_ID, &w);
4570*4882a593Smuzhiyun 
4571*4882a593Smuzhiyun 	if (is_qla80XX(ha))
4572*4882a593Smuzhiyun 		qla4_8xxx_watchdog(ha);
4573*4882a593Smuzhiyun 
4574*4882a593Smuzhiyun 	if (is_qla40XX(ha)) {
4575*4882a593Smuzhiyun 		/* Check for heartbeat interval. */
4576*4882a593Smuzhiyun 		if (ha->firmware_options & FWOPT_HEARTBEAT_ENABLE &&
4577*4882a593Smuzhiyun 		    ha->heartbeat_interval != 0) {
4578*4882a593Smuzhiyun 			ha->seconds_since_last_heartbeat++;
4579*4882a593Smuzhiyun 			if (ha->seconds_since_last_heartbeat >
4580*4882a593Smuzhiyun 			    ha->heartbeat_interval + 2)
4581*4882a593Smuzhiyun 				set_bit(DPC_RESET_HA, &ha->dpc_flags);
4582*4882a593Smuzhiyun 		}
4583*4882a593Smuzhiyun 	}
4584*4882a593Smuzhiyun 
4585*4882a593Smuzhiyun 	/* Process any deferred work. */
4586*4882a593Smuzhiyun 	if (!list_empty(&ha->work_list))
4587*4882a593Smuzhiyun 		start_dpc++;
4588*4882a593Smuzhiyun 
4589*4882a593Smuzhiyun 	/* Wakeup the dpc routine for this adapter, if needed. */
4590*4882a593Smuzhiyun 	if (start_dpc ||
4591*4882a593Smuzhiyun 	     test_bit(DPC_RESET_HA, &ha->dpc_flags) ||
4592*4882a593Smuzhiyun 	     test_bit(DPC_RETRY_RESET_HA, &ha->dpc_flags) ||
4593*4882a593Smuzhiyun 	     test_bit(DPC_RELOGIN_DEVICE, &ha->dpc_flags) ||
4594*4882a593Smuzhiyun 	     test_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags) ||
4595*4882a593Smuzhiyun 	     test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags) ||
4596*4882a593Smuzhiyun 	     test_bit(DPC_GET_DHCP_IP_ADDR, &ha->dpc_flags) ||
4597*4882a593Smuzhiyun 	     test_bit(DPC_LINK_CHANGED, &ha->dpc_flags) ||
4598*4882a593Smuzhiyun 	     test_bit(DPC_HA_UNRECOVERABLE, &ha->dpc_flags) ||
4599*4882a593Smuzhiyun 	     test_bit(DPC_HA_NEED_QUIESCENT, &ha->dpc_flags) ||
4600*4882a593Smuzhiyun 	     test_bit(DPC_SYSFS_DDB_EXPORT, &ha->dpc_flags) ||
4601*4882a593Smuzhiyun 	     test_bit(DPC_AEN, &ha->dpc_flags)) {
4602*4882a593Smuzhiyun 		DEBUG2(printk("scsi%ld: %s: scheduling dpc routine"
4603*4882a593Smuzhiyun 			      " - dpc flags = 0x%lx\n",
4604*4882a593Smuzhiyun 			      ha->host_no, __func__, ha->dpc_flags));
4605*4882a593Smuzhiyun 		qla4xxx_wake_dpc(ha);
4606*4882a593Smuzhiyun 	}
4607*4882a593Smuzhiyun 
4608*4882a593Smuzhiyun 	/* Reschedule timer thread to call us back in one second */
4609*4882a593Smuzhiyun 	mod_timer(&ha->timer, jiffies + HZ);
4610*4882a593Smuzhiyun 
4611*4882a593Smuzhiyun 	DEBUG2(ha->seconds_since_last_intr++);
4612*4882a593Smuzhiyun }
4613*4882a593Smuzhiyun 
4614*4882a593Smuzhiyun /**
4615*4882a593Smuzhiyun  * qla4xxx_cmd_wait - waits for all outstanding commands to complete
4616*4882a593Smuzhiyun  * @ha: Pointer to host adapter structure.
4617*4882a593Smuzhiyun  *
4618*4882a593Smuzhiyun  * This routine stalls the driver until all outstanding commands are returned.
4619*4882a593Smuzhiyun  * Caller must release the Hardware Lock prior to calling this routine.
4620*4882a593Smuzhiyun  **/
qla4xxx_cmd_wait(struct scsi_qla_host * ha)4621*4882a593Smuzhiyun static int qla4xxx_cmd_wait(struct scsi_qla_host *ha)
4622*4882a593Smuzhiyun {
4623*4882a593Smuzhiyun 	uint32_t index = 0;
4624*4882a593Smuzhiyun 	unsigned long flags;
4625*4882a593Smuzhiyun 	struct scsi_cmnd *cmd;
4626*4882a593Smuzhiyun 	unsigned long wtime;
4627*4882a593Smuzhiyun 	uint32_t wtmo;
4628*4882a593Smuzhiyun 
4629*4882a593Smuzhiyun 	if (is_qla40XX(ha))
4630*4882a593Smuzhiyun 		wtmo = WAIT_CMD_TOV;
4631*4882a593Smuzhiyun 	else
4632*4882a593Smuzhiyun 		wtmo = ha->nx_reset_timeout / 2;
4633*4882a593Smuzhiyun 
4634*4882a593Smuzhiyun 	wtime = jiffies + (wtmo * HZ);
4635*4882a593Smuzhiyun 
4636*4882a593Smuzhiyun 	DEBUG2(ql4_printk(KERN_INFO, ha,
4637*4882a593Smuzhiyun 			  "Wait up to %u seconds for cmds to complete\n",
4638*4882a593Smuzhiyun 			  wtmo));
4639*4882a593Smuzhiyun 
4640*4882a593Smuzhiyun 	while (!time_after_eq(jiffies, wtime)) {
4641*4882a593Smuzhiyun 		spin_lock_irqsave(&ha->hardware_lock, flags);
4642*4882a593Smuzhiyun 		/* Find a command that hasn't completed. */
4643*4882a593Smuzhiyun 		for (index = 0; index < ha->host->can_queue; index++) {
4644*4882a593Smuzhiyun 			cmd = scsi_host_find_tag(ha->host, index);
4645*4882a593Smuzhiyun 			/*
4646*4882a593Smuzhiyun 			 * We cannot just check if the index is valid,
4647*4882a593Smuzhiyun 			 * becase if we are run from the scsi eh, then
4648*4882a593Smuzhiyun 			 * the scsi/block layer is going to prevent
4649*4882a593Smuzhiyun 			 * the tag from being released.
4650*4882a593Smuzhiyun 			 */
4651*4882a593Smuzhiyun 			if (cmd != NULL && CMD_SP(cmd))
4652*4882a593Smuzhiyun 				break;
4653*4882a593Smuzhiyun 		}
4654*4882a593Smuzhiyun 		spin_unlock_irqrestore(&ha->hardware_lock, flags);
4655*4882a593Smuzhiyun 
4656*4882a593Smuzhiyun 		/* If No Commands are pending, wait is complete */
4657*4882a593Smuzhiyun 		if (index == ha->host->can_queue)
4658*4882a593Smuzhiyun 			return QLA_SUCCESS;
4659*4882a593Smuzhiyun 
4660*4882a593Smuzhiyun 		msleep(1000);
4661*4882a593Smuzhiyun 	}
4662*4882a593Smuzhiyun 	/* If we timed out on waiting for commands to come back
4663*4882a593Smuzhiyun 	 * return ERROR. */
4664*4882a593Smuzhiyun 	return QLA_ERROR;
4665*4882a593Smuzhiyun }
4666*4882a593Smuzhiyun 
qla4xxx_hw_reset(struct scsi_qla_host * ha)4667*4882a593Smuzhiyun int qla4xxx_hw_reset(struct scsi_qla_host *ha)
4668*4882a593Smuzhiyun {
4669*4882a593Smuzhiyun 	uint32_t ctrl_status;
4670*4882a593Smuzhiyun 	unsigned long flags = 0;
4671*4882a593Smuzhiyun 
4672*4882a593Smuzhiyun 	DEBUG2(printk(KERN_ERR "scsi%ld: %s\n", ha->host_no, __func__));
4673*4882a593Smuzhiyun 
4674*4882a593Smuzhiyun 	if (ql4xxx_lock_drvr_wait(ha) != QLA_SUCCESS)
4675*4882a593Smuzhiyun 		return QLA_ERROR;
4676*4882a593Smuzhiyun 
4677*4882a593Smuzhiyun 	spin_lock_irqsave(&ha->hardware_lock, flags);
4678*4882a593Smuzhiyun 
4679*4882a593Smuzhiyun 	/*
4680*4882a593Smuzhiyun 	 * If the SCSI Reset Interrupt bit is set, clear it.
4681*4882a593Smuzhiyun 	 * Otherwise, the Soft Reset won't work.
4682*4882a593Smuzhiyun 	 */
4683*4882a593Smuzhiyun 	ctrl_status = readw(&ha->reg->ctrl_status);
4684*4882a593Smuzhiyun 	if ((ctrl_status & CSR_SCSI_RESET_INTR) != 0)
4685*4882a593Smuzhiyun 		writel(set_rmask(CSR_SCSI_RESET_INTR), &ha->reg->ctrl_status);
4686*4882a593Smuzhiyun 
4687*4882a593Smuzhiyun 	/* Issue Soft Reset */
4688*4882a593Smuzhiyun 	writel(set_rmask(CSR_SOFT_RESET), &ha->reg->ctrl_status);
4689*4882a593Smuzhiyun 	readl(&ha->reg->ctrl_status);
4690*4882a593Smuzhiyun 
4691*4882a593Smuzhiyun 	spin_unlock_irqrestore(&ha->hardware_lock, flags);
4692*4882a593Smuzhiyun 	return QLA_SUCCESS;
4693*4882a593Smuzhiyun }
4694*4882a593Smuzhiyun 
4695*4882a593Smuzhiyun /**
4696*4882a593Smuzhiyun  * qla4xxx_soft_reset - performs soft reset.
4697*4882a593Smuzhiyun  * @ha: Pointer to host adapter structure.
4698*4882a593Smuzhiyun  **/
qla4xxx_soft_reset(struct scsi_qla_host * ha)4699*4882a593Smuzhiyun int qla4xxx_soft_reset(struct scsi_qla_host *ha)
4700*4882a593Smuzhiyun {
4701*4882a593Smuzhiyun 	uint32_t max_wait_time;
4702*4882a593Smuzhiyun 	unsigned long flags = 0;
4703*4882a593Smuzhiyun 	int status;
4704*4882a593Smuzhiyun 	uint32_t ctrl_status;
4705*4882a593Smuzhiyun 
4706*4882a593Smuzhiyun 	status = qla4xxx_hw_reset(ha);
4707*4882a593Smuzhiyun 	if (status != QLA_SUCCESS)
4708*4882a593Smuzhiyun 		return status;
4709*4882a593Smuzhiyun 
4710*4882a593Smuzhiyun 	status = QLA_ERROR;
4711*4882a593Smuzhiyun 	/* Wait until the Network Reset Intr bit is cleared */
4712*4882a593Smuzhiyun 	max_wait_time = RESET_INTR_TOV;
4713*4882a593Smuzhiyun 	do {
4714*4882a593Smuzhiyun 		spin_lock_irqsave(&ha->hardware_lock, flags);
4715*4882a593Smuzhiyun 		ctrl_status = readw(&ha->reg->ctrl_status);
4716*4882a593Smuzhiyun 		spin_unlock_irqrestore(&ha->hardware_lock, flags);
4717*4882a593Smuzhiyun 
4718*4882a593Smuzhiyun 		if ((ctrl_status & CSR_NET_RESET_INTR) == 0)
4719*4882a593Smuzhiyun 			break;
4720*4882a593Smuzhiyun 
4721*4882a593Smuzhiyun 		msleep(1000);
4722*4882a593Smuzhiyun 	} while ((--max_wait_time));
4723*4882a593Smuzhiyun 
4724*4882a593Smuzhiyun 	if ((ctrl_status & CSR_NET_RESET_INTR) != 0) {
4725*4882a593Smuzhiyun 		DEBUG2(printk(KERN_WARNING
4726*4882a593Smuzhiyun 			      "scsi%ld: Network Reset Intr not cleared by "
4727*4882a593Smuzhiyun 			      "Network function, clearing it now!\n",
4728*4882a593Smuzhiyun 			      ha->host_no));
4729*4882a593Smuzhiyun 		spin_lock_irqsave(&ha->hardware_lock, flags);
4730*4882a593Smuzhiyun 		writel(set_rmask(CSR_NET_RESET_INTR), &ha->reg->ctrl_status);
4731*4882a593Smuzhiyun 		readl(&ha->reg->ctrl_status);
4732*4882a593Smuzhiyun 		spin_unlock_irqrestore(&ha->hardware_lock, flags);
4733*4882a593Smuzhiyun 	}
4734*4882a593Smuzhiyun 
4735*4882a593Smuzhiyun 	/* Wait until the firmware tells us the Soft Reset is done */
4736*4882a593Smuzhiyun 	max_wait_time = SOFT_RESET_TOV;
4737*4882a593Smuzhiyun 	do {
4738*4882a593Smuzhiyun 		spin_lock_irqsave(&ha->hardware_lock, flags);
4739*4882a593Smuzhiyun 		ctrl_status = readw(&ha->reg->ctrl_status);
4740*4882a593Smuzhiyun 		spin_unlock_irqrestore(&ha->hardware_lock, flags);
4741*4882a593Smuzhiyun 
4742*4882a593Smuzhiyun 		if ((ctrl_status & CSR_SOFT_RESET) == 0) {
4743*4882a593Smuzhiyun 			status = QLA_SUCCESS;
4744*4882a593Smuzhiyun 			break;
4745*4882a593Smuzhiyun 		}
4746*4882a593Smuzhiyun 
4747*4882a593Smuzhiyun 		msleep(1000);
4748*4882a593Smuzhiyun 	} while ((--max_wait_time));
4749*4882a593Smuzhiyun 
4750*4882a593Smuzhiyun 	/*
4751*4882a593Smuzhiyun 	 * Also, make sure that the SCSI Reset Interrupt bit has been cleared
4752*4882a593Smuzhiyun 	 * after the soft reset has taken place.
4753*4882a593Smuzhiyun 	 */
4754*4882a593Smuzhiyun 	spin_lock_irqsave(&ha->hardware_lock, flags);
4755*4882a593Smuzhiyun 	ctrl_status = readw(&ha->reg->ctrl_status);
4756*4882a593Smuzhiyun 	if ((ctrl_status & CSR_SCSI_RESET_INTR) != 0) {
4757*4882a593Smuzhiyun 		writel(set_rmask(CSR_SCSI_RESET_INTR), &ha->reg->ctrl_status);
4758*4882a593Smuzhiyun 		readl(&ha->reg->ctrl_status);
4759*4882a593Smuzhiyun 	}
4760*4882a593Smuzhiyun 	spin_unlock_irqrestore(&ha->hardware_lock, flags);
4761*4882a593Smuzhiyun 
4762*4882a593Smuzhiyun 	/* If soft reset fails then most probably the bios on other
4763*4882a593Smuzhiyun 	 * function is also enabled.
4764*4882a593Smuzhiyun 	 * Since the initialization is sequential the other fn
4765*4882a593Smuzhiyun 	 * wont be able to acknowledge the soft reset.
4766*4882a593Smuzhiyun 	 * Issue a force soft reset to workaround this scenario.
4767*4882a593Smuzhiyun 	 */
4768*4882a593Smuzhiyun 	if (max_wait_time == 0) {
4769*4882a593Smuzhiyun 		/* Issue Force Soft Reset */
4770*4882a593Smuzhiyun 		spin_lock_irqsave(&ha->hardware_lock, flags);
4771*4882a593Smuzhiyun 		writel(set_rmask(CSR_FORCE_SOFT_RESET), &ha->reg->ctrl_status);
4772*4882a593Smuzhiyun 		readl(&ha->reg->ctrl_status);
4773*4882a593Smuzhiyun 		spin_unlock_irqrestore(&ha->hardware_lock, flags);
4774*4882a593Smuzhiyun 		/* Wait until the firmware tells us the Soft Reset is done */
4775*4882a593Smuzhiyun 		max_wait_time = SOFT_RESET_TOV;
4776*4882a593Smuzhiyun 		do {
4777*4882a593Smuzhiyun 			spin_lock_irqsave(&ha->hardware_lock, flags);
4778*4882a593Smuzhiyun 			ctrl_status = readw(&ha->reg->ctrl_status);
4779*4882a593Smuzhiyun 			spin_unlock_irqrestore(&ha->hardware_lock, flags);
4780*4882a593Smuzhiyun 
4781*4882a593Smuzhiyun 			if ((ctrl_status & CSR_FORCE_SOFT_RESET) == 0) {
4782*4882a593Smuzhiyun 				status = QLA_SUCCESS;
4783*4882a593Smuzhiyun 				break;
4784*4882a593Smuzhiyun 			}
4785*4882a593Smuzhiyun 
4786*4882a593Smuzhiyun 			msleep(1000);
4787*4882a593Smuzhiyun 		} while ((--max_wait_time));
4788*4882a593Smuzhiyun 	}
4789*4882a593Smuzhiyun 
4790*4882a593Smuzhiyun 	return status;
4791*4882a593Smuzhiyun }
4792*4882a593Smuzhiyun 
4793*4882a593Smuzhiyun /**
4794*4882a593Smuzhiyun  * qla4xxx_abort_active_cmds - returns all outstanding i/o requests to O.S.
4795*4882a593Smuzhiyun  * @ha: Pointer to host adapter structure.
4796*4882a593Smuzhiyun  * @res: returned scsi status
4797*4882a593Smuzhiyun  *
4798*4882a593Smuzhiyun  * This routine is called just prior to a HARD RESET to return all
4799*4882a593Smuzhiyun  * outstanding commands back to the Operating System.
4800*4882a593Smuzhiyun  * Caller should make sure that the following locks are released
4801*4882a593Smuzhiyun  * before this calling routine: Hardware lock, and io_request_lock.
4802*4882a593Smuzhiyun  **/
qla4xxx_abort_active_cmds(struct scsi_qla_host * ha,int res)4803*4882a593Smuzhiyun static void qla4xxx_abort_active_cmds(struct scsi_qla_host *ha, int res)
4804*4882a593Smuzhiyun {
4805*4882a593Smuzhiyun 	struct srb *srb;
4806*4882a593Smuzhiyun 	int i;
4807*4882a593Smuzhiyun 	unsigned long flags;
4808*4882a593Smuzhiyun 
4809*4882a593Smuzhiyun 	spin_lock_irqsave(&ha->hardware_lock, flags);
4810*4882a593Smuzhiyun 	for (i = 0; i < ha->host->can_queue; i++) {
4811*4882a593Smuzhiyun 		srb = qla4xxx_del_from_active_array(ha, i);
4812*4882a593Smuzhiyun 		if (srb != NULL) {
4813*4882a593Smuzhiyun 			srb->cmd->result = res;
4814*4882a593Smuzhiyun 			kref_put(&srb->srb_ref, qla4xxx_srb_compl);
4815*4882a593Smuzhiyun 		}
4816*4882a593Smuzhiyun 	}
4817*4882a593Smuzhiyun 	spin_unlock_irqrestore(&ha->hardware_lock, flags);
4818*4882a593Smuzhiyun }
4819*4882a593Smuzhiyun 
qla4xxx_dead_adapter_cleanup(struct scsi_qla_host * ha)4820*4882a593Smuzhiyun void qla4xxx_dead_adapter_cleanup(struct scsi_qla_host *ha)
4821*4882a593Smuzhiyun {
4822*4882a593Smuzhiyun 	clear_bit(AF_ONLINE, &ha->flags);
4823*4882a593Smuzhiyun 
4824*4882a593Smuzhiyun 	/* Disable the board */
4825*4882a593Smuzhiyun 	ql4_printk(KERN_INFO, ha, "Disabling the board\n");
4826*4882a593Smuzhiyun 
4827*4882a593Smuzhiyun 	qla4xxx_abort_active_cmds(ha, DID_NO_CONNECT << 16);
4828*4882a593Smuzhiyun 	qla4xxx_mark_all_devices_missing(ha);
4829*4882a593Smuzhiyun 	clear_bit(AF_INIT_DONE, &ha->flags);
4830*4882a593Smuzhiyun }
4831*4882a593Smuzhiyun 
qla4xxx_fail_session(struct iscsi_cls_session * cls_session)4832*4882a593Smuzhiyun static void qla4xxx_fail_session(struct iscsi_cls_session *cls_session)
4833*4882a593Smuzhiyun {
4834*4882a593Smuzhiyun 	struct iscsi_session *sess;
4835*4882a593Smuzhiyun 	struct ddb_entry *ddb_entry;
4836*4882a593Smuzhiyun 
4837*4882a593Smuzhiyun 	sess = cls_session->dd_data;
4838*4882a593Smuzhiyun 	ddb_entry = sess->dd_data;
4839*4882a593Smuzhiyun 	ddb_entry->fw_ddb_device_state = DDB_DS_SESSION_FAILED;
4840*4882a593Smuzhiyun 
4841*4882a593Smuzhiyun 	if (ddb_entry->ddb_type == FLASH_DDB)
4842*4882a593Smuzhiyun 		iscsi_block_session(ddb_entry->sess);
4843*4882a593Smuzhiyun 	else
4844*4882a593Smuzhiyun 		iscsi_session_failure(cls_session->dd_data,
4845*4882a593Smuzhiyun 				      ISCSI_ERR_CONN_FAILED);
4846*4882a593Smuzhiyun }
4847*4882a593Smuzhiyun 
4848*4882a593Smuzhiyun /**
4849*4882a593Smuzhiyun  * qla4xxx_recover_adapter - recovers adapter after a fatal error
4850*4882a593Smuzhiyun  * @ha: Pointer to host adapter structure.
4851*4882a593Smuzhiyun  **/
qla4xxx_recover_adapter(struct scsi_qla_host * ha)4852*4882a593Smuzhiyun static int qla4xxx_recover_adapter(struct scsi_qla_host *ha)
4853*4882a593Smuzhiyun {
4854*4882a593Smuzhiyun 	int status = QLA_ERROR;
4855*4882a593Smuzhiyun 	uint8_t reset_chip = 0;
4856*4882a593Smuzhiyun 	uint32_t dev_state;
4857*4882a593Smuzhiyun 	unsigned long wait;
4858*4882a593Smuzhiyun 
4859*4882a593Smuzhiyun 	/* Stall incoming I/O until we are done */
4860*4882a593Smuzhiyun 	scsi_block_requests(ha->host);
4861*4882a593Smuzhiyun 	clear_bit(AF_ONLINE, &ha->flags);
4862*4882a593Smuzhiyun 	clear_bit(AF_LINK_UP, &ha->flags);
4863*4882a593Smuzhiyun 
4864*4882a593Smuzhiyun 	DEBUG2(ql4_printk(KERN_INFO, ha, "%s: adapter OFFLINE\n", __func__));
4865*4882a593Smuzhiyun 
4866*4882a593Smuzhiyun 	set_bit(DPC_RESET_ACTIVE, &ha->dpc_flags);
4867*4882a593Smuzhiyun 
4868*4882a593Smuzhiyun 	if ((is_qla8032(ha) || is_qla8042(ha)) &&
4869*4882a593Smuzhiyun 	    !test_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags)) {
4870*4882a593Smuzhiyun 		ql4_printk(KERN_INFO, ha, "%s: disabling pause transmit on port 0 & 1.\n",
4871*4882a593Smuzhiyun 			   __func__);
4872*4882a593Smuzhiyun 		/* disable pause frame for ISP83xx */
4873*4882a593Smuzhiyun 		qla4_83xx_disable_pause(ha);
4874*4882a593Smuzhiyun 	}
4875*4882a593Smuzhiyun 
4876*4882a593Smuzhiyun 	iscsi_host_for_each_session(ha->host, qla4xxx_fail_session);
4877*4882a593Smuzhiyun 
4878*4882a593Smuzhiyun 	if (test_bit(DPC_RESET_HA, &ha->dpc_flags))
4879*4882a593Smuzhiyun 		reset_chip = 1;
4880*4882a593Smuzhiyun 
4881*4882a593Smuzhiyun 	/* For the DPC_RESET_HA_INTR case (ISP-4xxx specific)
4882*4882a593Smuzhiyun 	 * do not reset adapter, jump to initialize_adapter */
4883*4882a593Smuzhiyun 	if (test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags)) {
4884*4882a593Smuzhiyun 		status = QLA_SUCCESS;
4885*4882a593Smuzhiyun 		goto recover_ha_init_adapter;
4886*4882a593Smuzhiyun 	}
4887*4882a593Smuzhiyun 
4888*4882a593Smuzhiyun 	/* For the ISP-8xxx adapter, issue a stop_firmware if invoked
4889*4882a593Smuzhiyun 	 * from eh_host_reset or ioctl module */
4890*4882a593Smuzhiyun 	if (is_qla80XX(ha) && !reset_chip &&
4891*4882a593Smuzhiyun 	    test_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags)) {
4892*4882a593Smuzhiyun 
4893*4882a593Smuzhiyun 		DEBUG2(ql4_printk(KERN_INFO, ha,
4894*4882a593Smuzhiyun 		    "scsi%ld: %s - Performing stop_firmware...\n",
4895*4882a593Smuzhiyun 		    ha->host_no, __func__));
4896*4882a593Smuzhiyun 		status = ha->isp_ops->reset_firmware(ha);
4897*4882a593Smuzhiyun 		if (status == QLA_SUCCESS) {
4898*4882a593Smuzhiyun 			ha->isp_ops->disable_intrs(ha);
4899*4882a593Smuzhiyun 			qla4xxx_process_aen(ha, FLUSH_DDB_CHANGED_AENS);
4900*4882a593Smuzhiyun 			qla4xxx_abort_active_cmds(ha, DID_RESET << 16);
4901*4882a593Smuzhiyun 		} else {
4902*4882a593Smuzhiyun 			/* If the stop_firmware fails then
4903*4882a593Smuzhiyun 			 * reset the entire chip */
4904*4882a593Smuzhiyun 			reset_chip = 1;
4905*4882a593Smuzhiyun 			clear_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags);
4906*4882a593Smuzhiyun 			set_bit(DPC_RESET_HA, &ha->dpc_flags);
4907*4882a593Smuzhiyun 		}
4908*4882a593Smuzhiyun 	}
4909*4882a593Smuzhiyun 
4910*4882a593Smuzhiyun 	/* Issue full chip reset if recovering from a catastrophic error,
4911*4882a593Smuzhiyun 	 * or if stop_firmware fails for ISP-8xxx.
4912*4882a593Smuzhiyun 	 * This is the default case for ISP-4xxx */
4913*4882a593Smuzhiyun 	if (is_qla40XX(ha) || reset_chip) {
4914*4882a593Smuzhiyun 		if (is_qla40XX(ha))
4915*4882a593Smuzhiyun 			goto chip_reset;
4916*4882a593Smuzhiyun 
4917*4882a593Smuzhiyun 		/* Check if 8XXX firmware is alive or not
4918*4882a593Smuzhiyun 		 * We may have arrived here from NEED_RESET
4919*4882a593Smuzhiyun 		 * detection only */
4920*4882a593Smuzhiyun 		if (test_bit(AF_FW_RECOVERY, &ha->flags))
4921*4882a593Smuzhiyun 			goto chip_reset;
4922*4882a593Smuzhiyun 
4923*4882a593Smuzhiyun 		wait = jiffies + (FW_ALIVE_WAIT_TOV * HZ);
4924*4882a593Smuzhiyun 		while (time_before(jiffies, wait)) {
4925*4882a593Smuzhiyun 			if (qla4_8xxx_check_fw_alive(ha)) {
4926*4882a593Smuzhiyun 				qla4xxx_mailbox_premature_completion(ha);
4927*4882a593Smuzhiyun 				break;
4928*4882a593Smuzhiyun 			}
4929*4882a593Smuzhiyun 
4930*4882a593Smuzhiyun 			set_current_state(TASK_UNINTERRUPTIBLE);
4931*4882a593Smuzhiyun 			schedule_timeout(HZ);
4932*4882a593Smuzhiyun 		}
4933*4882a593Smuzhiyun chip_reset:
4934*4882a593Smuzhiyun 		if (!test_bit(AF_FW_RECOVERY, &ha->flags))
4935*4882a593Smuzhiyun 			qla4xxx_cmd_wait(ha);
4936*4882a593Smuzhiyun 
4937*4882a593Smuzhiyun 		qla4xxx_process_aen(ha, FLUSH_DDB_CHANGED_AENS);
4938*4882a593Smuzhiyun 		DEBUG2(ql4_printk(KERN_INFO, ha,
4939*4882a593Smuzhiyun 		    "scsi%ld: %s - Performing chip reset..\n",
4940*4882a593Smuzhiyun 		    ha->host_no, __func__));
4941*4882a593Smuzhiyun 		status = ha->isp_ops->reset_chip(ha);
4942*4882a593Smuzhiyun 		qla4xxx_abort_active_cmds(ha, DID_RESET << 16);
4943*4882a593Smuzhiyun 	}
4944*4882a593Smuzhiyun 
4945*4882a593Smuzhiyun 	/* Flush any pending ddb changed AENs */
4946*4882a593Smuzhiyun 	qla4xxx_process_aen(ha, FLUSH_DDB_CHANGED_AENS);
4947*4882a593Smuzhiyun 
4948*4882a593Smuzhiyun recover_ha_init_adapter:
4949*4882a593Smuzhiyun 	/* Upon successful firmware/chip reset, re-initialize the adapter */
4950*4882a593Smuzhiyun 	if (status == QLA_SUCCESS) {
4951*4882a593Smuzhiyun 		/* For ISP-4xxx, force function 1 to always initialize
4952*4882a593Smuzhiyun 		 * before function 3 to prevent both funcions from
4953*4882a593Smuzhiyun 		 * stepping on top of the other */
4954*4882a593Smuzhiyun 		if (is_qla40XX(ha) && (ha->mac_index == 3))
4955*4882a593Smuzhiyun 			ssleep(6);
4956*4882a593Smuzhiyun 
4957*4882a593Smuzhiyun 		/* NOTE: AF_ONLINE flag set upon successful completion of
4958*4882a593Smuzhiyun 		 * qla4xxx_initialize_adapter */
4959*4882a593Smuzhiyun 		status = qla4xxx_initialize_adapter(ha, RESET_ADAPTER);
4960*4882a593Smuzhiyun 		if (is_qla80XX(ha) && (status == QLA_ERROR)) {
4961*4882a593Smuzhiyun 			status = qla4_8xxx_check_init_adapter_retry(ha);
4962*4882a593Smuzhiyun 			if (status == QLA_ERROR) {
4963*4882a593Smuzhiyun 				ql4_printk(KERN_INFO, ha, "scsi%ld: %s: Don't retry recover adapter\n",
4964*4882a593Smuzhiyun 					   ha->host_no, __func__);
4965*4882a593Smuzhiyun 				qla4xxx_dead_adapter_cleanup(ha);
4966*4882a593Smuzhiyun 				clear_bit(DPC_RETRY_RESET_HA, &ha->dpc_flags);
4967*4882a593Smuzhiyun 				clear_bit(DPC_RESET_HA, &ha->dpc_flags);
4968*4882a593Smuzhiyun 				clear_bit(DPC_RESET_HA_FW_CONTEXT,
4969*4882a593Smuzhiyun 					  &ha->dpc_flags);
4970*4882a593Smuzhiyun 				goto exit_recover;
4971*4882a593Smuzhiyun 			}
4972*4882a593Smuzhiyun 		}
4973*4882a593Smuzhiyun 	}
4974*4882a593Smuzhiyun 
4975*4882a593Smuzhiyun 	/* Retry failed adapter initialization, if necessary
4976*4882a593Smuzhiyun 	 * Do not retry initialize_adapter for RESET_HA_INTR (ISP-4xxx specific)
4977*4882a593Smuzhiyun 	 * case to prevent ping-pong resets between functions */
4978*4882a593Smuzhiyun 	if (!test_bit(AF_ONLINE, &ha->flags) &&
4979*4882a593Smuzhiyun 	    !test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags)) {
4980*4882a593Smuzhiyun 		/* Adapter initialization failed, see if we can retry
4981*4882a593Smuzhiyun 		 * resetting the ha.
4982*4882a593Smuzhiyun 		 * Since we don't want to block the DPC for too long
4983*4882a593Smuzhiyun 		 * with multiple resets in the same thread,
4984*4882a593Smuzhiyun 		 * utilize DPC to retry */
4985*4882a593Smuzhiyun 		if (is_qla80XX(ha)) {
4986*4882a593Smuzhiyun 			ha->isp_ops->idc_lock(ha);
4987*4882a593Smuzhiyun 			dev_state = qla4_8xxx_rd_direct(ha,
4988*4882a593Smuzhiyun 							QLA8XXX_CRB_DEV_STATE);
4989*4882a593Smuzhiyun 			ha->isp_ops->idc_unlock(ha);
4990*4882a593Smuzhiyun 			if (dev_state == QLA8XXX_DEV_FAILED) {
4991*4882a593Smuzhiyun 				ql4_printk(KERN_INFO, ha, "%s: don't retry "
4992*4882a593Smuzhiyun 					   "recover adapter. H/W is in Failed "
4993*4882a593Smuzhiyun 					   "state\n", __func__);
4994*4882a593Smuzhiyun 				qla4xxx_dead_adapter_cleanup(ha);
4995*4882a593Smuzhiyun 				clear_bit(DPC_RETRY_RESET_HA, &ha->dpc_flags);
4996*4882a593Smuzhiyun 				clear_bit(DPC_RESET_HA, &ha->dpc_flags);
4997*4882a593Smuzhiyun 				clear_bit(DPC_RESET_HA_FW_CONTEXT,
4998*4882a593Smuzhiyun 						&ha->dpc_flags);
4999*4882a593Smuzhiyun 				status = QLA_ERROR;
5000*4882a593Smuzhiyun 
5001*4882a593Smuzhiyun 				goto exit_recover;
5002*4882a593Smuzhiyun 			}
5003*4882a593Smuzhiyun 		}
5004*4882a593Smuzhiyun 
5005*4882a593Smuzhiyun 		if (!test_bit(DPC_RETRY_RESET_HA, &ha->dpc_flags)) {
5006*4882a593Smuzhiyun 			ha->retry_reset_ha_cnt = MAX_RESET_HA_RETRIES;
5007*4882a593Smuzhiyun 			DEBUG2(printk("scsi%ld: recover adapter - retrying "
5008*4882a593Smuzhiyun 				      "(%d) more times\n", ha->host_no,
5009*4882a593Smuzhiyun 				      ha->retry_reset_ha_cnt));
5010*4882a593Smuzhiyun 			set_bit(DPC_RETRY_RESET_HA, &ha->dpc_flags);
5011*4882a593Smuzhiyun 			status = QLA_ERROR;
5012*4882a593Smuzhiyun 		} else {
5013*4882a593Smuzhiyun 			if (ha->retry_reset_ha_cnt > 0) {
5014*4882a593Smuzhiyun 				/* Schedule another Reset HA--DPC will retry */
5015*4882a593Smuzhiyun 				ha->retry_reset_ha_cnt--;
5016*4882a593Smuzhiyun 				DEBUG2(printk("scsi%ld: recover adapter - "
5017*4882a593Smuzhiyun 					      "retry remaining %d\n",
5018*4882a593Smuzhiyun 					      ha->host_no,
5019*4882a593Smuzhiyun 					      ha->retry_reset_ha_cnt));
5020*4882a593Smuzhiyun 				status = QLA_ERROR;
5021*4882a593Smuzhiyun 			}
5022*4882a593Smuzhiyun 
5023*4882a593Smuzhiyun 			if (ha->retry_reset_ha_cnt == 0) {
5024*4882a593Smuzhiyun 				/* Recover adapter retries have been exhausted.
5025*4882a593Smuzhiyun 				 * Adapter DEAD */
5026*4882a593Smuzhiyun 				DEBUG2(printk("scsi%ld: recover adapter "
5027*4882a593Smuzhiyun 					      "failed - board disabled\n",
5028*4882a593Smuzhiyun 					      ha->host_no));
5029*4882a593Smuzhiyun 				qla4xxx_dead_adapter_cleanup(ha);
5030*4882a593Smuzhiyun 				clear_bit(DPC_RETRY_RESET_HA, &ha->dpc_flags);
5031*4882a593Smuzhiyun 				clear_bit(DPC_RESET_HA, &ha->dpc_flags);
5032*4882a593Smuzhiyun 				clear_bit(DPC_RESET_HA_FW_CONTEXT,
5033*4882a593Smuzhiyun 					  &ha->dpc_flags);
5034*4882a593Smuzhiyun 				status = QLA_ERROR;
5035*4882a593Smuzhiyun 			}
5036*4882a593Smuzhiyun 		}
5037*4882a593Smuzhiyun 	} else {
5038*4882a593Smuzhiyun 		clear_bit(DPC_RESET_HA, &ha->dpc_flags);
5039*4882a593Smuzhiyun 		clear_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags);
5040*4882a593Smuzhiyun 		clear_bit(DPC_RETRY_RESET_HA, &ha->dpc_flags);
5041*4882a593Smuzhiyun 	}
5042*4882a593Smuzhiyun 
5043*4882a593Smuzhiyun exit_recover:
5044*4882a593Smuzhiyun 	ha->adapter_error_count++;
5045*4882a593Smuzhiyun 
5046*4882a593Smuzhiyun 	if (test_bit(AF_ONLINE, &ha->flags))
5047*4882a593Smuzhiyun 		ha->isp_ops->enable_intrs(ha);
5048*4882a593Smuzhiyun 
5049*4882a593Smuzhiyun 	scsi_unblock_requests(ha->host);
5050*4882a593Smuzhiyun 
5051*4882a593Smuzhiyun 	clear_bit(DPC_RESET_ACTIVE, &ha->dpc_flags);
5052*4882a593Smuzhiyun 	DEBUG2(printk("scsi%ld: recover adapter: %s\n", ha->host_no,
5053*4882a593Smuzhiyun 	    status == QLA_ERROR ? "FAILED" : "SUCCEEDED"));
5054*4882a593Smuzhiyun 
5055*4882a593Smuzhiyun 	return status;
5056*4882a593Smuzhiyun }
5057*4882a593Smuzhiyun 
qla4xxx_relogin_devices(struct iscsi_cls_session * cls_session)5058*4882a593Smuzhiyun static void qla4xxx_relogin_devices(struct iscsi_cls_session *cls_session)
5059*4882a593Smuzhiyun {
5060*4882a593Smuzhiyun 	struct iscsi_session *sess;
5061*4882a593Smuzhiyun 	struct ddb_entry *ddb_entry;
5062*4882a593Smuzhiyun 	struct scsi_qla_host *ha;
5063*4882a593Smuzhiyun 
5064*4882a593Smuzhiyun 	sess = cls_session->dd_data;
5065*4882a593Smuzhiyun 	ddb_entry = sess->dd_data;
5066*4882a593Smuzhiyun 	ha = ddb_entry->ha;
5067*4882a593Smuzhiyun 	if (!iscsi_is_session_online(cls_session)) {
5068*4882a593Smuzhiyun 		if (ddb_entry->fw_ddb_device_state == DDB_DS_SESSION_ACTIVE) {
5069*4882a593Smuzhiyun 			ql4_printk(KERN_INFO, ha, "scsi%ld: %s: ddb[%d]"
5070*4882a593Smuzhiyun 				   " unblock session\n", ha->host_no, __func__,
5071*4882a593Smuzhiyun 				   ddb_entry->fw_ddb_index);
5072*4882a593Smuzhiyun 			iscsi_unblock_session(ddb_entry->sess);
5073*4882a593Smuzhiyun 		} else {
5074*4882a593Smuzhiyun 			/* Trigger relogin */
5075*4882a593Smuzhiyun 			if (ddb_entry->ddb_type == FLASH_DDB) {
5076*4882a593Smuzhiyun 				if (!(test_bit(DF_RELOGIN, &ddb_entry->flags) ||
5077*4882a593Smuzhiyun 				      test_bit(DF_DISABLE_RELOGIN,
5078*4882a593Smuzhiyun 					       &ddb_entry->flags)))
5079*4882a593Smuzhiyun 					qla4xxx_arm_relogin_timer(ddb_entry);
5080*4882a593Smuzhiyun 			} else
5081*4882a593Smuzhiyun 				iscsi_session_failure(cls_session->dd_data,
5082*4882a593Smuzhiyun 						      ISCSI_ERR_CONN_FAILED);
5083*4882a593Smuzhiyun 		}
5084*4882a593Smuzhiyun 	}
5085*4882a593Smuzhiyun }
5086*4882a593Smuzhiyun 
qla4xxx_unblock_flash_ddb(struct iscsi_cls_session * cls_session)5087*4882a593Smuzhiyun int qla4xxx_unblock_flash_ddb(struct iscsi_cls_session *cls_session)
5088*4882a593Smuzhiyun {
5089*4882a593Smuzhiyun 	struct iscsi_session *sess;
5090*4882a593Smuzhiyun 	struct ddb_entry *ddb_entry;
5091*4882a593Smuzhiyun 	struct scsi_qla_host *ha;
5092*4882a593Smuzhiyun 
5093*4882a593Smuzhiyun 	sess = cls_session->dd_data;
5094*4882a593Smuzhiyun 	ddb_entry = sess->dd_data;
5095*4882a593Smuzhiyun 	ha = ddb_entry->ha;
5096*4882a593Smuzhiyun 	ql4_printk(KERN_INFO, ha, "scsi%ld: %s: ddb[%d]"
5097*4882a593Smuzhiyun 		   " unblock session\n", ha->host_no, __func__,
5098*4882a593Smuzhiyun 		   ddb_entry->fw_ddb_index);
5099*4882a593Smuzhiyun 
5100*4882a593Smuzhiyun 	iscsi_unblock_session(ddb_entry->sess);
5101*4882a593Smuzhiyun 
5102*4882a593Smuzhiyun 	/* Start scan target */
5103*4882a593Smuzhiyun 	if (test_bit(AF_ONLINE, &ha->flags)) {
5104*4882a593Smuzhiyun 		ql4_printk(KERN_INFO, ha, "scsi%ld: %s: ddb[%d]"
5105*4882a593Smuzhiyun 			   " start scan\n", ha->host_no, __func__,
5106*4882a593Smuzhiyun 			   ddb_entry->fw_ddb_index);
5107*4882a593Smuzhiyun 		scsi_queue_work(ha->host, &ddb_entry->sess->scan_work);
5108*4882a593Smuzhiyun 	}
5109*4882a593Smuzhiyun 	return QLA_SUCCESS;
5110*4882a593Smuzhiyun }
5111*4882a593Smuzhiyun 
qla4xxx_unblock_ddb(struct iscsi_cls_session * cls_session)5112*4882a593Smuzhiyun int qla4xxx_unblock_ddb(struct iscsi_cls_session *cls_session)
5113*4882a593Smuzhiyun {
5114*4882a593Smuzhiyun 	struct iscsi_session *sess;
5115*4882a593Smuzhiyun 	struct ddb_entry *ddb_entry;
5116*4882a593Smuzhiyun 	struct scsi_qla_host *ha;
5117*4882a593Smuzhiyun 	int status = QLA_SUCCESS;
5118*4882a593Smuzhiyun 
5119*4882a593Smuzhiyun 	sess = cls_session->dd_data;
5120*4882a593Smuzhiyun 	ddb_entry = sess->dd_data;
5121*4882a593Smuzhiyun 	ha = ddb_entry->ha;
5122*4882a593Smuzhiyun 	ql4_printk(KERN_INFO, ha, "scsi%ld: %s: ddb[%d]"
5123*4882a593Smuzhiyun 		   " unblock user space session\n", ha->host_no, __func__,
5124*4882a593Smuzhiyun 		   ddb_entry->fw_ddb_index);
5125*4882a593Smuzhiyun 
5126*4882a593Smuzhiyun 	if (!iscsi_is_session_online(cls_session)) {
5127*4882a593Smuzhiyun 		iscsi_conn_start(ddb_entry->conn);
5128*4882a593Smuzhiyun 		iscsi_conn_login_event(ddb_entry->conn,
5129*4882a593Smuzhiyun 				       ISCSI_CONN_STATE_LOGGED_IN);
5130*4882a593Smuzhiyun 	} else {
5131*4882a593Smuzhiyun 		ql4_printk(KERN_INFO, ha,
5132*4882a593Smuzhiyun 			   "scsi%ld: %s: ddb[%d] session [%d] already logged in\n",
5133*4882a593Smuzhiyun 			   ha->host_no, __func__, ddb_entry->fw_ddb_index,
5134*4882a593Smuzhiyun 			   cls_session->sid);
5135*4882a593Smuzhiyun 		status = QLA_ERROR;
5136*4882a593Smuzhiyun 	}
5137*4882a593Smuzhiyun 
5138*4882a593Smuzhiyun 	return status;
5139*4882a593Smuzhiyun }
5140*4882a593Smuzhiyun 
qla4xxx_relogin_all_devices(struct scsi_qla_host * ha)5141*4882a593Smuzhiyun static void qla4xxx_relogin_all_devices(struct scsi_qla_host *ha)
5142*4882a593Smuzhiyun {
5143*4882a593Smuzhiyun 	iscsi_host_for_each_session(ha->host, qla4xxx_relogin_devices);
5144*4882a593Smuzhiyun }
5145*4882a593Smuzhiyun 
qla4xxx_relogin_flash_ddb(struct iscsi_cls_session * cls_sess)5146*4882a593Smuzhiyun static void qla4xxx_relogin_flash_ddb(struct iscsi_cls_session *cls_sess)
5147*4882a593Smuzhiyun {
5148*4882a593Smuzhiyun 	uint16_t relogin_timer;
5149*4882a593Smuzhiyun 	struct iscsi_session *sess;
5150*4882a593Smuzhiyun 	struct ddb_entry *ddb_entry;
5151*4882a593Smuzhiyun 	struct scsi_qla_host *ha;
5152*4882a593Smuzhiyun 
5153*4882a593Smuzhiyun 	sess = cls_sess->dd_data;
5154*4882a593Smuzhiyun 	ddb_entry = sess->dd_data;
5155*4882a593Smuzhiyun 	ha = ddb_entry->ha;
5156*4882a593Smuzhiyun 
5157*4882a593Smuzhiyun 	relogin_timer = max(ddb_entry->default_relogin_timeout,
5158*4882a593Smuzhiyun 			    (uint16_t)RELOGIN_TOV);
5159*4882a593Smuzhiyun 	atomic_set(&ddb_entry->relogin_timer, relogin_timer);
5160*4882a593Smuzhiyun 
5161*4882a593Smuzhiyun 	DEBUG2(ql4_printk(KERN_INFO, ha,
5162*4882a593Smuzhiyun 			  "scsi%ld: Relogin index [%d]. TOV=%d\n", ha->host_no,
5163*4882a593Smuzhiyun 			  ddb_entry->fw_ddb_index, relogin_timer));
5164*4882a593Smuzhiyun 
5165*4882a593Smuzhiyun 	qla4xxx_login_flash_ddb(cls_sess);
5166*4882a593Smuzhiyun }
5167*4882a593Smuzhiyun 
qla4xxx_dpc_relogin(struct iscsi_cls_session * cls_sess)5168*4882a593Smuzhiyun static void qla4xxx_dpc_relogin(struct iscsi_cls_session *cls_sess)
5169*4882a593Smuzhiyun {
5170*4882a593Smuzhiyun 	struct iscsi_session *sess;
5171*4882a593Smuzhiyun 	struct ddb_entry *ddb_entry;
5172*4882a593Smuzhiyun 	struct scsi_qla_host *ha;
5173*4882a593Smuzhiyun 
5174*4882a593Smuzhiyun 	sess = cls_sess->dd_data;
5175*4882a593Smuzhiyun 	ddb_entry = sess->dd_data;
5176*4882a593Smuzhiyun 	ha = ddb_entry->ha;
5177*4882a593Smuzhiyun 
5178*4882a593Smuzhiyun 	if (!(ddb_entry->ddb_type == FLASH_DDB))
5179*4882a593Smuzhiyun 		return;
5180*4882a593Smuzhiyun 
5181*4882a593Smuzhiyun 	if (test_bit(DF_DISABLE_RELOGIN, &ddb_entry->flags))
5182*4882a593Smuzhiyun 		return;
5183*4882a593Smuzhiyun 
5184*4882a593Smuzhiyun 	if (test_and_clear_bit(DF_RELOGIN, &ddb_entry->flags) &&
5185*4882a593Smuzhiyun 	    !iscsi_is_session_online(cls_sess)) {
5186*4882a593Smuzhiyun 		DEBUG2(ql4_printk(KERN_INFO, ha,
5187*4882a593Smuzhiyun 				  "relogin issued\n"));
5188*4882a593Smuzhiyun 		qla4xxx_relogin_flash_ddb(cls_sess);
5189*4882a593Smuzhiyun 	}
5190*4882a593Smuzhiyun }
5191*4882a593Smuzhiyun 
qla4xxx_wake_dpc(struct scsi_qla_host * ha)5192*4882a593Smuzhiyun void qla4xxx_wake_dpc(struct scsi_qla_host *ha)
5193*4882a593Smuzhiyun {
5194*4882a593Smuzhiyun 	if (ha->dpc_thread)
5195*4882a593Smuzhiyun 		queue_work(ha->dpc_thread, &ha->dpc_work);
5196*4882a593Smuzhiyun }
5197*4882a593Smuzhiyun 
5198*4882a593Smuzhiyun static struct qla4_work_evt *
qla4xxx_alloc_work(struct scsi_qla_host * ha,uint32_t data_size,enum qla4_work_type type)5199*4882a593Smuzhiyun qla4xxx_alloc_work(struct scsi_qla_host *ha, uint32_t data_size,
5200*4882a593Smuzhiyun 		   enum qla4_work_type type)
5201*4882a593Smuzhiyun {
5202*4882a593Smuzhiyun 	struct qla4_work_evt *e;
5203*4882a593Smuzhiyun 	uint32_t size = sizeof(struct qla4_work_evt) + data_size;
5204*4882a593Smuzhiyun 
5205*4882a593Smuzhiyun 	e = kzalloc(size, GFP_ATOMIC);
5206*4882a593Smuzhiyun 	if (!e)
5207*4882a593Smuzhiyun 		return NULL;
5208*4882a593Smuzhiyun 
5209*4882a593Smuzhiyun 	INIT_LIST_HEAD(&e->list);
5210*4882a593Smuzhiyun 	e->type = type;
5211*4882a593Smuzhiyun 	return e;
5212*4882a593Smuzhiyun }
5213*4882a593Smuzhiyun 
qla4xxx_post_work(struct scsi_qla_host * ha,struct qla4_work_evt * e)5214*4882a593Smuzhiyun static void qla4xxx_post_work(struct scsi_qla_host *ha,
5215*4882a593Smuzhiyun 			     struct qla4_work_evt *e)
5216*4882a593Smuzhiyun {
5217*4882a593Smuzhiyun 	unsigned long flags;
5218*4882a593Smuzhiyun 
5219*4882a593Smuzhiyun 	spin_lock_irqsave(&ha->work_lock, flags);
5220*4882a593Smuzhiyun 	list_add_tail(&e->list, &ha->work_list);
5221*4882a593Smuzhiyun 	spin_unlock_irqrestore(&ha->work_lock, flags);
5222*4882a593Smuzhiyun 	qla4xxx_wake_dpc(ha);
5223*4882a593Smuzhiyun }
5224*4882a593Smuzhiyun 
qla4xxx_post_aen_work(struct scsi_qla_host * ha,enum iscsi_host_event_code aen_code,uint32_t data_size,uint8_t * data)5225*4882a593Smuzhiyun int qla4xxx_post_aen_work(struct scsi_qla_host *ha,
5226*4882a593Smuzhiyun 			  enum iscsi_host_event_code aen_code,
5227*4882a593Smuzhiyun 			  uint32_t data_size, uint8_t *data)
5228*4882a593Smuzhiyun {
5229*4882a593Smuzhiyun 	struct qla4_work_evt *e;
5230*4882a593Smuzhiyun 
5231*4882a593Smuzhiyun 	e = qla4xxx_alloc_work(ha, data_size, QLA4_EVENT_AEN);
5232*4882a593Smuzhiyun 	if (!e)
5233*4882a593Smuzhiyun 		return QLA_ERROR;
5234*4882a593Smuzhiyun 
5235*4882a593Smuzhiyun 	e->u.aen.code = aen_code;
5236*4882a593Smuzhiyun 	e->u.aen.data_size = data_size;
5237*4882a593Smuzhiyun 	memcpy(e->u.aen.data, data, data_size);
5238*4882a593Smuzhiyun 
5239*4882a593Smuzhiyun 	qla4xxx_post_work(ha, e);
5240*4882a593Smuzhiyun 
5241*4882a593Smuzhiyun 	return QLA_SUCCESS;
5242*4882a593Smuzhiyun }
5243*4882a593Smuzhiyun 
qla4xxx_post_ping_evt_work(struct scsi_qla_host * ha,uint32_t status,uint32_t pid,uint32_t data_size,uint8_t * data)5244*4882a593Smuzhiyun int qla4xxx_post_ping_evt_work(struct scsi_qla_host *ha,
5245*4882a593Smuzhiyun 			       uint32_t status, uint32_t pid,
5246*4882a593Smuzhiyun 			       uint32_t data_size, uint8_t *data)
5247*4882a593Smuzhiyun {
5248*4882a593Smuzhiyun 	struct qla4_work_evt *e;
5249*4882a593Smuzhiyun 
5250*4882a593Smuzhiyun 	e = qla4xxx_alloc_work(ha, data_size, QLA4_EVENT_PING_STATUS);
5251*4882a593Smuzhiyun 	if (!e)
5252*4882a593Smuzhiyun 		return QLA_ERROR;
5253*4882a593Smuzhiyun 
5254*4882a593Smuzhiyun 	e->u.ping.status = status;
5255*4882a593Smuzhiyun 	e->u.ping.pid = pid;
5256*4882a593Smuzhiyun 	e->u.ping.data_size = data_size;
5257*4882a593Smuzhiyun 	memcpy(e->u.ping.data, data, data_size);
5258*4882a593Smuzhiyun 
5259*4882a593Smuzhiyun 	qla4xxx_post_work(ha, e);
5260*4882a593Smuzhiyun 
5261*4882a593Smuzhiyun 	return QLA_SUCCESS;
5262*4882a593Smuzhiyun }
5263*4882a593Smuzhiyun 
qla4xxx_do_work(struct scsi_qla_host * ha)5264*4882a593Smuzhiyun static void qla4xxx_do_work(struct scsi_qla_host *ha)
5265*4882a593Smuzhiyun {
5266*4882a593Smuzhiyun 	struct qla4_work_evt *e, *tmp;
5267*4882a593Smuzhiyun 	unsigned long flags;
5268*4882a593Smuzhiyun 	LIST_HEAD(work);
5269*4882a593Smuzhiyun 
5270*4882a593Smuzhiyun 	spin_lock_irqsave(&ha->work_lock, flags);
5271*4882a593Smuzhiyun 	list_splice_init(&ha->work_list, &work);
5272*4882a593Smuzhiyun 	spin_unlock_irqrestore(&ha->work_lock, flags);
5273*4882a593Smuzhiyun 
5274*4882a593Smuzhiyun 	list_for_each_entry_safe(e, tmp, &work, list) {
5275*4882a593Smuzhiyun 		list_del_init(&e->list);
5276*4882a593Smuzhiyun 
5277*4882a593Smuzhiyun 		switch (e->type) {
5278*4882a593Smuzhiyun 		case QLA4_EVENT_AEN:
5279*4882a593Smuzhiyun 			iscsi_post_host_event(ha->host_no,
5280*4882a593Smuzhiyun 					      &qla4xxx_iscsi_transport,
5281*4882a593Smuzhiyun 					      e->u.aen.code,
5282*4882a593Smuzhiyun 					      e->u.aen.data_size,
5283*4882a593Smuzhiyun 					      e->u.aen.data);
5284*4882a593Smuzhiyun 			break;
5285*4882a593Smuzhiyun 		case QLA4_EVENT_PING_STATUS:
5286*4882a593Smuzhiyun 			iscsi_ping_comp_event(ha->host_no,
5287*4882a593Smuzhiyun 					      &qla4xxx_iscsi_transport,
5288*4882a593Smuzhiyun 					      e->u.ping.status,
5289*4882a593Smuzhiyun 					      e->u.ping.pid,
5290*4882a593Smuzhiyun 					      e->u.ping.data_size,
5291*4882a593Smuzhiyun 					      e->u.ping.data);
5292*4882a593Smuzhiyun 			break;
5293*4882a593Smuzhiyun 		default:
5294*4882a593Smuzhiyun 			ql4_printk(KERN_WARNING, ha, "event type: 0x%x not "
5295*4882a593Smuzhiyun 				   "supported", e->type);
5296*4882a593Smuzhiyun 		}
5297*4882a593Smuzhiyun 		kfree(e);
5298*4882a593Smuzhiyun 	}
5299*4882a593Smuzhiyun }
5300*4882a593Smuzhiyun 
5301*4882a593Smuzhiyun /**
5302*4882a593Smuzhiyun  * qla4xxx_do_dpc - dpc routine
5303*4882a593Smuzhiyun  * @work: Context to obtain pointer to host adapter structure.
5304*4882a593Smuzhiyun  *
5305*4882a593Smuzhiyun  * This routine is a task that is schedule by the interrupt handler
5306*4882a593Smuzhiyun  * to perform the background processing for interrupts.  We put it
5307*4882a593Smuzhiyun  * on a task queue that is consumed whenever the scheduler runs; that's
5308*4882a593Smuzhiyun  * so you can do anything (i.e. put the process to sleep etc).  In fact,
5309*4882a593Smuzhiyun  * the mid-level tries to sleep when it reaches the driver threshold
5310*4882a593Smuzhiyun  * "host->can_queue". This can cause a panic if we were in our interrupt code.
5311*4882a593Smuzhiyun  **/
qla4xxx_do_dpc(struct work_struct * work)5312*4882a593Smuzhiyun static void qla4xxx_do_dpc(struct work_struct *work)
5313*4882a593Smuzhiyun {
5314*4882a593Smuzhiyun 	struct scsi_qla_host *ha =
5315*4882a593Smuzhiyun 		container_of(work, struct scsi_qla_host, dpc_work);
5316*4882a593Smuzhiyun 	int status = QLA_ERROR;
5317*4882a593Smuzhiyun 
5318*4882a593Smuzhiyun 	DEBUG2(ql4_printk(KERN_INFO, ha,
5319*4882a593Smuzhiyun 			  "scsi%ld: %s: DPC handler waking up. flags = 0x%08lx, dpc_flags = 0x%08lx\n",
5320*4882a593Smuzhiyun 			  ha->host_no, __func__, ha->flags, ha->dpc_flags));
5321*4882a593Smuzhiyun 
5322*4882a593Smuzhiyun 	/* Initialization not yet finished. Don't do anything yet. */
5323*4882a593Smuzhiyun 	if (!test_bit(AF_INIT_DONE, &ha->flags))
5324*4882a593Smuzhiyun 		return;
5325*4882a593Smuzhiyun 
5326*4882a593Smuzhiyun 	if (test_bit(AF_EEH_BUSY, &ha->flags)) {
5327*4882a593Smuzhiyun 		DEBUG2(printk(KERN_INFO "scsi%ld: %s: flags = %lx\n",
5328*4882a593Smuzhiyun 		    ha->host_no, __func__, ha->flags));
5329*4882a593Smuzhiyun 		return;
5330*4882a593Smuzhiyun 	}
5331*4882a593Smuzhiyun 
5332*4882a593Smuzhiyun 	/* post events to application */
5333*4882a593Smuzhiyun 	qla4xxx_do_work(ha);
5334*4882a593Smuzhiyun 
5335*4882a593Smuzhiyun 	if (is_qla80XX(ha)) {
5336*4882a593Smuzhiyun 		if (test_bit(DPC_HA_UNRECOVERABLE, &ha->dpc_flags)) {
5337*4882a593Smuzhiyun 			if (is_qla8032(ha) || is_qla8042(ha)) {
5338*4882a593Smuzhiyun 				ql4_printk(KERN_INFO, ha, "%s: disabling pause transmit on port 0 & 1.\n",
5339*4882a593Smuzhiyun 					   __func__);
5340*4882a593Smuzhiyun 				/* disable pause frame for ISP83xx */
5341*4882a593Smuzhiyun 				qla4_83xx_disable_pause(ha);
5342*4882a593Smuzhiyun 			}
5343*4882a593Smuzhiyun 
5344*4882a593Smuzhiyun 			ha->isp_ops->idc_lock(ha);
5345*4882a593Smuzhiyun 			qla4_8xxx_wr_direct(ha, QLA8XXX_CRB_DEV_STATE,
5346*4882a593Smuzhiyun 					    QLA8XXX_DEV_FAILED);
5347*4882a593Smuzhiyun 			ha->isp_ops->idc_unlock(ha);
5348*4882a593Smuzhiyun 			ql4_printk(KERN_INFO, ha, "HW State: FAILED\n");
5349*4882a593Smuzhiyun 			qla4_8xxx_device_state_handler(ha);
5350*4882a593Smuzhiyun 		}
5351*4882a593Smuzhiyun 
5352*4882a593Smuzhiyun 		if (test_bit(DPC_POST_IDC_ACK, &ha->dpc_flags)) {
5353*4882a593Smuzhiyun 			if (is_qla8042(ha)) {
5354*4882a593Smuzhiyun 				if (ha->idc_info.info2 &
5355*4882a593Smuzhiyun 				    ENABLE_INTERNAL_LOOPBACK) {
5356*4882a593Smuzhiyun 					ql4_printk(KERN_INFO, ha, "%s: Disabling ACB\n",
5357*4882a593Smuzhiyun 						   __func__);
5358*4882a593Smuzhiyun 					status = qla4_84xx_config_acb(ha,
5359*4882a593Smuzhiyun 							    ACB_CONFIG_DISABLE);
5360*4882a593Smuzhiyun 					if (status != QLA_SUCCESS) {
5361*4882a593Smuzhiyun 						ql4_printk(KERN_INFO, ha, "%s: ACB config failed\n",
5362*4882a593Smuzhiyun 							   __func__);
5363*4882a593Smuzhiyun 					}
5364*4882a593Smuzhiyun 				}
5365*4882a593Smuzhiyun 			}
5366*4882a593Smuzhiyun 			qla4_83xx_post_idc_ack(ha);
5367*4882a593Smuzhiyun 			clear_bit(DPC_POST_IDC_ACK, &ha->dpc_flags);
5368*4882a593Smuzhiyun 		}
5369*4882a593Smuzhiyun 
5370*4882a593Smuzhiyun 		if (is_qla8042(ha) &&
5371*4882a593Smuzhiyun 		    test_bit(DPC_RESTORE_ACB, &ha->dpc_flags)) {
5372*4882a593Smuzhiyun 			ql4_printk(KERN_INFO, ha, "%s: Restoring ACB\n",
5373*4882a593Smuzhiyun 				   __func__);
5374*4882a593Smuzhiyun 			if (qla4_84xx_config_acb(ha, ACB_CONFIG_SET) !=
5375*4882a593Smuzhiyun 			    QLA_SUCCESS) {
5376*4882a593Smuzhiyun 				ql4_printk(KERN_INFO, ha, "%s: ACB config failed ",
5377*4882a593Smuzhiyun 					   __func__);
5378*4882a593Smuzhiyun 			}
5379*4882a593Smuzhiyun 			clear_bit(DPC_RESTORE_ACB, &ha->dpc_flags);
5380*4882a593Smuzhiyun 		}
5381*4882a593Smuzhiyun 
5382*4882a593Smuzhiyun 		if (test_and_clear_bit(DPC_HA_NEED_QUIESCENT, &ha->dpc_flags)) {
5383*4882a593Smuzhiyun 			qla4_8xxx_need_qsnt_handler(ha);
5384*4882a593Smuzhiyun 		}
5385*4882a593Smuzhiyun 	}
5386*4882a593Smuzhiyun 
5387*4882a593Smuzhiyun 	if (!test_bit(DPC_RESET_ACTIVE, &ha->dpc_flags) &&
5388*4882a593Smuzhiyun 	    (test_bit(DPC_RESET_HA, &ha->dpc_flags) ||
5389*4882a593Smuzhiyun 	    test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags) ||
5390*4882a593Smuzhiyun 	    test_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags))) {
5391*4882a593Smuzhiyun 		if ((is_qla8022(ha) && ql4xdontresethba) ||
5392*4882a593Smuzhiyun 		    ((is_qla8032(ha) || is_qla8042(ha)) &&
5393*4882a593Smuzhiyun 		     qla4_83xx_idc_dontreset(ha))) {
5394*4882a593Smuzhiyun 			DEBUG2(printk("scsi%ld: %s: Don't Reset HBA\n",
5395*4882a593Smuzhiyun 			    ha->host_no, __func__));
5396*4882a593Smuzhiyun 			clear_bit(DPC_RESET_HA, &ha->dpc_flags);
5397*4882a593Smuzhiyun 			clear_bit(DPC_RESET_HA_INTR, &ha->dpc_flags);
5398*4882a593Smuzhiyun 			clear_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags);
5399*4882a593Smuzhiyun 			goto dpc_post_reset_ha;
5400*4882a593Smuzhiyun 		}
5401*4882a593Smuzhiyun 		if (test_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags) ||
5402*4882a593Smuzhiyun 		    test_bit(DPC_RESET_HA, &ha->dpc_flags))
5403*4882a593Smuzhiyun 			qla4xxx_recover_adapter(ha);
5404*4882a593Smuzhiyun 
5405*4882a593Smuzhiyun 		if (test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags)) {
5406*4882a593Smuzhiyun 			uint8_t wait_time = RESET_INTR_TOV;
5407*4882a593Smuzhiyun 
5408*4882a593Smuzhiyun 			while ((readw(&ha->reg->ctrl_status) &
5409*4882a593Smuzhiyun 				(CSR_SOFT_RESET | CSR_FORCE_SOFT_RESET)) != 0) {
5410*4882a593Smuzhiyun 				if (--wait_time == 0)
5411*4882a593Smuzhiyun 					break;
5412*4882a593Smuzhiyun 				msleep(1000);
5413*4882a593Smuzhiyun 			}
5414*4882a593Smuzhiyun 			if (wait_time == 0)
5415*4882a593Smuzhiyun 				DEBUG2(printk("scsi%ld: %s: SR|FSR "
5416*4882a593Smuzhiyun 					      "bit not cleared-- resetting\n",
5417*4882a593Smuzhiyun 					      ha->host_no, __func__));
5418*4882a593Smuzhiyun 			qla4xxx_abort_active_cmds(ha, DID_RESET << 16);
5419*4882a593Smuzhiyun 			if (ql4xxx_lock_drvr_wait(ha) == QLA_SUCCESS) {
5420*4882a593Smuzhiyun 				qla4xxx_process_aen(ha, FLUSH_DDB_CHANGED_AENS);
5421*4882a593Smuzhiyun 				status = qla4xxx_recover_adapter(ha);
5422*4882a593Smuzhiyun 			}
5423*4882a593Smuzhiyun 			clear_bit(DPC_RESET_HA_INTR, &ha->dpc_flags);
5424*4882a593Smuzhiyun 			if (status == QLA_SUCCESS)
5425*4882a593Smuzhiyun 				ha->isp_ops->enable_intrs(ha);
5426*4882a593Smuzhiyun 		}
5427*4882a593Smuzhiyun 	}
5428*4882a593Smuzhiyun 
5429*4882a593Smuzhiyun dpc_post_reset_ha:
5430*4882a593Smuzhiyun 	/* ---- process AEN? --- */
5431*4882a593Smuzhiyun 	if (test_and_clear_bit(DPC_AEN, &ha->dpc_flags))
5432*4882a593Smuzhiyun 		qla4xxx_process_aen(ha, PROCESS_ALL_AENS);
5433*4882a593Smuzhiyun 
5434*4882a593Smuzhiyun 	/* ---- Get DHCP IP Address? --- */
5435*4882a593Smuzhiyun 	if (test_and_clear_bit(DPC_GET_DHCP_IP_ADDR, &ha->dpc_flags))
5436*4882a593Smuzhiyun 		qla4xxx_get_dhcp_ip_address(ha);
5437*4882a593Smuzhiyun 
5438*4882a593Smuzhiyun 	/* ---- relogin device? --- */
5439*4882a593Smuzhiyun 	if (adapter_up(ha) &&
5440*4882a593Smuzhiyun 	    test_and_clear_bit(DPC_RELOGIN_DEVICE, &ha->dpc_flags)) {
5441*4882a593Smuzhiyun 		iscsi_host_for_each_session(ha->host, qla4xxx_dpc_relogin);
5442*4882a593Smuzhiyun 	}
5443*4882a593Smuzhiyun 
5444*4882a593Smuzhiyun 	/* ---- link change? --- */
5445*4882a593Smuzhiyun 	if (!test_bit(AF_LOOPBACK, &ha->flags) &&
5446*4882a593Smuzhiyun 	    test_and_clear_bit(DPC_LINK_CHANGED, &ha->dpc_flags)) {
5447*4882a593Smuzhiyun 		if (!test_bit(AF_LINK_UP, &ha->flags)) {
5448*4882a593Smuzhiyun 			/* ---- link down? --- */
5449*4882a593Smuzhiyun 			qla4xxx_mark_all_devices_missing(ha);
5450*4882a593Smuzhiyun 		} else {
5451*4882a593Smuzhiyun 			/* ---- link up? --- *
5452*4882a593Smuzhiyun 			 * F/W will auto login to all devices ONLY ONCE after
5453*4882a593Smuzhiyun 			 * link up during driver initialization and runtime
5454*4882a593Smuzhiyun 			 * fatal error recovery.  Therefore, the driver must
5455*4882a593Smuzhiyun 			 * manually relogin to devices when recovering from
5456*4882a593Smuzhiyun 			 * connection failures, logouts, expired KATO, etc. */
5457*4882a593Smuzhiyun 			if (test_and_clear_bit(AF_BUILD_DDB_LIST, &ha->flags)) {
5458*4882a593Smuzhiyun 				qla4xxx_build_ddb_list(ha, ha->is_reset);
5459*4882a593Smuzhiyun 				iscsi_host_for_each_session(ha->host,
5460*4882a593Smuzhiyun 						qla4xxx_login_flash_ddb);
5461*4882a593Smuzhiyun 			} else
5462*4882a593Smuzhiyun 				qla4xxx_relogin_all_devices(ha);
5463*4882a593Smuzhiyun 		}
5464*4882a593Smuzhiyun 	}
5465*4882a593Smuzhiyun 	if (test_and_clear_bit(DPC_SYSFS_DDB_EXPORT, &ha->dpc_flags)) {
5466*4882a593Smuzhiyun 		if (qla4xxx_sysfs_ddb_export(ha))
5467*4882a593Smuzhiyun 			ql4_printk(KERN_ERR, ha, "%s: Error exporting ddb to sysfs\n",
5468*4882a593Smuzhiyun 				   __func__);
5469*4882a593Smuzhiyun 	}
5470*4882a593Smuzhiyun }
5471*4882a593Smuzhiyun 
5472*4882a593Smuzhiyun /**
5473*4882a593Smuzhiyun  * qla4xxx_free_adapter - release the adapter
5474*4882a593Smuzhiyun  * @ha: pointer to adapter structure
5475*4882a593Smuzhiyun  **/
qla4xxx_free_adapter(struct scsi_qla_host * ha)5476*4882a593Smuzhiyun static void qla4xxx_free_adapter(struct scsi_qla_host *ha)
5477*4882a593Smuzhiyun {
5478*4882a593Smuzhiyun 	qla4xxx_abort_active_cmds(ha, DID_NO_CONNECT << 16);
5479*4882a593Smuzhiyun 
5480*4882a593Smuzhiyun 	/* Turn-off interrupts on the card. */
5481*4882a593Smuzhiyun 	ha->isp_ops->disable_intrs(ha);
5482*4882a593Smuzhiyun 
5483*4882a593Smuzhiyun 	if (is_qla40XX(ha)) {
5484*4882a593Smuzhiyun 		writel(set_rmask(CSR_SCSI_PROCESSOR_INTR),
5485*4882a593Smuzhiyun 		       &ha->reg->ctrl_status);
5486*4882a593Smuzhiyun 		readl(&ha->reg->ctrl_status);
5487*4882a593Smuzhiyun 	} else if (is_qla8022(ha)) {
5488*4882a593Smuzhiyun 		writel(0, &ha->qla4_82xx_reg->host_int);
5489*4882a593Smuzhiyun 		readl(&ha->qla4_82xx_reg->host_int);
5490*4882a593Smuzhiyun 	} else if (is_qla8032(ha) || is_qla8042(ha)) {
5491*4882a593Smuzhiyun 		writel(0, &ha->qla4_83xx_reg->risc_intr);
5492*4882a593Smuzhiyun 		readl(&ha->qla4_83xx_reg->risc_intr);
5493*4882a593Smuzhiyun 	}
5494*4882a593Smuzhiyun 
5495*4882a593Smuzhiyun 	/* Remove timer thread, if present */
5496*4882a593Smuzhiyun 	if (ha->timer_active)
5497*4882a593Smuzhiyun 		qla4xxx_stop_timer(ha);
5498*4882a593Smuzhiyun 
5499*4882a593Smuzhiyun 	/* Kill the kernel thread for this host */
5500*4882a593Smuzhiyun 	if (ha->dpc_thread)
5501*4882a593Smuzhiyun 		destroy_workqueue(ha->dpc_thread);
5502*4882a593Smuzhiyun 
5503*4882a593Smuzhiyun 	/* Kill the kernel thread for this host */
5504*4882a593Smuzhiyun 	if (ha->task_wq)
5505*4882a593Smuzhiyun 		destroy_workqueue(ha->task_wq);
5506*4882a593Smuzhiyun 
5507*4882a593Smuzhiyun 	/* Put firmware in known state */
5508*4882a593Smuzhiyun 	ha->isp_ops->reset_firmware(ha);
5509*4882a593Smuzhiyun 
5510*4882a593Smuzhiyun 	if (is_qla80XX(ha)) {
5511*4882a593Smuzhiyun 		ha->isp_ops->idc_lock(ha);
5512*4882a593Smuzhiyun 		qla4_8xxx_clear_drv_active(ha);
5513*4882a593Smuzhiyun 		ha->isp_ops->idc_unlock(ha);
5514*4882a593Smuzhiyun 	}
5515*4882a593Smuzhiyun 
5516*4882a593Smuzhiyun 	/* Detach interrupts */
5517*4882a593Smuzhiyun 	qla4xxx_free_irqs(ha);
5518*4882a593Smuzhiyun 
5519*4882a593Smuzhiyun 	/* free extra memory */
5520*4882a593Smuzhiyun 	qla4xxx_mem_free(ha);
5521*4882a593Smuzhiyun }
5522*4882a593Smuzhiyun 
qla4_8xxx_iospace_config(struct scsi_qla_host * ha)5523*4882a593Smuzhiyun int qla4_8xxx_iospace_config(struct scsi_qla_host *ha)
5524*4882a593Smuzhiyun {
5525*4882a593Smuzhiyun 	int status = 0;
5526*4882a593Smuzhiyun 	unsigned long mem_base, mem_len;
5527*4882a593Smuzhiyun 	struct pci_dev *pdev = ha->pdev;
5528*4882a593Smuzhiyun 
5529*4882a593Smuzhiyun 	status = pci_request_regions(pdev, DRIVER_NAME);
5530*4882a593Smuzhiyun 	if (status) {
5531*4882a593Smuzhiyun 		printk(KERN_WARNING
5532*4882a593Smuzhiyun 		    "scsi(%ld) Failed to reserve PIO regions (%s) "
5533*4882a593Smuzhiyun 		    "status=%d\n", ha->host_no, pci_name(pdev), status);
5534*4882a593Smuzhiyun 		goto iospace_error_exit;
5535*4882a593Smuzhiyun 	}
5536*4882a593Smuzhiyun 
5537*4882a593Smuzhiyun 	DEBUG2(printk(KERN_INFO "%s: revision-id=%d\n",
5538*4882a593Smuzhiyun 	    __func__, pdev->revision));
5539*4882a593Smuzhiyun 	ha->revision_id = pdev->revision;
5540*4882a593Smuzhiyun 
5541*4882a593Smuzhiyun 	/* remap phys address */
5542*4882a593Smuzhiyun 	mem_base = pci_resource_start(pdev, 0); /* 0 is for BAR 0 */
5543*4882a593Smuzhiyun 	mem_len = pci_resource_len(pdev, 0);
5544*4882a593Smuzhiyun 	DEBUG2(printk(KERN_INFO "%s: ioremap from %lx a size of %lx\n",
5545*4882a593Smuzhiyun 	    __func__, mem_base, mem_len));
5546*4882a593Smuzhiyun 
5547*4882a593Smuzhiyun 	/* mapping of pcibase pointer */
5548*4882a593Smuzhiyun 	ha->nx_pcibase = (unsigned long)ioremap(mem_base, mem_len);
5549*4882a593Smuzhiyun 	if (!ha->nx_pcibase) {
5550*4882a593Smuzhiyun 		printk(KERN_ERR
5551*4882a593Smuzhiyun 		    "cannot remap MMIO (%s), aborting\n", pci_name(pdev));
5552*4882a593Smuzhiyun 		pci_release_regions(ha->pdev);
5553*4882a593Smuzhiyun 		goto iospace_error_exit;
5554*4882a593Smuzhiyun 	}
5555*4882a593Smuzhiyun 
5556*4882a593Smuzhiyun 	/* Mapping of IO base pointer, door bell read and write pointer */
5557*4882a593Smuzhiyun 
5558*4882a593Smuzhiyun 	/* mapping of IO base pointer */
5559*4882a593Smuzhiyun 	if (is_qla8022(ha)) {
5560*4882a593Smuzhiyun 		ha->qla4_82xx_reg = (struct device_reg_82xx  __iomem *)
5561*4882a593Smuzhiyun 				    ((uint8_t *)ha->nx_pcibase + 0xbc000 +
5562*4882a593Smuzhiyun 				     (ha->pdev->devfn << 11));
5563*4882a593Smuzhiyun 		ha->nx_db_wr_ptr = (ha->pdev->devfn == 4 ? QLA82XX_CAM_RAM_DB1 :
5564*4882a593Smuzhiyun 				    QLA82XX_CAM_RAM_DB2);
5565*4882a593Smuzhiyun 	} else if (is_qla8032(ha) || is_qla8042(ha)) {
5566*4882a593Smuzhiyun 		ha->qla4_83xx_reg = (struct device_reg_83xx __iomem *)
5567*4882a593Smuzhiyun 				    ((uint8_t *)ha->nx_pcibase);
5568*4882a593Smuzhiyun 	}
5569*4882a593Smuzhiyun 
5570*4882a593Smuzhiyun 	return 0;
5571*4882a593Smuzhiyun iospace_error_exit:
5572*4882a593Smuzhiyun 	return -ENOMEM;
5573*4882a593Smuzhiyun }
5574*4882a593Smuzhiyun 
5575*4882a593Smuzhiyun /***
5576*4882a593Smuzhiyun  * qla4xxx_iospace_config - maps registers
5577*4882a593Smuzhiyun  * @ha: pointer to adapter structure
5578*4882a593Smuzhiyun  *
5579*4882a593Smuzhiyun  * This routines maps HBA's registers from the pci address space
5580*4882a593Smuzhiyun  * into the kernel virtual address space for memory mapped i/o.
5581*4882a593Smuzhiyun  **/
qla4xxx_iospace_config(struct scsi_qla_host * ha)5582*4882a593Smuzhiyun int qla4xxx_iospace_config(struct scsi_qla_host *ha)
5583*4882a593Smuzhiyun {
5584*4882a593Smuzhiyun 	unsigned long pio, pio_len, pio_flags;
5585*4882a593Smuzhiyun 	unsigned long mmio, mmio_len, mmio_flags;
5586*4882a593Smuzhiyun 
5587*4882a593Smuzhiyun 	pio = pci_resource_start(ha->pdev, 0);
5588*4882a593Smuzhiyun 	pio_len = pci_resource_len(ha->pdev, 0);
5589*4882a593Smuzhiyun 	pio_flags = pci_resource_flags(ha->pdev, 0);
5590*4882a593Smuzhiyun 	if (pio_flags & IORESOURCE_IO) {
5591*4882a593Smuzhiyun 		if (pio_len < MIN_IOBASE_LEN) {
5592*4882a593Smuzhiyun 			ql4_printk(KERN_WARNING, ha,
5593*4882a593Smuzhiyun 				"Invalid PCI I/O region size\n");
5594*4882a593Smuzhiyun 			pio = 0;
5595*4882a593Smuzhiyun 		}
5596*4882a593Smuzhiyun 	} else {
5597*4882a593Smuzhiyun 		ql4_printk(KERN_WARNING, ha, "region #0 not a PIO resource\n");
5598*4882a593Smuzhiyun 		pio = 0;
5599*4882a593Smuzhiyun 	}
5600*4882a593Smuzhiyun 
5601*4882a593Smuzhiyun 	/* Use MMIO operations for all accesses. */
5602*4882a593Smuzhiyun 	mmio = pci_resource_start(ha->pdev, 1);
5603*4882a593Smuzhiyun 	mmio_len = pci_resource_len(ha->pdev, 1);
5604*4882a593Smuzhiyun 	mmio_flags = pci_resource_flags(ha->pdev, 1);
5605*4882a593Smuzhiyun 
5606*4882a593Smuzhiyun 	if (!(mmio_flags & IORESOURCE_MEM)) {
5607*4882a593Smuzhiyun 		ql4_printk(KERN_ERR, ha,
5608*4882a593Smuzhiyun 		    "region #0 not an MMIO resource, aborting\n");
5609*4882a593Smuzhiyun 
5610*4882a593Smuzhiyun 		goto iospace_error_exit;
5611*4882a593Smuzhiyun 	}
5612*4882a593Smuzhiyun 
5613*4882a593Smuzhiyun 	if (mmio_len < MIN_IOBASE_LEN) {
5614*4882a593Smuzhiyun 		ql4_printk(KERN_ERR, ha,
5615*4882a593Smuzhiyun 		    "Invalid PCI mem region size, aborting\n");
5616*4882a593Smuzhiyun 		goto iospace_error_exit;
5617*4882a593Smuzhiyun 	}
5618*4882a593Smuzhiyun 
5619*4882a593Smuzhiyun 	if (pci_request_regions(ha->pdev, DRIVER_NAME)) {
5620*4882a593Smuzhiyun 		ql4_printk(KERN_WARNING, ha,
5621*4882a593Smuzhiyun 		    "Failed to reserve PIO/MMIO regions\n");
5622*4882a593Smuzhiyun 
5623*4882a593Smuzhiyun 		goto iospace_error_exit;
5624*4882a593Smuzhiyun 	}
5625*4882a593Smuzhiyun 
5626*4882a593Smuzhiyun 	ha->pio_address = pio;
5627*4882a593Smuzhiyun 	ha->pio_length = pio_len;
5628*4882a593Smuzhiyun 	ha->reg = ioremap(mmio, MIN_IOBASE_LEN);
5629*4882a593Smuzhiyun 	if (!ha->reg) {
5630*4882a593Smuzhiyun 		ql4_printk(KERN_ERR, ha,
5631*4882a593Smuzhiyun 		    "cannot remap MMIO, aborting\n");
5632*4882a593Smuzhiyun 
5633*4882a593Smuzhiyun 		goto iospace_error_exit;
5634*4882a593Smuzhiyun 	}
5635*4882a593Smuzhiyun 
5636*4882a593Smuzhiyun 	return 0;
5637*4882a593Smuzhiyun 
5638*4882a593Smuzhiyun iospace_error_exit:
5639*4882a593Smuzhiyun 	return -ENOMEM;
5640*4882a593Smuzhiyun }
5641*4882a593Smuzhiyun 
5642*4882a593Smuzhiyun static struct isp_operations qla4xxx_isp_ops = {
5643*4882a593Smuzhiyun 	.iospace_config         = qla4xxx_iospace_config,
5644*4882a593Smuzhiyun 	.pci_config             = qla4xxx_pci_config,
5645*4882a593Smuzhiyun 	.disable_intrs          = qla4xxx_disable_intrs,
5646*4882a593Smuzhiyun 	.enable_intrs           = qla4xxx_enable_intrs,
5647*4882a593Smuzhiyun 	.start_firmware         = qla4xxx_start_firmware,
5648*4882a593Smuzhiyun 	.intr_handler           = qla4xxx_intr_handler,
5649*4882a593Smuzhiyun 	.interrupt_service_routine = qla4xxx_interrupt_service_routine,
5650*4882a593Smuzhiyun 	.reset_chip             = qla4xxx_soft_reset,
5651*4882a593Smuzhiyun 	.reset_firmware         = qla4xxx_hw_reset,
5652*4882a593Smuzhiyun 	.queue_iocb             = qla4xxx_queue_iocb,
5653*4882a593Smuzhiyun 	.complete_iocb          = qla4xxx_complete_iocb,
5654*4882a593Smuzhiyun 	.rd_shdw_req_q_out      = qla4xxx_rd_shdw_req_q_out,
5655*4882a593Smuzhiyun 	.rd_shdw_rsp_q_in       = qla4xxx_rd_shdw_rsp_q_in,
5656*4882a593Smuzhiyun 	.get_sys_info           = qla4xxx_get_sys_info,
5657*4882a593Smuzhiyun 	.queue_mailbox_command	= qla4xxx_queue_mbox_cmd,
5658*4882a593Smuzhiyun 	.process_mailbox_interrupt = qla4xxx_process_mbox_intr,
5659*4882a593Smuzhiyun };
5660*4882a593Smuzhiyun 
5661*4882a593Smuzhiyun static struct isp_operations qla4_82xx_isp_ops = {
5662*4882a593Smuzhiyun 	.iospace_config         = qla4_8xxx_iospace_config,
5663*4882a593Smuzhiyun 	.pci_config             = qla4_8xxx_pci_config,
5664*4882a593Smuzhiyun 	.disable_intrs          = qla4_82xx_disable_intrs,
5665*4882a593Smuzhiyun 	.enable_intrs           = qla4_82xx_enable_intrs,
5666*4882a593Smuzhiyun 	.start_firmware         = qla4_8xxx_load_risc,
5667*4882a593Smuzhiyun 	.restart_firmware	= qla4_82xx_try_start_fw,
5668*4882a593Smuzhiyun 	.intr_handler           = qla4_82xx_intr_handler,
5669*4882a593Smuzhiyun 	.interrupt_service_routine = qla4_82xx_interrupt_service_routine,
5670*4882a593Smuzhiyun 	.need_reset		= qla4_8xxx_need_reset,
5671*4882a593Smuzhiyun 	.reset_chip             = qla4_82xx_isp_reset,
5672*4882a593Smuzhiyun 	.reset_firmware         = qla4_8xxx_stop_firmware,
5673*4882a593Smuzhiyun 	.queue_iocb             = qla4_82xx_queue_iocb,
5674*4882a593Smuzhiyun 	.complete_iocb          = qla4_82xx_complete_iocb,
5675*4882a593Smuzhiyun 	.rd_shdw_req_q_out      = qla4_82xx_rd_shdw_req_q_out,
5676*4882a593Smuzhiyun 	.rd_shdw_rsp_q_in       = qla4_82xx_rd_shdw_rsp_q_in,
5677*4882a593Smuzhiyun 	.get_sys_info           = qla4_8xxx_get_sys_info,
5678*4882a593Smuzhiyun 	.rd_reg_direct		= qla4_82xx_rd_32,
5679*4882a593Smuzhiyun 	.wr_reg_direct		= qla4_82xx_wr_32,
5680*4882a593Smuzhiyun 	.rd_reg_indirect	= qla4_82xx_md_rd_32,
5681*4882a593Smuzhiyun 	.wr_reg_indirect	= qla4_82xx_md_wr_32,
5682*4882a593Smuzhiyun 	.idc_lock		= qla4_82xx_idc_lock,
5683*4882a593Smuzhiyun 	.idc_unlock		= qla4_82xx_idc_unlock,
5684*4882a593Smuzhiyun 	.rom_lock_recovery	= qla4_82xx_rom_lock_recovery,
5685*4882a593Smuzhiyun 	.queue_mailbox_command	= qla4_82xx_queue_mbox_cmd,
5686*4882a593Smuzhiyun 	.process_mailbox_interrupt = qla4_82xx_process_mbox_intr,
5687*4882a593Smuzhiyun };
5688*4882a593Smuzhiyun 
5689*4882a593Smuzhiyun static struct isp_operations qla4_83xx_isp_ops = {
5690*4882a593Smuzhiyun 	.iospace_config		= qla4_8xxx_iospace_config,
5691*4882a593Smuzhiyun 	.pci_config		= qla4_8xxx_pci_config,
5692*4882a593Smuzhiyun 	.disable_intrs		= qla4_83xx_disable_intrs,
5693*4882a593Smuzhiyun 	.enable_intrs		= qla4_83xx_enable_intrs,
5694*4882a593Smuzhiyun 	.start_firmware		= qla4_8xxx_load_risc,
5695*4882a593Smuzhiyun 	.restart_firmware	= qla4_83xx_start_firmware,
5696*4882a593Smuzhiyun 	.intr_handler		= qla4_83xx_intr_handler,
5697*4882a593Smuzhiyun 	.interrupt_service_routine = qla4_83xx_interrupt_service_routine,
5698*4882a593Smuzhiyun 	.need_reset		= qla4_8xxx_need_reset,
5699*4882a593Smuzhiyun 	.reset_chip		= qla4_83xx_isp_reset,
5700*4882a593Smuzhiyun 	.reset_firmware		= qla4_8xxx_stop_firmware,
5701*4882a593Smuzhiyun 	.queue_iocb		= qla4_83xx_queue_iocb,
5702*4882a593Smuzhiyun 	.complete_iocb		= qla4_83xx_complete_iocb,
5703*4882a593Smuzhiyun 	.rd_shdw_req_q_out	= qla4xxx_rd_shdw_req_q_out,
5704*4882a593Smuzhiyun 	.rd_shdw_rsp_q_in	= qla4xxx_rd_shdw_rsp_q_in,
5705*4882a593Smuzhiyun 	.get_sys_info		= qla4_8xxx_get_sys_info,
5706*4882a593Smuzhiyun 	.rd_reg_direct		= qla4_83xx_rd_reg,
5707*4882a593Smuzhiyun 	.wr_reg_direct		= qla4_83xx_wr_reg,
5708*4882a593Smuzhiyun 	.rd_reg_indirect	= qla4_83xx_rd_reg_indirect,
5709*4882a593Smuzhiyun 	.wr_reg_indirect	= qla4_83xx_wr_reg_indirect,
5710*4882a593Smuzhiyun 	.idc_lock		= qla4_83xx_drv_lock,
5711*4882a593Smuzhiyun 	.idc_unlock		= qla4_83xx_drv_unlock,
5712*4882a593Smuzhiyun 	.rom_lock_recovery	= qla4_83xx_rom_lock_recovery,
5713*4882a593Smuzhiyun 	.queue_mailbox_command	= qla4_83xx_queue_mbox_cmd,
5714*4882a593Smuzhiyun 	.process_mailbox_interrupt = qla4_83xx_process_mbox_intr,
5715*4882a593Smuzhiyun };
5716*4882a593Smuzhiyun 
qla4xxx_rd_shdw_req_q_out(struct scsi_qla_host * ha)5717*4882a593Smuzhiyun uint16_t qla4xxx_rd_shdw_req_q_out(struct scsi_qla_host *ha)
5718*4882a593Smuzhiyun {
5719*4882a593Smuzhiyun 	return (uint16_t)le32_to_cpu(ha->shadow_regs->req_q_out);
5720*4882a593Smuzhiyun }
5721*4882a593Smuzhiyun 
qla4_82xx_rd_shdw_req_q_out(struct scsi_qla_host * ha)5722*4882a593Smuzhiyun uint16_t qla4_82xx_rd_shdw_req_q_out(struct scsi_qla_host *ha)
5723*4882a593Smuzhiyun {
5724*4882a593Smuzhiyun 	return (uint16_t)le32_to_cpu(readl(&ha->qla4_82xx_reg->req_q_out));
5725*4882a593Smuzhiyun }
5726*4882a593Smuzhiyun 
qla4xxx_rd_shdw_rsp_q_in(struct scsi_qla_host * ha)5727*4882a593Smuzhiyun uint16_t qla4xxx_rd_shdw_rsp_q_in(struct scsi_qla_host *ha)
5728*4882a593Smuzhiyun {
5729*4882a593Smuzhiyun 	return (uint16_t)le32_to_cpu(ha->shadow_regs->rsp_q_in);
5730*4882a593Smuzhiyun }
5731*4882a593Smuzhiyun 
qla4_82xx_rd_shdw_rsp_q_in(struct scsi_qla_host * ha)5732*4882a593Smuzhiyun uint16_t qla4_82xx_rd_shdw_rsp_q_in(struct scsi_qla_host *ha)
5733*4882a593Smuzhiyun {
5734*4882a593Smuzhiyun 	return (uint16_t)le32_to_cpu(readl(&ha->qla4_82xx_reg->rsp_q_in));
5735*4882a593Smuzhiyun }
5736*4882a593Smuzhiyun 
qla4xxx_show_boot_eth_info(void * data,int type,char * buf)5737*4882a593Smuzhiyun static ssize_t qla4xxx_show_boot_eth_info(void *data, int type, char *buf)
5738*4882a593Smuzhiyun {
5739*4882a593Smuzhiyun 	struct scsi_qla_host *ha = data;
5740*4882a593Smuzhiyun 	char *str = buf;
5741*4882a593Smuzhiyun 	int rc;
5742*4882a593Smuzhiyun 
5743*4882a593Smuzhiyun 	switch (type) {
5744*4882a593Smuzhiyun 	case ISCSI_BOOT_ETH_FLAGS:
5745*4882a593Smuzhiyun 		rc = sprintf(str, "%d\n", SYSFS_FLAG_FW_SEL_BOOT);
5746*4882a593Smuzhiyun 		break;
5747*4882a593Smuzhiyun 	case ISCSI_BOOT_ETH_INDEX:
5748*4882a593Smuzhiyun 		rc = sprintf(str, "0\n");
5749*4882a593Smuzhiyun 		break;
5750*4882a593Smuzhiyun 	case ISCSI_BOOT_ETH_MAC:
5751*4882a593Smuzhiyun 		rc = sysfs_format_mac(str, ha->my_mac,
5752*4882a593Smuzhiyun 				      MAC_ADDR_LEN);
5753*4882a593Smuzhiyun 		break;
5754*4882a593Smuzhiyun 	default:
5755*4882a593Smuzhiyun 		rc = -ENOSYS;
5756*4882a593Smuzhiyun 		break;
5757*4882a593Smuzhiyun 	}
5758*4882a593Smuzhiyun 	return rc;
5759*4882a593Smuzhiyun }
5760*4882a593Smuzhiyun 
qla4xxx_eth_get_attr_visibility(void * data,int type)5761*4882a593Smuzhiyun static umode_t qla4xxx_eth_get_attr_visibility(void *data, int type)
5762*4882a593Smuzhiyun {
5763*4882a593Smuzhiyun 	int rc;
5764*4882a593Smuzhiyun 
5765*4882a593Smuzhiyun 	switch (type) {
5766*4882a593Smuzhiyun 	case ISCSI_BOOT_ETH_FLAGS:
5767*4882a593Smuzhiyun 	case ISCSI_BOOT_ETH_MAC:
5768*4882a593Smuzhiyun 	case ISCSI_BOOT_ETH_INDEX:
5769*4882a593Smuzhiyun 		rc = S_IRUGO;
5770*4882a593Smuzhiyun 		break;
5771*4882a593Smuzhiyun 	default:
5772*4882a593Smuzhiyun 		rc = 0;
5773*4882a593Smuzhiyun 		break;
5774*4882a593Smuzhiyun 	}
5775*4882a593Smuzhiyun 	return rc;
5776*4882a593Smuzhiyun }
5777*4882a593Smuzhiyun 
qla4xxx_show_boot_ini_info(void * data,int type,char * buf)5778*4882a593Smuzhiyun static ssize_t qla4xxx_show_boot_ini_info(void *data, int type, char *buf)
5779*4882a593Smuzhiyun {
5780*4882a593Smuzhiyun 	struct scsi_qla_host *ha = data;
5781*4882a593Smuzhiyun 	char *str = buf;
5782*4882a593Smuzhiyun 	int rc;
5783*4882a593Smuzhiyun 
5784*4882a593Smuzhiyun 	switch (type) {
5785*4882a593Smuzhiyun 	case ISCSI_BOOT_INI_INITIATOR_NAME:
5786*4882a593Smuzhiyun 		rc = sprintf(str, "%s\n", ha->name_string);
5787*4882a593Smuzhiyun 		break;
5788*4882a593Smuzhiyun 	default:
5789*4882a593Smuzhiyun 		rc = -ENOSYS;
5790*4882a593Smuzhiyun 		break;
5791*4882a593Smuzhiyun 	}
5792*4882a593Smuzhiyun 	return rc;
5793*4882a593Smuzhiyun }
5794*4882a593Smuzhiyun 
qla4xxx_ini_get_attr_visibility(void * data,int type)5795*4882a593Smuzhiyun static umode_t qla4xxx_ini_get_attr_visibility(void *data, int type)
5796*4882a593Smuzhiyun {
5797*4882a593Smuzhiyun 	int rc;
5798*4882a593Smuzhiyun 
5799*4882a593Smuzhiyun 	switch (type) {
5800*4882a593Smuzhiyun 	case ISCSI_BOOT_INI_INITIATOR_NAME:
5801*4882a593Smuzhiyun 		rc = S_IRUGO;
5802*4882a593Smuzhiyun 		break;
5803*4882a593Smuzhiyun 	default:
5804*4882a593Smuzhiyun 		rc = 0;
5805*4882a593Smuzhiyun 		break;
5806*4882a593Smuzhiyun 	}
5807*4882a593Smuzhiyun 	return rc;
5808*4882a593Smuzhiyun }
5809*4882a593Smuzhiyun 
5810*4882a593Smuzhiyun static ssize_t
qla4xxx_show_boot_tgt_info(struct ql4_boot_session_info * boot_sess,int type,char * buf)5811*4882a593Smuzhiyun qla4xxx_show_boot_tgt_info(struct ql4_boot_session_info *boot_sess, int type,
5812*4882a593Smuzhiyun 			   char *buf)
5813*4882a593Smuzhiyun {
5814*4882a593Smuzhiyun 	struct ql4_conn_info *boot_conn = &boot_sess->conn_list[0];
5815*4882a593Smuzhiyun 	char *str = buf;
5816*4882a593Smuzhiyun 	int rc;
5817*4882a593Smuzhiyun 
5818*4882a593Smuzhiyun 	switch (type) {
5819*4882a593Smuzhiyun 	case ISCSI_BOOT_TGT_NAME:
5820*4882a593Smuzhiyun 		rc = sprintf(buf, "%s\n", (char *)&boot_sess->target_name);
5821*4882a593Smuzhiyun 		break;
5822*4882a593Smuzhiyun 	case ISCSI_BOOT_TGT_IP_ADDR:
5823*4882a593Smuzhiyun 		if (boot_sess->conn_list[0].dest_ipaddr.ip_type == 0x1)
5824*4882a593Smuzhiyun 			rc = sprintf(buf, "%pI4\n",
5825*4882a593Smuzhiyun 				     &boot_conn->dest_ipaddr.ip_address);
5826*4882a593Smuzhiyun 		else
5827*4882a593Smuzhiyun 			rc = sprintf(str, "%pI6\n",
5828*4882a593Smuzhiyun 				     &boot_conn->dest_ipaddr.ip_address);
5829*4882a593Smuzhiyun 		break;
5830*4882a593Smuzhiyun 	case ISCSI_BOOT_TGT_PORT:
5831*4882a593Smuzhiyun 			rc = sprintf(str, "%d\n", boot_conn->dest_port);
5832*4882a593Smuzhiyun 		break;
5833*4882a593Smuzhiyun 	case ISCSI_BOOT_TGT_CHAP_NAME:
5834*4882a593Smuzhiyun 		rc = sprintf(str,  "%.*s\n",
5835*4882a593Smuzhiyun 			     boot_conn->chap.target_chap_name_length,
5836*4882a593Smuzhiyun 			     (char *)&boot_conn->chap.target_chap_name);
5837*4882a593Smuzhiyun 		break;
5838*4882a593Smuzhiyun 	case ISCSI_BOOT_TGT_CHAP_SECRET:
5839*4882a593Smuzhiyun 		rc = sprintf(str,  "%.*s\n",
5840*4882a593Smuzhiyun 			     boot_conn->chap.target_secret_length,
5841*4882a593Smuzhiyun 			     (char *)&boot_conn->chap.target_secret);
5842*4882a593Smuzhiyun 		break;
5843*4882a593Smuzhiyun 	case ISCSI_BOOT_TGT_REV_CHAP_NAME:
5844*4882a593Smuzhiyun 		rc = sprintf(str,  "%.*s\n",
5845*4882a593Smuzhiyun 			     boot_conn->chap.intr_chap_name_length,
5846*4882a593Smuzhiyun 			     (char *)&boot_conn->chap.intr_chap_name);
5847*4882a593Smuzhiyun 		break;
5848*4882a593Smuzhiyun 	case ISCSI_BOOT_TGT_REV_CHAP_SECRET:
5849*4882a593Smuzhiyun 		rc = sprintf(str,  "%.*s\n",
5850*4882a593Smuzhiyun 			     boot_conn->chap.intr_secret_length,
5851*4882a593Smuzhiyun 			     (char *)&boot_conn->chap.intr_secret);
5852*4882a593Smuzhiyun 		break;
5853*4882a593Smuzhiyun 	case ISCSI_BOOT_TGT_FLAGS:
5854*4882a593Smuzhiyun 		rc = sprintf(str, "%d\n", SYSFS_FLAG_FW_SEL_BOOT);
5855*4882a593Smuzhiyun 		break;
5856*4882a593Smuzhiyun 	case ISCSI_BOOT_TGT_NIC_ASSOC:
5857*4882a593Smuzhiyun 		rc = sprintf(str, "0\n");
5858*4882a593Smuzhiyun 		break;
5859*4882a593Smuzhiyun 	default:
5860*4882a593Smuzhiyun 		rc = -ENOSYS;
5861*4882a593Smuzhiyun 		break;
5862*4882a593Smuzhiyun 	}
5863*4882a593Smuzhiyun 	return rc;
5864*4882a593Smuzhiyun }
5865*4882a593Smuzhiyun 
qla4xxx_show_boot_tgt_pri_info(void * data,int type,char * buf)5866*4882a593Smuzhiyun static ssize_t qla4xxx_show_boot_tgt_pri_info(void *data, int type, char *buf)
5867*4882a593Smuzhiyun {
5868*4882a593Smuzhiyun 	struct scsi_qla_host *ha = data;
5869*4882a593Smuzhiyun 	struct ql4_boot_session_info *boot_sess = &(ha->boot_tgt.boot_pri_sess);
5870*4882a593Smuzhiyun 
5871*4882a593Smuzhiyun 	return qla4xxx_show_boot_tgt_info(boot_sess, type, buf);
5872*4882a593Smuzhiyun }
5873*4882a593Smuzhiyun 
qla4xxx_show_boot_tgt_sec_info(void * data,int type,char * buf)5874*4882a593Smuzhiyun static ssize_t qla4xxx_show_boot_tgt_sec_info(void *data, int type, char *buf)
5875*4882a593Smuzhiyun {
5876*4882a593Smuzhiyun 	struct scsi_qla_host *ha = data;
5877*4882a593Smuzhiyun 	struct ql4_boot_session_info *boot_sess = &(ha->boot_tgt.boot_sec_sess);
5878*4882a593Smuzhiyun 
5879*4882a593Smuzhiyun 	return qla4xxx_show_boot_tgt_info(boot_sess, type, buf);
5880*4882a593Smuzhiyun }
5881*4882a593Smuzhiyun 
qla4xxx_tgt_get_attr_visibility(void * data,int type)5882*4882a593Smuzhiyun static umode_t qla4xxx_tgt_get_attr_visibility(void *data, int type)
5883*4882a593Smuzhiyun {
5884*4882a593Smuzhiyun 	int rc;
5885*4882a593Smuzhiyun 
5886*4882a593Smuzhiyun 	switch (type) {
5887*4882a593Smuzhiyun 	case ISCSI_BOOT_TGT_NAME:
5888*4882a593Smuzhiyun 	case ISCSI_BOOT_TGT_IP_ADDR:
5889*4882a593Smuzhiyun 	case ISCSI_BOOT_TGT_PORT:
5890*4882a593Smuzhiyun 	case ISCSI_BOOT_TGT_CHAP_NAME:
5891*4882a593Smuzhiyun 	case ISCSI_BOOT_TGT_CHAP_SECRET:
5892*4882a593Smuzhiyun 	case ISCSI_BOOT_TGT_REV_CHAP_NAME:
5893*4882a593Smuzhiyun 	case ISCSI_BOOT_TGT_REV_CHAP_SECRET:
5894*4882a593Smuzhiyun 	case ISCSI_BOOT_TGT_NIC_ASSOC:
5895*4882a593Smuzhiyun 	case ISCSI_BOOT_TGT_FLAGS:
5896*4882a593Smuzhiyun 		rc = S_IRUGO;
5897*4882a593Smuzhiyun 		break;
5898*4882a593Smuzhiyun 	default:
5899*4882a593Smuzhiyun 		rc = 0;
5900*4882a593Smuzhiyun 		break;
5901*4882a593Smuzhiyun 	}
5902*4882a593Smuzhiyun 	return rc;
5903*4882a593Smuzhiyun }
5904*4882a593Smuzhiyun 
qla4xxx_boot_release(void * data)5905*4882a593Smuzhiyun static void qla4xxx_boot_release(void *data)
5906*4882a593Smuzhiyun {
5907*4882a593Smuzhiyun 	struct scsi_qla_host *ha = data;
5908*4882a593Smuzhiyun 
5909*4882a593Smuzhiyun 	scsi_host_put(ha->host);
5910*4882a593Smuzhiyun }
5911*4882a593Smuzhiyun 
get_fw_boot_info(struct scsi_qla_host * ha,uint16_t ddb_index[])5912*4882a593Smuzhiyun static int get_fw_boot_info(struct scsi_qla_host *ha, uint16_t ddb_index[])
5913*4882a593Smuzhiyun {
5914*4882a593Smuzhiyun 	dma_addr_t buf_dma;
5915*4882a593Smuzhiyun 	uint32_t addr, pri_addr, sec_addr;
5916*4882a593Smuzhiyun 	uint32_t offset;
5917*4882a593Smuzhiyun 	uint16_t func_num;
5918*4882a593Smuzhiyun 	uint8_t val;
5919*4882a593Smuzhiyun 	uint8_t *buf = NULL;
5920*4882a593Smuzhiyun 	size_t size = 13 * sizeof(uint8_t);
5921*4882a593Smuzhiyun 	int ret = QLA_SUCCESS;
5922*4882a593Smuzhiyun 
5923*4882a593Smuzhiyun 	func_num = PCI_FUNC(ha->pdev->devfn);
5924*4882a593Smuzhiyun 
5925*4882a593Smuzhiyun 	ql4_printk(KERN_INFO, ha, "%s: Get FW boot info for 0x%x func %d\n",
5926*4882a593Smuzhiyun 		   __func__, ha->pdev->device, func_num);
5927*4882a593Smuzhiyun 
5928*4882a593Smuzhiyun 	if (is_qla40XX(ha)) {
5929*4882a593Smuzhiyun 		if (func_num == 1) {
5930*4882a593Smuzhiyun 			addr = NVRAM_PORT0_BOOT_MODE;
5931*4882a593Smuzhiyun 			pri_addr = NVRAM_PORT0_BOOT_PRI_TGT;
5932*4882a593Smuzhiyun 			sec_addr = NVRAM_PORT0_BOOT_SEC_TGT;
5933*4882a593Smuzhiyun 		} else if (func_num == 3) {
5934*4882a593Smuzhiyun 			addr = NVRAM_PORT1_BOOT_MODE;
5935*4882a593Smuzhiyun 			pri_addr = NVRAM_PORT1_BOOT_PRI_TGT;
5936*4882a593Smuzhiyun 			sec_addr = NVRAM_PORT1_BOOT_SEC_TGT;
5937*4882a593Smuzhiyun 		} else {
5938*4882a593Smuzhiyun 			ret = QLA_ERROR;
5939*4882a593Smuzhiyun 			goto exit_boot_info;
5940*4882a593Smuzhiyun 		}
5941*4882a593Smuzhiyun 
5942*4882a593Smuzhiyun 		/* Check Boot Mode */
5943*4882a593Smuzhiyun 		val = rd_nvram_byte(ha, addr);
5944*4882a593Smuzhiyun 		if (!(val & 0x07)) {
5945*4882a593Smuzhiyun 			DEBUG2(ql4_printk(KERN_INFO, ha, "%s: Adapter boot "
5946*4882a593Smuzhiyun 					  "options : 0x%x\n", __func__, val));
5947*4882a593Smuzhiyun 			ret = QLA_ERROR;
5948*4882a593Smuzhiyun 			goto exit_boot_info;
5949*4882a593Smuzhiyun 		}
5950*4882a593Smuzhiyun 
5951*4882a593Smuzhiyun 		/* get primary valid target index */
5952*4882a593Smuzhiyun 		val = rd_nvram_byte(ha, pri_addr);
5953*4882a593Smuzhiyun 		if (val & BIT_7)
5954*4882a593Smuzhiyun 			ddb_index[0] = (val & 0x7f);
5955*4882a593Smuzhiyun 
5956*4882a593Smuzhiyun 		/* get secondary valid target index */
5957*4882a593Smuzhiyun 		val = rd_nvram_byte(ha, sec_addr);
5958*4882a593Smuzhiyun 		if (val & BIT_7)
5959*4882a593Smuzhiyun 			ddb_index[1] = (val & 0x7f);
5960*4882a593Smuzhiyun 		goto exit_boot_info;
5961*4882a593Smuzhiyun 	} else if (is_qla80XX(ha)) {
5962*4882a593Smuzhiyun 		buf = dma_alloc_coherent(&ha->pdev->dev, size,
5963*4882a593Smuzhiyun 					 &buf_dma, GFP_KERNEL);
5964*4882a593Smuzhiyun 		if (!buf) {
5965*4882a593Smuzhiyun 			DEBUG2(ql4_printk(KERN_ERR, ha,
5966*4882a593Smuzhiyun 					  "%s: Unable to allocate dma buffer\n",
5967*4882a593Smuzhiyun 					   __func__));
5968*4882a593Smuzhiyun 			ret = QLA_ERROR;
5969*4882a593Smuzhiyun 			goto exit_boot_info;
5970*4882a593Smuzhiyun 		}
5971*4882a593Smuzhiyun 
5972*4882a593Smuzhiyun 		if (ha->port_num == 0)
5973*4882a593Smuzhiyun 			offset = BOOT_PARAM_OFFSET_PORT0;
5974*4882a593Smuzhiyun 		else if (ha->port_num == 1)
5975*4882a593Smuzhiyun 			offset = BOOT_PARAM_OFFSET_PORT1;
5976*4882a593Smuzhiyun 		else {
5977*4882a593Smuzhiyun 			ret = QLA_ERROR;
5978*4882a593Smuzhiyun 			goto exit_boot_info_free;
5979*4882a593Smuzhiyun 		}
5980*4882a593Smuzhiyun 		addr = FLASH_RAW_ACCESS_ADDR + (ha->hw.flt_iscsi_param * 4) +
5981*4882a593Smuzhiyun 		       offset;
5982*4882a593Smuzhiyun 		if (qla4xxx_get_flash(ha, buf_dma, addr,
5983*4882a593Smuzhiyun 				      13 * sizeof(uint8_t)) != QLA_SUCCESS) {
5984*4882a593Smuzhiyun 			DEBUG2(ql4_printk(KERN_ERR, ha, "scsi%ld: %s: Get Flash"
5985*4882a593Smuzhiyun 					  " failed\n", ha->host_no, __func__));
5986*4882a593Smuzhiyun 			ret = QLA_ERROR;
5987*4882a593Smuzhiyun 			goto exit_boot_info_free;
5988*4882a593Smuzhiyun 		}
5989*4882a593Smuzhiyun 		/* Check Boot Mode */
5990*4882a593Smuzhiyun 		if (!(buf[1] & 0x07)) {
5991*4882a593Smuzhiyun 			DEBUG2(ql4_printk(KERN_INFO, ha, "Firmware boot options"
5992*4882a593Smuzhiyun 					  " : 0x%x\n", buf[1]));
5993*4882a593Smuzhiyun 			ret = QLA_ERROR;
5994*4882a593Smuzhiyun 			goto exit_boot_info_free;
5995*4882a593Smuzhiyun 		}
5996*4882a593Smuzhiyun 
5997*4882a593Smuzhiyun 		/* get primary valid target index */
5998*4882a593Smuzhiyun 		if (buf[2] & BIT_7)
5999*4882a593Smuzhiyun 			ddb_index[0] = buf[2] & 0x7f;
6000*4882a593Smuzhiyun 
6001*4882a593Smuzhiyun 		/* get secondary valid target index */
6002*4882a593Smuzhiyun 		if (buf[11] & BIT_7)
6003*4882a593Smuzhiyun 			ddb_index[1] = buf[11] & 0x7f;
6004*4882a593Smuzhiyun 	} else {
6005*4882a593Smuzhiyun 		ret = QLA_ERROR;
6006*4882a593Smuzhiyun 		goto exit_boot_info;
6007*4882a593Smuzhiyun 	}
6008*4882a593Smuzhiyun 
6009*4882a593Smuzhiyun 	DEBUG2(ql4_printk(KERN_INFO, ha, "%s: Primary target ID %d, Secondary"
6010*4882a593Smuzhiyun 			  " target ID %d\n", __func__, ddb_index[0],
6011*4882a593Smuzhiyun 			  ddb_index[1]));
6012*4882a593Smuzhiyun 
6013*4882a593Smuzhiyun exit_boot_info_free:
6014*4882a593Smuzhiyun 	dma_free_coherent(&ha->pdev->dev, size, buf, buf_dma);
6015*4882a593Smuzhiyun exit_boot_info:
6016*4882a593Smuzhiyun 	ha->pri_ddb_idx = ddb_index[0];
6017*4882a593Smuzhiyun 	ha->sec_ddb_idx = ddb_index[1];
6018*4882a593Smuzhiyun 	return ret;
6019*4882a593Smuzhiyun }
6020*4882a593Smuzhiyun 
6021*4882a593Smuzhiyun /**
6022*4882a593Smuzhiyun  * qla4xxx_get_bidi_chap - Get a BIDI CHAP user and password
6023*4882a593Smuzhiyun  * @ha: pointer to adapter structure
6024*4882a593Smuzhiyun  * @username: CHAP username to be returned
6025*4882a593Smuzhiyun  * @password: CHAP password to be returned
6026*4882a593Smuzhiyun  *
6027*4882a593Smuzhiyun  * If a boot entry has BIDI CHAP enabled then we need to set the BIDI CHAP
6028*4882a593Smuzhiyun  * user and password in the sysfs entry in /sys/firmware/iscsi_boot#/.
6029*4882a593Smuzhiyun  * So from the CHAP cache find the first BIDI CHAP entry and set it
6030*4882a593Smuzhiyun  * to the boot record in sysfs.
6031*4882a593Smuzhiyun  **/
qla4xxx_get_bidi_chap(struct scsi_qla_host * ha,char * username,char * password)6032*4882a593Smuzhiyun static int qla4xxx_get_bidi_chap(struct scsi_qla_host *ha, char *username,
6033*4882a593Smuzhiyun 			    char *password)
6034*4882a593Smuzhiyun {
6035*4882a593Smuzhiyun 	int i, ret = -EINVAL;
6036*4882a593Smuzhiyun 	int max_chap_entries = 0;
6037*4882a593Smuzhiyun 	struct ql4_chap_table *chap_table;
6038*4882a593Smuzhiyun 
6039*4882a593Smuzhiyun 	if (is_qla80XX(ha))
6040*4882a593Smuzhiyun 		max_chap_entries = (ha->hw.flt_chap_size / 2) /
6041*4882a593Smuzhiyun 						sizeof(struct ql4_chap_table);
6042*4882a593Smuzhiyun 	else
6043*4882a593Smuzhiyun 		max_chap_entries = MAX_CHAP_ENTRIES_40XX;
6044*4882a593Smuzhiyun 
6045*4882a593Smuzhiyun 	if (!ha->chap_list) {
6046*4882a593Smuzhiyun 		ql4_printk(KERN_ERR, ha, "Do not have CHAP table cache\n");
6047*4882a593Smuzhiyun 		return ret;
6048*4882a593Smuzhiyun 	}
6049*4882a593Smuzhiyun 
6050*4882a593Smuzhiyun 	mutex_lock(&ha->chap_sem);
6051*4882a593Smuzhiyun 	for (i = 0; i < max_chap_entries; i++) {
6052*4882a593Smuzhiyun 		chap_table = (struct ql4_chap_table *)ha->chap_list + i;
6053*4882a593Smuzhiyun 		if (chap_table->cookie !=
6054*4882a593Smuzhiyun 		    __constant_cpu_to_le16(CHAP_VALID_COOKIE)) {
6055*4882a593Smuzhiyun 			continue;
6056*4882a593Smuzhiyun 		}
6057*4882a593Smuzhiyun 
6058*4882a593Smuzhiyun 		if (chap_table->flags & BIT_7) /* local */
6059*4882a593Smuzhiyun 			continue;
6060*4882a593Smuzhiyun 
6061*4882a593Smuzhiyun 		if (!(chap_table->flags & BIT_6)) /* Not BIDI */
6062*4882a593Smuzhiyun 			continue;
6063*4882a593Smuzhiyun 
6064*4882a593Smuzhiyun 		strlcpy(password, chap_table->secret, QL4_CHAP_MAX_SECRET_LEN);
6065*4882a593Smuzhiyun 		strlcpy(username, chap_table->name, QL4_CHAP_MAX_NAME_LEN);
6066*4882a593Smuzhiyun 		ret = 0;
6067*4882a593Smuzhiyun 		break;
6068*4882a593Smuzhiyun 	}
6069*4882a593Smuzhiyun 	mutex_unlock(&ha->chap_sem);
6070*4882a593Smuzhiyun 
6071*4882a593Smuzhiyun 	return ret;
6072*4882a593Smuzhiyun }
6073*4882a593Smuzhiyun 
6074*4882a593Smuzhiyun 
qla4xxx_get_boot_target(struct scsi_qla_host * ha,struct ql4_boot_session_info * boot_sess,uint16_t ddb_index)6075*4882a593Smuzhiyun static int qla4xxx_get_boot_target(struct scsi_qla_host *ha,
6076*4882a593Smuzhiyun 				   struct ql4_boot_session_info *boot_sess,
6077*4882a593Smuzhiyun 				   uint16_t ddb_index)
6078*4882a593Smuzhiyun {
6079*4882a593Smuzhiyun 	struct ql4_conn_info *boot_conn = &boot_sess->conn_list[0];
6080*4882a593Smuzhiyun 	struct dev_db_entry *fw_ddb_entry;
6081*4882a593Smuzhiyun 	dma_addr_t fw_ddb_entry_dma;
6082*4882a593Smuzhiyun 	uint16_t idx;
6083*4882a593Smuzhiyun 	uint16_t options;
6084*4882a593Smuzhiyun 	int ret = QLA_SUCCESS;
6085*4882a593Smuzhiyun 
6086*4882a593Smuzhiyun 	fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
6087*4882a593Smuzhiyun 					  &fw_ddb_entry_dma, GFP_KERNEL);
6088*4882a593Smuzhiyun 	if (!fw_ddb_entry) {
6089*4882a593Smuzhiyun 		DEBUG2(ql4_printk(KERN_ERR, ha,
6090*4882a593Smuzhiyun 				  "%s: Unable to allocate dma buffer.\n",
6091*4882a593Smuzhiyun 				  __func__));
6092*4882a593Smuzhiyun 		ret = QLA_ERROR;
6093*4882a593Smuzhiyun 		return ret;
6094*4882a593Smuzhiyun 	}
6095*4882a593Smuzhiyun 
6096*4882a593Smuzhiyun 	if (qla4xxx_bootdb_by_index(ha, fw_ddb_entry,
6097*4882a593Smuzhiyun 				   fw_ddb_entry_dma, ddb_index)) {
6098*4882a593Smuzhiyun 		DEBUG2(ql4_printk(KERN_INFO, ha, "%s: No Flash DDB found at "
6099*4882a593Smuzhiyun 				  "index [%d]\n", __func__, ddb_index));
6100*4882a593Smuzhiyun 		ret = QLA_ERROR;
6101*4882a593Smuzhiyun 		goto exit_boot_target;
6102*4882a593Smuzhiyun 	}
6103*4882a593Smuzhiyun 
6104*4882a593Smuzhiyun 	/* Update target name and IP from DDB */
6105*4882a593Smuzhiyun 	memcpy(boot_sess->target_name, fw_ddb_entry->iscsi_name,
6106*4882a593Smuzhiyun 	       min(sizeof(boot_sess->target_name),
6107*4882a593Smuzhiyun 		   sizeof(fw_ddb_entry->iscsi_name)));
6108*4882a593Smuzhiyun 
6109*4882a593Smuzhiyun 	options = le16_to_cpu(fw_ddb_entry->options);
6110*4882a593Smuzhiyun 	if (options & DDB_OPT_IPV6_DEVICE) {
6111*4882a593Smuzhiyun 		memcpy(&boot_conn->dest_ipaddr.ip_address,
6112*4882a593Smuzhiyun 		       &fw_ddb_entry->ip_addr[0], IPv6_ADDR_LEN);
6113*4882a593Smuzhiyun 	} else {
6114*4882a593Smuzhiyun 		boot_conn->dest_ipaddr.ip_type = 0x1;
6115*4882a593Smuzhiyun 		memcpy(&boot_conn->dest_ipaddr.ip_address,
6116*4882a593Smuzhiyun 		       &fw_ddb_entry->ip_addr[0], IP_ADDR_LEN);
6117*4882a593Smuzhiyun 	}
6118*4882a593Smuzhiyun 
6119*4882a593Smuzhiyun 	boot_conn->dest_port = le16_to_cpu(fw_ddb_entry->port);
6120*4882a593Smuzhiyun 
6121*4882a593Smuzhiyun 	/* update chap information */
6122*4882a593Smuzhiyun 	idx = __le16_to_cpu(fw_ddb_entry->chap_tbl_idx);
6123*4882a593Smuzhiyun 
6124*4882a593Smuzhiyun 	if (BIT_7 & le16_to_cpu(fw_ddb_entry->iscsi_options))	{
6125*4882a593Smuzhiyun 
6126*4882a593Smuzhiyun 		DEBUG2(ql4_printk(KERN_INFO, ha, "Setting chap\n"));
6127*4882a593Smuzhiyun 
6128*4882a593Smuzhiyun 		ret = qla4xxx_get_chap(ha, (char *)&boot_conn->chap.
6129*4882a593Smuzhiyun 				       target_chap_name,
6130*4882a593Smuzhiyun 				       (char *)&boot_conn->chap.target_secret,
6131*4882a593Smuzhiyun 				       idx);
6132*4882a593Smuzhiyun 		if (ret) {
6133*4882a593Smuzhiyun 			ql4_printk(KERN_ERR, ha, "Failed to set chap\n");
6134*4882a593Smuzhiyun 			ret = QLA_ERROR;
6135*4882a593Smuzhiyun 			goto exit_boot_target;
6136*4882a593Smuzhiyun 		}
6137*4882a593Smuzhiyun 
6138*4882a593Smuzhiyun 		boot_conn->chap.target_chap_name_length = QL4_CHAP_MAX_NAME_LEN;
6139*4882a593Smuzhiyun 		boot_conn->chap.target_secret_length = QL4_CHAP_MAX_SECRET_LEN;
6140*4882a593Smuzhiyun 	}
6141*4882a593Smuzhiyun 
6142*4882a593Smuzhiyun 	if (BIT_4 & le16_to_cpu(fw_ddb_entry->iscsi_options)) {
6143*4882a593Smuzhiyun 
6144*4882a593Smuzhiyun 		DEBUG2(ql4_printk(KERN_INFO, ha, "Setting BIDI chap\n"));
6145*4882a593Smuzhiyun 
6146*4882a593Smuzhiyun 		ret = qla4xxx_get_bidi_chap(ha,
6147*4882a593Smuzhiyun 				    (char *)&boot_conn->chap.intr_chap_name,
6148*4882a593Smuzhiyun 				    (char *)&boot_conn->chap.intr_secret);
6149*4882a593Smuzhiyun 
6150*4882a593Smuzhiyun 		if (ret) {
6151*4882a593Smuzhiyun 			ql4_printk(KERN_ERR, ha, "Failed to set BIDI chap\n");
6152*4882a593Smuzhiyun 			ret = QLA_ERROR;
6153*4882a593Smuzhiyun 			goto exit_boot_target;
6154*4882a593Smuzhiyun 		}
6155*4882a593Smuzhiyun 
6156*4882a593Smuzhiyun 		boot_conn->chap.intr_chap_name_length = QL4_CHAP_MAX_NAME_LEN;
6157*4882a593Smuzhiyun 		boot_conn->chap.intr_secret_length = QL4_CHAP_MAX_SECRET_LEN;
6158*4882a593Smuzhiyun 	}
6159*4882a593Smuzhiyun 
6160*4882a593Smuzhiyun exit_boot_target:
6161*4882a593Smuzhiyun 	dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
6162*4882a593Smuzhiyun 			  fw_ddb_entry, fw_ddb_entry_dma);
6163*4882a593Smuzhiyun 	return ret;
6164*4882a593Smuzhiyun }
6165*4882a593Smuzhiyun 
qla4xxx_get_boot_info(struct scsi_qla_host * ha)6166*4882a593Smuzhiyun static int qla4xxx_get_boot_info(struct scsi_qla_host *ha)
6167*4882a593Smuzhiyun {
6168*4882a593Smuzhiyun 	uint16_t ddb_index[2];
6169*4882a593Smuzhiyun 	int ret = QLA_ERROR;
6170*4882a593Smuzhiyun 	int rval;
6171*4882a593Smuzhiyun 
6172*4882a593Smuzhiyun 	memset(ddb_index, 0, sizeof(ddb_index));
6173*4882a593Smuzhiyun 	ddb_index[0] = 0xffff;
6174*4882a593Smuzhiyun 	ddb_index[1] = 0xffff;
6175*4882a593Smuzhiyun 	ret = get_fw_boot_info(ha, ddb_index);
6176*4882a593Smuzhiyun 	if (ret != QLA_SUCCESS) {
6177*4882a593Smuzhiyun 		DEBUG2(ql4_printk(KERN_INFO, ha,
6178*4882a593Smuzhiyun 				"%s: No boot target configured.\n", __func__));
6179*4882a593Smuzhiyun 		return ret;
6180*4882a593Smuzhiyun 	}
6181*4882a593Smuzhiyun 
6182*4882a593Smuzhiyun 	if (ql4xdisablesysfsboot)
6183*4882a593Smuzhiyun 		return QLA_SUCCESS;
6184*4882a593Smuzhiyun 
6185*4882a593Smuzhiyun 	if (ddb_index[0] == 0xffff)
6186*4882a593Smuzhiyun 		goto sec_target;
6187*4882a593Smuzhiyun 
6188*4882a593Smuzhiyun 	rval = qla4xxx_get_boot_target(ha, &(ha->boot_tgt.boot_pri_sess),
6189*4882a593Smuzhiyun 				      ddb_index[0]);
6190*4882a593Smuzhiyun 	if (rval != QLA_SUCCESS) {
6191*4882a593Smuzhiyun 		DEBUG2(ql4_printk(KERN_INFO, ha, "%s: Primary boot target not "
6192*4882a593Smuzhiyun 				  "configured\n", __func__));
6193*4882a593Smuzhiyun 	} else
6194*4882a593Smuzhiyun 		ret = QLA_SUCCESS;
6195*4882a593Smuzhiyun 
6196*4882a593Smuzhiyun sec_target:
6197*4882a593Smuzhiyun 	if (ddb_index[1] == 0xffff)
6198*4882a593Smuzhiyun 		goto exit_get_boot_info;
6199*4882a593Smuzhiyun 
6200*4882a593Smuzhiyun 	rval = qla4xxx_get_boot_target(ha, &(ha->boot_tgt.boot_sec_sess),
6201*4882a593Smuzhiyun 				      ddb_index[1]);
6202*4882a593Smuzhiyun 	if (rval != QLA_SUCCESS) {
6203*4882a593Smuzhiyun 		DEBUG2(ql4_printk(KERN_INFO, ha, "%s: Secondary boot target not"
6204*4882a593Smuzhiyun 				  " configured\n", __func__));
6205*4882a593Smuzhiyun 	} else
6206*4882a593Smuzhiyun 		ret = QLA_SUCCESS;
6207*4882a593Smuzhiyun 
6208*4882a593Smuzhiyun exit_get_boot_info:
6209*4882a593Smuzhiyun 	return ret;
6210*4882a593Smuzhiyun }
6211*4882a593Smuzhiyun 
qla4xxx_setup_boot_info(struct scsi_qla_host * ha)6212*4882a593Smuzhiyun static int qla4xxx_setup_boot_info(struct scsi_qla_host *ha)
6213*4882a593Smuzhiyun {
6214*4882a593Smuzhiyun 	struct iscsi_boot_kobj *boot_kobj;
6215*4882a593Smuzhiyun 
6216*4882a593Smuzhiyun 	if (qla4xxx_get_boot_info(ha) != QLA_SUCCESS)
6217*4882a593Smuzhiyun 		return QLA_ERROR;
6218*4882a593Smuzhiyun 
6219*4882a593Smuzhiyun 	if (ql4xdisablesysfsboot) {
6220*4882a593Smuzhiyun 		ql4_printk(KERN_INFO, ha,
6221*4882a593Smuzhiyun 			   "%s: syfsboot disabled - driver will trigger login "
6222*4882a593Smuzhiyun 			   "and publish session for discovery .\n", __func__);
6223*4882a593Smuzhiyun 		return QLA_SUCCESS;
6224*4882a593Smuzhiyun 	}
6225*4882a593Smuzhiyun 
6226*4882a593Smuzhiyun 
6227*4882a593Smuzhiyun 	ha->boot_kset = iscsi_boot_create_host_kset(ha->host->host_no);
6228*4882a593Smuzhiyun 	if (!ha->boot_kset)
6229*4882a593Smuzhiyun 		goto kset_free;
6230*4882a593Smuzhiyun 
6231*4882a593Smuzhiyun 	if (!scsi_host_get(ha->host))
6232*4882a593Smuzhiyun 		goto kset_free;
6233*4882a593Smuzhiyun 	boot_kobj = iscsi_boot_create_target(ha->boot_kset, 0, ha,
6234*4882a593Smuzhiyun 					     qla4xxx_show_boot_tgt_pri_info,
6235*4882a593Smuzhiyun 					     qla4xxx_tgt_get_attr_visibility,
6236*4882a593Smuzhiyun 					     qla4xxx_boot_release);
6237*4882a593Smuzhiyun 	if (!boot_kobj)
6238*4882a593Smuzhiyun 		goto put_host;
6239*4882a593Smuzhiyun 
6240*4882a593Smuzhiyun 	if (!scsi_host_get(ha->host))
6241*4882a593Smuzhiyun 		goto kset_free;
6242*4882a593Smuzhiyun 	boot_kobj = iscsi_boot_create_target(ha->boot_kset, 1, ha,
6243*4882a593Smuzhiyun 					     qla4xxx_show_boot_tgt_sec_info,
6244*4882a593Smuzhiyun 					     qla4xxx_tgt_get_attr_visibility,
6245*4882a593Smuzhiyun 					     qla4xxx_boot_release);
6246*4882a593Smuzhiyun 	if (!boot_kobj)
6247*4882a593Smuzhiyun 		goto put_host;
6248*4882a593Smuzhiyun 
6249*4882a593Smuzhiyun 	if (!scsi_host_get(ha->host))
6250*4882a593Smuzhiyun 		goto kset_free;
6251*4882a593Smuzhiyun 	boot_kobj = iscsi_boot_create_initiator(ha->boot_kset, 0, ha,
6252*4882a593Smuzhiyun 					       qla4xxx_show_boot_ini_info,
6253*4882a593Smuzhiyun 					       qla4xxx_ini_get_attr_visibility,
6254*4882a593Smuzhiyun 					       qla4xxx_boot_release);
6255*4882a593Smuzhiyun 	if (!boot_kobj)
6256*4882a593Smuzhiyun 		goto put_host;
6257*4882a593Smuzhiyun 
6258*4882a593Smuzhiyun 	if (!scsi_host_get(ha->host))
6259*4882a593Smuzhiyun 		goto kset_free;
6260*4882a593Smuzhiyun 	boot_kobj = iscsi_boot_create_ethernet(ha->boot_kset, 0, ha,
6261*4882a593Smuzhiyun 					       qla4xxx_show_boot_eth_info,
6262*4882a593Smuzhiyun 					       qla4xxx_eth_get_attr_visibility,
6263*4882a593Smuzhiyun 					       qla4xxx_boot_release);
6264*4882a593Smuzhiyun 	if (!boot_kobj)
6265*4882a593Smuzhiyun 		goto put_host;
6266*4882a593Smuzhiyun 
6267*4882a593Smuzhiyun 	return QLA_SUCCESS;
6268*4882a593Smuzhiyun 
6269*4882a593Smuzhiyun put_host:
6270*4882a593Smuzhiyun 	scsi_host_put(ha->host);
6271*4882a593Smuzhiyun kset_free:
6272*4882a593Smuzhiyun 	iscsi_boot_destroy_kset(ha->boot_kset);
6273*4882a593Smuzhiyun 	return -ENOMEM;
6274*4882a593Smuzhiyun }
6275*4882a593Smuzhiyun 
6276*4882a593Smuzhiyun 
qla4xxx_get_param_ddb(struct ddb_entry * ddb_entry,struct ql4_tuple_ddb * tddb)6277*4882a593Smuzhiyun static void qla4xxx_get_param_ddb(struct ddb_entry *ddb_entry,
6278*4882a593Smuzhiyun 				  struct ql4_tuple_ddb *tddb)
6279*4882a593Smuzhiyun {
6280*4882a593Smuzhiyun 	struct iscsi_cls_session *cls_sess;
6281*4882a593Smuzhiyun 	struct iscsi_cls_conn *cls_conn;
6282*4882a593Smuzhiyun 	struct iscsi_session *sess;
6283*4882a593Smuzhiyun 	struct iscsi_conn *conn;
6284*4882a593Smuzhiyun 
6285*4882a593Smuzhiyun 	DEBUG2(printk(KERN_INFO "Func: %s\n", __func__));
6286*4882a593Smuzhiyun 	cls_sess = ddb_entry->sess;
6287*4882a593Smuzhiyun 	sess = cls_sess->dd_data;
6288*4882a593Smuzhiyun 	cls_conn = ddb_entry->conn;
6289*4882a593Smuzhiyun 	conn = cls_conn->dd_data;
6290*4882a593Smuzhiyun 
6291*4882a593Smuzhiyun 	tddb->tpgt = sess->tpgt;
6292*4882a593Smuzhiyun 	tddb->port = conn->persistent_port;
6293*4882a593Smuzhiyun 	strlcpy(tddb->iscsi_name, sess->targetname, ISCSI_NAME_SIZE);
6294*4882a593Smuzhiyun 	strlcpy(tddb->ip_addr, conn->persistent_address, DDB_IPADDR_LEN);
6295*4882a593Smuzhiyun }
6296*4882a593Smuzhiyun 
qla4xxx_convert_param_ddb(struct dev_db_entry * fw_ddb_entry,struct ql4_tuple_ddb * tddb,uint8_t * flash_isid)6297*4882a593Smuzhiyun static void qla4xxx_convert_param_ddb(struct dev_db_entry *fw_ddb_entry,
6298*4882a593Smuzhiyun 				      struct ql4_tuple_ddb *tddb,
6299*4882a593Smuzhiyun 				      uint8_t *flash_isid)
6300*4882a593Smuzhiyun {
6301*4882a593Smuzhiyun 	uint16_t options = 0;
6302*4882a593Smuzhiyun 
6303*4882a593Smuzhiyun 	tddb->tpgt = le32_to_cpu(fw_ddb_entry->tgt_portal_grp);
6304*4882a593Smuzhiyun 	memcpy(&tddb->iscsi_name[0], &fw_ddb_entry->iscsi_name[0],
6305*4882a593Smuzhiyun 	       min(sizeof(tddb->iscsi_name), sizeof(fw_ddb_entry->iscsi_name)));
6306*4882a593Smuzhiyun 
6307*4882a593Smuzhiyun 	options = le16_to_cpu(fw_ddb_entry->options);
6308*4882a593Smuzhiyun 	if (options & DDB_OPT_IPV6_DEVICE)
6309*4882a593Smuzhiyun 		sprintf(tddb->ip_addr, "%pI6", fw_ddb_entry->ip_addr);
6310*4882a593Smuzhiyun 	else
6311*4882a593Smuzhiyun 		sprintf(tddb->ip_addr, "%pI4", fw_ddb_entry->ip_addr);
6312*4882a593Smuzhiyun 
6313*4882a593Smuzhiyun 	tddb->port = le16_to_cpu(fw_ddb_entry->port);
6314*4882a593Smuzhiyun 
6315*4882a593Smuzhiyun 	if (flash_isid == NULL)
6316*4882a593Smuzhiyun 		memcpy(&tddb->isid[0], &fw_ddb_entry->isid[0],
6317*4882a593Smuzhiyun 		       sizeof(tddb->isid));
6318*4882a593Smuzhiyun 	else
6319*4882a593Smuzhiyun 		memcpy(&tddb->isid[0], &flash_isid[0], sizeof(tddb->isid));
6320*4882a593Smuzhiyun }
6321*4882a593Smuzhiyun 
qla4xxx_compare_tuple_ddb(struct scsi_qla_host * ha,struct ql4_tuple_ddb * old_tddb,struct ql4_tuple_ddb * new_tddb,uint8_t is_isid_compare)6322*4882a593Smuzhiyun static int qla4xxx_compare_tuple_ddb(struct scsi_qla_host *ha,
6323*4882a593Smuzhiyun 				     struct ql4_tuple_ddb *old_tddb,
6324*4882a593Smuzhiyun 				     struct ql4_tuple_ddb *new_tddb,
6325*4882a593Smuzhiyun 				     uint8_t is_isid_compare)
6326*4882a593Smuzhiyun {
6327*4882a593Smuzhiyun 	if (strcmp(old_tddb->iscsi_name, new_tddb->iscsi_name))
6328*4882a593Smuzhiyun 		return QLA_ERROR;
6329*4882a593Smuzhiyun 
6330*4882a593Smuzhiyun 	if (strcmp(old_tddb->ip_addr, new_tddb->ip_addr))
6331*4882a593Smuzhiyun 		return QLA_ERROR;
6332*4882a593Smuzhiyun 
6333*4882a593Smuzhiyun 	if (old_tddb->port != new_tddb->port)
6334*4882a593Smuzhiyun 		return QLA_ERROR;
6335*4882a593Smuzhiyun 
6336*4882a593Smuzhiyun 	/* For multi sessions, driver generates the ISID, so do not compare
6337*4882a593Smuzhiyun 	 * ISID in reset path since it would be a comparison between the
6338*4882a593Smuzhiyun 	 * driver generated ISID and firmware generated ISID. This could
6339*4882a593Smuzhiyun 	 * lead to adding duplicated DDBs in the list as driver generated
6340*4882a593Smuzhiyun 	 * ISID would not match firmware generated ISID.
6341*4882a593Smuzhiyun 	 */
6342*4882a593Smuzhiyun 	if (is_isid_compare) {
6343*4882a593Smuzhiyun 		DEBUG2(ql4_printk(KERN_INFO, ha,
6344*4882a593Smuzhiyun 			"%s: old ISID [%pmR] New ISID [%pmR]\n",
6345*4882a593Smuzhiyun 			__func__, old_tddb->isid, new_tddb->isid));
6346*4882a593Smuzhiyun 
6347*4882a593Smuzhiyun 		if (memcmp(&old_tddb->isid[0], &new_tddb->isid[0],
6348*4882a593Smuzhiyun 			   sizeof(old_tddb->isid)))
6349*4882a593Smuzhiyun 			return QLA_ERROR;
6350*4882a593Smuzhiyun 	}
6351*4882a593Smuzhiyun 
6352*4882a593Smuzhiyun 	DEBUG2(ql4_printk(KERN_INFO, ha,
6353*4882a593Smuzhiyun 			  "Match Found, fw[%d,%d,%s,%s], [%d,%d,%s,%s]",
6354*4882a593Smuzhiyun 			  old_tddb->port, old_tddb->tpgt, old_tddb->ip_addr,
6355*4882a593Smuzhiyun 			  old_tddb->iscsi_name, new_tddb->port, new_tddb->tpgt,
6356*4882a593Smuzhiyun 			  new_tddb->ip_addr, new_tddb->iscsi_name));
6357*4882a593Smuzhiyun 
6358*4882a593Smuzhiyun 	return QLA_SUCCESS;
6359*4882a593Smuzhiyun }
6360*4882a593Smuzhiyun 
qla4xxx_is_session_exists(struct scsi_qla_host * ha,struct dev_db_entry * fw_ddb_entry,uint32_t * index)6361*4882a593Smuzhiyun static int qla4xxx_is_session_exists(struct scsi_qla_host *ha,
6362*4882a593Smuzhiyun 				     struct dev_db_entry *fw_ddb_entry,
6363*4882a593Smuzhiyun 				     uint32_t *index)
6364*4882a593Smuzhiyun {
6365*4882a593Smuzhiyun 	struct ddb_entry *ddb_entry;
6366*4882a593Smuzhiyun 	struct ql4_tuple_ddb *fw_tddb = NULL;
6367*4882a593Smuzhiyun 	struct ql4_tuple_ddb *tmp_tddb = NULL;
6368*4882a593Smuzhiyun 	int idx;
6369*4882a593Smuzhiyun 	int ret = QLA_ERROR;
6370*4882a593Smuzhiyun 
6371*4882a593Smuzhiyun 	fw_tddb = vzalloc(sizeof(*fw_tddb));
6372*4882a593Smuzhiyun 	if (!fw_tddb) {
6373*4882a593Smuzhiyun 		DEBUG2(ql4_printk(KERN_WARNING, ha,
6374*4882a593Smuzhiyun 				  "Memory Allocation failed.\n"));
6375*4882a593Smuzhiyun 		ret = QLA_SUCCESS;
6376*4882a593Smuzhiyun 		goto exit_check;
6377*4882a593Smuzhiyun 	}
6378*4882a593Smuzhiyun 
6379*4882a593Smuzhiyun 	tmp_tddb = vzalloc(sizeof(*tmp_tddb));
6380*4882a593Smuzhiyun 	if (!tmp_tddb) {
6381*4882a593Smuzhiyun 		DEBUG2(ql4_printk(KERN_WARNING, ha,
6382*4882a593Smuzhiyun 				  "Memory Allocation failed.\n"));
6383*4882a593Smuzhiyun 		ret = QLA_SUCCESS;
6384*4882a593Smuzhiyun 		goto exit_check;
6385*4882a593Smuzhiyun 	}
6386*4882a593Smuzhiyun 
6387*4882a593Smuzhiyun 	qla4xxx_convert_param_ddb(fw_ddb_entry, fw_tddb, NULL);
6388*4882a593Smuzhiyun 
6389*4882a593Smuzhiyun 	for (idx = 0; idx < MAX_DDB_ENTRIES; idx++) {
6390*4882a593Smuzhiyun 		ddb_entry = qla4xxx_lookup_ddb_by_fw_index(ha, idx);
6391*4882a593Smuzhiyun 		if (ddb_entry == NULL)
6392*4882a593Smuzhiyun 			continue;
6393*4882a593Smuzhiyun 
6394*4882a593Smuzhiyun 		qla4xxx_get_param_ddb(ddb_entry, tmp_tddb);
6395*4882a593Smuzhiyun 		if (!qla4xxx_compare_tuple_ddb(ha, fw_tddb, tmp_tddb, false)) {
6396*4882a593Smuzhiyun 			ret = QLA_SUCCESS; /* found */
6397*4882a593Smuzhiyun 			if (index != NULL)
6398*4882a593Smuzhiyun 				*index = idx;
6399*4882a593Smuzhiyun 			goto exit_check;
6400*4882a593Smuzhiyun 		}
6401*4882a593Smuzhiyun 	}
6402*4882a593Smuzhiyun 
6403*4882a593Smuzhiyun exit_check:
6404*4882a593Smuzhiyun 	if (fw_tddb)
6405*4882a593Smuzhiyun 		vfree(fw_tddb);
6406*4882a593Smuzhiyun 	if (tmp_tddb)
6407*4882a593Smuzhiyun 		vfree(tmp_tddb);
6408*4882a593Smuzhiyun 	return ret;
6409*4882a593Smuzhiyun }
6410*4882a593Smuzhiyun 
6411*4882a593Smuzhiyun /**
6412*4882a593Smuzhiyun  * qla4xxx_check_existing_isid - check if target with same isid exist
6413*4882a593Smuzhiyun  *				 in target list
6414*4882a593Smuzhiyun  * @list_nt: list of target
6415*4882a593Smuzhiyun  * @isid: isid to check
6416*4882a593Smuzhiyun  *
6417*4882a593Smuzhiyun  * This routine return QLA_SUCCESS if target with same isid exist
6418*4882a593Smuzhiyun  **/
qla4xxx_check_existing_isid(struct list_head * list_nt,uint8_t * isid)6419*4882a593Smuzhiyun static int qla4xxx_check_existing_isid(struct list_head *list_nt, uint8_t *isid)
6420*4882a593Smuzhiyun {
6421*4882a593Smuzhiyun 	struct qla_ddb_index *nt_ddb_idx, *nt_ddb_idx_tmp;
6422*4882a593Smuzhiyun 	struct dev_db_entry *fw_ddb_entry;
6423*4882a593Smuzhiyun 
6424*4882a593Smuzhiyun 	list_for_each_entry_safe(nt_ddb_idx, nt_ddb_idx_tmp, list_nt, list) {
6425*4882a593Smuzhiyun 		fw_ddb_entry = &nt_ddb_idx->fw_ddb;
6426*4882a593Smuzhiyun 
6427*4882a593Smuzhiyun 		if (memcmp(&fw_ddb_entry->isid[0], &isid[0],
6428*4882a593Smuzhiyun 			   sizeof(nt_ddb_idx->fw_ddb.isid)) == 0) {
6429*4882a593Smuzhiyun 			return QLA_SUCCESS;
6430*4882a593Smuzhiyun 		}
6431*4882a593Smuzhiyun 	}
6432*4882a593Smuzhiyun 	return QLA_ERROR;
6433*4882a593Smuzhiyun }
6434*4882a593Smuzhiyun 
6435*4882a593Smuzhiyun /**
6436*4882a593Smuzhiyun  * qla4xxx_update_isid - compare ddbs and updated isid
6437*4882a593Smuzhiyun  * @ha: Pointer to host adapter structure.
6438*4882a593Smuzhiyun  * @list_nt: list of nt target
6439*4882a593Smuzhiyun  * @fw_ddb_entry: firmware ddb entry
6440*4882a593Smuzhiyun  *
6441*4882a593Smuzhiyun  * This routine update isid if ddbs have same iqn, same isid and
6442*4882a593Smuzhiyun  * different IP addr.
6443*4882a593Smuzhiyun  * Return QLA_SUCCESS if isid is updated.
6444*4882a593Smuzhiyun  **/
qla4xxx_update_isid(struct scsi_qla_host * ha,struct list_head * list_nt,struct dev_db_entry * fw_ddb_entry)6445*4882a593Smuzhiyun static int qla4xxx_update_isid(struct scsi_qla_host *ha,
6446*4882a593Smuzhiyun 			       struct list_head *list_nt,
6447*4882a593Smuzhiyun 			       struct dev_db_entry *fw_ddb_entry)
6448*4882a593Smuzhiyun {
6449*4882a593Smuzhiyun 	uint8_t base_value, i;
6450*4882a593Smuzhiyun 
6451*4882a593Smuzhiyun 	base_value = fw_ddb_entry->isid[1] & 0x1f;
6452*4882a593Smuzhiyun 	for (i = 0; i < 8; i++) {
6453*4882a593Smuzhiyun 		fw_ddb_entry->isid[1] = (base_value | (i << 5));
6454*4882a593Smuzhiyun 		if (qla4xxx_check_existing_isid(list_nt, fw_ddb_entry->isid))
6455*4882a593Smuzhiyun 			break;
6456*4882a593Smuzhiyun 	}
6457*4882a593Smuzhiyun 
6458*4882a593Smuzhiyun 	if (!qla4xxx_check_existing_isid(list_nt, fw_ddb_entry->isid))
6459*4882a593Smuzhiyun 		return QLA_ERROR;
6460*4882a593Smuzhiyun 
6461*4882a593Smuzhiyun 	return QLA_SUCCESS;
6462*4882a593Smuzhiyun }
6463*4882a593Smuzhiyun 
6464*4882a593Smuzhiyun /**
6465*4882a593Smuzhiyun  * qla4xxx_should_update_isid - check if isid need to update
6466*4882a593Smuzhiyun  * @ha: Pointer to host adapter structure.
6467*4882a593Smuzhiyun  * @old_tddb: ddb tuple
6468*4882a593Smuzhiyun  * @new_tddb: ddb tuple
6469*4882a593Smuzhiyun  *
6470*4882a593Smuzhiyun  * Return QLA_SUCCESS if different IP, different PORT, same iqn,
6471*4882a593Smuzhiyun  * same isid
6472*4882a593Smuzhiyun  **/
qla4xxx_should_update_isid(struct scsi_qla_host * ha,struct ql4_tuple_ddb * old_tddb,struct ql4_tuple_ddb * new_tddb)6473*4882a593Smuzhiyun static int qla4xxx_should_update_isid(struct scsi_qla_host *ha,
6474*4882a593Smuzhiyun 				      struct ql4_tuple_ddb *old_tddb,
6475*4882a593Smuzhiyun 				      struct ql4_tuple_ddb *new_tddb)
6476*4882a593Smuzhiyun {
6477*4882a593Smuzhiyun 	if (strcmp(old_tddb->ip_addr, new_tddb->ip_addr) == 0) {
6478*4882a593Smuzhiyun 		/* Same ip */
6479*4882a593Smuzhiyun 		if (old_tddb->port == new_tddb->port)
6480*4882a593Smuzhiyun 			return QLA_ERROR;
6481*4882a593Smuzhiyun 	}
6482*4882a593Smuzhiyun 
6483*4882a593Smuzhiyun 	if (strcmp(old_tddb->iscsi_name, new_tddb->iscsi_name))
6484*4882a593Smuzhiyun 		/* different iqn */
6485*4882a593Smuzhiyun 		return QLA_ERROR;
6486*4882a593Smuzhiyun 
6487*4882a593Smuzhiyun 	if (memcmp(&old_tddb->isid[0], &new_tddb->isid[0],
6488*4882a593Smuzhiyun 		   sizeof(old_tddb->isid)))
6489*4882a593Smuzhiyun 		/* different isid */
6490*4882a593Smuzhiyun 		return QLA_ERROR;
6491*4882a593Smuzhiyun 
6492*4882a593Smuzhiyun 	return QLA_SUCCESS;
6493*4882a593Smuzhiyun }
6494*4882a593Smuzhiyun 
6495*4882a593Smuzhiyun /**
6496*4882a593Smuzhiyun  * qla4xxx_is_flash_ddb_exists - check if fw_ddb_entry already exists in list_nt
6497*4882a593Smuzhiyun  * @ha: Pointer to host adapter structure.
6498*4882a593Smuzhiyun  * @list_nt: list of nt target.
6499*4882a593Smuzhiyun  * @fw_ddb_entry: firmware ddb entry.
6500*4882a593Smuzhiyun  *
6501*4882a593Smuzhiyun  * This routine check if fw_ddb_entry already exists in list_nt to avoid
6502*4882a593Smuzhiyun  * duplicate ddb in list_nt.
6503*4882a593Smuzhiyun  * Return QLA_SUCCESS if duplicate ddb exit in list_nl.
6504*4882a593Smuzhiyun  * Note: This function also update isid of DDB if required.
6505*4882a593Smuzhiyun  **/
6506*4882a593Smuzhiyun 
qla4xxx_is_flash_ddb_exists(struct scsi_qla_host * ha,struct list_head * list_nt,struct dev_db_entry * fw_ddb_entry)6507*4882a593Smuzhiyun static int qla4xxx_is_flash_ddb_exists(struct scsi_qla_host *ha,
6508*4882a593Smuzhiyun 				       struct list_head *list_nt,
6509*4882a593Smuzhiyun 				       struct dev_db_entry *fw_ddb_entry)
6510*4882a593Smuzhiyun {
6511*4882a593Smuzhiyun 	struct qla_ddb_index  *nt_ddb_idx, *nt_ddb_idx_tmp;
6512*4882a593Smuzhiyun 	struct ql4_tuple_ddb *fw_tddb = NULL;
6513*4882a593Smuzhiyun 	struct ql4_tuple_ddb *tmp_tddb = NULL;
6514*4882a593Smuzhiyun 	int rval, ret = QLA_ERROR;
6515*4882a593Smuzhiyun 
6516*4882a593Smuzhiyun 	fw_tddb = vzalloc(sizeof(*fw_tddb));
6517*4882a593Smuzhiyun 	if (!fw_tddb) {
6518*4882a593Smuzhiyun 		DEBUG2(ql4_printk(KERN_WARNING, ha,
6519*4882a593Smuzhiyun 				  "Memory Allocation failed.\n"));
6520*4882a593Smuzhiyun 		ret = QLA_SUCCESS;
6521*4882a593Smuzhiyun 		goto exit_check;
6522*4882a593Smuzhiyun 	}
6523*4882a593Smuzhiyun 
6524*4882a593Smuzhiyun 	tmp_tddb = vzalloc(sizeof(*tmp_tddb));
6525*4882a593Smuzhiyun 	if (!tmp_tddb) {
6526*4882a593Smuzhiyun 		DEBUG2(ql4_printk(KERN_WARNING, ha,
6527*4882a593Smuzhiyun 				  "Memory Allocation failed.\n"));
6528*4882a593Smuzhiyun 		ret = QLA_SUCCESS;
6529*4882a593Smuzhiyun 		goto exit_check;
6530*4882a593Smuzhiyun 	}
6531*4882a593Smuzhiyun 
6532*4882a593Smuzhiyun 	qla4xxx_convert_param_ddb(fw_ddb_entry, fw_tddb, NULL);
6533*4882a593Smuzhiyun 
6534*4882a593Smuzhiyun 	list_for_each_entry_safe(nt_ddb_idx, nt_ddb_idx_tmp, list_nt, list) {
6535*4882a593Smuzhiyun 		qla4xxx_convert_param_ddb(&nt_ddb_idx->fw_ddb, tmp_tddb,
6536*4882a593Smuzhiyun 					  nt_ddb_idx->flash_isid);
6537*4882a593Smuzhiyun 		ret = qla4xxx_compare_tuple_ddb(ha, fw_tddb, tmp_tddb, true);
6538*4882a593Smuzhiyun 		/* found duplicate ddb */
6539*4882a593Smuzhiyun 		if (ret == QLA_SUCCESS)
6540*4882a593Smuzhiyun 			goto exit_check;
6541*4882a593Smuzhiyun 	}
6542*4882a593Smuzhiyun 
6543*4882a593Smuzhiyun 	list_for_each_entry_safe(nt_ddb_idx, nt_ddb_idx_tmp, list_nt, list) {
6544*4882a593Smuzhiyun 		qla4xxx_convert_param_ddb(&nt_ddb_idx->fw_ddb, tmp_tddb, NULL);
6545*4882a593Smuzhiyun 
6546*4882a593Smuzhiyun 		ret = qla4xxx_should_update_isid(ha, tmp_tddb, fw_tddb);
6547*4882a593Smuzhiyun 		if (ret == QLA_SUCCESS) {
6548*4882a593Smuzhiyun 			rval = qla4xxx_update_isid(ha, list_nt, fw_ddb_entry);
6549*4882a593Smuzhiyun 			if (rval == QLA_SUCCESS)
6550*4882a593Smuzhiyun 				ret = QLA_ERROR;
6551*4882a593Smuzhiyun 			else
6552*4882a593Smuzhiyun 				ret = QLA_SUCCESS;
6553*4882a593Smuzhiyun 
6554*4882a593Smuzhiyun 			goto exit_check;
6555*4882a593Smuzhiyun 		}
6556*4882a593Smuzhiyun 	}
6557*4882a593Smuzhiyun 
6558*4882a593Smuzhiyun exit_check:
6559*4882a593Smuzhiyun 	if (fw_tddb)
6560*4882a593Smuzhiyun 		vfree(fw_tddb);
6561*4882a593Smuzhiyun 	if (tmp_tddb)
6562*4882a593Smuzhiyun 		vfree(tmp_tddb);
6563*4882a593Smuzhiyun 	return ret;
6564*4882a593Smuzhiyun }
6565*4882a593Smuzhiyun 
qla4xxx_free_ddb_list(struct list_head * list_ddb)6566*4882a593Smuzhiyun static void qla4xxx_free_ddb_list(struct list_head *list_ddb)
6567*4882a593Smuzhiyun {
6568*4882a593Smuzhiyun 	struct qla_ddb_index  *ddb_idx, *ddb_idx_tmp;
6569*4882a593Smuzhiyun 
6570*4882a593Smuzhiyun 	list_for_each_entry_safe(ddb_idx, ddb_idx_tmp, list_ddb, list) {
6571*4882a593Smuzhiyun 		list_del_init(&ddb_idx->list);
6572*4882a593Smuzhiyun 		vfree(ddb_idx);
6573*4882a593Smuzhiyun 	}
6574*4882a593Smuzhiyun }
6575*4882a593Smuzhiyun 
qla4xxx_get_ep_fwdb(struct scsi_qla_host * ha,struct dev_db_entry * fw_ddb_entry)6576*4882a593Smuzhiyun static struct iscsi_endpoint *qla4xxx_get_ep_fwdb(struct scsi_qla_host *ha,
6577*4882a593Smuzhiyun 					struct dev_db_entry *fw_ddb_entry)
6578*4882a593Smuzhiyun {
6579*4882a593Smuzhiyun 	struct iscsi_endpoint *ep;
6580*4882a593Smuzhiyun 	struct sockaddr_in *addr;
6581*4882a593Smuzhiyun 	struct sockaddr_in6 *addr6;
6582*4882a593Smuzhiyun 	struct sockaddr *t_addr;
6583*4882a593Smuzhiyun 	struct sockaddr_storage *dst_addr;
6584*4882a593Smuzhiyun 	char *ip;
6585*4882a593Smuzhiyun 
6586*4882a593Smuzhiyun 	/* TODO: need to destroy on unload iscsi_endpoint*/
6587*4882a593Smuzhiyun 	dst_addr = vmalloc(sizeof(*dst_addr));
6588*4882a593Smuzhiyun 	if (!dst_addr)
6589*4882a593Smuzhiyun 		return NULL;
6590*4882a593Smuzhiyun 
6591*4882a593Smuzhiyun 	if (fw_ddb_entry->options & DDB_OPT_IPV6_DEVICE) {
6592*4882a593Smuzhiyun 		t_addr = (struct sockaddr *)dst_addr;
6593*4882a593Smuzhiyun 		t_addr->sa_family = AF_INET6;
6594*4882a593Smuzhiyun 		addr6 = (struct sockaddr_in6 *)dst_addr;
6595*4882a593Smuzhiyun 		ip = (char *)&addr6->sin6_addr;
6596*4882a593Smuzhiyun 		memcpy(ip, fw_ddb_entry->ip_addr, IPv6_ADDR_LEN);
6597*4882a593Smuzhiyun 		addr6->sin6_port = htons(le16_to_cpu(fw_ddb_entry->port));
6598*4882a593Smuzhiyun 
6599*4882a593Smuzhiyun 	} else {
6600*4882a593Smuzhiyun 		t_addr = (struct sockaddr *)dst_addr;
6601*4882a593Smuzhiyun 		t_addr->sa_family = AF_INET;
6602*4882a593Smuzhiyun 		addr = (struct sockaddr_in *)dst_addr;
6603*4882a593Smuzhiyun 		ip = (char *)&addr->sin_addr;
6604*4882a593Smuzhiyun 		memcpy(ip, fw_ddb_entry->ip_addr, IP_ADDR_LEN);
6605*4882a593Smuzhiyun 		addr->sin_port = htons(le16_to_cpu(fw_ddb_entry->port));
6606*4882a593Smuzhiyun 	}
6607*4882a593Smuzhiyun 
6608*4882a593Smuzhiyun 	ep = qla4xxx_ep_connect(ha->host, (struct sockaddr *)dst_addr, 0);
6609*4882a593Smuzhiyun 	vfree(dst_addr);
6610*4882a593Smuzhiyun 	return ep;
6611*4882a593Smuzhiyun }
6612*4882a593Smuzhiyun 
qla4xxx_verify_boot_idx(struct scsi_qla_host * ha,uint16_t idx)6613*4882a593Smuzhiyun static int qla4xxx_verify_boot_idx(struct scsi_qla_host *ha, uint16_t idx)
6614*4882a593Smuzhiyun {
6615*4882a593Smuzhiyun 	if (ql4xdisablesysfsboot)
6616*4882a593Smuzhiyun 		return QLA_SUCCESS;
6617*4882a593Smuzhiyun 	if (idx == ha->pri_ddb_idx || idx == ha->sec_ddb_idx)
6618*4882a593Smuzhiyun 		return QLA_ERROR;
6619*4882a593Smuzhiyun 	return QLA_SUCCESS;
6620*4882a593Smuzhiyun }
6621*4882a593Smuzhiyun 
qla4xxx_setup_flash_ddb_entry(struct scsi_qla_host * ha,struct ddb_entry * ddb_entry,uint16_t idx)6622*4882a593Smuzhiyun static void qla4xxx_setup_flash_ddb_entry(struct scsi_qla_host *ha,
6623*4882a593Smuzhiyun 					  struct ddb_entry *ddb_entry,
6624*4882a593Smuzhiyun 					  uint16_t idx)
6625*4882a593Smuzhiyun {
6626*4882a593Smuzhiyun 	uint16_t def_timeout;
6627*4882a593Smuzhiyun 
6628*4882a593Smuzhiyun 	ddb_entry->ddb_type = FLASH_DDB;
6629*4882a593Smuzhiyun 	ddb_entry->fw_ddb_index = INVALID_ENTRY;
6630*4882a593Smuzhiyun 	ddb_entry->fw_ddb_device_state = DDB_DS_NO_CONNECTION_ACTIVE;
6631*4882a593Smuzhiyun 	ddb_entry->ha = ha;
6632*4882a593Smuzhiyun 	ddb_entry->unblock_sess = qla4xxx_unblock_flash_ddb;
6633*4882a593Smuzhiyun 	ddb_entry->ddb_change = qla4xxx_flash_ddb_change;
6634*4882a593Smuzhiyun 	ddb_entry->chap_tbl_idx = INVALID_ENTRY;
6635*4882a593Smuzhiyun 
6636*4882a593Smuzhiyun 	atomic_set(&ddb_entry->retry_relogin_timer, INVALID_ENTRY);
6637*4882a593Smuzhiyun 	atomic_set(&ddb_entry->relogin_timer, 0);
6638*4882a593Smuzhiyun 	atomic_set(&ddb_entry->relogin_retry_count, 0);
6639*4882a593Smuzhiyun 	def_timeout = le16_to_cpu(ddb_entry->fw_ddb_entry.def_timeout);
6640*4882a593Smuzhiyun 	ddb_entry->default_relogin_timeout =
6641*4882a593Smuzhiyun 		(def_timeout > LOGIN_TOV) && (def_timeout < LOGIN_TOV * 10) ?
6642*4882a593Smuzhiyun 		def_timeout : LOGIN_TOV;
6643*4882a593Smuzhiyun 	ddb_entry->default_time2wait =
6644*4882a593Smuzhiyun 		le16_to_cpu(ddb_entry->fw_ddb_entry.iscsi_def_time2wait);
6645*4882a593Smuzhiyun 
6646*4882a593Smuzhiyun 	if (ql4xdisablesysfsboot &&
6647*4882a593Smuzhiyun 	    (idx == ha->pri_ddb_idx || idx == ha->sec_ddb_idx))
6648*4882a593Smuzhiyun 		set_bit(DF_BOOT_TGT, &ddb_entry->flags);
6649*4882a593Smuzhiyun }
6650*4882a593Smuzhiyun 
qla4xxx_wait_for_ip_configuration(struct scsi_qla_host * ha)6651*4882a593Smuzhiyun static void qla4xxx_wait_for_ip_configuration(struct scsi_qla_host *ha)
6652*4882a593Smuzhiyun {
6653*4882a593Smuzhiyun 	uint32_t idx = 0;
6654*4882a593Smuzhiyun 	uint32_t ip_idx[IP_ADDR_COUNT] = {0, 1, 2, 3}; /* 4 IP interfaces */
6655*4882a593Smuzhiyun 	uint32_t sts[MBOX_REG_COUNT];
6656*4882a593Smuzhiyun 	uint32_t ip_state;
6657*4882a593Smuzhiyun 	unsigned long wtime;
6658*4882a593Smuzhiyun 	int ret;
6659*4882a593Smuzhiyun 
6660*4882a593Smuzhiyun 	wtime = jiffies + (HZ * IP_CONFIG_TOV);
6661*4882a593Smuzhiyun 	do {
6662*4882a593Smuzhiyun 		for (idx = 0; idx < IP_ADDR_COUNT; idx++) {
6663*4882a593Smuzhiyun 			if (ip_idx[idx] == -1)
6664*4882a593Smuzhiyun 				continue;
6665*4882a593Smuzhiyun 
6666*4882a593Smuzhiyun 			ret = qla4xxx_get_ip_state(ha, 0, ip_idx[idx], sts);
6667*4882a593Smuzhiyun 
6668*4882a593Smuzhiyun 			if (ret == QLA_ERROR) {
6669*4882a593Smuzhiyun 				ip_idx[idx] = -1;
6670*4882a593Smuzhiyun 				continue;
6671*4882a593Smuzhiyun 			}
6672*4882a593Smuzhiyun 
6673*4882a593Smuzhiyun 			ip_state = (sts[1] & IP_STATE_MASK) >> IP_STATE_SHIFT;
6674*4882a593Smuzhiyun 
6675*4882a593Smuzhiyun 			DEBUG2(ql4_printk(KERN_INFO, ha,
6676*4882a593Smuzhiyun 					  "Waiting for IP state for idx = %d, state = 0x%x\n",
6677*4882a593Smuzhiyun 					  ip_idx[idx], ip_state));
6678*4882a593Smuzhiyun 			if (ip_state == IP_ADDRSTATE_UNCONFIGURED ||
6679*4882a593Smuzhiyun 			    ip_state == IP_ADDRSTATE_INVALID ||
6680*4882a593Smuzhiyun 			    ip_state == IP_ADDRSTATE_PREFERRED ||
6681*4882a593Smuzhiyun 			    ip_state == IP_ADDRSTATE_DEPRICATED ||
6682*4882a593Smuzhiyun 			    ip_state == IP_ADDRSTATE_DISABLING)
6683*4882a593Smuzhiyun 				ip_idx[idx] = -1;
6684*4882a593Smuzhiyun 		}
6685*4882a593Smuzhiyun 
6686*4882a593Smuzhiyun 		/* Break if all IP states checked */
6687*4882a593Smuzhiyun 		if ((ip_idx[0] == -1) &&
6688*4882a593Smuzhiyun 		    (ip_idx[1] == -1) &&
6689*4882a593Smuzhiyun 		    (ip_idx[2] == -1) &&
6690*4882a593Smuzhiyun 		    (ip_idx[3] == -1))
6691*4882a593Smuzhiyun 			break;
6692*4882a593Smuzhiyun 		schedule_timeout_uninterruptible(HZ);
6693*4882a593Smuzhiyun 	} while (time_after(wtime, jiffies));
6694*4882a593Smuzhiyun }
6695*4882a593Smuzhiyun 
qla4xxx_cmp_fw_stentry(struct dev_db_entry * fw_ddb_entry,struct dev_db_entry * flash_ddb_entry)6696*4882a593Smuzhiyun static int qla4xxx_cmp_fw_stentry(struct dev_db_entry *fw_ddb_entry,
6697*4882a593Smuzhiyun 				  struct dev_db_entry *flash_ddb_entry)
6698*4882a593Smuzhiyun {
6699*4882a593Smuzhiyun 	uint16_t options = 0;
6700*4882a593Smuzhiyun 	size_t ip_len = IP_ADDR_LEN;
6701*4882a593Smuzhiyun 
6702*4882a593Smuzhiyun 	options = le16_to_cpu(fw_ddb_entry->options);
6703*4882a593Smuzhiyun 	if (options & DDB_OPT_IPV6_DEVICE)
6704*4882a593Smuzhiyun 		ip_len = IPv6_ADDR_LEN;
6705*4882a593Smuzhiyun 
6706*4882a593Smuzhiyun 	if (memcmp(fw_ddb_entry->ip_addr, flash_ddb_entry->ip_addr, ip_len))
6707*4882a593Smuzhiyun 		return QLA_ERROR;
6708*4882a593Smuzhiyun 
6709*4882a593Smuzhiyun 	if (memcmp(&fw_ddb_entry->isid[0], &flash_ddb_entry->isid[0],
6710*4882a593Smuzhiyun 		   sizeof(fw_ddb_entry->isid)))
6711*4882a593Smuzhiyun 		return QLA_ERROR;
6712*4882a593Smuzhiyun 
6713*4882a593Smuzhiyun 	if (memcmp(&fw_ddb_entry->port, &flash_ddb_entry->port,
6714*4882a593Smuzhiyun 		   sizeof(fw_ddb_entry->port)))
6715*4882a593Smuzhiyun 		return QLA_ERROR;
6716*4882a593Smuzhiyun 
6717*4882a593Smuzhiyun 	return QLA_SUCCESS;
6718*4882a593Smuzhiyun }
6719*4882a593Smuzhiyun 
qla4xxx_find_flash_st_idx(struct scsi_qla_host * ha,struct dev_db_entry * fw_ddb_entry,uint32_t fw_idx,uint32_t * flash_index)6720*4882a593Smuzhiyun static int qla4xxx_find_flash_st_idx(struct scsi_qla_host *ha,
6721*4882a593Smuzhiyun 				     struct dev_db_entry *fw_ddb_entry,
6722*4882a593Smuzhiyun 				     uint32_t fw_idx, uint32_t *flash_index)
6723*4882a593Smuzhiyun {
6724*4882a593Smuzhiyun 	struct dev_db_entry *flash_ddb_entry;
6725*4882a593Smuzhiyun 	dma_addr_t flash_ddb_entry_dma;
6726*4882a593Smuzhiyun 	uint32_t idx = 0;
6727*4882a593Smuzhiyun 	int max_ddbs;
6728*4882a593Smuzhiyun 	int ret = QLA_ERROR, status;
6729*4882a593Smuzhiyun 
6730*4882a593Smuzhiyun 	max_ddbs =  is_qla40XX(ha) ? MAX_DEV_DB_ENTRIES_40XX :
6731*4882a593Smuzhiyun 				     MAX_DEV_DB_ENTRIES;
6732*4882a593Smuzhiyun 
6733*4882a593Smuzhiyun 	flash_ddb_entry = dma_pool_alloc(ha->fw_ddb_dma_pool, GFP_KERNEL,
6734*4882a593Smuzhiyun 					 &flash_ddb_entry_dma);
6735*4882a593Smuzhiyun 	if (flash_ddb_entry == NULL || fw_ddb_entry == NULL) {
6736*4882a593Smuzhiyun 		ql4_printk(KERN_ERR, ha, "Out of memory\n");
6737*4882a593Smuzhiyun 		goto exit_find_st_idx;
6738*4882a593Smuzhiyun 	}
6739*4882a593Smuzhiyun 
6740*4882a593Smuzhiyun 	status = qla4xxx_flashdb_by_index(ha, flash_ddb_entry,
6741*4882a593Smuzhiyun 					  flash_ddb_entry_dma, fw_idx);
6742*4882a593Smuzhiyun 	if (status == QLA_SUCCESS) {
6743*4882a593Smuzhiyun 		status = qla4xxx_cmp_fw_stentry(fw_ddb_entry, flash_ddb_entry);
6744*4882a593Smuzhiyun 		if (status == QLA_SUCCESS) {
6745*4882a593Smuzhiyun 			*flash_index = fw_idx;
6746*4882a593Smuzhiyun 			ret = QLA_SUCCESS;
6747*4882a593Smuzhiyun 			goto exit_find_st_idx;
6748*4882a593Smuzhiyun 		}
6749*4882a593Smuzhiyun 	}
6750*4882a593Smuzhiyun 
6751*4882a593Smuzhiyun 	for (idx = 0; idx < max_ddbs; idx++) {
6752*4882a593Smuzhiyun 		status = qla4xxx_flashdb_by_index(ha, flash_ddb_entry,
6753*4882a593Smuzhiyun 						  flash_ddb_entry_dma, idx);
6754*4882a593Smuzhiyun 		if (status == QLA_ERROR)
6755*4882a593Smuzhiyun 			continue;
6756*4882a593Smuzhiyun 
6757*4882a593Smuzhiyun 		status = qla4xxx_cmp_fw_stentry(fw_ddb_entry, flash_ddb_entry);
6758*4882a593Smuzhiyun 		if (status == QLA_SUCCESS) {
6759*4882a593Smuzhiyun 			*flash_index = idx;
6760*4882a593Smuzhiyun 			ret = QLA_SUCCESS;
6761*4882a593Smuzhiyun 			goto exit_find_st_idx;
6762*4882a593Smuzhiyun 		}
6763*4882a593Smuzhiyun 	}
6764*4882a593Smuzhiyun 
6765*4882a593Smuzhiyun 	if (idx == max_ddbs)
6766*4882a593Smuzhiyun 		ql4_printk(KERN_ERR, ha, "Failed to find ST [%d] in flash\n",
6767*4882a593Smuzhiyun 			   fw_idx);
6768*4882a593Smuzhiyun 
6769*4882a593Smuzhiyun exit_find_st_idx:
6770*4882a593Smuzhiyun 	if (flash_ddb_entry)
6771*4882a593Smuzhiyun 		dma_pool_free(ha->fw_ddb_dma_pool, flash_ddb_entry,
6772*4882a593Smuzhiyun 			      flash_ddb_entry_dma);
6773*4882a593Smuzhiyun 
6774*4882a593Smuzhiyun 	return ret;
6775*4882a593Smuzhiyun }
6776*4882a593Smuzhiyun 
qla4xxx_build_st_list(struct scsi_qla_host * ha,struct list_head * list_st)6777*4882a593Smuzhiyun static void qla4xxx_build_st_list(struct scsi_qla_host *ha,
6778*4882a593Smuzhiyun 				  struct list_head *list_st)
6779*4882a593Smuzhiyun {
6780*4882a593Smuzhiyun 	struct qla_ddb_index  *st_ddb_idx;
6781*4882a593Smuzhiyun 	int max_ddbs;
6782*4882a593Smuzhiyun 	int fw_idx_size;
6783*4882a593Smuzhiyun 	struct dev_db_entry *fw_ddb_entry;
6784*4882a593Smuzhiyun 	dma_addr_t fw_ddb_dma;
6785*4882a593Smuzhiyun 	int ret;
6786*4882a593Smuzhiyun 	uint32_t idx = 0, next_idx = 0;
6787*4882a593Smuzhiyun 	uint32_t state = 0, conn_err = 0;
6788*4882a593Smuzhiyun 	uint32_t flash_index = -1;
6789*4882a593Smuzhiyun 	uint16_t conn_id = 0;
6790*4882a593Smuzhiyun 
6791*4882a593Smuzhiyun 	fw_ddb_entry = dma_pool_alloc(ha->fw_ddb_dma_pool, GFP_KERNEL,
6792*4882a593Smuzhiyun 				      &fw_ddb_dma);
6793*4882a593Smuzhiyun 	if (fw_ddb_entry == NULL) {
6794*4882a593Smuzhiyun 		DEBUG2(ql4_printk(KERN_ERR, ha, "Out of memory\n"));
6795*4882a593Smuzhiyun 		goto exit_st_list;
6796*4882a593Smuzhiyun 	}
6797*4882a593Smuzhiyun 
6798*4882a593Smuzhiyun 	max_ddbs =  is_qla40XX(ha) ? MAX_DEV_DB_ENTRIES_40XX :
6799*4882a593Smuzhiyun 				     MAX_DEV_DB_ENTRIES;
6800*4882a593Smuzhiyun 	fw_idx_size = sizeof(struct qla_ddb_index);
6801*4882a593Smuzhiyun 
6802*4882a593Smuzhiyun 	for (idx = 0; idx < max_ddbs; idx = next_idx) {
6803*4882a593Smuzhiyun 		ret = qla4xxx_get_fwddb_entry(ha, idx, fw_ddb_entry, fw_ddb_dma,
6804*4882a593Smuzhiyun 					      NULL, &next_idx, &state,
6805*4882a593Smuzhiyun 					      &conn_err, NULL, &conn_id);
6806*4882a593Smuzhiyun 		if (ret == QLA_ERROR)
6807*4882a593Smuzhiyun 			break;
6808*4882a593Smuzhiyun 
6809*4882a593Smuzhiyun 		/* Ignore DDB if invalid state (unassigned) */
6810*4882a593Smuzhiyun 		if (state == DDB_DS_UNASSIGNED)
6811*4882a593Smuzhiyun 			goto continue_next_st;
6812*4882a593Smuzhiyun 
6813*4882a593Smuzhiyun 		/* Check if ST, add to the list_st */
6814*4882a593Smuzhiyun 		if (strlen((char *) fw_ddb_entry->iscsi_name) != 0)
6815*4882a593Smuzhiyun 			goto continue_next_st;
6816*4882a593Smuzhiyun 
6817*4882a593Smuzhiyun 		st_ddb_idx = vzalloc(fw_idx_size);
6818*4882a593Smuzhiyun 		if (!st_ddb_idx)
6819*4882a593Smuzhiyun 			break;
6820*4882a593Smuzhiyun 
6821*4882a593Smuzhiyun 		ret = qla4xxx_find_flash_st_idx(ha, fw_ddb_entry, idx,
6822*4882a593Smuzhiyun 						&flash_index);
6823*4882a593Smuzhiyun 		if (ret == QLA_ERROR) {
6824*4882a593Smuzhiyun 			ql4_printk(KERN_ERR, ha,
6825*4882a593Smuzhiyun 				   "No flash entry for ST at idx [%d]\n", idx);
6826*4882a593Smuzhiyun 			st_ddb_idx->flash_ddb_idx = idx;
6827*4882a593Smuzhiyun 		} else {
6828*4882a593Smuzhiyun 			ql4_printk(KERN_INFO, ha,
6829*4882a593Smuzhiyun 				   "ST at idx [%d] is stored at flash [%d]\n",
6830*4882a593Smuzhiyun 				   idx, flash_index);
6831*4882a593Smuzhiyun 			st_ddb_idx->flash_ddb_idx = flash_index;
6832*4882a593Smuzhiyun 		}
6833*4882a593Smuzhiyun 
6834*4882a593Smuzhiyun 		st_ddb_idx->fw_ddb_idx = idx;
6835*4882a593Smuzhiyun 
6836*4882a593Smuzhiyun 		list_add_tail(&st_ddb_idx->list, list_st);
6837*4882a593Smuzhiyun continue_next_st:
6838*4882a593Smuzhiyun 		if (next_idx == 0)
6839*4882a593Smuzhiyun 			break;
6840*4882a593Smuzhiyun 	}
6841*4882a593Smuzhiyun 
6842*4882a593Smuzhiyun exit_st_list:
6843*4882a593Smuzhiyun 	if (fw_ddb_entry)
6844*4882a593Smuzhiyun 		dma_pool_free(ha->fw_ddb_dma_pool, fw_ddb_entry, fw_ddb_dma);
6845*4882a593Smuzhiyun }
6846*4882a593Smuzhiyun 
6847*4882a593Smuzhiyun /**
6848*4882a593Smuzhiyun  * qla4xxx_remove_failed_ddb - Remove inactive or failed ddb from list
6849*4882a593Smuzhiyun  * @ha: pointer to adapter structure
6850*4882a593Smuzhiyun  * @list_ddb: List from which failed ddb to be removed
6851*4882a593Smuzhiyun  *
6852*4882a593Smuzhiyun  * Iterate over the list of DDBs and find and remove DDBs that are either in
6853*4882a593Smuzhiyun  * no connection active state or failed state
6854*4882a593Smuzhiyun  **/
qla4xxx_remove_failed_ddb(struct scsi_qla_host * ha,struct list_head * list_ddb)6855*4882a593Smuzhiyun static void qla4xxx_remove_failed_ddb(struct scsi_qla_host *ha,
6856*4882a593Smuzhiyun 				      struct list_head *list_ddb)
6857*4882a593Smuzhiyun {
6858*4882a593Smuzhiyun 	struct qla_ddb_index  *ddb_idx, *ddb_idx_tmp;
6859*4882a593Smuzhiyun 	uint32_t next_idx = 0;
6860*4882a593Smuzhiyun 	uint32_t state = 0, conn_err = 0;
6861*4882a593Smuzhiyun 	int ret;
6862*4882a593Smuzhiyun 
6863*4882a593Smuzhiyun 	list_for_each_entry_safe(ddb_idx, ddb_idx_tmp, list_ddb, list) {
6864*4882a593Smuzhiyun 		ret = qla4xxx_get_fwddb_entry(ha, ddb_idx->fw_ddb_idx,
6865*4882a593Smuzhiyun 					      NULL, 0, NULL, &next_idx, &state,
6866*4882a593Smuzhiyun 					      &conn_err, NULL, NULL);
6867*4882a593Smuzhiyun 		if (ret == QLA_ERROR)
6868*4882a593Smuzhiyun 			continue;
6869*4882a593Smuzhiyun 
6870*4882a593Smuzhiyun 		if (state == DDB_DS_NO_CONNECTION_ACTIVE ||
6871*4882a593Smuzhiyun 		    state == DDB_DS_SESSION_FAILED) {
6872*4882a593Smuzhiyun 			list_del_init(&ddb_idx->list);
6873*4882a593Smuzhiyun 			vfree(ddb_idx);
6874*4882a593Smuzhiyun 		}
6875*4882a593Smuzhiyun 	}
6876*4882a593Smuzhiyun }
6877*4882a593Smuzhiyun 
qla4xxx_update_sess_disc_idx(struct scsi_qla_host * ha,struct ddb_entry * ddb_entry,struct dev_db_entry * fw_ddb_entry)6878*4882a593Smuzhiyun static void qla4xxx_update_sess_disc_idx(struct scsi_qla_host *ha,
6879*4882a593Smuzhiyun 					 struct ddb_entry *ddb_entry,
6880*4882a593Smuzhiyun 					 struct dev_db_entry *fw_ddb_entry)
6881*4882a593Smuzhiyun {
6882*4882a593Smuzhiyun 	struct iscsi_cls_session *cls_sess;
6883*4882a593Smuzhiyun 	struct iscsi_session *sess;
6884*4882a593Smuzhiyun 	uint32_t max_ddbs = 0;
6885*4882a593Smuzhiyun 	uint16_t ddb_link = -1;
6886*4882a593Smuzhiyun 
6887*4882a593Smuzhiyun 	max_ddbs =  is_qla40XX(ha) ? MAX_DEV_DB_ENTRIES_40XX :
6888*4882a593Smuzhiyun 				     MAX_DEV_DB_ENTRIES;
6889*4882a593Smuzhiyun 
6890*4882a593Smuzhiyun 	cls_sess = ddb_entry->sess;
6891*4882a593Smuzhiyun 	sess = cls_sess->dd_data;
6892*4882a593Smuzhiyun 
6893*4882a593Smuzhiyun 	ddb_link = le16_to_cpu(fw_ddb_entry->ddb_link);
6894*4882a593Smuzhiyun 	if (ddb_link < max_ddbs)
6895*4882a593Smuzhiyun 		sess->discovery_parent_idx = ddb_link;
6896*4882a593Smuzhiyun 	else
6897*4882a593Smuzhiyun 		sess->discovery_parent_idx = DDB_NO_LINK;
6898*4882a593Smuzhiyun }
6899*4882a593Smuzhiyun 
qla4xxx_sess_conn_setup(struct scsi_qla_host * ha,struct dev_db_entry * fw_ddb_entry,int is_reset,uint16_t idx)6900*4882a593Smuzhiyun static int qla4xxx_sess_conn_setup(struct scsi_qla_host *ha,
6901*4882a593Smuzhiyun 				   struct dev_db_entry *fw_ddb_entry,
6902*4882a593Smuzhiyun 				   int is_reset, uint16_t idx)
6903*4882a593Smuzhiyun {
6904*4882a593Smuzhiyun 	struct iscsi_cls_session *cls_sess;
6905*4882a593Smuzhiyun 	struct iscsi_session *sess;
6906*4882a593Smuzhiyun 	struct iscsi_cls_conn *cls_conn;
6907*4882a593Smuzhiyun 	struct iscsi_endpoint *ep;
6908*4882a593Smuzhiyun 	uint16_t cmds_max = 32;
6909*4882a593Smuzhiyun 	uint16_t conn_id = 0;
6910*4882a593Smuzhiyun 	uint32_t initial_cmdsn = 0;
6911*4882a593Smuzhiyun 	int ret = QLA_SUCCESS;
6912*4882a593Smuzhiyun 
6913*4882a593Smuzhiyun 	struct ddb_entry *ddb_entry = NULL;
6914*4882a593Smuzhiyun 
6915*4882a593Smuzhiyun 	/* Create session object, with INVALID_ENTRY,
6916*4882a593Smuzhiyun 	 * the targer_id would get set when we issue the login
6917*4882a593Smuzhiyun 	 */
6918*4882a593Smuzhiyun 	cls_sess = iscsi_session_setup(&qla4xxx_iscsi_transport, ha->host,
6919*4882a593Smuzhiyun 				       cmds_max, sizeof(struct ddb_entry),
6920*4882a593Smuzhiyun 				       sizeof(struct ql4_task_data),
6921*4882a593Smuzhiyun 				       initial_cmdsn, INVALID_ENTRY);
6922*4882a593Smuzhiyun 	if (!cls_sess) {
6923*4882a593Smuzhiyun 		ret = QLA_ERROR;
6924*4882a593Smuzhiyun 		goto exit_setup;
6925*4882a593Smuzhiyun 	}
6926*4882a593Smuzhiyun 
6927*4882a593Smuzhiyun 	/*
6928*4882a593Smuzhiyun 	 * so calling module_put function to decrement the
6929*4882a593Smuzhiyun 	 * reference count.
6930*4882a593Smuzhiyun 	 **/
6931*4882a593Smuzhiyun 	module_put(qla4xxx_iscsi_transport.owner);
6932*4882a593Smuzhiyun 	sess = cls_sess->dd_data;
6933*4882a593Smuzhiyun 	ddb_entry = sess->dd_data;
6934*4882a593Smuzhiyun 	ddb_entry->sess = cls_sess;
6935*4882a593Smuzhiyun 
6936*4882a593Smuzhiyun 	cls_sess->recovery_tmo = ql4xsess_recovery_tmo;
6937*4882a593Smuzhiyun 	memcpy(&ddb_entry->fw_ddb_entry, fw_ddb_entry,
6938*4882a593Smuzhiyun 	       sizeof(struct dev_db_entry));
6939*4882a593Smuzhiyun 
6940*4882a593Smuzhiyun 	qla4xxx_setup_flash_ddb_entry(ha, ddb_entry, idx);
6941*4882a593Smuzhiyun 
6942*4882a593Smuzhiyun 	cls_conn = iscsi_conn_setup(cls_sess, sizeof(struct qla_conn), conn_id);
6943*4882a593Smuzhiyun 
6944*4882a593Smuzhiyun 	if (!cls_conn) {
6945*4882a593Smuzhiyun 		ret = QLA_ERROR;
6946*4882a593Smuzhiyun 		goto exit_setup;
6947*4882a593Smuzhiyun 	}
6948*4882a593Smuzhiyun 
6949*4882a593Smuzhiyun 	ddb_entry->conn = cls_conn;
6950*4882a593Smuzhiyun 
6951*4882a593Smuzhiyun 	/* Setup ep, for displaying attributes in sysfs */
6952*4882a593Smuzhiyun 	ep = qla4xxx_get_ep_fwdb(ha, fw_ddb_entry);
6953*4882a593Smuzhiyun 	if (ep) {
6954*4882a593Smuzhiyun 		ep->conn = cls_conn;
6955*4882a593Smuzhiyun 		cls_conn->ep = ep;
6956*4882a593Smuzhiyun 	} else {
6957*4882a593Smuzhiyun 		DEBUG2(ql4_printk(KERN_ERR, ha, "Unable to get ep\n"));
6958*4882a593Smuzhiyun 		ret = QLA_ERROR;
6959*4882a593Smuzhiyun 		goto exit_setup;
6960*4882a593Smuzhiyun 	}
6961*4882a593Smuzhiyun 
6962*4882a593Smuzhiyun 	/* Update sess/conn params */
6963*4882a593Smuzhiyun 	qla4xxx_copy_fwddb_param(ha, fw_ddb_entry, cls_sess, cls_conn);
6964*4882a593Smuzhiyun 	qla4xxx_update_sess_disc_idx(ha, ddb_entry, fw_ddb_entry);
6965*4882a593Smuzhiyun 
6966*4882a593Smuzhiyun 	if (is_reset == RESET_ADAPTER) {
6967*4882a593Smuzhiyun 		iscsi_block_session(cls_sess);
6968*4882a593Smuzhiyun 		/* Use the relogin path to discover new devices
6969*4882a593Smuzhiyun 		 *  by short-circuting the logic of setting
6970*4882a593Smuzhiyun 		 *  timer to relogin - instead set the flags
6971*4882a593Smuzhiyun 		 *  to initiate login right away.
6972*4882a593Smuzhiyun 		 */
6973*4882a593Smuzhiyun 		set_bit(DPC_RELOGIN_DEVICE, &ha->dpc_flags);
6974*4882a593Smuzhiyun 		set_bit(DF_RELOGIN, &ddb_entry->flags);
6975*4882a593Smuzhiyun 	}
6976*4882a593Smuzhiyun 
6977*4882a593Smuzhiyun exit_setup:
6978*4882a593Smuzhiyun 	return ret;
6979*4882a593Smuzhiyun }
6980*4882a593Smuzhiyun 
qla4xxx_update_fw_ddb_link(struct scsi_qla_host * ha,struct list_head * list_ddb,struct dev_db_entry * fw_ddb_entry)6981*4882a593Smuzhiyun static void qla4xxx_update_fw_ddb_link(struct scsi_qla_host *ha,
6982*4882a593Smuzhiyun 				       struct list_head *list_ddb,
6983*4882a593Smuzhiyun 				       struct dev_db_entry *fw_ddb_entry)
6984*4882a593Smuzhiyun {
6985*4882a593Smuzhiyun 	struct qla_ddb_index  *ddb_idx, *ddb_idx_tmp;
6986*4882a593Smuzhiyun 	uint16_t ddb_link;
6987*4882a593Smuzhiyun 
6988*4882a593Smuzhiyun 	ddb_link = le16_to_cpu(fw_ddb_entry->ddb_link);
6989*4882a593Smuzhiyun 
6990*4882a593Smuzhiyun 	list_for_each_entry_safe(ddb_idx, ddb_idx_tmp, list_ddb, list) {
6991*4882a593Smuzhiyun 		if (ddb_idx->fw_ddb_idx == ddb_link) {
6992*4882a593Smuzhiyun 			DEBUG2(ql4_printk(KERN_INFO, ha,
6993*4882a593Smuzhiyun 					  "Updating NT parent idx from [%d] to [%d]\n",
6994*4882a593Smuzhiyun 					  ddb_link, ddb_idx->flash_ddb_idx));
6995*4882a593Smuzhiyun 			fw_ddb_entry->ddb_link =
6996*4882a593Smuzhiyun 					    cpu_to_le16(ddb_idx->flash_ddb_idx);
6997*4882a593Smuzhiyun 			return;
6998*4882a593Smuzhiyun 		}
6999*4882a593Smuzhiyun 	}
7000*4882a593Smuzhiyun }
7001*4882a593Smuzhiyun 
qla4xxx_build_nt_list(struct scsi_qla_host * ha,struct list_head * list_nt,struct list_head * list_st,int is_reset)7002*4882a593Smuzhiyun static void qla4xxx_build_nt_list(struct scsi_qla_host *ha,
7003*4882a593Smuzhiyun 				  struct list_head *list_nt,
7004*4882a593Smuzhiyun 				  struct list_head *list_st,
7005*4882a593Smuzhiyun 				  int is_reset)
7006*4882a593Smuzhiyun {
7007*4882a593Smuzhiyun 	struct dev_db_entry *fw_ddb_entry;
7008*4882a593Smuzhiyun 	struct ddb_entry *ddb_entry = NULL;
7009*4882a593Smuzhiyun 	dma_addr_t fw_ddb_dma;
7010*4882a593Smuzhiyun 	int max_ddbs;
7011*4882a593Smuzhiyun 	int fw_idx_size;
7012*4882a593Smuzhiyun 	int ret;
7013*4882a593Smuzhiyun 	uint32_t idx = 0, next_idx = 0;
7014*4882a593Smuzhiyun 	uint32_t state = 0, conn_err = 0;
7015*4882a593Smuzhiyun 	uint32_t ddb_idx = -1;
7016*4882a593Smuzhiyun 	uint16_t conn_id = 0;
7017*4882a593Smuzhiyun 	uint16_t ddb_link = -1;
7018*4882a593Smuzhiyun 	struct qla_ddb_index  *nt_ddb_idx;
7019*4882a593Smuzhiyun 
7020*4882a593Smuzhiyun 	fw_ddb_entry = dma_pool_alloc(ha->fw_ddb_dma_pool, GFP_KERNEL,
7021*4882a593Smuzhiyun 				      &fw_ddb_dma);
7022*4882a593Smuzhiyun 	if (fw_ddb_entry == NULL) {
7023*4882a593Smuzhiyun 		DEBUG2(ql4_printk(KERN_ERR, ha, "Out of memory\n"));
7024*4882a593Smuzhiyun 		goto exit_nt_list;
7025*4882a593Smuzhiyun 	}
7026*4882a593Smuzhiyun 	max_ddbs =  is_qla40XX(ha) ? MAX_DEV_DB_ENTRIES_40XX :
7027*4882a593Smuzhiyun 				     MAX_DEV_DB_ENTRIES;
7028*4882a593Smuzhiyun 	fw_idx_size = sizeof(struct qla_ddb_index);
7029*4882a593Smuzhiyun 
7030*4882a593Smuzhiyun 	for (idx = 0; idx < max_ddbs; idx = next_idx) {
7031*4882a593Smuzhiyun 		ret = qla4xxx_get_fwddb_entry(ha, idx, fw_ddb_entry, fw_ddb_dma,
7032*4882a593Smuzhiyun 					      NULL, &next_idx, &state,
7033*4882a593Smuzhiyun 					      &conn_err, NULL, &conn_id);
7034*4882a593Smuzhiyun 		if (ret == QLA_ERROR)
7035*4882a593Smuzhiyun 			break;
7036*4882a593Smuzhiyun 
7037*4882a593Smuzhiyun 		if (qla4xxx_verify_boot_idx(ha, idx) != QLA_SUCCESS)
7038*4882a593Smuzhiyun 			goto continue_next_nt;
7039*4882a593Smuzhiyun 
7040*4882a593Smuzhiyun 		/* Check if NT, then add to list it */
7041*4882a593Smuzhiyun 		if (strlen((char *) fw_ddb_entry->iscsi_name) == 0)
7042*4882a593Smuzhiyun 			goto continue_next_nt;
7043*4882a593Smuzhiyun 
7044*4882a593Smuzhiyun 		ddb_link = le16_to_cpu(fw_ddb_entry->ddb_link);
7045*4882a593Smuzhiyun 		if (ddb_link < max_ddbs)
7046*4882a593Smuzhiyun 			qla4xxx_update_fw_ddb_link(ha, list_st, fw_ddb_entry);
7047*4882a593Smuzhiyun 
7048*4882a593Smuzhiyun 		if (!(state == DDB_DS_NO_CONNECTION_ACTIVE ||
7049*4882a593Smuzhiyun 		    state == DDB_DS_SESSION_FAILED) &&
7050*4882a593Smuzhiyun 		    (is_reset == INIT_ADAPTER))
7051*4882a593Smuzhiyun 			goto continue_next_nt;
7052*4882a593Smuzhiyun 
7053*4882a593Smuzhiyun 		DEBUG2(ql4_printk(KERN_INFO, ha,
7054*4882a593Smuzhiyun 				  "Adding  DDB to session = 0x%x\n", idx));
7055*4882a593Smuzhiyun 
7056*4882a593Smuzhiyun 		if (is_reset == INIT_ADAPTER) {
7057*4882a593Smuzhiyun 			nt_ddb_idx = vmalloc(fw_idx_size);
7058*4882a593Smuzhiyun 			if (!nt_ddb_idx)
7059*4882a593Smuzhiyun 				break;
7060*4882a593Smuzhiyun 
7061*4882a593Smuzhiyun 			nt_ddb_idx->fw_ddb_idx = idx;
7062*4882a593Smuzhiyun 
7063*4882a593Smuzhiyun 			/* Copy original isid as it may get updated in function
7064*4882a593Smuzhiyun 			 * qla4xxx_update_isid(). We need original isid in
7065*4882a593Smuzhiyun 			 * function qla4xxx_compare_tuple_ddb to find duplicate
7066*4882a593Smuzhiyun 			 * target */
7067*4882a593Smuzhiyun 			memcpy(&nt_ddb_idx->flash_isid[0],
7068*4882a593Smuzhiyun 			       &fw_ddb_entry->isid[0],
7069*4882a593Smuzhiyun 			       sizeof(nt_ddb_idx->flash_isid));
7070*4882a593Smuzhiyun 
7071*4882a593Smuzhiyun 			ret = qla4xxx_is_flash_ddb_exists(ha, list_nt,
7072*4882a593Smuzhiyun 							  fw_ddb_entry);
7073*4882a593Smuzhiyun 			if (ret == QLA_SUCCESS) {
7074*4882a593Smuzhiyun 				/* free nt_ddb_idx and do not add to list_nt */
7075*4882a593Smuzhiyun 				vfree(nt_ddb_idx);
7076*4882a593Smuzhiyun 				goto continue_next_nt;
7077*4882a593Smuzhiyun 			}
7078*4882a593Smuzhiyun 
7079*4882a593Smuzhiyun 			/* Copy updated isid */
7080*4882a593Smuzhiyun 			memcpy(&nt_ddb_idx->fw_ddb, fw_ddb_entry,
7081*4882a593Smuzhiyun 			       sizeof(struct dev_db_entry));
7082*4882a593Smuzhiyun 
7083*4882a593Smuzhiyun 			list_add_tail(&nt_ddb_idx->list, list_nt);
7084*4882a593Smuzhiyun 		} else if (is_reset == RESET_ADAPTER) {
7085*4882a593Smuzhiyun 			ret = qla4xxx_is_session_exists(ha, fw_ddb_entry,
7086*4882a593Smuzhiyun 							&ddb_idx);
7087*4882a593Smuzhiyun 			if (ret == QLA_SUCCESS) {
7088*4882a593Smuzhiyun 				ddb_entry = qla4xxx_lookup_ddb_by_fw_index(ha,
7089*4882a593Smuzhiyun 								       ddb_idx);
7090*4882a593Smuzhiyun 				if (ddb_entry != NULL)
7091*4882a593Smuzhiyun 					qla4xxx_update_sess_disc_idx(ha,
7092*4882a593Smuzhiyun 								     ddb_entry,
7093*4882a593Smuzhiyun 								  fw_ddb_entry);
7094*4882a593Smuzhiyun 				goto continue_next_nt;
7095*4882a593Smuzhiyun 			}
7096*4882a593Smuzhiyun 		}
7097*4882a593Smuzhiyun 
7098*4882a593Smuzhiyun 		ret = qla4xxx_sess_conn_setup(ha, fw_ddb_entry, is_reset, idx);
7099*4882a593Smuzhiyun 		if (ret == QLA_ERROR)
7100*4882a593Smuzhiyun 			goto exit_nt_list;
7101*4882a593Smuzhiyun 
7102*4882a593Smuzhiyun continue_next_nt:
7103*4882a593Smuzhiyun 		if (next_idx == 0)
7104*4882a593Smuzhiyun 			break;
7105*4882a593Smuzhiyun 	}
7106*4882a593Smuzhiyun 
7107*4882a593Smuzhiyun exit_nt_list:
7108*4882a593Smuzhiyun 	if (fw_ddb_entry)
7109*4882a593Smuzhiyun 		dma_pool_free(ha->fw_ddb_dma_pool, fw_ddb_entry, fw_ddb_dma);
7110*4882a593Smuzhiyun }
7111*4882a593Smuzhiyun 
qla4xxx_build_new_nt_list(struct scsi_qla_host * ha,struct list_head * list_nt,uint16_t target_id)7112*4882a593Smuzhiyun static void qla4xxx_build_new_nt_list(struct scsi_qla_host *ha,
7113*4882a593Smuzhiyun 				      struct list_head *list_nt,
7114*4882a593Smuzhiyun 				      uint16_t target_id)
7115*4882a593Smuzhiyun {
7116*4882a593Smuzhiyun 	struct dev_db_entry *fw_ddb_entry;
7117*4882a593Smuzhiyun 	dma_addr_t fw_ddb_dma;
7118*4882a593Smuzhiyun 	int max_ddbs;
7119*4882a593Smuzhiyun 	int fw_idx_size;
7120*4882a593Smuzhiyun 	int ret;
7121*4882a593Smuzhiyun 	uint32_t idx = 0, next_idx = 0;
7122*4882a593Smuzhiyun 	uint32_t state = 0, conn_err = 0;
7123*4882a593Smuzhiyun 	uint16_t conn_id = 0;
7124*4882a593Smuzhiyun 	struct qla_ddb_index  *nt_ddb_idx;
7125*4882a593Smuzhiyun 
7126*4882a593Smuzhiyun 	fw_ddb_entry = dma_pool_alloc(ha->fw_ddb_dma_pool, GFP_KERNEL,
7127*4882a593Smuzhiyun 				      &fw_ddb_dma);
7128*4882a593Smuzhiyun 	if (fw_ddb_entry == NULL) {
7129*4882a593Smuzhiyun 		DEBUG2(ql4_printk(KERN_ERR, ha, "Out of memory\n"));
7130*4882a593Smuzhiyun 		goto exit_new_nt_list;
7131*4882a593Smuzhiyun 	}
7132*4882a593Smuzhiyun 	max_ddbs =  is_qla40XX(ha) ? MAX_DEV_DB_ENTRIES_40XX :
7133*4882a593Smuzhiyun 				     MAX_DEV_DB_ENTRIES;
7134*4882a593Smuzhiyun 	fw_idx_size = sizeof(struct qla_ddb_index);
7135*4882a593Smuzhiyun 
7136*4882a593Smuzhiyun 	for (idx = 0; idx < max_ddbs; idx = next_idx) {
7137*4882a593Smuzhiyun 		ret = qla4xxx_get_fwddb_entry(ha, idx, fw_ddb_entry, fw_ddb_dma,
7138*4882a593Smuzhiyun 					      NULL, &next_idx, &state,
7139*4882a593Smuzhiyun 					      &conn_err, NULL, &conn_id);
7140*4882a593Smuzhiyun 		if (ret == QLA_ERROR)
7141*4882a593Smuzhiyun 			break;
7142*4882a593Smuzhiyun 
7143*4882a593Smuzhiyun 		/* Check if NT, then add it to list */
7144*4882a593Smuzhiyun 		if (strlen((char *)fw_ddb_entry->iscsi_name) == 0)
7145*4882a593Smuzhiyun 			goto continue_next_new_nt;
7146*4882a593Smuzhiyun 
7147*4882a593Smuzhiyun 		if (!(state == DDB_DS_NO_CONNECTION_ACTIVE))
7148*4882a593Smuzhiyun 			goto continue_next_new_nt;
7149*4882a593Smuzhiyun 
7150*4882a593Smuzhiyun 		DEBUG2(ql4_printk(KERN_INFO, ha,
7151*4882a593Smuzhiyun 				  "Adding  DDB to session = 0x%x\n", idx));
7152*4882a593Smuzhiyun 
7153*4882a593Smuzhiyun 		nt_ddb_idx = vmalloc(fw_idx_size);
7154*4882a593Smuzhiyun 		if (!nt_ddb_idx)
7155*4882a593Smuzhiyun 			break;
7156*4882a593Smuzhiyun 
7157*4882a593Smuzhiyun 		nt_ddb_idx->fw_ddb_idx = idx;
7158*4882a593Smuzhiyun 
7159*4882a593Smuzhiyun 		ret = qla4xxx_is_session_exists(ha, fw_ddb_entry, NULL);
7160*4882a593Smuzhiyun 		if (ret == QLA_SUCCESS) {
7161*4882a593Smuzhiyun 			/* free nt_ddb_idx and do not add to list_nt */
7162*4882a593Smuzhiyun 			vfree(nt_ddb_idx);
7163*4882a593Smuzhiyun 			goto continue_next_new_nt;
7164*4882a593Smuzhiyun 		}
7165*4882a593Smuzhiyun 
7166*4882a593Smuzhiyun 		if (target_id < max_ddbs)
7167*4882a593Smuzhiyun 			fw_ddb_entry->ddb_link = cpu_to_le16(target_id);
7168*4882a593Smuzhiyun 
7169*4882a593Smuzhiyun 		list_add_tail(&nt_ddb_idx->list, list_nt);
7170*4882a593Smuzhiyun 
7171*4882a593Smuzhiyun 		ret = qla4xxx_sess_conn_setup(ha, fw_ddb_entry, RESET_ADAPTER,
7172*4882a593Smuzhiyun 					      idx);
7173*4882a593Smuzhiyun 		if (ret == QLA_ERROR)
7174*4882a593Smuzhiyun 			goto exit_new_nt_list;
7175*4882a593Smuzhiyun 
7176*4882a593Smuzhiyun continue_next_new_nt:
7177*4882a593Smuzhiyun 		if (next_idx == 0)
7178*4882a593Smuzhiyun 			break;
7179*4882a593Smuzhiyun 	}
7180*4882a593Smuzhiyun 
7181*4882a593Smuzhiyun exit_new_nt_list:
7182*4882a593Smuzhiyun 	if (fw_ddb_entry)
7183*4882a593Smuzhiyun 		dma_pool_free(ha->fw_ddb_dma_pool, fw_ddb_entry, fw_ddb_dma);
7184*4882a593Smuzhiyun }
7185*4882a593Smuzhiyun 
7186*4882a593Smuzhiyun /**
7187*4882a593Smuzhiyun  * qla4xxx_sysfs_ddb_is_non_persistent - check for non-persistence of ddb entry
7188*4882a593Smuzhiyun  * @dev: dev associated with the sysfs entry
7189*4882a593Smuzhiyun  * @data: pointer to flashnode session object
7190*4882a593Smuzhiyun  *
7191*4882a593Smuzhiyun  * Returns:
7192*4882a593Smuzhiyun  *	1: if flashnode entry is non-persistent
7193*4882a593Smuzhiyun  *	0: if flashnode entry is persistent
7194*4882a593Smuzhiyun  **/
qla4xxx_sysfs_ddb_is_non_persistent(struct device * dev,void * data)7195*4882a593Smuzhiyun static int qla4xxx_sysfs_ddb_is_non_persistent(struct device *dev, void *data)
7196*4882a593Smuzhiyun {
7197*4882a593Smuzhiyun 	struct iscsi_bus_flash_session *fnode_sess;
7198*4882a593Smuzhiyun 
7199*4882a593Smuzhiyun 	if (!iscsi_flashnode_bus_match(dev, NULL))
7200*4882a593Smuzhiyun 		return 0;
7201*4882a593Smuzhiyun 
7202*4882a593Smuzhiyun 	fnode_sess = iscsi_dev_to_flash_session(dev);
7203*4882a593Smuzhiyun 
7204*4882a593Smuzhiyun 	return (fnode_sess->flash_state == DEV_DB_NON_PERSISTENT);
7205*4882a593Smuzhiyun }
7206*4882a593Smuzhiyun 
7207*4882a593Smuzhiyun /**
7208*4882a593Smuzhiyun  * qla4xxx_sysfs_ddb_tgt_create - Create sysfs entry for target
7209*4882a593Smuzhiyun  * @ha: pointer to host
7210*4882a593Smuzhiyun  * @fw_ddb_entry: flash ddb data
7211*4882a593Smuzhiyun  * @idx: target index
7212*4882a593Smuzhiyun  * @user: if set then this call is made from userland else from kernel
7213*4882a593Smuzhiyun  *
7214*4882a593Smuzhiyun  * Returns:
7215*4882a593Smuzhiyun  * On sucess: QLA_SUCCESS
7216*4882a593Smuzhiyun  * On failure: QLA_ERROR
7217*4882a593Smuzhiyun  *
7218*4882a593Smuzhiyun  * This create separate sysfs entries for session and connection attributes of
7219*4882a593Smuzhiyun  * the given fw ddb entry.
7220*4882a593Smuzhiyun  * If this is invoked as a result of a userspace call then the entry is marked
7221*4882a593Smuzhiyun  * as nonpersistent using flash_state field.
7222*4882a593Smuzhiyun  **/
qla4xxx_sysfs_ddb_tgt_create(struct scsi_qla_host * ha,struct dev_db_entry * fw_ddb_entry,uint16_t * idx,int user)7223*4882a593Smuzhiyun static int qla4xxx_sysfs_ddb_tgt_create(struct scsi_qla_host *ha,
7224*4882a593Smuzhiyun 					struct dev_db_entry *fw_ddb_entry,
7225*4882a593Smuzhiyun 					uint16_t *idx, int user)
7226*4882a593Smuzhiyun {
7227*4882a593Smuzhiyun 	struct iscsi_bus_flash_session *fnode_sess = NULL;
7228*4882a593Smuzhiyun 	struct iscsi_bus_flash_conn *fnode_conn = NULL;
7229*4882a593Smuzhiyun 	int rc = QLA_ERROR;
7230*4882a593Smuzhiyun 
7231*4882a593Smuzhiyun 	fnode_sess = iscsi_create_flashnode_sess(ha->host, *idx,
7232*4882a593Smuzhiyun 						 &qla4xxx_iscsi_transport, 0);
7233*4882a593Smuzhiyun 	if (!fnode_sess) {
7234*4882a593Smuzhiyun 		ql4_printk(KERN_ERR, ha,
7235*4882a593Smuzhiyun 			   "%s: Unable to create session sysfs entry for flashnode %d of host%lu\n",
7236*4882a593Smuzhiyun 			   __func__, *idx, ha->host_no);
7237*4882a593Smuzhiyun 		goto exit_tgt_create;
7238*4882a593Smuzhiyun 	}
7239*4882a593Smuzhiyun 
7240*4882a593Smuzhiyun 	fnode_conn = iscsi_create_flashnode_conn(ha->host, fnode_sess,
7241*4882a593Smuzhiyun 						 &qla4xxx_iscsi_transport, 0);
7242*4882a593Smuzhiyun 	if (!fnode_conn) {
7243*4882a593Smuzhiyun 		ql4_printk(KERN_ERR, ha,
7244*4882a593Smuzhiyun 			   "%s: Unable to create conn sysfs entry for flashnode %d of host%lu\n",
7245*4882a593Smuzhiyun 			   __func__, *idx, ha->host_no);
7246*4882a593Smuzhiyun 		goto free_sess;
7247*4882a593Smuzhiyun 	}
7248*4882a593Smuzhiyun 
7249*4882a593Smuzhiyun 	if (user) {
7250*4882a593Smuzhiyun 		fnode_sess->flash_state = DEV_DB_NON_PERSISTENT;
7251*4882a593Smuzhiyun 	} else {
7252*4882a593Smuzhiyun 		fnode_sess->flash_state = DEV_DB_PERSISTENT;
7253*4882a593Smuzhiyun 
7254*4882a593Smuzhiyun 		if (*idx == ha->pri_ddb_idx || *idx == ha->sec_ddb_idx)
7255*4882a593Smuzhiyun 			fnode_sess->is_boot_target = 1;
7256*4882a593Smuzhiyun 		else
7257*4882a593Smuzhiyun 			fnode_sess->is_boot_target = 0;
7258*4882a593Smuzhiyun 	}
7259*4882a593Smuzhiyun 
7260*4882a593Smuzhiyun 	rc = qla4xxx_copy_from_fwddb_param(fnode_sess, fnode_conn,
7261*4882a593Smuzhiyun 					   fw_ddb_entry);
7262*4882a593Smuzhiyun 	if (rc)
7263*4882a593Smuzhiyun 		goto free_sess;
7264*4882a593Smuzhiyun 
7265*4882a593Smuzhiyun 	ql4_printk(KERN_INFO, ha, "%s: sysfs entry %s created\n",
7266*4882a593Smuzhiyun 		   __func__, fnode_sess->dev.kobj.name);
7267*4882a593Smuzhiyun 
7268*4882a593Smuzhiyun 	ql4_printk(KERN_INFO, ha, "%s: sysfs entry %s created\n",
7269*4882a593Smuzhiyun 		   __func__, fnode_conn->dev.kobj.name);
7270*4882a593Smuzhiyun 
7271*4882a593Smuzhiyun 	return QLA_SUCCESS;
7272*4882a593Smuzhiyun 
7273*4882a593Smuzhiyun free_sess:
7274*4882a593Smuzhiyun 	iscsi_destroy_flashnode_sess(fnode_sess);
7275*4882a593Smuzhiyun 
7276*4882a593Smuzhiyun exit_tgt_create:
7277*4882a593Smuzhiyun 	return QLA_ERROR;
7278*4882a593Smuzhiyun }
7279*4882a593Smuzhiyun 
7280*4882a593Smuzhiyun /**
7281*4882a593Smuzhiyun  * qla4xxx_sysfs_ddb_add - Add new ddb entry in flash
7282*4882a593Smuzhiyun  * @shost: pointer to host
7283*4882a593Smuzhiyun  * @buf: type of ddb entry (ipv4/ipv6)
7284*4882a593Smuzhiyun  * @len: length of buf
7285*4882a593Smuzhiyun  *
7286*4882a593Smuzhiyun  * This creates new ddb entry in the flash by finding first free index and
7287*4882a593Smuzhiyun  * storing default ddb there. And then create sysfs entry for the new ddb entry.
7288*4882a593Smuzhiyun  **/
qla4xxx_sysfs_ddb_add(struct Scsi_Host * shost,const char * buf,int len)7289*4882a593Smuzhiyun static int qla4xxx_sysfs_ddb_add(struct Scsi_Host *shost, const char *buf,
7290*4882a593Smuzhiyun 				 int len)
7291*4882a593Smuzhiyun {
7292*4882a593Smuzhiyun 	struct scsi_qla_host *ha = to_qla_host(shost);
7293*4882a593Smuzhiyun 	struct dev_db_entry *fw_ddb_entry = NULL;
7294*4882a593Smuzhiyun 	dma_addr_t fw_ddb_entry_dma;
7295*4882a593Smuzhiyun 	struct device *dev;
7296*4882a593Smuzhiyun 	uint16_t idx = 0;
7297*4882a593Smuzhiyun 	uint16_t max_ddbs = 0;
7298*4882a593Smuzhiyun 	uint32_t options = 0;
7299*4882a593Smuzhiyun 	uint32_t rval = QLA_ERROR;
7300*4882a593Smuzhiyun 
7301*4882a593Smuzhiyun 	if (strncasecmp(PORTAL_TYPE_IPV4, buf, 4) &&
7302*4882a593Smuzhiyun 	    strncasecmp(PORTAL_TYPE_IPV6, buf, 4)) {
7303*4882a593Smuzhiyun 		DEBUG2(ql4_printk(KERN_ERR, ha, "%s: Invalid portal type\n",
7304*4882a593Smuzhiyun 				  __func__));
7305*4882a593Smuzhiyun 		goto exit_ddb_add;
7306*4882a593Smuzhiyun 	}
7307*4882a593Smuzhiyun 
7308*4882a593Smuzhiyun 	max_ddbs =  is_qla40XX(ha) ? MAX_PRST_DEV_DB_ENTRIES :
7309*4882a593Smuzhiyun 				     MAX_DEV_DB_ENTRIES;
7310*4882a593Smuzhiyun 
7311*4882a593Smuzhiyun 	fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
7312*4882a593Smuzhiyun 					  &fw_ddb_entry_dma, GFP_KERNEL);
7313*4882a593Smuzhiyun 	if (!fw_ddb_entry) {
7314*4882a593Smuzhiyun 		DEBUG2(ql4_printk(KERN_ERR, ha,
7315*4882a593Smuzhiyun 				  "%s: Unable to allocate dma buffer\n",
7316*4882a593Smuzhiyun 				  __func__));
7317*4882a593Smuzhiyun 		goto exit_ddb_add;
7318*4882a593Smuzhiyun 	}
7319*4882a593Smuzhiyun 
7320*4882a593Smuzhiyun 	dev = iscsi_find_flashnode_sess(ha->host, NULL,
7321*4882a593Smuzhiyun 					qla4xxx_sysfs_ddb_is_non_persistent);
7322*4882a593Smuzhiyun 	if (dev) {
7323*4882a593Smuzhiyun 		ql4_printk(KERN_ERR, ha,
7324*4882a593Smuzhiyun 			   "%s: A non-persistent entry %s found\n",
7325*4882a593Smuzhiyun 			   __func__, dev->kobj.name);
7326*4882a593Smuzhiyun 		put_device(dev);
7327*4882a593Smuzhiyun 		goto exit_ddb_add;
7328*4882a593Smuzhiyun 	}
7329*4882a593Smuzhiyun 
7330*4882a593Smuzhiyun 	/* Index 0 and 1 are reserved for boot target entries */
7331*4882a593Smuzhiyun 	for (idx = 2; idx < max_ddbs; idx++) {
7332*4882a593Smuzhiyun 		if (qla4xxx_flashdb_by_index(ha, fw_ddb_entry,
7333*4882a593Smuzhiyun 					     fw_ddb_entry_dma, idx))
7334*4882a593Smuzhiyun 			break;
7335*4882a593Smuzhiyun 	}
7336*4882a593Smuzhiyun 
7337*4882a593Smuzhiyun 	if (idx == max_ddbs)
7338*4882a593Smuzhiyun 		goto exit_ddb_add;
7339*4882a593Smuzhiyun 
7340*4882a593Smuzhiyun 	if (!strncasecmp("ipv6", buf, 4))
7341*4882a593Smuzhiyun 		options |= IPV6_DEFAULT_DDB_ENTRY;
7342*4882a593Smuzhiyun 
7343*4882a593Smuzhiyun 	rval = qla4xxx_get_default_ddb(ha, options, fw_ddb_entry_dma);
7344*4882a593Smuzhiyun 	if (rval == QLA_ERROR)
7345*4882a593Smuzhiyun 		goto exit_ddb_add;
7346*4882a593Smuzhiyun 
7347*4882a593Smuzhiyun 	rval = qla4xxx_sysfs_ddb_tgt_create(ha, fw_ddb_entry, &idx, 1);
7348*4882a593Smuzhiyun 
7349*4882a593Smuzhiyun exit_ddb_add:
7350*4882a593Smuzhiyun 	if (fw_ddb_entry)
7351*4882a593Smuzhiyun 		dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
7352*4882a593Smuzhiyun 				  fw_ddb_entry, fw_ddb_entry_dma);
7353*4882a593Smuzhiyun 	if (rval == QLA_SUCCESS)
7354*4882a593Smuzhiyun 		return idx;
7355*4882a593Smuzhiyun 	else
7356*4882a593Smuzhiyun 		return -EIO;
7357*4882a593Smuzhiyun }
7358*4882a593Smuzhiyun 
7359*4882a593Smuzhiyun /**
7360*4882a593Smuzhiyun  * qla4xxx_sysfs_ddb_apply - write the target ddb contents to Flash
7361*4882a593Smuzhiyun  * @fnode_sess: pointer to session attrs of flash ddb entry
7362*4882a593Smuzhiyun  * @fnode_conn: pointer to connection attrs of flash ddb entry
7363*4882a593Smuzhiyun  *
7364*4882a593Smuzhiyun  * This writes the contents of target ddb buffer to Flash with a valid cookie
7365*4882a593Smuzhiyun  * value in order to make the ddb entry persistent.
7366*4882a593Smuzhiyun  **/
qla4xxx_sysfs_ddb_apply(struct iscsi_bus_flash_session * fnode_sess,struct iscsi_bus_flash_conn * fnode_conn)7367*4882a593Smuzhiyun static int  qla4xxx_sysfs_ddb_apply(struct iscsi_bus_flash_session *fnode_sess,
7368*4882a593Smuzhiyun 				    struct iscsi_bus_flash_conn *fnode_conn)
7369*4882a593Smuzhiyun {
7370*4882a593Smuzhiyun 	struct Scsi_Host *shost = iscsi_flash_session_to_shost(fnode_sess);
7371*4882a593Smuzhiyun 	struct scsi_qla_host *ha = to_qla_host(shost);
7372*4882a593Smuzhiyun 	uint32_t dev_db_start_offset = FLASH_OFFSET_DB_INFO;
7373*4882a593Smuzhiyun 	struct dev_db_entry *fw_ddb_entry = NULL;
7374*4882a593Smuzhiyun 	dma_addr_t fw_ddb_entry_dma;
7375*4882a593Smuzhiyun 	uint32_t options = 0;
7376*4882a593Smuzhiyun 	int rval = 0;
7377*4882a593Smuzhiyun 
7378*4882a593Smuzhiyun 	fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
7379*4882a593Smuzhiyun 					  &fw_ddb_entry_dma, GFP_KERNEL);
7380*4882a593Smuzhiyun 	if (!fw_ddb_entry) {
7381*4882a593Smuzhiyun 		DEBUG2(ql4_printk(KERN_ERR, ha,
7382*4882a593Smuzhiyun 				  "%s: Unable to allocate dma buffer\n",
7383*4882a593Smuzhiyun 				  __func__));
7384*4882a593Smuzhiyun 		rval = -ENOMEM;
7385*4882a593Smuzhiyun 		goto exit_ddb_apply;
7386*4882a593Smuzhiyun 	}
7387*4882a593Smuzhiyun 
7388*4882a593Smuzhiyun 	if (!strncasecmp(fnode_sess->portal_type, PORTAL_TYPE_IPV6, 4))
7389*4882a593Smuzhiyun 		options |= IPV6_DEFAULT_DDB_ENTRY;
7390*4882a593Smuzhiyun 
7391*4882a593Smuzhiyun 	rval = qla4xxx_get_default_ddb(ha, options, fw_ddb_entry_dma);
7392*4882a593Smuzhiyun 	if (rval == QLA_ERROR)
7393*4882a593Smuzhiyun 		goto exit_ddb_apply;
7394*4882a593Smuzhiyun 
7395*4882a593Smuzhiyun 	dev_db_start_offset += (fnode_sess->target_id *
7396*4882a593Smuzhiyun 				sizeof(*fw_ddb_entry));
7397*4882a593Smuzhiyun 
7398*4882a593Smuzhiyun 	qla4xxx_copy_to_fwddb_param(fnode_sess, fnode_conn, fw_ddb_entry);
7399*4882a593Smuzhiyun 	fw_ddb_entry->cookie = DDB_VALID_COOKIE;
7400*4882a593Smuzhiyun 
7401*4882a593Smuzhiyun 	rval = qla4xxx_set_flash(ha, fw_ddb_entry_dma, dev_db_start_offset,
7402*4882a593Smuzhiyun 				 sizeof(*fw_ddb_entry), FLASH_OPT_RMW_COMMIT);
7403*4882a593Smuzhiyun 
7404*4882a593Smuzhiyun 	if (rval == QLA_SUCCESS) {
7405*4882a593Smuzhiyun 		fnode_sess->flash_state = DEV_DB_PERSISTENT;
7406*4882a593Smuzhiyun 		ql4_printk(KERN_INFO, ha,
7407*4882a593Smuzhiyun 			   "%s: flash node %u of host %lu written to flash\n",
7408*4882a593Smuzhiyun 			   __func__, fnode_sess->target_id, ha->host_no);
7409*4882a593Smuzhiyun 	} else {
7410*4882a593Smuzhiyun 		rval = -EIO;
7411*4882a593Smuzhiyun 		ql4_printk(KERN_ERR, ha,
7412*4882a593Smuzhiyun 			   "%s: Error while writing flash node %u of host %lu to flash\n",
7413*4882a593Smuzhiyun 			   __func__, fnode_sess->target_id, ha->host_no);
7414*4882a593Smuzhiyun 	}
7415*4882a593Smuzhiyun 
7416*4882a593Smuzhiyun exit_ddb_apply:
7417*4882a593Smuzhiyun 	if (fw_ddb_entry)
7418*4882a593Smuzhiyun 		dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
7419*4882a593Smuzhiyun 				  fw_ddb_entry, fw_ddb_entry_dma);
7420*4882a593Smuzhiyun 	return rval;
7421*4882a593Smuzhiyun }
7422*4882a593Smuzhiyun 
qla4xxx_sysfs_ddb_conn_open(struct scsi_qla_host * ha,struct dev_db_entry * fw_ddb_entry,uint16_t idx)7423*4882a593Smuzhiyun static ssize_t qla4xxx_sysfs_ddb_conn_open(struct scsi_qla_host *ha,
7424*4882a593Smuzhiyun 					   struct dev_db_entry *fw_ddb_entry,
7425*4882a593Smuzhiyun 					   uint16_t idx)
7426*4882a593Smuzhiyun {
7427*4882a593Smuzhiyun 	struct dev_db_entry *ddb_entry = NULL;
7428*4882a593Smuzhiyun 	dma_addr_t ddb_entry_dma;
7429*4882a593Smuzhiyun 	unsigned long wtime;
7430*4882a593Smuzhiyun 	uint32_t mbx_sts = 0;
7431*4882a593Smuzhiyun 	uint32_t state = 0, conn_err = 0;
7432*4882a593Smuzhiyun 	uint16_t tmo = 0;
7433*4882a593Smuzhiyun 	int ret = 0;
7434*4882a593Smuzhiyun 
7435*4882a593Smuzhiyun 	ddb_entry = dma_alloc_coherent(&ha->pdev->dev, sizeof(*ddb_entry),
7436*4882a593Smuzhiyun 				       &ddb_entry_dma, GFP_KERNEL);
7437*4882a593Smuzhiyun 	if (!ddb_entry) {
7438*4882a593Smuzhiyun 		DEBUG2(ql4_printk(KERN_ERR, ha,
7439*4882a593Smuzhiyun 				  "%s: Unable to allocate dma buffer\n",
7440*4882a593Smuzhiyun 				  __func__));
7441*4882a593Smuzhiyun 		return QLA_ERROR;
7442*4882a593Smuzhiyun 	}
7443*4882a593Smuzhiyun 
7444*4882a593Smuzhiyun 	memcpy(ddb_entry, fw_ddb_entry, sizeof(*ddb_entry));
7445*4882a593Smuzhiyun 
7446*4882a593Smuzhiyun 	ret = qla4xxx_set_ddb_entry(ha, idx, ddb_entry_dma, &mbx_sts);
7447*4882a593Smuzhiyun 	if (ret != QLA_SUCCESS) {
7448*4882a593Smuzhiyun 		DEBUG2(ql4_printk(KERN_ERR, ha,
7449*4882a593Smuzhiyun 				  "%s: Unable to set ddb entry for index %d\n",
7450*4882a593Smuzhiyun 				  __func__, idx));
7451*4882a593Smuzhiyun 		goto exit_ddb_conn_open;
7452*4882a593Smuzhiyun 	}
7453*4882a593Smuzhiyun 
7454*4882a593Smuzhiyun 	qla4xxx_conn_open(ha, idx);
7455*4882a593Smuzhiyun 
7456*4882a593Smuzhiyun 	/* To ensure that sendtargets is done, wait for at least 12 secs */
7457*4882a593Smuzhiyun 	tmo = ((ha->def_timeout > LOGIN_TOV) &&
7458*4882a593Smuzhiyun 	       (ha->def_timeout < LOGIN_TOV * 10) ?
7459*4882a593Smuzhiyun 	       ha->def_timeout : LOGIN_TOV);
7460*4882a593Smuzhiyun 
7461*4882a593Smuzhiyun 	DEBUG2(ql4_printk(KERN_INFO, ha,
7462*4882a593Smuzhiyun 			  "Default time to wait for login to ddb %d\n", tmo));
7463*4882a593Smuzhiyun 
7464*4882a593Smuzhiyun 	wtime = jiffies + (HZ * tmo);
7465*4882a593Smuzhiyun 	do {
7466*4882a593Smuzhiyun 		ret = qla4xxx_get_fwddb_entry(ha, idx, NULL, 0, NULL,
7467*4882a593Smuzhiyun 					      NULL, &state, &conn_err, NULL,
7468*4882a593Smuzhiyun 					      NULL);
7469*4882a593Smuzhiyun 		if (ret == QLA_ERROR)
7470*4882a593Smuzhiyun 			continue;
7471*4882a593Smuzhiyun 
7472*4882a593Smuzhiyun 		if (state == DDB_DS_NO_CONNECTION_ACTIVE ||
7473*4882a593Smuzhiyun 		    state == DDB_DS_SESSION_FAILED)
7474*4882a593Smuzhiyun 			break;
7475*4882a593Smuzhiyun 
7476*4882a593Smuzhiyun 		schedule_timeout_uninterruptible(HZ / 10);
7477*4882a593Smuzhiyun 	} while (time_after(wtime, jiffies));
7478*4882a593Smuzhiyun 
7479*4882a593Smuzhiyun exit_ddb_conn_open:
7480*4882a593Smuzhiyun 	if (ddb_entry)
7481*4882a593Smuzhiyun 		dma_free_coherent(&ha->pdev->dev, sizeof(*ddb_entry),
7482*4882a593Smuzhiyun 				  ddb_entry, ddb_entry_dma);
7483*4882a593Smuzhiyun 	return ret;
7484*4882a593Smuzhiyun }
7485*4882a593Smuzhiyun 
qla4xxx_ddb_login_st(struct scsi_qla_host * ha,struct dev_db_entry * fw_ddb_entry,uint16_t target_id)7486*4882a593Smuzhiyun static int qla4xxx_ddb_login_st(struct scsi_qla_host *ha,
7487*4882a593Smuzhiyun 				struct dev_db_entry *fw_ddb_entry,
7488*4882a593Smuzhiyun 				uint16_t target_id)
7489*4882a593Smuzhiyun {
7490*4882a593Smuzhiyun 	struct qla_ddb_index *ddb_idx, *ddb_idx_tmp;
7491*4882a593Smuzhiyun 	struct list_head list_nt;
7492*4882a593Smuzhiyun 	uint16_t ddb_index;
7493*4882a593Smuzhiyun 	int ret = 0;
7494*4882a593Smuzhiyun 
7495*4882a593Smuzhiyun 	if (test_bit(AF_ST_DISCOVERY_IN_PROGRESS, &ha->flags)) {
7496*4882a593Smuzhiyun 		ql4_printk(KERN_WARNING, ha,
7497*4882a593Smuzhiyun 			   "%s: A discovery already in progress!\n", __func__);
7498*4882a593Smuzhiyun 		return QLA_ERROR;
7499*4882a593Smuzhiyun 	}
7500*4882a593Smuzhiyun 
7501*4882a593Smuzhiyun 	INIT_LIST_HEAD(&list_nt);
7502*4882a593Smuzhiyun 
7503*4882a593Smuzhiyun 	set_bit(AF_ST_DISCOVERY_IN_PROGRESS, &ha->flags);
7504*4882a593Smuzhiyun 
7505*4882a593Smuzhiyun 	ret = qla4xxx_get_ddb_index(ha, &ddb_index);
7506*4882a593Smuzhiyun 	if (ret == QLA_ERROR)
7507*4882a593Smuzhiyun 		goto exit_login_st_clr_bit;
7508*4882a593Smuzhiyun 
7509*4882a593Smuzhiyun 	ret = qla4xxx_sysfs_ddb_conn_open(ha, fw_ddb_entry, ddb_index);
7510*4882a593Smuzhiyun 	if (ret == QLA_ERROR)
7511*4882a593Smuzhiyun 		goto exit_login_st;
7512*4882a593Smuzhiyun 
7513*4882a593Smuzhiyun 	qla4xxx_build_new_nt_list(ha, &list_nt, target_id);
7514*4882a593Smuzhiyun 
7515*4882a593Smuzhiyun 	list_for_each_entry_safe(ddb_idx, ddb_idx_tmp, &list_nt, list) {
7516*4882a593Smuzhiyun 		list_del_init(&ddb_idx->list);
7517*4882a593Smuzhiyun 		qla4xxx_clear_ddb_entry(ha, ddb_idx->fw_ddb_idx);
7518*4882a593Smuzhiyun 		vfree(ddb_idx);
7519*4882a593Smuzhiyun 	}
7520*4882a593Smuzhiyun 
7521*4882a593Smuzhiyun exit_login_st:
7522*4882a593Smuzhiyun 	if (qla4xxx_clear_ddb_entry(ha, ddb_index) == QLA_ERROR) {
7523*4882a593Smuzhiyun 		ql4_printk(KERN_ERR, ha,
7524*4882a593Smuzhiyun 			   "Unable to clear DDB index = 0x%x\n", ddb_index);
7525*4882a593Smuzhiyun 	}
7526*4882a593Smuzhiyun 
7527*4882a593Smuzhiyun 	clear_bit(ddb_index, ha->ddb_idx_map);
7528*4882a593Smuzhiyun 
7529*4882a593Smuzhiyun exit_login_st_clr_bit:
7530*4882a593Smuzhiyun 	clear_bit(AF_ST_DISCOVERY_IN_PROGRESS, &ha->flags);
7531*4882a593Smuzhiyun 	return ret;
7532*4882a593Smuzhiyun }
7533*4882a593Smuzhiyun 
qla4xxx_ddb_login_nt(struct scsi_qla_host * ha,struct dev_db_entry * fw_ddb_entry,uint16_t idx)7534*4882a593Smuzhiyun static int qla4xxx_ddb_login_nt(struct scsi_qla_host *ha,
7535*4882a593Smuzhiyun 				struct dev_db_entry *fw_ddb_entry,
7536*4882a593Smuzhiyun 				uint16_t idx)
7537*4882a593Smuzhiyun {
7538*4882a593Smuzhiyun 	int ret = QLA_ERROR;
7539*4882a593Smuzhiyun 
7540*4882a593Smuzhiyun 	ret = qla4xxx_is_session_exists(ha, fw_ddb_entry, NULL);
7541*4882a593Smuzhiyun 	if (ret != QLA_SUCCESS)
7542*4882a593Smuzhiyun 		ret = qla4xxx_sess_conn_setup(ha, fw_ddb_entry, RESET_ADAPTER,
7543*4882a593Smuzhiyun 					      idx);
7544*4882a593Smuzhiyun 	else
7545*4882a593Smuzhiyun 		ret = -EPERM;
7546*4882a593Smuzhiyun 
7547*4882a593Smuzhiyun 	return ret;
7548*4882a593Smuzhiyun }
7549*4882a593Smuzhiyun 
7550*4882a593Smuzhiyun /**
7551*4882a593Smuzhiyun  * qla4xxx_sysfs_ddb_login - Login to the specified target
7552*4882a593Smuzhiyun  * @fnode_sess: pointer to session attrs of flash ddb entry
7553*4882a593Smuzhiyun  * @fnode_conn: pointer to connection attrs of flash ddb entry
7554*4882a593Smuzhiyun  *
7555*4882a593Smuzhiyun  * This logs in to the specified target
7556*4882a593Smuzhiyun  **/
qla4xxx_sysfs_ddb_login(struct iscsi_bus_flash_session * fnode_sess,struct iscsi_bus_flash_conn * fnode_conn)7557*4882a593Smuzhiyun static int qla4xxx_sysfs_ddb_login(struct iscsi_bus_flash_session *fnode_sess,
7558*4882a593Smuzhiyun 				   struct iscsi_bus_flash_conn *fnode_conn)
7559*4882a593Smuzhiyun {
7560*4882a593Smuzhiyun 	struct Scsi_Host *shost = iscsi_flash_session_to_shost(fnode_sess);
7561*4882a593Smuzhiyun 	struct scsi_qla_host *ha = to_qla_host(shost);
7562*4882a593Smuzhiyun 	struct dev_db_entry *fw_ddb_entry = NULL;
7563*4882a593Smuzhiyun 	dma_addr_t fw_ddb_entry_dma;
7564*4882a593Smuzhiyun 	uint32_t options = 0;
7565*4882a593Smuzhiyun 	int ret = 0;
7566*4882a593Smuzhiyun 
7567*4882a593Smuzhiyun 	if (fnode_sess->flash_state == DEV_DB_NON_PERSISTENT) {
7568*4882a593Smuzhiyun 		ql4_printk(KERN_ERR, ha,
7569*4882a593Smuzhiyun 			   "%s: Target info is not persistent\n", __func__);
7570*4882a593Smuzhiyun 		ret = -EIO;
7571*4882a593Smuzhiyun 		goto exit_ddb_login;
7572*4882a593Smuzhiyun 	}
7573*4882a593Smuzhiyun 
7574*4882a593Smuzhiyun 	fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
7575*4882a593Smuzhiyun 					  &fw_ddb_entry_dma, GFP_KERNEL);
7576*4882a593Smuzhiyun 	if (!fw_ddb_entry) {
7577*4882a593Smuzhiyun 		DEBUG2(ql4_printk(KERN_ERR, ha,
7578*4882a593Smuzhiyun 				  "%s: Unable to allocate dma buffer\n",
7579*4882a593Smuzhiyun 				  __func__));
7580*4882a593Smuzhiyun 		ret = -ENOMEM;
7581*4882a593Smuzhiyun 		goto exit_ddb_login;
7582*4882a593Smuzhiyun 	}
7583*4882a593Smuzhiyun 
7584*4882a593Smuzhiyun 	if (!strncasecmp(fnode_sess->portal_type, PORTAL_TYPE_IPV6, 4))
7585*4882a593Smuzhiyun 		options |= IPV6_DEFAULT_DDB_ENTRY;
7586*4882a593Smuzhiyun 
7587*4882a593Smuzhiyun 	ret = qla4xxx_get_default_ddb(ha, options, fw_ddb_entry_dma);
7588*4882a593Smuzhiyun 	if (ret == QLA_ERROR)
7589*4882a593Smuzhiyun 		goto exit_ddb_login;
7590*4882a593Smuzhiyun 
7591*4882a593Smuzhiyun 	qla4xxx_copy_to_fwddb_param(fnode_sess, fnode_conn, fw_ddb_entry);
7592*4882a593Smuzhiyun 	fw_ddb_entry->cookie = DDB_VALID_COOKIE;
7593*4882a593Smuzhiyun 
7594*4882a593Smuzhiyun 	if (strlen((char *)fw_ddb_entry->iscsi_name) == 0)
7595*4882a593Smuzhiyun 		ret = qla4xxx_ddb_login_st(ha, fw_ddb_entry,
7596*4882a593Smuzhiyun 					   fnode_sess->target_id);
7597*4882a593Smuzhiyun 	else
7598*4882a593Smuzhiyun 		ret = qla4xxx_ddb_login_nt(ha, fw_ddb_entry,
7599*4882a593Smuzhiyun 					   fnode_sess->target_id);
7600*4882a593Smuzhiyun 
7601*4882a593Smuzhiyun 	if (ret > 0)
7602*4882a593Smuzhiyun 		ret = -EIO;
7603*4882a593Smuzhiyun 
7604*4882a593Smuzhiyun exit_ddb_login:
7605*4882a593Smuzhiyun 	if (fw_ddb_entry)
7606*4882a593Smuzhiyun 		dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
7607*4882a593Smuzhiyun 				  fw_ddb_entry, fw_ddb_entry_dma);
7608*4882a593Smuzhiyun 	return ret;
7609*4882a593Smuzhiyun }
7610*4882a593Smuzhiyun 
7611*4882a593Smuzhiyun /**
7612*4882a593Smuzhiyun  * qla4xxx_sysfs_ddb_logout_sid - Logout session for the specified target
7613*4882a593Smuzhiyun  * @cls_sess: pointer to session to be logged out
7614*4882a593Smuzhiyun  *
7615*4882a593Smuzhiyun  * This performs session log out from the specified target
7616*4882a593Smuzhiyun  **/
qla4xxx_sysfs_ddb_logout_sid(struct iscsi_cls_session * cls_sess)7617*4882a593Smuzhiyun static int qla4xxx_sysfs_ddb_logout_sid(struct iscsi_cls_session *cls_sess)
7618*4882a593Smuzhiyun {
7619*4882a593Smuzhiyun 	struct iscsi_session *sess;
7620*4882a593Smuzhiyun 	struct ddb_entry *ddb_entry = NULL;
7621*4882a593Smuzhiyun 	struct scsi_qla_host *ha;
7622*4882a593Smuzhiyun 	struct dev_db_entry *fw_ddb_entry = NULL;
7623*4882a593Smuzhiyun 	dma_addr_t fw_ddb_entry_dma;
7624*4882a593Smuzhiyun 	unsigned long flags;
7625*4882a593Smuzhiyun 	unsigned long wtime;
7626*4882a593Smuzhiyun 	uint32_t ddb_state;
7627*4882a593Smuzhiyun 	int options;
7628*4882a593Smuzhiyun 	int ret = 0;
7629*4882a593Smuzhiyun 
7630*4882a593Smuzhiyun 	sess = cls_sess->dd_data;
7631*4882a593Smuzhiyun 	ddb_entry = sess->dd_data;
7632*4882a593Smuzhiyun 	ha = ddb_entry->ha;
7633*4882a593Smuzhiyun 
7634*4882a593Smuzhiyun 	if (ddb_entry->ddb_type != FLASH_DDB) {
7635*4882a593Smuzhiyun 		ql4_printk(KERN_ERR, ha, "%s: Not a flash node session\n",
7636*4882a593Smuzhiyun 			   __func__);
7637*4882a593Smuzhiyun 		ret = -ENXIO;
7638*4882a593Smuzhiyun 		goto exit_ddb_logout;
7639*4882a593Smuzhiyun 	}
7640*4882a593Smuzhiyun 
7641*4882a593Smuzhiyun 	if (test_bit(DF_BOOT_TGT, &ddb_entry->flags)) {
7642*4882a593Smuzhiyun 		ql4_printk(KERN_ERR, ha,
7643*4882a593Smuzhiyun 			   "%s: Logout from boot target entry is not permitted.\n",
7644*4882a593Smuzhiyun 			   __func__);
7645*4882a593Smuzhiyun 		ret = -EPERM;
7646*4882a593Smuzhiyun 		goto exit_ddb_logout;
7647*4882a593Smuzhiyun 	}
7648*4882a593Smuzhiyun 
7649*4882a593Smuzhiyun 	fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
7650*4882a593Smuzhiyun 					  &fw_ddb_entry_dma, GFP_KERNEL);
7651*4882a593Smuzhiyun 	if (!fw_ddb_entry) {
7652*4882a593Smuzhiyun 		ql4_printk(KERN_ERR, ha,
7653*4882a593Smuzhiyun 			   "%s: Unable to allocate dma buffer\n", __func__);
7654*4882a593Smuzhiyun 		ret = -ENOMEM;
7655*4882a593Smuzhiyun 		goto exit_ddb_logout;
7656*4882a593Smuzhiyun 	}
7657*4882a593Smuzhiyun 
7658*4882a593Smuzhiyun 	if (test_and_set_bit(DF_DISABLE_RELOGIN, &ddb_entry->flags))
7659*4882a593Smuzhiyun 		goto ddb_logout_init;
7660*4882a593Smuzhiyun 
7661*4882a593Smuzhiyun 	ret = qla4xxx_get_fwddb_entry(ha, ddb_entry->fw_ddb_index,
7662*4882a593Smuzhiyun 				      fw_ddb_entry, fw_ddb_entry_dma,
7663*4882a593Smuzhiyun 				      NULL, NULL, &ddb_state, NULL,
7664*4882a593Smuzhiyun 				      NULL, NULL);
7665*4882a593Smuzhiyun 	if (ret == QLA_ERROR)
7666*4882a593Smuzhiyun 		goto ddb_logout_init;
7667*4882a593Smuzhiyun 
7668*4882a593Smuzhiyun 	if (ddb_state == DDB_DS_SESSION_ACTIVE)
7669*4882a593Smuzhiyun 		goto ddb_logout_init;
7670*4882a593Smuzhiyun 
7671*4882a593Smuzhiyun 	/* wait until next relogin is triggered using DF_RELOGIN and
7672*4882a593Smuzhiyun 	 * clear DF_RELOGIN to avoid invocation of further relogin
7673*4882a593Smuzhiyun 	 */
7674*4882a593Smuzhiyun 	wtime = jiffies + (HZ * RELOGIN_TOV);
7675*4882a593Smuzhiyun 	do {
7676*4882a593Smuzhiyun 		if (test_and_clear_bit(DF_RELOGIN, &ddb_entry->flags))
7677*4882a593Smuzhiyun 			goto ddb_logout_init;
7678*4882a593Smuzhiyun 
7679*4882a593Smuzhiyun 		schedule_timeout_uninterruptible(HZ);
7680*4882a593Smuzhiyun 	} while ((time_after(wtime, jiffies)));
7681*4882a593Smuzhiyun 
7682*4882a593Smuzhiyun ddb_logout_init:
7683*4882a593Smuzhiyun 	atomic_set(&ddb_entry->retry_relogin_timer, INVALID_ENTRY);
7684*4882a593Smuzhiyun 	atomic_set(&ddb_entry->relogin_timer, 0);
7685*4882a593Smuzhiyun 
7686*4882a593Smuzhiyun 	options = LOGOUT_OPTION_CLOSE_SESSION;
7687*4882a593Smuzhiyun 	qla4xxx_session_logout_ddb(ha, ddb_entry, options);
7688*4882a593Smuzhiyun 
7689*4882a593Smuzhiyun 	memset(fw_ddb_entry, 0, sizeof(*fw_ddb_entry));
7690*4882a593Smuzhiyun 	wtime = jiffies + (HZ * LOGOUT_TOV);
7691*4882a593Smuzhiyun 	do {
7692*4882a593Smuzhiyun 		ret = qla4xxx_get_fwddb_entry(ha, ddb_entry->fw_ddb_index,
7693*4882a593Smuzhiyun 					      fw_ddb_entry, fw_ddb_entry_dma,
7694*4882a593Smuzhiyun 					      NULL, NULL, &ddb_state, NULL,
7695*4882a593Smuzhiyun 					      NULL, NULL);
7696*4882a593Smuzhiyun 		if (ret == QLA_ERROR)
7697*4882a593Smuzhiyun 			goto ddb_logout_clr_sess;
7698*4882a593Smuzhiyun 
7699*4882a593Smuzhiyun 		if ((ddb_state == DDB_DS_NO_CONNECTION_ACTIVE) ||
7700*4882a593Smuzhiyun 		    (ddb_state == DDB_DS_SESSION_FAILED))
7701*4882a593Smuzhiyun 			goto ddb_logout_clr_sess;
7702*4882a593Smuzhiyun 
7703*4882a593Smuzhiyun 		schedule_timeout_uninterruptible(HZ);
7704*4882a593Smuzhiyun 	} while ((time_after(wtime, jiffies)));
7705*4882a593Smuzhiyun 
7706*4882a593Smuzhiyun ddb_logout_clr_sess:
7707*4882a593Smuzhiyun 	qla4xxx_clear_ddb_entry(ha, ddb_entry->fw_ddb_index);
7708*4882a593Smuzhiyun 	/*
7709*4882a593Smuzhiyun 	 * we have decremented the reference count of the driver
7710*4882a593Smuzhiyun 	 * when we setup the session to have the driver unload
7711*4882a593Smuzhiyun 	 * to be seamless without actually destroying the
7712*4882a593Smuzhiyun 	 * session
7713*4882a593Smuzhiyun 	 **/
7714*4882a593Smuzhiyun 	try_module_get(qla4xxx_iscsi_transport.owner);
7715*4882a593Smuzhiyun 	iscsi_destroy_endpoint(ddb_entry->conn->ep);
7716*4882a593Smuzhiyun 
7717*4882a593Smuzhiyun 	spin_lock_irqsave(&ha->hardware_lock, flags);
7718*4882a593Smuzhiyun 	qla4xxx_free_ddb(ha, ddb_entry);
7719*4882a593Smuzhiyun 	clear_bit(ddb_entry->fw_ddb_index, ha->ddb_idx_map);
7720*4882a593Smuzhiyun 	spin_unlock_irqrestore(&ha->hardware_lock, flags);
7721*4882a593Smuzhiyun 
7722*4882a593Smuzhiyun 	iscsi_session_teardown(ddb_entry->sess);
7723*4882a593Smuzhiyun 
7724*4882a593Smuzhiyun 	clear_bit(DF_DISABLE_RELOGIN, &ddb_entry->flags);
7725*4882a593Smuzhiyun 	ret = QLA_SUCCESS;
7726*4882a593Smuzhiyun 
7727*4882a593Smuzhiyun exit_ddb_logout:
7728*4882a593Smuzhiyun 	if (fw_ddb_entry)
7729*4882a593Smuzhiyun 		dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
7730*4882a593Smuzhiyun 				  fw_ddb_entry, fw_ddb_entry_dma);
7731*4882a593Smuzhiyun 	return ret;
7732*4882a593Smuzhiyun }
7733*4882a593Smuzhiyun 
7734*4882a593Smuzhiyun /**
7735*4882a593Smuzhiyun  * qla4xxx_sysfs_ddb_logout - Logout from the specified target
7736*4882a593Smuzhiyun  * @fnode_sess: pointer to session attrs of flash ddb entry
7737*4882a593Smuzhiyun  * @fnode_conn: pointer to connection attrs of flash ddb entry
7738*4882a593Smuzhiyun  *
7739*4882a593Smuzhiyun  * This performs log out from the specified target
7740*4882a593Smuzhiyun  **/
qla4xxx_sysfs_ddb_logout(struct iscsi_bus_flash_session * fnode_sess,struct iscsi_bus_flash_conn * fnode_conn)7741*4882a593Smuzhiyun static int qla4xxx_sysfs_ddb_logout(struct iscsi_bus_flash_session *fnode_sess,
7742*4882a593Smuzhiyun 				    struct iscsi_bus_flash_conn *fnode_conn)
7743*4882a593Smuzhiyun {
7744*4882a593Smuzhiyun 	struct Scsi_Host *shost = iscsi_flash_session_to_shost(fnode_sess);
7745*4882a593Smuzhiyun 	struct scsi_qla_host *ha = to_qla_host(shost);
7746*4882a593Smuzhiyun 	struct ql4_tuple_ddb *flash_tddb = NULL;
7747*4882a593Smuzhiyun 	struct ql4_tuple_ddb *tmp_tddb = NULL;
7748*4882a593Smuzhiyun 	struct dev_db_entry *fw_ddb_entry = NULL;
7749*4882a593Smuzhiyun 	struct ddb_entry *ddb_entry = NULL;
7750*4882a593Smuzhiyun 	dma_addr_t fw_ddb_dma;
7751*4882a593Smuzhiyun 	uint32_t next_idx = 0;
7752*4882a593Smuzhiyun 	uint32_t state = 0, conn_err = 0;
7753*4882a593Smuzhiyun 	uint16_t conn_id = 0;
7754*4882a593Smuzhiyun 	int idx, index;
7755*4882a593Smuzhiyun 	int status, ret = 0;
7756*4882a593Smuzhiyun 
7757*4882a593Smuzhiyun 	fw_ddb_entry = dma_pool_alloc(ha->fw_ddb_dma_pool, GFP_KERNEL,
7758*4882a593Smuzhiyun 				      &fw_ddb_dma);
7759*4882a593Smuzhiyun 	if (fw_ddb_entry == NULL) {
7760*4882a593Smuzhiyun 		ql4_printk(KERN_ERR, ha, "%s:Out of memory\n", __func__);
7761*4882a593Smuzhiyun 		ret = -ENOMEM;
7762*4882a593Smuzhiyun 		goto exit_ddb_logout;
7763*4882a593Smuzhiyun 	}
7764*4882a593Smuzhiyun 
7765*4882a593Smuzhiyun 	flash_tddb = vzalloc(sizeof(*flash_tddb));
7766*4882a593Smuzhiyun 	if (!flash_tddb) {
7767*4882a593Smuzhiyun 		ql4_printk(KERN_WARNING, ha,
7768*4882a593Smuzhiyun 			   "%s:Memory Allocation failed.\n", __func__);
7769*4882a593Smuzhiyun 		ret = -ENOMEM;
7770*4882a593Smuzhiyun 		goto exit_ddb_logout;
7771*4882a593Smuzhiyun 	}
7772*4882a593Smuzhiyun 
7773*4882a593Smuzhiyun 	tmp_tddb = vzalloc(sizeof(*tmp_tddb));
7774*4882a593Smuzhiyun 	if (!tmp_tddb) {
7775*4882a593Smuzhiyun 		ql4_printk(KERN_WARNING, ha,
7776*4882a593Smuzhiyun 			   "%s:Memory Allocation failed.\n", __func__);
7777*4882a593Smuzhiyun 		ret = -ENOMEM;
7778*4882a593Smuzhiyun 		goto exit_ddb_logout;
7779*4882a593Smuzhiyun 	}
7780*4882a593Smuzhiyun 
7781*4882a593Smuzhiyun 	if (!fnode_sess->targetname) {
7782*4882a593Smuzhiyun 		ql4_printk(KERN_ERR, ha,
7783*4882a593Smuzhiyun 			   "%s:Cannot logout from SendTarget entry\n",
7784*4882a593Smuzhiyun 			   __func__);
7785*4882a593Smuzhiyun 		ret = -EPERM;
7786*4882a593Smuzhiyun 		goto exit_ddb_logout;
7787*4882a593Smuzhiyun 	}
7788*4882a593Smuzhiyun 
7789*4882a593Smuzhiyun 	if (fnode_sess->is_boot_target) {
7790*4882a593Smuzhiyun 		ql4_printk(KERN_ERR, ha,
7791*4882a593Smuzhiyun 			   "%s: Logout from boot target entry is not permitted.\n",
7792*4882a593Smuzhiyun 			   __func__);
7793*4882a593Smuzhiyun 		ret = -EPERM;
7794*4882a593Smuzhiyun 		goto exit_ddb_logout;
7795*4882a593Smuzhiyun 	}
7796*4882a593Smuzhiyun 
7797*4882a593Smuzhiyun 	strlcpy(flash_tddb->iscsi_name, fnode_sess->targetname,
7798*4882a593Smuzhiyun 		ISCSI_NAME_SIZE);
7799*4882a593Smuzhiyun 
7800*4882a593Smuzhiyun 	if (!strncmp(fnode_sess->portal_type, PORTAL_TYPE_IPV6, 4))
7801*4882a593Smuzhiyun 		sprintf(flash_tddb->ip_addr, "%pI6", fnode_conn->ipaddress);
7802*4882a593Smuzhiyun 	else
7803*4882a593Smuzhiyun 		sprintf(flash_tddb->ip_addr, "%pI4", fnode_conn->ipaddress);
7804*4882a593Smuzhiyun 
7805*4882a593Smuzhiyun 	flash_tddb->tpgt = fnode_sess->tpgt;
7806*4882a593Smuzhiyun 	flash_tddb->port = fnode_conn->port;
7807*4882a593Smuzhiyun 
7808*4882a593Smuzhiyun 	COPY_ISID(flash_tddb->isid, fnode_sess->isid);
7809*4882a593Smuzhiyun 
7810*4882a593Smuzhiyun 	for (idx = 0; idx < MAX_DDB_ENTRIES; idx++) {
7811*4882a593Smuzhiyun 		ddb_entry = qla4xxx_lookup_ddb_by_fw_index(ha, idx);
7812*4882a593Smuzhiyun 		if (ddb_entry == NULL)
7813*4882a593Smuzhiyun 			continue;
7814*4882a593Smuzhiyun 
7815*4882a593Smuzhiyun 		if (ddb_entry->ddb_type != FLASH_DDB)
7816*4882a593Smuzhiyun 			continue;
7817*4882a593Smuzhiyun 
7818*4882a593Smuzhiyun 		index = ddb_entry->sess->target_id;
7819*4882a593Smuzhiyun 		status = qla4xxx_get_fwddb_entry(ha, index, fw_ddb_entry,
7820*4882a593Smuzhiyun 						 fw_ddb_dma, NULL, &next_idx,
7821*4882a593Smuzhiyun 						 &state, &conn_err, NULL,
7822*4882a593Smuzhiyun 						 &conn_id);
7823*4882a593Smuzhiyun 		if (status == QLA_ERROR) {
7824*4882a593Smuzhiyun 			ret = -ENOMEM;
7825*4882a593Smuzhiyun 			break;
7826*4882a593Smuzhiyun 		}
7827*4882a593Smuzhiyun 
7828*4882a593Smuzhiyun 		qla4xxx_convert_param_ddb(fw_ddb_entry, tmp_tddb, NULL);
7829*4882a593Smuzhiyun 
7830*4882a593Smuzhiyun 		status = qla4xxx_compare_tuple_ddb(ha, flash_tddb, tmp_tddb,
7831*4882a593Smuzhiyun 						   true);
7832*4882a593Smuzhiyun 		if (status == QLA_SUCCESS) {
7833*4882a593Smuzhiyun 			ret = qla4xxx_sysfs_ddb_logout_sid(ddb_entry->sess);
7834*4882a593Smuzhiyun 			break;
7835*4882a593Smuzhiyun 		}
7836*4882a593Smuzhiyun 	}
7837*4882a593Smuzhiyun 
7838*4882a593Smuzhiyun 	if (idx == MAX_DDB_ENTRIES)
7839*4882a593Smuzhiyun 		ret = -ESRCH;
7840*4882a593Smuzhiyun 
7841*4882a593Smuzhiyun exit_ddb_logout:
7842*4882a593Smuzhiyun 	if (flash_tddb)
7843*4882a593Smuzhiyun 		vfree(flash_tddb);
7844*4882a593Smuzhiyun 	if (tmp_tddb)
7845*4882a593Smuzhiyun 		vfree(tmp_tddb);
7846*4882a593Smuzhiyun 	if (fw_ddb_entry)
7847*4882a593Smuzhiyun 		dma_pool_free(ha->fw_ddb_dma_pool, fw_ddb_entry, fw_ddb_dma);
7848*4882a593Smuzhiyun 
7849*4882a593Smuzhiyun 	return ret;
7850*4882a593Smuzhiyun }
7851*4882a593Smuzhiyun 
7852*4882a593Smuzhiyun static int
qla4xxx_sysfs_ddb_get_param(struct iscsi_bus_flash_session * fnode_sess,int param,char * buf)7853*4882a593Smuzhiyun qla4xxx_sysfs_ddb_get_param(struct iscsi_bus_flash_session *fnode_sess,
7854*4882a593Smuzhiyun 			    int param, char *buf)
7855*4882a593Smuzhiyun {
7856*4882a593Smuzhiyun 	struct Scsi_Host *shost = iscsi_flash_session_to_shost(fnode_sess);
7857*4882a593Smuzhiyun 	struct scsi_qla_host *ha = to_qla_host(shost);
7858*4882a593Smuzhiyun 	struct iscsi_bus_flash_conn *fnode_conn;
7859*4882a593Smuzhiyun 	struct ql4_chap_table chap_tbl;
7860*4882a593Smuzhiyun 	struct device *dev;
7861*4882a593Smuzhiyun 	int parent_type;
7862*4882a593Smuzhiyun 	int rc = 0;
7863*4882a593Smuzhiyun 
7864*4882a593Smuzhiyun 	dev = iscsi_find_flashnode_conn(fnode_sess);
7865*4882a593Smuzhiyun 	if (!dev)
7866*4882a593Smuzhiyun 		return -EIO;
7867*4882a593Smuzhiyun 
7868*4882a593Smuzhiyun 	fnode_conn = iscsi_dev_to_flash_conn(dev);
7869*4882a593Smuzhiyun 
7870*4882a593Smuzhiyun 	switch (param) {
7871*4882a593Smuzhiyun 	case ISCSI_FLASHNODE_IS_FW_ASSIGNED_IPV6:
7872*4882a593Smuzhiyun 		rc = sprintf(buf, "%u\n", fnode_conn->is_fw_assigned_ipv6);
7873*4882a593Smuzhiyun 		break;
7874*4882a593Smuzhiyun 	case ISCSI_FLASHNODE_PORTAL_TYPE:
7875*4882a593Smuzhiyun 		rc = sprintf(buf, "%s\n", fnode_sess->portal_type);
7876*4882a593Smuzhiyun 		break;
7877*4882a593Smuzhiyun 	case ISCSI_FLASHNODE_AUTO_SND_TGT_DISABLE:
7878*4882a593Smuzhiyun 		rc = sprintf(buf, "%u\n", fnode_sess->auto_snd_tgt_disable);
7879*4882a593Smuzhiyun 		break;
7880*4882a593Smuzhiyun 	case ISCSI_FLASHNODE_DISCOVERY_SESS:
7881*4882a593Smuzhiyun 		rc = sprintf(buf, "%u\n", fnode_sess->discovery_sess);
7882*4882a593Smuzhiyun 		break;
7883*4882a593Smuzhiyun 	case ISCSI_FLASHNODE_ENTRY_EN:
7884*4882a593Smuzhiyun 		rc = sprintf(buf, "%u\n", fnode_sess->entry_state);
7885*4882a593Smuzhiyun 		break;
7886*4882a593Smuzhiyun 	case ISCSI_FLASHNODE_HDR_DGST_EN:
7887*4882a593Smuzhiyun 		rc = sprintf(buf, "%u\n", fnode_conn->hdrdgst_en);
7888*4882a593Smuzhiyun 		break;
7889*4882a593Smuzhiyun 	case ISCSI_FLASHNODE_DATA_DGST_EN:
7890*4882a593Smuzhiyun 		rc = sprintf(buf, "%u\n", fnode_conn->datadgst_en);
7891*4882a593Smuzhiyun 		break;
7892*4882a593Smuzhiyun 	case ISCSI_FLASHNODE_IMM_DATA_EN:
7893*4882a593Smuzhiyun 		rc = sprintf(buf, "%u\n", fnode_sess->imm_data_en);
7894*4882a593Smuzhiyun 		break;
7895*4882a593Smuzhiyun 	case ISCSI_FLASHNODE_INITIAL_R2T_EN:
7896*4882a593Smuzhiyun 		rc = sprintf(buf, "%u\n", fnode_sess->initial_r2t_en);
7897*4882a593Smuzhiyun 		break;
7898*4882a593Smuzhiyun 	case ISCSI_FLASHNODE_DATASEQ_INORDER:
7899*4882a593Smuzhiyun 		rc = sprintf(buf, "%u\n", fnode_sess->dataseq_inorder_en);
7900*4882a593Smuzhiyun 		break;
7901*4882a593Smuzhiyun 	case ISCSI_FLASHNODE_PDU_INORDER:
7902*4882a593Smuzhiyun 		rc = sprintf(buf, "%u\n", fnode_sess->pdu_inorder_en);
7903*4882a593Smuzhiyun 		break;
7904*4882a593Smuzhiyun 	case ISCSI_FLASHNODE_CHAP_AUTH_EN:
7905*4882a593Smuzhiyun 		rc = sprintf(buf, "%u\n", fnode_sess->chap_auth_en);
7906*4882a593Smuzhiyun 		break;
7907*4882a593Smuzhiyun 	case ISCSI_FLASHNODE_SNACK_REQ_EN:
7908*4882a593Smuzhiyun 		rc = sprintf(buf, "%u\n", fnode_conn->snack_req_en);
7909*4882a593Smuzhiyun 		break;
7910*4882a593Smuzhiyun 	case ISCSI_FLASHNODE_DISCOVERY_LOGOUT_EN:
7911*4882a593Smuzhiyun 		rc = sprintf(buf, "%u\n", fnode_sess->discovery_logout_en);
7912*4882a593Smuzhiyun 		break;
7913*4882a593Smuzhiyun 	case ISCSI_FLASHNODE_BIDI_CHAP_EN:
7914*4882a593Smuzhiyun 		rc = sprintf(buf, "%u\n", fnode_sess->bidi_chap_en);
7915*4882a593Smuzhiyun 		break;
7916*4882a593Smuzhiyun 	case ISCSI_FLASHNODE_DISCOVERY_AUTH_OPTIONAL:
7917*4882a593Smuzhiyun 		rc = sprintf(buf, "%u\n", fnode_sess->discovery_auth_optional);
7918*4882a593Smuzhiyun 		break;
7919*4882a593Smuzhiyun 	case ISCSI_FLASHNODE_ERL:
7920*4882a593Smuzhiyun 		rc = sprintf(buf, "%u\n", fnode_sess->erl);
7921*4882a593Smuzhiyun 		break;
7922*4882a593Smuzhiyun 	case ISCSI_FLASHNODE_TCP_TIMESTAMP_STAT:
7923*4882a593Smuzhiyun 		rc = sprintf(buf, "%u\n", fnode_conn->tcp_timestamp_stat);
7924*4882a593Smuzhiyun 		break;
7925*4882a593Smuzhiyun 	case ISCSI_FLASHNODE_TCP_NAGLE_DISABLE:
7926*4882a593Smuzhiyun 		rc = sprintf(buf, "%u\n", fnode_conn->tcp_nagle_disable);
7927*4882a593Smuzhiyun 		break;
7928*4882a593Smuzhiyun 	case ISCSI_FLASHNODE_TCP_WSF_DISABLE:
7929*4882a593Smuzhiyun 		rc = sprintf(buf, "%u\n", fnode_conn->tcp_wsf_disable);
7930*4882a593Smuzhiyun 		break;
7931*4882a593Smuzhiyun 	case ISCSI_FLASHNODE_TCP_TIMER_SCALE:
7932*4882a593Smuzhiyun 		rc = sprintf(buf, "%u\n", fnode_conn->tcp_timer_scale);
7933*4882a593Smuzhiyun 		break;
7934*4882a593Smuzhiyun 	case ISCSI_FLASHNODE_TCP_TIMESTAMP_EN:
7935*4882a593Smuzhiyun 		rc = sprintf(buf, "%u\n", fnode_conn->tcp_timestamp_en);
7936*4882a593Smuzhiyun 		break;
7937*4882a593Smuzhiyun 	case ISCSI_FLASHNODE_IP_FRAG_DISABLE:
7938*4882a593Smuzhiyun 		rc = sprintf(buf, "%u\n", fnode_conn->fragment_disable);
7939*4882a593Smuzhiyun 		break;
7940*4882a593Smuzhiyun 	case ISCSI_FLASHNODE_MAX_RECV_DLENGTH:
7941*4882a593Smuzhiyun 		rc = sprintf(buf, "%u\n", fnode_conn->max_recv_dlength);
7942*4882a593Smuzhiyun 		break;
7943*4882a593Smuzhiyun 	case ISCSI_FLASHNODE_MAX_XMIT_DLENGTH:
7944*4882a593Smuzhiyun 		rc = sprintf(buf, "%u\n", fnode_conn->max_xmit_dlength);
7945*4882a593Smuzhiyun 		break;
7946*4882a593Smuzhiyun 	case ISCSI_FLASHNODE_FIRST_BURST:
7947*4882a593Smuzhiyun 		rc = sprintf(buf, "%u\n", fnode_sess->first_burst);
7948*4882a593Smuzhiyun 		break;
7949*4882a593Smuzhiyun 	case ISCSI_FLASHNODE_DEF_TIME2WAIT:
7950*4882a593Smuzhiyun 		rc = sprintf(buf, "%u\n", fnode_sess->time2wait);
7951*4882a593Smuzhiyun 		break;
7952*4882a593Smuzhiyun 	case ISCSI_FLASHNODE_DEF_TIME2RETAIN:
7953*4882a593Smuzhiyun 		rc = sprintf(buf, "%u\n", fnode_sess->time2retain);
7954*4882a593Smuzhiyun 		break;
7955*4882a593Smuzhiyun 	case ISCSI_FLASHNODE_MAX_R2T:
7956*4882a593Smuzhiyun 		rc = sprintf(buf, "%u\n", fnode_sess->max_r2t);
7957*4882a593Smuzhiyun 		break;
7958*4882a593Smuzhiyun 	case ISCSI_FLASHNODE_KEEPALIVE_TMO:
7959*4882a593Smuzhiyun 		rc = sprintf(buf, "%u\n", fnode_conn->keepalive_timeout);
7960*4882a593Smuzhiyun 		break;
7961*4882a593Smuzhiyun 	case ISCSI_FLASHNODE_ISID:
7962*4882a593Smuzhiyun 		rc = sprintf(buf, "%pm\n", fnode_sess->isid);
7963*4882a593Smuzhiyun 		break;
7964*4882a593Smuzhiyun 	case ISCSI_FLASHNODE_TSID:
7965*4882a593Smuzhiyun 		rc = sprintf(buf, "%u\n", fnode_sess->tsid);
7966*4882a593Smuzhiyun 		break;
7967*4882a593Smuzhiyun 	case ISCSI_FLASHNODE_PORT:
7968*4882a593Smuzhiyun 		rc = sprintf(buf, "%d\n", fnode_conn->port);
7969*4882a593Smuzhiyun 		break;
7970*4882a593Smuzhiyun 	case ISCSI_FLASHNODE_MAX_BURST:
7971*4882a593Smuzhiyun 		rc = sprintf(buf, "%u\n", fnode_sess->max_burst);
7972*4882a593Smuzhiyun 		break;
7973*4882a593Smuzhiyun 	case ISCSI_FLASHNODE_DEF_TASKMGMT_TMO:
7974*4882a593Smuzhiyun 		rc = sprintf(buf, "%u\n",
7975*4882a593Smuzhiyun 			     fnode_sess->default_taskmgmt_timeout);
7976*4882a593Smuzhiyun 		break;
7977*4882a593Smuzhiyun 	case ISCSI_FLASHNODE_IPADDR:
7978*4882a593Smuzhiyun 		if (!strncmp(fnode_sess->portal_type, PORTAL_TYPE_IPV6, 4))
7979*4882a593Smuzhiyun 			rc = sprintf(buf, "%pI6\n", fnode_conn->ipaddress);
7980*4882a593Smuzhiyun 		else
7981*4882a593Smuzhiyun 			rc = sprintf(buf, "%pI4\n", fnode_conn->ipaddress);
7982*4882a593Smuzhiyun 		break;
7983*4882a593Smuzhiyun 	case ISCSI_FLASHNODE_ALIAS:
7984*4882a593Smuzhiyun 		if (fnode_sess->targetalias)
7985*4882a593Smuzhiyun 			rc = sprintf(buf, "%s\n", fnode_sess->targetalias);
7986*4882a593Smuzhiyun 		else
7987*4882a593Smuzhiyun 			rc = sprintf(buf, "\n");
7988*4882a593Smuzhiyun 		break;
7989*4882a593Smuzhiyun 	case ISCSI_FLASHNODE_REDIRECT_IPADDR:
7990*4882a593Smuzhiyun 		if (!strncmp(fnode_sess->portal_type, PORTAL_TYPE_IPV6, 4))
7991*4882a593Smuzhiyun 			rc = sprintf(buf, "%pI6\n",
7992*4882a593Smuzhiyun 				     fnode_conn->redirect_ipaddr);
7993*4882a593Smuzhiyun 		else
7994*4882a593Smuzhiyun 			rc = sprintf(buf, "%pI4\n",
7995*4882a593Smuzhiyun 				     fnode_conn->redirect_ipaddr);
7996*4882a593Smuzhiyun 		break;
7997*4882a593Smuzhiyun 	case ISCSI_FLASHNODE_MAX_SEGMENT_SIZE:
7998*4882a593Smuzhiyun 		rc = sprintf(buf, "%u\n", fnode_conn->max_segment_size);
7999*4882a593Smuzhiyun 		break;
8000*4882a593Smuzhiyun 	case ISCSI_FLASHNODE_LOCAL_PORT:
8001*4882a593Smuzhiyun 		rc = sprintf(buf, "%u\n", fnode_conn->local_port);
8002*4882a593Smuzhiyun 		break;
8003*4882a593Smuzhiyun 	case ISCSI_FLASHNODE_IPV4_TOS:
8004*4882a593Smuzhiyun 		rc = sprintf(buf, "%u\n", fnode_conn->ipv4_tos);
8005*4882a593Smuzhiyun 		break;
8006*4882a593Smuzhiyun 	case ISCSI_FLASHNODE_IPV6_TC:
8007*4882a593Smuzhiyun 		if (!strncmp(fnode_sess->portal_type, PORTAL_TYPE_IPV6, 4))
8008*4882a593Smuzhiyun 			rc = sprintf(buf, "%u\n",
8009*4882a593Smuzhiyun 				     fnode_conn->ipv6_traffic_class);
8010*4882a593Smuzhiyun 		else
8011*4882a593Smuzhiyun 			rc = sprintf(buf, "\n");
8012*4882a593Smuzhiyun 		break;
8013*4882a593Smuzhiyun 	case ISCSI_FLASHNODE_IPV6_FLOW_LABEL:
8014*4882a593Smuzhiyun 		rc = sprintf(buf, "%u\n", fnode_conn->ipv6_flow_label);
8015*4882a593Smuzhiyun 		break;
8016*4882a593Smuzhiyun 	case ISCSI_FLASHNODE_LINK_LOCAL_IPV6:
8017*4882a593Smuzhiyun 		if (!strncmp(fnode_sess->portal_type, PORTAL_TYPE_IPV6, 4))
8018*4882a593Smuzhiyun 			rc = sprintf(buf, "%pI6\n",
8019*4882a593Smuzhiyun 				     fnode_conn->link_local_ipv6_addr);
8020*4882a593Smuzhiyun 		else
8021*4882a593Smuzhiyun 			rc = sprintf(buf, "\n");
8022*4882a593Smuzhiyun 		break;
8023*4882a593Smuzhiyun 	case ISCSI_FLASHNODE_DISCOVERY_PARENT_IDX:
8024*4882a593Smuzhiyun 		rc = sprintf(buf, "%u\n", fnode_sess->discovery_parent_idx);
8025*4882a593Smuzhiyun 		break;
8026*4882a593Smuzhiyun 	case ISCSI_FLASHNODE_DISCOVERY_PARENT_TYPE:
8027*4882a593Smuzhiyun 		if (fnode_sess->discovery_parent_type == DDB_ISNS)
8028*4882a593Smuzhiyun 			parent_type = ISCSI_DISC_PARENT_ISNS;
8029*4882a593Smuzhiyun 		else if (fnode_sess->discovery_parent_type == DDB_NO_LINK)
8030*4882a593Smuzhiyun 			parent_type = ISCSI_DISC_PARENT_UNKNOWN;
8031*4882a593Smuzhiyun 		else if (fnode_sess->discovery_parent_type < MAX_DDB_ENTRIES)
8032*4882a593Smuzhiyun 			parent_type = ISCSI_DISC_PARENT_SENDTGT;
8033*4882a593Smuzhiyun 		else
8034*4882a593Smuzhiyun 			parent_type = ISCSI_DISC_PARENT_UNKNOWN;
8035*4882a593Smuzhiyun 
8036*4882a593Smuzhiyun 		rc = sprintf(buf, "%s\n",
8037*4882a593Smuzhiyun 			     iscsi_get_discovery_parent_name(parent_type));
8038*4882a593Smuzhiyun 		break;
8039*4882a593Smuzhiyun 	case ISCSI_FLASHNODE_NAME:
8040*4882a593Smuzhiyun 		if (fnode_sess->targetname)
8041*4882a593Smuzhiyun 			rc = sprintf(buf, "%s\n", fnode_sess->targetname);
8042*4882a593Smuzhiyun 		else
8043*4882a593Smuzhiyun 			rc = sprintf(buf, "\n");
8044*4882a593Smuzhiyun 		break;
8045*4882a593Smuzhiyun 	case ISCSI_FLASHNODE_TPGT:
8046*4882a593Smuzhiyun 		rc = sprintf(buf, "%u\n", fnode_sess->tpgt);
8047*4882a593Smuzhiyun 		break;
8048*4882a593Smuzhiyun 	case ISCSI_FLASHNODE_TCP_XMIT_WSF:
8049*4882a593Smuzhiyun 		rc = sprintf(buf, "%u\n", fnode_conn->tcp_xmit_wsf);
8050*4882a593Smuzhiyun 		break;
8051*4882a593Smuzhiyun 	case ISCSI_FLASHNODE_TCP_RECV_WSF:
8052*4882a593Smuzhiyun 		rc = sprintf(buf, "%u\n", fnode_conn->tcp_recv_wsf);
8053*4882a593Smuzhiyun 		break;
8054*4882a593Smuzhiyun 	case ISCSI_FLASHNODE_CHAP_OUT_IDX:
8055*4882a593Smuzhiyun 		rc = sprintf(buf, "%u\n", fnode_sess->chap_out_idx);
8056*4882a593Smuzhiyun 		break;
8057*4882a593Smuzhiyun 	case ISCSI_FLASHNODE_USERNAME:
8058*4882a593Smuzhiyun 		if (fnode_sess->chap_auth_en) {
8059*4882a593Smuzhiyun 			qla4xxx_get_uni_chap_at_index(ha,
8060*4882a593Smuzhiyun 						      chap_tbl.name,
8061*4882a593Smuzhiyun 						      chap_tbl.secret,
8062*4882a593Smuzhiyun 						      fnode_sess->chap_out_idx);
8063*4882a593Smuzhiyun 			rc = sprintf(buf, "%s\n", chap_tbl.name);
8064*4882a593Smuzhiyun 		} else {
8065*4882a593Smuzhiyun 			rc = sprintf(buf, "\n");
8066*4882a593Smuzhiyun 		}
8067*4882a593Smuzhiyun 		break;
8068*4882a593Smuzhiyun 	case ISCSI_FLASHNODE_PASSWORD:
8069*4882a593Smuzhiyun 		if (fnode_sess->chap_auth_en) {
8070*4882a593Smuzhiyun 			qla4xxx_get_uni_chap_at_index(ha,
8071*4882a593Smuzhiyun 						      chap_tbl.name,
8072*4882a593Smuzhiyun 						      chap_tbl.secret,
8073*4882a593Smuzhiyun 						      fnode_sess->chap_out_idx);
8074*4882a593Smuzhiyun 			rc = sprintf(buf, "%s\n", chap_tbl.secret);
8075*4882a593Smuzhiyun 		} else {
8076*4882a593Smuzhiyun 			rc = sprintf(buf, "\n");
8077*4882a593Smuzhiyun 		}
8078*4882a593Smuzhiyun 		break;
8079*4882a593Smuzhiyun 	case ISCSI_FLASHNODE_STATSN:
8080*4882a593Smuzhiyun 		rc = sprintf(buf, "%u\n", fnode_conn->statsn);
8081*4882a593Smuzhiyun 		break;
8082*4882a593Smuzhiyun 	case ISCSI_FLASHNODE_EXP_STATSN:
8083*4882a593Smuzhiyun 		rc = sprintf(buf, "%u\n", fnode_conn->exp_statsn);
8084*4882a593Smuzhiyun 		break;
8085*4882a593Smuzhiyun 	case ISCSI_FLASHNODE_IS_BOOT_TGT:
8086*4882a593Smuzhiyun 		rc = sprintf(buf, "%u\n", fnode_sess->is_boot_target);
8087*4882a593Smuzhiyun 		break;
8088*4882a593Smuzhiyun 	default:
8089*4882a593Smuzhiyun 		rc = -ENOSYS;
8090*4882a593Smuzhiyun 		break;
8091*4882a593Smuzhiyun 	}
8092*4882a593Smuzhiyun 
8093*4882a593Smuzhiyun 	put_device(dev);
8094*4882a593Smuzhiyun 	return rc;
8095*4882a593Smuzhiyun }
8096*4882a593Smuzhiyun 
8097*4882a593Smuzhiyun /**
8098*4882a593Smuzhiyun  * qla4xxx_sysfs_ddb_set_param - Set parameter for firmware DDB entry
8099*4882a593Smuzhiyun  * @fnode_sess: pointer to session attrs of flash ddb entry
8100*4882a593Smuzhiyun  * @fnode_conn: pointer to connection attrs of flash ddb entry
8101*4882a593Smuzhiyun  * @data: Parameters and their values to update
8102*4882a593Smuzhiyun  * @len: len of data
8103*4882a593Smuzhiyun  *
8104*4882a593Smuzhiyun  * This sets the parameter of flash ddb entry and writes them to flash
8105*4882a593Smuzhiyun  **/
8106*4882a593Smuzhiyun static int
qla4xxx_sysfs_ddb_set_param(struct iscsi_bus_flash_session * fnode_sess,struct iscsi_bus_flash_conn * fnode_conn,void * data,int len)8107*4882a593Smuzhiyun qla4xxx_sysfs_ddb_set_param(struct iscsi_bus_flash_session *fnode_sess,
8108*4882a593Smuzhiyun 			    struct iscsi_bus_flash_conn *fnode_conn,
8109*4882a593Smuzhiyun 			    void *data, int len)
8110*4882a593Smuzhiyun {
8111*4882a593Smuzhiyun 	struct Scsi_Host *shost = iscsi_flash_session_to_shost(fnode_sess);
8112*4882a593Smuzhiyun 	struct scsi_qla_host *ha = to_qla_host(shost);
8113*4882a593Smuzhiyun 	struct iscsi_flashnode_param_info *fnode_param;
8114*4882a593Smuzhiyun 	struct ql4_chap_table chap_tbl;
8115*4882a593Smuzhiyun 	struct nlattr *attr;
8116*4882a593Smuzhiyun 	uint16_t chap_out_idx = INVALID_ENTRY;
8117*4882a593Smuzhiyun 	int rc = QLA_ERROR;
8118*4882a593Smuzhiyun 	uint32_t rem = len;
8119*4882a593Smuzhiyun 
8120*4882a593Smuzhiyun 	memset((void *)&chap_tbl, 0, sizeof(chap_tbl));
8121*4882a593Smuzhiyun 	nla_for_each_attr(attr, data, len, rem) {
8122*4882a593Smuzhiyun 		fnode_param = nla_data(attr);
8123*4882a593Smuzhiyun 
8124*4882a593Smuzhiyun 		switch (fnode_param->param) {
8125*4882a593Smuzhiyun 		case ISCSI_FLASHNODE_IS_FW_ASSIGNED_IPV6:
8126*4882a593Smuzhiyun 			fnode_conn->is_fw_assigned_ipv6 = fnode_param->value[0];
8127*4882a593Smuzhiyun 			break;
8128*4882a593Smuzhiyun 		case ISCSI_FLASHNODE_PORTAL_TYPE:
8129*4882a593Smuzhiyun 			memcpy(fnode_sess->portal_type, fnode_param->value,
8130*4882a593Smuzhiyun 			       strlen(fnode_sess->portal_type));
8131*4882a593Smuzhiyun 			break;
8132*4882a593Smuzhiyun 		case ISCSI_FLASHNODE_AUTO_SND_TGT_DISABLE:
8133*4882a593Smuzhiyun 			fnode_sess->auto_snd_tgt_disable =
8134*4882a593Smuzhiyun 							fnode_param->value[0];
8135*4882a593Smuzhiyun 			break;
8136*4882a593Smuzhiyun 		case ISCSI_FLASHNODE_DISCOVERY_SESS:
8137*4882a593Smuzhiyun 			fnode_sess->discovery_sess = fnode_param->value[0];
8138*4882a593Smuzhiyun 			break;
8139*4882a593Smuzhiyun 		case ISCSI_FLASHNODE_ENTRY_EN:
8140*4882a593Smuzhiyun 			fnode_sess->entry_state = fnode_param->value[0];
8141*4882a593Smuzhiyun 			break;
8142*4882a593Smuzhiyun 		case ISCSI_FLASHNODE_HDR_DGST_EN:
8143*4882a593Smuzhiyun 			fnode_conn->hdrdgst_en = fnode_param->value[0];
8144*4882a593Smuzhiyun 			break;
8145*4882a593Smuzhiyun 		case ISCSI_FLASHNODE_DATA_DGST_EN:
8146*4882a593Smuzhiyun 			fnode_conn->datadgst_en = fnode_param->value[0];
8147*4882a593Smuzhiyun 			break;
8148*4882a593Smuzhiyun 		case ISCSI_FLASHNODE_IMM_DATA_EN:
8149*4882a593Smuzhiyun 			fnode_sess->imm_data_en = fnode_param->value[0];
8150*4882a593Smuzhiyun 			break;
8151*4882a593Smuzhiyun 		case ISCSI_FLASHNODE_INITIAL_R2T_EN:
8152*4882a593Smuzhiyun 			fnode_sess->initial_r2t_en = fnode_param->value[0];
8153*4882a593Smuzhiyun 			break;
8154*4882a593Smuzhiyun 		case ISCSI_FLASHNODE_DATASEQ_INORDER:
8155*4882a593Smuzhiyun 			fnode_sess->dataseq_inorder_en = fnode_param->value[0];
8156*4882a593Smuzhiyun 			break;
8157*4882a593Smuzhiyun 		case ISCSI_FLASHNODE_PDU_INORDER:
8158*4882a593Smuzhiyun 			fnode_sess->pdu_inorder_en = fnode_param->value[0];
8159*4882a593Smuzhiyun 			break;
8160*4882a593Smuzhiyun 		case ISCSI_FLASHNODE_CHAP_AUTH_EN:
8161*4882a593Smuzhiyun 			fnode_sess->chap_auth_en = fnode_param->value[0];
8162*4882a593Smuzhiyun 			/* Invalidate chap index if chap auth is disabled */
8163*4882a593Smuzhiyun 			if (!fnode_sess->chap_auth_en)
8164*4882a593Smuzhiyun 				fnode_sess->chap_out_idx = INVALID_ENTRY;
8165*4882a593Smuzhiyun 
8166*4882a593Smuzhiyun 			break;
8167*4882a593Smuzhiyun 		case ISCSI_FLASHNODE_SNACK_REQ_EN:
8168*4882a593Smuzhiyun 			fnode_conn->snack_req_en = fnode_param->value[0];
8169*4882a593Smuzhiyun 			break;
8170*4882a593Smuzhiyun 		case ISCSI_FLASHNODE_DISCOVERY_LOGOUT_EN:
8171*4882a593Smuzhiyun 			fnode_sess->discovery_logout_en = fnode_param->value[0];
8172*4882a593Smuzhiyun 			break;
8173*4882a593Smuzhiyun 		case ISCSI_FLASHNODE_BIDI_CHAP_EN:
8174*4882a593Smuzhiyun 			fnode_sess->bidi_chap_en = fnode_param->value[0];
8175*4882a593Smuzhiyun 			break;
8176*4882a593Smuzhiyun 		case ISCSI_FLASHNODE_DISCOVERY_AUTH_OPTIONAL:
8177*4882a593Smuzhiyun 			fnode_sess->discovery_auth_optional =
8178*4882a593Smuzhiyun 							fnode_param->value[0];
8179*4882a593Smuzhiyun 			break;
8180*4882a593Smuzhiyun 		case ISCSI_FLASHNODE_ERL:
8181*4882a593Smuzhiyun 			fnode_sess->erl = fnode_param->value[0];
8182*4882a593Smuzhiyun 			break;
8183*4882a593Smuzhiyun 		case ISCSI_FLASHNODE_TCP_TIMESTAMP_STAT:
8184*4882a593Smuzhiyun 			fnode_conn->tcp_timestamp_stat = fnode_param->value[0];
8185*4882a593Smuzhiyun 			break;
8186*4882a593Smuzhiyun 		case ISCSI_FLASHNODE_TCP_NAGLE_DISABLE:
8187*4882a593Smuzhiyun 			fnode_conn->tcp_nagle_disable = fnode_param->value[0];
8188*4882a593Smuzhiyun 			break;
8189*4882a593Smuzhiyun 		case ISCSI_FLASHNODE_TCP_WSF_DISABLE:
8190*4882a593Smuzhiyun 			fnode_conn->tcp_wsf_disable = fnode_param->value[0];
8191*4882a593Smuzhiyun 			break;
8192*4882a593Smuzhiyun 		case ISCSI_FLASHNODE_TCP_TIMER_SCALE:
8193*4882a593Smuzhiyun 			fnode_conn->tcp_timer_scale = fnode_param->value[0];
8194*4882a593Smuzhiyun 			break;
8195*4882a593Smuzhiyun 		case ISCSI_FLASHNODE_TCP_TIMESTAMP_EN:
8196*4882a593Smuzhiyun 			fnode_conn->tcp_timestamp_en = fnode_param->value[0];
8197*4882a593Smuzhiyun 			break;
8198*4882a593Smuzhiyun 		case ISCSI_FLASHNODE_IP_FRAG_DISABLE:
8199*4882a593Smuzhiyun 			fnode_conn->fragment_disable = fnode_param->value[0];
8200*4882a593Smuzhiyun 			break;
8201*4882a593Smuzhiyun 		case ISCSI_FLASHNODE_MAX_RECV_DLENGTH:
8202*4882a593Smuzhiyun 			fnode_conn->max_recv_dlength =
8203*4882a593Smuzhiyun 					*(unsigned *)fnode_param->value;
8204*4882a593Smuzhiyun 			break;
8205*4882a593Smuzhiyun 		case ISCSI_FLASHNODE_MAX_XMIT_DLENGTH:
8206*4882a593Smuzhiyun 			fnode_conn->max_xmit_dlength =
8207*4882a593Smuzhiyun 					*(unsigned *)fnode_param->value;
8208*4882a593Smuzhiyun 			break;
8209*4882a593Smuzhiyun 		case ISCSI_FLASHNODE_FIRST_BURST:
8210*4882a593Smuzhiyun 			fnode_sess->first_burst =
8211*4882a593Smuzhiyun 					*(unsigned *)fnode_param->value;
8212*4882a593Smuzhiyun 			break;
8213*4882a593Smuzhiyun 		case ISCSI_FLASHNODE_DEF_TIME2WAIT:
8214*4882a593Smuzhiyun 			fnode_sess->time2wait = *(uint16_t *)fnode_param->value;
8215*4882a593Smuzhiyun 			break;
8216*4882a593Smuzhiyun 		case ISCSI_FLASHNODE_DEF_TIME2RETAIN:
8217*4882a593Smuzhiyun 			fnode_sess->time2retain =
8218*4882a593Smuzhiyun 						*(uint16_t *)fnode_param->value;
8219*4882a593Smuzhiyun 			break;
8220*4882a593Smuzhiyun 		case ISCSI_FLASHNODE_MAX_R2T:
8221*4882a593Smuzhiyun 			fnode_sess->max_r2t =
8222*4882a593Smuzhiyun 					*(uint16_t *)fnode_param->value;
8223*4882a593Smuzhiyun 			break;
8224*4882a593Smuzhiyun 		case ISCSI_FLASHNODE_KEEPALIVE_TMO:
8225*4882a593Smuzhiyun 			fnode_conn->keepalive_timeout =
8226*4882a593Smuzhiyun 				*(uint16_t *)fnode_param->value;
8227*4882a593Smuzhiyun 			break;
8228*4882a593Smuzhiyun 		case ISCSI_FLASHNODE_ISID:
8229*4882a593Smuzhiyun 			memcpy(fnode_sess->isid, fnode_param->value,
8230*4882a593Smuzhiyun 			       sizeof(fnode_sess->isid));
8231*4882a593Smuzhiyun 			break;
8232*4882a593Smuzhiyun 		case ISCSI_FLASHNODE_TSID:
8233*4882a593Smuzhiyun 			fnode_sess->tsid = *(uint16_t *)fnode_param->value;
8234*4882a593Smuzhiyun 			break;
8235*4882a593Smuzhiyun 		case ISCSI_FLASHNODE_PORT:
8236*4882a593Smuzhiyun 			fnode_conn->port = *(uint16_t *)fnode_param->value;
8237*4882a593Smuzhiyun 			break;
8238*4882a593Smuzhiyun 		case ISCSI_FLASHNODE_MAX_BURST:
8239*4882a593Smuzhiyun 			fnode_sess->max_burst = *(unsigned *)fnode_param->value;
8240*4882a593Smuzhiyun 			break;
8241*4882a593Smuzhiyun 		case ISCSI_FLASHNODE_DEF_TASKMGMT_TMO:
8242*4882a593Smuzhiyun 			fnode_sess->default_taskmgmt_timeout =
8243*4882a593Smuzhiyun 						*(uint16_t *)fnode_param->value;
8244*4882a593Smuzhiyun 			break;
8245*4882a593Smuzhiyun 		case ISCSI_FLASHNODE_IPADDR:
8246*4882a593Smuzhiyun 			memcpy(fnode_conn->ipaddress, fnode_param->value,
8247*4882a593Smuzhiyun 			       IPv6_ADDR_LEN);
8248*4882a593Smuzhiyun 			break;
8249*4882a593Smuzhiyun 		case ISCSI_FLASHNODE_ALIAS:
8250*4882a593Smuzhiyun 			rc = iscsi_switch_str_param(&fnode_sess->targetalias,
8251*4882a593Smuzhiyun 						    (char *)fnode_param->value);
8252*4882a593Smuzhiyun 			break;
8253*4882a593Smuzhiyun 		case ISCSI_FLASHNODE_REDIRECT_IPADDR:
8254*4882a593Smuzhiyun 			memcpy(fnode_conn->redirect_ipaddr, fnode_param->value,
8255*4882a593Smuzhiyun 			       IPv6_ADDR_LEN);
8256*4882a593Smuzhiyun 			break;
8257*4882a593Smuzhiyun 		case ISCSI_FLASHNODE_MAX_SEGMENT_SIZE:
8258*4882a593Smuzhiyun 			fnode_conn->max_segment_size =
8259*4882a593Smuzhiyun 					*(unsigned *)fnode_param->value;
8260*4882a593Smuzhiyun 			break;
8261*4882a593Smuzhiyun 		case ISCSI_FLASHNODE_LOCAL_PORT:
8262*4882a593Smuzhiyun 			fnode_conn->local_port =
8263*4882a593Smuzhiyun 						*(uint16_t *)fnode_param->value;
8264*4882a593Smuzhiyun 			break;
8265*4882a593Smuzhiyun 		case ISCSI_FLASHNODE_IPV4_TOS:
8266*4882a593Smuzhiyun 			fnode_conn->ipv4_tos = fnode_param->value[0];
8267*4882a593Smuzhiyun 			break;
8268*4882a593Smuzhiyun 		case ISCSI_FLASHNODE_IPV6_TC:
8269*4882a593Smuzhiyun 			fnode_conn->ipv6_traffic_class = fnode_param->value[0];
8270*4882a593Smuzhiyun 			break;
8271*4882a593Smuzhiyun 		case ISCSI_FLASHNODE_IPV6_FLOW_LABEL:
8272*4882a593Smuzhiyun 			fnode_conn->ipv6_flow_label = fnode_param->value[0];
8273*4882a593Smuzhiyun 			break;
8274*4882a593Smuzhiyun 		case ISCSI_FLASHNODE_NAME:
8275*4882a593Smuzhiyun 			rc = iscsi_switch_str_param(&fnode_sess->targetname,
8276*4882a593Smuzhiyun 						    (char *)fnode_param->value);
8277*4882a593Smuzhiyun 			break;
8278*4882a593Smuzhiyun 		case ISCSI_FLASHNODE_TPGT:
8279*4882a593Smuzhiyun 			fnode_sess->tpgt = *(uint16_t *)fnode_param->value;
8280*4882a593Smuzhiyun 			break;
8281*4882a593Smuzhiyun 		case ISCSI_FLASHNODE_LINK_LOCAL_IPV6:
8282*4882a593Smuzhiyun 			memcpy(fnode_conn->link_local_ipv6_addr,
8283*4882a593Smuzhiyun 			       fnode_param->value, IPv6_ADDR_LEN);
8284*4882a593Smuzhiyun 			break;
8285*4882a593Smuzhiyun 		case ISCSI_FLASHNODE_DISCOVERY_PARENT_IDX:
8286*4882a593Smuzhiyun 			fnode_sess->discovery_parent_idx =
8287*4882a593Smuzhiyun 						*(uint16_t *)fnode_param->value;
8288*4882a593Smuzhiyun 			break;
8289*4882a593Smuzhiyun 		case ISCSI_FLASHNODE_TCP_XMIT_WSF:
8290*4882a593Smuzhiyun 			fnode_conn->tcp_xmit_wsf =
8291*4882a593Smuzhiyun 						*(uint8_t *)fnode_param->value;
8292*4882a593Smuzhiyun 			break;
8293*4882a593Smuzhiyun 		case ISCSI_FLASHNODE_TCP_RECV_WSF:
8294*4882a593Smuzhiyun 			fnode_conn->tcp_recv_wsf =
8295*4882a593Smuzhiyun 						*(uint8_t *)fnode_param->value;
8296*4882a593Smuzhiyun 			break;
8297*4882a593Smuzhiyun 		case ISCSI_FLASHNODE_STATSN:
8298*4882a593Smuzhiyun 			fnode_conn->statsn = *(uint32_t *)fnode_param->value;
8299*4882a593Smuzhiyun 			break;
8300*4882a593Smuzhiyun 		case ISCSI_FLASHNODE_EXP_STATSN:
8301*4882a593Smuzhiyun 			fnode_conn->exp_statsn =
8302*4882a593Smuzhiyun 						*(uint32_t *)fnode_param->value;
8303*4882a593Smuzhiyun 			break;
8304*4882a593Smuzhiyun 		case ISCSI_FLASHNODE_CHAP_OUT_IDX:
8305*4882a593Smuzhiyun 			chap_out_idx = *(uint16_t *)fnode_param->value;
8306*4882a593Smuzhiyun 			if (!qla4xxx_get_uni_chap_at_index(ha,
8307*4882a593Smuzhiyun 							   chap_tbl.name,
8308*4882a593Smuzhiyun 							   chap_tbl.secret,
8309*4882a593Smuzhiyun 							   chap_out_idx)) {
8310*4882a593Smuzhiyun 				fnode_sess->chap_out_idx = chap_out_idx;
8311*4882a593Smuzhiyun 				/* Enable chap auth if chap index is valid */
8312*4882a593Smuzhiyun 				fnode_sess->chap_auth_en = QL4_PARAM_ENABLE;
8313*4882a593Smuzhiyun 			}
8314*4882a593Smuzhiyun 			break;
8315*4882a593Smuzhiyun 		default:
8316*4882a593Smuzhiyun 			ql4_printk(KERN_ERR, ha,
8317*4882a593Smuzhiyun 				   "%s: No such sysfs attribute\n", __func__);
8318*4882a593Smuzhiyun 			rc = -ENOSYS;
8319*4882a593Smuzhiyun 			goto exit_set_param;
8320*4882a593Smuzhiyun 		}
8321*4882a593Smuzhiyun 	}
8322*4882a593Smuzhiyun 
8323*4882a593Smuzhiyun 	rc = qla4xxx_sysfs_ddb_apply(fnode_sess, fnode_conn);
8324*4882a593Smuzhiyun 
8325*4882a593Smuzhiyun exit_set_param:
8326*4882a593Smuzhiyun 	return rc;
8327*4882a593Smuzhiyun }
8328*4882a593Smuzhiyun 
8329*4882a593Smuzhiyun /**
8330*4882a593Smuzhiyun  * qla4xxx_sysfs_ddb_delete - Delete firmware DDB entry
8331*4882a593Smuzhiyun  * @fnode_sess: pointer to session attrs of flash ddb entry
8332*4882a593Smuzhiyun  *
8333*4882a593Smuzhiyun  * This invalidates the flash ddb entry at the given index
8334*4882a593Smuzhiyun  **/
qla4xxx_sysfs_ddb_delete(struct iscsi_bus_flash_session * fnode_sess)8335*4882a593Smuzhiyun static int qla4xxx_sysfs_ddb_delete(struct iscsi_bus_flash_session *fnode_sess)
8336*4882a593Smuzhiyun {
8337*4882a593Smuzhiyun 	struct Scsi_Host *shost = iscsi_flash_session_to_shost(fnode_sess);
8338*4882a593Smuzhiyun 	struct scsi_qla_host *ha = to_qla_host(shost);
8339*4882a593Smuzhiyun 	uint32_t dev_db_start_offset;
8340*4882a593Smuzhiyun 	uint32_t dev_db_end_offset;
8341*4882a593Smuzhiyun 	struct dev_db_entry *fw_ddb_entry = NULL;
8342*4882a593Smuzhiyun 	dma_addr_t fw_ddb_entry_dma;
8343*4882a593Smuzhiyun 	uint16_t *ddb_cookie = NULL;
8344*4882a593Smuzhiyun 	size_t ddb_size = 0;
8345*4882a593Smuzhiyun 	void *pddb = NULL;
8346*4882a593Smuzhiyun 	int target_id;
8347*4882a593Smuzhiyun 	int rc = 0;
8348*4882a593Smuzhiyun 
8349*4882a593Smuzhiyun 	if (fnode_sess->is_boot_target) {
8350*4882a593Smuzhiyun 		rc = -EPERM;
8351*4882a593Smuzhiyun 		DEBUG2(ql4_printk(KERN_ERR, ha,
8352*4882a593Smuzhiyun 				  "%s: Deletion of boot target entry is not permitted.\n",
8353*4882a593Smuzhiyun 				  __func__));
8354*4882a593Smuzhiyun 		goto exit_ddb_del;
8355*4882a593Smuzhiyun 	}
8356*4882a593Smuzhiyun 
8357*4882a593Smuzhiyun 	if (fnode_sess->flash_state == DEV_DB_NON_PERSISTENT)
8358*4882a593Smuzhiyun 		goto sysfs_ddb_del;
8359*4882a593Smuzhiyun 
8360*4882a593Smuzhiyun 	if (is_qla40XX(ha)) {
8361*4882a593Smuzhiyun 		dev_db_start_offset = FLASH_OFFSET_DB_INFO;
8362*4882a593Smuzhiyun 		dev_db_end_offset = FLASH_OFFSET_DB_END;
8363*4882a593Smuzhiyun 		dev_db_start_offset += (fnode_sess->target_id *
8364*4882a593Smuzhiyun 				       sizeof(*fw_ddb_entry));
8365*4882a593Smuzhiyun 		ddb_size = sizeof(*fw_ddb_entry);
8366*4882a593Smuzhiyun 	} else {
8367*4882a593Smuzhiyun 		dev_db_start_offset = FLASH_RAW_ACCESS_ADDR +
8368*4882a593Smuzhiyun 				      (ha->hw.flt_region_ddb << 2);
8369*4882a593Smuzhiyun 		/* flt_ddb_size is DDB table size for both ports
8370*4882a593Smuzhiyun 		 * so divide it by 2 to calculate the offset for second port
8371*4882a593Smuzhiyun 		 */
8372*4882a593Smuzhiyun 		if (ha->port_num == 1)
8373*4882a593Smuzhiyun 			dev_db_start_offset += (ha->hw.flt_ddb_size / 2);
8374*4882a593Smuzhiyun 
8375*4882a593Smuzhiyun 		dev_db_end_offset = dev_db_start_offset +
8376*4882a593Smuzhiyun 				    (ha->hw.flt_ddb_size / 2);
8377*4882a593Smuzhiyun 
8378*4882a593Smuzhiyun 		dev_db_start_offset += (fnode_sess->target_id *
8379*4882a593Smuzhiyun 				       sizeof(*fw_ddb_entry));
8380*4882a593Smuzhiyun 		dev_db_start_offset += offsetof(struct dev_db_entry, cookie);
8381*4882a593Smuzhiyun 
8382*4882a593Smuzhiyun 		ddb_size = sizeof(*ddb_cookie);
8383*4882a593Smuzhiyun 	}
8384*4882a593Smuzhiyun 
8385*4882a593Smuzhiyun 	DEBUG2(ql4_printk(KERN_ERR, ha, "%s: start offset=%u, end offset=%u\n",
8386*4882a593Smuzhiyun 			  __func__, dev_db_start_offset, dev_db_end_offset));
8387*4882a593Smuzhiyun 
8388*4882a593Smuzhiyun 	if (dev_db_start_offset > dev_db_end_offset) {
8389*4882a593Smuzhiyun 		rc = -EIO;
8390*4882a593Smuzhiyun 		DEBUG2(ql4_printk(KERN_ERR, ha, "%s:Invalid DDB index %u\n",
8391*4882a593Smuzhiyun 				  __func__, fnode_sess->target_id));
8392*4882a593Smuzhiyun 		goto exit_ddb_del;
8393*4882a593Smuzhiyun 	}
8394*4882a593Smuzhiyun 
8395*4882a593Smuzhiyun 	pddb = dma_alloc_coherent(&ha->pdev->dev, ddb_size,
8396*4882a593Smuzhiyun 				  &fw_ddb_entry_dma, GFP_KERNEL);
8397*4882a593Smuzhiyun 	if (!pddb) {
8398*4882a593Smuzhiyun 		rc = -ENOMEM;
8399*4882a593Smuzhiyun 		DEBUG2(ql4_printk(KERN_ERR, ha,
8400*4882a593Smuzhiyun 				  "%s: Unable to allocate dma buffer\n",
8401*4882a593Smuzhiyun 				  __func__));
8402*4882a593Smuzhiyun 		goto exit_ddb_del;
8403*4882a593Smuzhiyun 	}
8404*4882a593Smuzhiyun 
8405*4882a593Smuzhiyun 	if (is_qla40XX(ha)) {
8406*4882a593Smuzhiyun 		fw_ddb_entry = pddb;
8407*4882a593Smuzhiyun 		memset(fw_ddb_entry, 0, ddb_size);
8408*4882a593Smuzhiyun 		ddb_cookie = &fw_ddb_entry->cookie;
8409*4882a593Smuzhiyun 	} else {
8410*4882a593Smuzhiyun 		ddb_cookie = pddb;
8411*4882a593Smuzhiyun 	}
8412*4882a593Smuzhiyun 
8413*4882a593Smuzhiyun 	/* invalidate the cookie */
8414*4882a593Smuzhiyun 	*ddb_cookie = 0xFFEE;
8415*4882a593Smuzhiyun 	qla4xxx_set_flash(ha, fw_ddb_entry_dma, dev_db_start_offset,
8416*4882a593Smuzhiyun 			  ddb_size, FLASH_OPT_RMW_COMMIT);
8417*4882a593Smuzhiyun 
8418*4882a593Smuzhiyun sysfs_ddb_del:
8419*4882a593Smuzhiyun 	target_id = fnode_sess->target_id;
8420*4882a593Smuzhiyun 	iscsi_destroy_flashnode_sess(fnode_sess);
8421*4882a593Smuzhiyun 	ql4_printk(KERN_INFO, ha,
8422*4882a593Smuzhiyun 		   "%s: session and conn entries for flashnode %u of host %lu deleted\n",
8423*4882a593Smuzhiyun 		   __func__, target_id, ha->host_no);
8424*4882a593Smuzhiyun exit_ddb_del:
8425*4882a593Smuzhiyun 	if (pddb)
8426*4882a593Smuzhiyun 		dma_free_coherent(&ha->pdev->dev, ddb_size, pddb,
8427*4882a593Smuzhiyun 				  fw_ddb_entry_dma);
8428*4882a593Smuzhiyun 	return rc;
8429*4882a593Smuzhiyun }
8430*4882a593Smuzhiyun 
8431*4882a593Smuzhiyun /**
8432*4882a593Smuzhiyun  * qla4xxx_sysfs_ddb_export - Create sysfs entries for firmware DDBs
8433*4882a593Smuzhiyun  * @ha: pointer to adapter structure
8434*4882a593Smuzhiyun  *
8435*4882a593Smuzhiyun  * Export the firmware DDB for all send targets and normal targets to sysfs.
8436*4882a593Smuzhiyun  **/
qla4xxx_sysfs_ddb_export(struct scsi_qla_host * ha)8437*4882a593Smuzhiyun int qla4xxx_sysfs_ddb_export(struct scsi_qla_host *ha)
8438*4882a593Smuzhiyun {
8439*4882a593Smuzhiyun 	struct dev_db_entry *fw_ddb_entry = NULL;
8440*4882a593Smuzhiyun 	dma_addr_t fw_ddb_entry_dma;
8441*4882a593Smuzhiyun 	uint16_t max_ddbs;
8442*4882a593Smuzhiyun 	uint16_t idx = 0;
8443*4882a593Smuzhiyun 	int ret = QLA_SUCCESS;
8444*4882a593Smuzhiyun 
8445*4882a593Smuzhiyun 	fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev,
8446*4882a593Smuzhiyun 					  sizeof(*fw_ddb_entry),
8447*4882a593Smuzhiyun 					  &fw_ddb_entry_dma, GFP_KERNEL);
8448*4882a593Smuzhiyun 	if (!fw_ddb_entry) {
8449*4882a593Smuzhiyun 		DEBUG2(ql4_printk(KERN_ERR, ha,
8450*4882a593Smuzhiyun 				  "%s: Unable to allocate dma buffer\n",
8451*4882a593Smuzhiyun 				  __func__));
8452*4882a593Smuzhiyun 		return -ENOMEM;
8453*4882a593Smuzhiyun 	}
8454*4882a593Smuzhiyun 
8455*4882a593Smuzhiyun 	max_ddbs =  is_qla40XX(ha) ? MAX_PRST_DEV_DB_ENTRIES :
8456*4882a593Smuzhiyun 				     MAX_DEV_DB_ENTRIES;
8457*4882a593Smuzhiyun 
8458*4882a593Smuzhiyun 	for (idx = 0; idx < max_ddbs; idx++) {
8459*4882a593Smuzhiyun 		if (qla4xxx_flashdb_by_index(ha, fw_ddb_entry, fw_ddb_entry_dma,
8460*4882a593Smuzhiyun 					     idx))
8461*4882a593Smuzhiyun 			continue;
8462*4882a593Smuzhiyun 
8463*4882a593Smuzhiyun 		ret = qla4xxx_sysfs_ddb_tgt_create(ha, fw_ddb_entry, &idx, 0);
8464*4882a593Smuzhiyun 		if (ret) {
8465*4882a593Smuzhiyun 			ret = -EIO;
8466*4882a593Smuzhiyun 			break;
8467*4882a593Smuzhiyun 		}
8468*4882a593Smuzhiyun 	}
8469*4882a593Smuzhiyun 
8470*4882a593Smuzhiyun 	dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), fw_ddb_entry,
8471*4882a593Smuzhiyun 			  fw_ddb_entry_dma);
8472*4882a593Smuzhiyun 
8473*4882a593Smuzhiyun 	return ret;
8474*4882a593Smuzhiyun }
8475*4882a593Smuzhiyun 
qla4xxx_sysfs_ddb_remove(struct scsi_qla_host * ha)8476*4882a593Smuzhiyun static void qla4xxx_sysfs_ddb_remove(struct scsi_qla_host *ha)
8477*4882a593Smuzhiyun {
8478*4882a593Smuzhiyun 	iscsi_destroy_all_flashnode(ha->host);
8479*4882a593Smuzhiyun }
8480*4882a593Smuzhiyun 
8481*4882a593Smuzhiyun /**
8482*4882a593Smuzhiyun  * qla4xxx_build_ddb_list - Build ddb list and setup sessions
8483*4882a593Smuzhiyun  * @ha: pointer to adapter structure
8484*4882a593Smuzhiyun  * @is_reset: Is this init path or reset path
8485*4882a593Smuzhiyun  *
8486*4882a593Smuzhiyun  * Create a list of sendtargets (st) from firmware DDBs, issue send targets
8487*4882a593Smuzhiyun  * using connection open, then create the list of normal targets (nt)
8488*4882a593Smuzhiyun  * from firmware DDBs. Based on the list of nt setup session and connection
8489*4882a593Smuzhiyun  * objects.
8490*4882a593Smuzhiyun  **/
qla4xxx_build_ddb_list(struct scsi_qla_host * ha,int is_reset)8491*4882a593Smuzhiyun void qla4xxx_build_ddb_list(struct scsi_qla_host *ha, int is_reset)
8492*4882a593Smuzhiyun {
8493*4882a593Smuzhiyun 	uint16_t tmo = 0;
8494*4882a593Smuzhiyun 	struct list_head list_st, list_nt;
8495*4882a593Smuzhiyun 	struct qla_ddb_index  *st_ddb_idx, *st_ddb_idx_tmp;
8496*4882a593Smuzhiyun 	unsigned long wtime;
8497*4882a593Smuzhiyun 
8498*4882a593Smuzhiyun 	if (!test_bit(AF_LINK_UP, &ha->flags)) {
8499*4882a593Smuzhiyun 		set_bit(AF_BUILD_DDB_LIST, &ha->flags);
8500*4882a593Smuzhiyun 		ha->is_reset = is_reset;
8501*4882a593Smuzhiyun 		return;
8502*4882a593Smuzhiyun 	}
8503*4882a593Smuzhiyun 
8504*4882a593Smuzhiyun 	INIT_LIST_HEAD(&list_st);
8505*4882a593Smuzhiyun 	INIT_LIST_HEAD(&list_nt);
8506*4882a593Smuzhiyun 
8507*4882a593Smuzhiyun 	qla4xxx_build_st_list(ha, &list_st);
8508*4882a593Smuzhiyun 
8509*4882a593Smuzhiyun 	/* Before issuing conn open mbox, ensure all IPs states are configured
8510*4882a593Smuzhiyun 	 * Note, conn open fails if IPs are not configured
8511*4882a593Smuzhiyun 	 */
8512*4882a593Smuzhiyun 	qla4xxx_wait_for_ip_configuration(ha);
8513*4882a593Smuzhiyun 
8514*4882a593Smuzhiyun 	/* Go thru the STs and fire the sendtargets by issuing conn open mbx */
8515*4882a593Smuzhiyun 	list_for_each_entry_safe(st_ddb_idx, st_ddb_idx_tmp, &list_st, list) {
8516*4882a593Smuzhiyun 		qla4xxx_conn_open(ha, st_ddb_idx->fw_ddb_idx);
8517*4882a593Smuzhiyun 	}
8518*4882a593Smuzhiyun 
8519*4882a593Smuzhiyun 	/* Wait to ensure all sendtargets are done for min 12 sec wait */
8520*4882a593Smuzhiyun 	tmo = ((ha->def_timeout > LOGIN_TOV) &&
8521*4882a593Smuzhiyun 	       (ha->def_timeout < LOGIN_TOV * 10) ?
8522*4882a593Smuzhiyun 	       ha->def_timeout : LOGIN_TOV);
8523*4882a593Smuzhiyun 
8524*4882a593Smuzhiyun 	DEBUG2(ql4_printk(KERN_INFO, ha,
8525*4882a593Smuzhiyun 			  "Default time to wait for build ddb %d\n", tmo));
8526*4882a593Smuzhiyun 
8527*4882a593Smuzhiyun 	wtime = jiffies + (HZ * tmo);
8528*4882a593Smuzhiyun 	do {
8529*4882a593Smuzhiyun 		if (list_empty(&list_st))
8530*4882a593Smuzhiyun 			break;
8531*4882a593Smuzhiyun 
8532*4882a593Smuzhiyun 		qla4xxx_remove_failed_ddb(ha, &list_st);
8533*4882a593Smuzhiyun 		schedule_timeout_uninterruptible(HZ / 10);
8534*4882a593Smuzhiyun 	} while (time_after(wtime, jiffies));
8535*4882a593Smuzhiyun 
8536*4882a593Smuzhiyun 
8537*4882a593Smuzhiyun 	qla4xxx_build_nt_list(ha, &list_nt, &list_st, is_reset);
8538*4882a593Smuzhiyun 
8539*4882a593Smuzhiyun 	qla4xxx_free_ddb_list(&list_st);
8540*4882a593Smuzhiyun 	qla4xxx_free_ddb_list(&list_nt);
8541*4882a593Smuzhiyun 
8542*4882a593Smuzhiyun 	qla4xxx_free_ddb_index(ha);
8543*4882a593Smuzhiyun }
8544*4882a593Smuzhiyun 
8545*4882a593Smuzhiyun /**
8546*4882a593Smuzhiyun  * qla4xxx_wait_login_resp_boot_tgt -  Wait for iSCSI boot target login
8547*4882a593Smuzhiyun  * response.
8548*4882a593Smuzhiyun  * @ha: pointer to adapter structure
8549*4882a593Smuzhiyun  *
8550*4882a593Smuzhiyun  * When the boot entry is normal iSCSI target then DF_BOOT_TGT flag will be
8551*4882a593Smuzhiyun  * set in DDB and we will wait for login response of boot targets during
8552*4882a593Smuzhiyun  * probe.
8553*4882a593Smuzhiyun  **/
qla4xxx_wait_login_resp_boot_tgt(struct scsi_qla_host * ha)8554*4882a593Smuzhiyun static void qla4xxx_wait_login_resp_boot_tgt(struct scsi_qla_host *ha)
8555*4882a593Smuzhiyun {
8556*4882a593Smuzhiyun 	struct ddb_entry *ddb_entry;
8557*4882a593Smuzhiyun 	struct dev_db_entry *fw_ddb_entry = NULL;
8558*4882a593Smuzhiyun 	dma_addr_t fw_ddb_entry_dma;
8559*4882a593Smuzhiyun 	unsigned long wtime;
8560*4882a593Smuzhiyun 	uint32_t ddb_state;
8561*4882a593Smuzhiyun 	int max_ddbs, idx, ret;
8562*4882a593Smuzhiyun 
8563*4882a593Smuzhiyun 	max_ddbs =  is_qla40XX(ha) ? MAX_DEV_DB_ENTRIES_40XX :
8564*4882a593Smuzhiyun 				     MAX_DEV_DB_ENTRIES;
8565*4882a593Smuzhiyun 
8566*4882a593Smuzhiyun 	fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
8567*4882a593Smuzhiyun 					  &fw_ddb_entry_dma, GFP_KERNEL);
8568*4882a593Smuzhiyun 	if (!fw_ddb_entry) {
8569*4882a593Smuzhiyun 		ql4_printk(KERN_ERR, ha,
8570*4882a593Smuzhiyun 			   "%s: Unable to allocate dma buffer\n", __func__);
8571*4882a593Smuzhiyun 		goto exit_login_resp;
8572*4882a593Smuzhiyun 	}
8573*4882a593Smuzhiyun 
8574*4882a593Smuzhiyun 	wtime = jiffies + (HZ * BOOT_LOGIN_RESP_TOV);
8575*4882a593Smuzhiyun 
8576*4882a593Smuzhiyun 	for (idx = 0; idx < max_ddbs; idx++) {
8577*4882a593Smuzhiyun 		ddb_entry = qla4xxx_lookup_ddb_by_fw_index(ha, idx);
8578*4882a593Smuzhiyun 		if (ddb_entry == NULL)
8579*4882a593Smuzhiyun 			continue;
8580*4882a593Smuzhiyun 
8581*4882a593Smuzhiyun 		if (test_bit(DF_BOOT_TGT, &ddb_entry->flags)) {
8582*4882a593Smuzhiyun 			DEBUG2(ql4_printk(KERN_INFO, ha,
8583*4882a593Smuzhiyun 					  "%s: DDB index [%d]\n", __func__,
8584*4882a593Smuzhiyun 					  ddb_entry->fw_ddb_index));
8585*4882a593Smuzhiyun 			do {
8586*4882a593Smuzhiyun 				ret = qla4xxx_get_fwddb_entry(ha,
8587*4882a593Smuzhiyun 						ddb_entry->fw_ddb_index,
8588*4882a593Smuzhiyun 						fw_ddb_entry, fw_ddb_entry_dma,
8589*4882a593Smuzhiyun 						NULL, NULL, &ddb_state, NULL,
8590*4882a593Smuzhiyun 						NULL, NULL);
8591*4882a593Smuzhiyun 				if (ret == QLA_ERROR)
8592*4882a593Smuzhiyun 					goto exit_login_resp;
8593*4882a593Smuzhiyun 
8594*4882a593Smuzhiyun 				if ((ddb_state == DDB_DS_SESSION_ACTIVE) ||
8595*4882a593Smuzhiyun 				    (ddb_state == DDB_DS_SESSION_FAILED))
8596*4882a593Smuzhiyun 					break;
8597*4882a593Smuzhiyun 
8598*4882a593Smuzhiyun 				schedule_timeout_uninterruptible(HZ);
8599*4882a593Smuzhiyun 
8600*4882a593Smuzhiyun 			} while ((time_after(wtime, jiffies)));
8601*4882a593Smuzhiyun 
8602*4882a593Smuzhiyun 			if (!time_after(wtime, jiffies)) {
8603*4882a593Smuzhiyun 				DEBUG2(ql4_printk(KERN_INFO, ha,
8604*4882a593Smuzhiyun 						  "%s: Login response wait timer expired\n",
8605*4882a593Smuzhiyun 						  __func__));
8606*4882a593Smuzhiyun 				 goto exit_login_resp;
8607*4882a593Smuzhiyun 			}
8608*4882a593Smuzhiyun 		}
8609*4882a593Smuzhiyun 	}
8610*4882a593Smuzhiyun 
8611*4882a593Smuzhiyun exit_login_resp:
8612*4882a593Smuzhiyun 	if (fw_ddb_entry)
8613*4882a593Smuzhiyun 		dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
8614*4882a593Smuzhiyun 				  fw_ddb_entry, fw_ddb_entry_dma);
8615*4882a593Smuzhiyun }
8616*4882a593Smuzhiyun 
8617*4882a593Smuzhiyun /**
8618*4882a593Smuzhiyun  * qla4xxx_probe_adapter - callback function to probe HBA
8619*4882a593Smuzhiyun  * @pdev: pointer to pci_dev structure
8620*4882a593Smuzhiyun  * @ent: pointer to pci_device entry
8621*4882a593Smuzhiyun  *
8622*4882a593Smuzhiyun  * This routine will probe for Qlogic 4xxx iSCSI host adapters.
8623*4882a593Smuzhiyun  * It returns zero if successful. It also initializes all data necessary for
8624*4882a593Smuzhiyun  * the driver.
8625*4882a593Smuzhiyun  **/
qla4xxx_probe_adapter(struct pci_dev * pdev,const struct pci_device_id * ent)8626*4882a593Smuzhiyun static int qla4xxx_probe_adapter(struct pci_dev *pdev,
8627*4882a593Smuzhiyun 				 const struct pci_device_id *ent)
8628*4882a593Smuzhiyun {
8629*4882a593Smuzhiyun 	int ret = -ENODEV, status;
8630*4882a593Smuzhiyun 	struct Scsi_Host *host;
8631*4882a593Smuzhiyun 	struct scsi_qla_host *ha;
8632*4882a593Smuzhiyun 	uint8_t init_retry_count = 0;
8633*4882a593Smuzhiyun 	char buf[34];
8634*4882a593Smuzhiyun 	struct qla4_8xxx_legacy_intr_set *nx_legacy_intr;
8635*4882a593Smuzhiyun 	uint32_t dev_state;
8636*4882a593Smuzhiyun 
8637*4882a593Smuzhiyun 	if (pci_enable_device(pdev))
8638*4882a593Smuzhiyun 		return -1;
8639*4882a593Smuzhiyun 
8640*4882a593Smuzhiyun 	host = iscsi_host_alloc(&qla4xxx_driver_template, sizeof(*ha), 0);
8641*4882a593Smuzhiyun 	if (host == NULL) {
8642*4882a593Smuzhiyun 		printk(KERN_WARNING
8643*4882a593Smuzhiyun 		       "qla4xxx: Couldn't allocate host from scsi layer!\n");
8644*4882a593Smuzhiyun 		goto probe_disable_device;
8645*4882a593Smuzhiyun 	}
8646*4882a593Smuzhiyun 
8647*4882a593Smuzhiyun 	/* Clear our data area */
8648*4882a593Smuzhiyun 	ha = to_qla_host(host);
8649*4882a593Smuzhiyun 	memset(ha, 0, sizeof(*ha));
8650*4882a593Smuzhiyun 
8651*4882a593Smuzhiyun 	/* Save the information from PCI BIOS.	*/
8652*4882a593Smuzhiyun 	ha->pdev = pdev;
8653*4882a593Smuzhiyun 	ha->host = host;
8654*4882a593Smuzhiyun 	ha->host_no = host->host_no;
8655*4882a593Smuzhiyun 	ha->func_num = PCI_FUNC(ha->pdev->devfn);
8656*4882a593Smuzhiyun 
8657*4882a593Smuzhiyun 	pci_enable_pcie_error_reporting(pdev);
8658*4882a593Smuzhiyun 
8659*4882a593Smuzhiyun 	/* Setup Runtime configurable options */
8660*4882a593Smuzhiyun 	if (is_qla8022(ha)) {
8661*4882a593Smuzhiyun 		ha->isp_ops = &qla4_82xx_isp_ops;
8662*4882a593Smuzhiyun 		ha->reg_tbl = (uint32_t *) qla4_82xx_reg_tbl;
8663*4882a593Smuzhiyun 		ha->qdr_sn_window = -1;
8664*4882a593Smuzhiyun 		ha->ddr_mn_window = -1;
8665*4882a593Smuzhiyun 		ha->curr_window = 255;
8666*4882a593Smuzhiyun 		nx_legacy_intr = &legacy_intr[ha->func_num];
8667*4882a593Smuzhiyun 		ha->nx_legacy_intr.int_vec_bit = nx_legacy_intr->int_vec_bit;
8668*4882a593Smuzhiyun 		ha->nx_legacy_intr.tgt_status_reg =
8669*4882a593Smuzhiyun 			nx_legacy_intr->tgt_status_reg;
8670*4882a593Smuzhiyun 		ha->nx_legacy_intr.tgt_mask_reg = nx_legacy_intr->tgt_mask_reg;
8671*4882a593Smuzhiyun 		ha->nx_legacy_intr.pci_int_reg = nx_legacy_intr->pci_int_reg;
8672*4882a593Smuzhiyun 	} else if (is_qla8032(ha) || is_qla8042(ha)) {
8673*4882a593Smuzhiyun 		ha->isp_ops = &qla4_83xx_isp_ops;
8674*4882a593Smuzhiyun 		ha->reg_tbl = (uint32_t *)qla4_83xx_reg_tbl;
8675*4882a593Smuzhiyun 	} else {
8676*4882a593Smuzhiyun 		ha->isp_ops = &qla4xxx_isp_ops;
8677*4882a593Smuzhiyun 	}
8678*4882a593Smuzhiyun 
8679*4882a593Smuzhiyun 	if (is_qla80XX(ha)) {
8680*4882a593Smuzhiyun 		rwlock_init(&ha->hw_lock);
8681*4882a593Smuzhiyun 		ha->pf_bit = ha->func_num << 16;
8682*4882a593Smuzhiyun 		/* Set EEH reset type to fundamental if required by hba */
8683*4882a593Smuzhiyun 		pdev->needs_freset = 1;
8684*4882a593Smuzhiyun 	}
8685*4882a593Smuzhiyun 
8686*4882a593Smuzhiyun 	/* Configure PCI I/O space. */
8687*4882a593Smuzhiyun 	ret = ha->isp_ops->iospace_config(ha);
8688*4882a593Smuzhiyun 	if (ret)
8689*4882a593Smuzhiyun 		goto probe_failed_ioconfig;
8690*4882a593Smuzhiyun 
8691*4882a593Smuzhiyun 	ql4_printk(KERN_INFO, ha, "Found an ISP%04x, irq %d, iobase 0x%p\n",
8692*4882a593Smuzhiyun 		   pdev->device, pdev->irq, ha->reg);
8693*4882a593Smuzhiyun 
8694*4882a593Smuzhiyun 	qla4xxx_config_dma_addressing(ha);
8695*4882a593Smuzhiyun 
8696*4882a593Smuzhiyun 	/* Initialize lists and spinlocks. */
8697*4882a593Smuzhiyun 	INIT_LIST_HEAD(&ha->free_srb_q);
8698*4882a593Smuzhiyun 
8699*4882a593Smuzhiyun 	mutex_init(&ha->mbox_sem);
8700*4882a593Smuzhiyun 	mutex_init(&ha->chap_sem);
8701*4882a593Smuzhiyun 	init_completion(&ha->mbx_intr_comp);
8702*4882a593Smuzhiyun 	init_completion(&ha->disable_acb_comp);
8703*4882a593Smuzhiyun 	init_completion(&ha->idc_comp);
8704*4882a593Smuzhiyun 	init_completion(&ha->link_up_comp);
8705*4882a593Smuzhiyun 
8706*4882a593Smuzhiyun 	spin_lock_init(&ha->hardware_lock);
8707*4882a593Smuzhiyun 	spin_lock_init(&ha->work_lock);
8708*4882a593Smuzhiyun 
8709*4882a593Smuzhiyun 	/* Initialize work list */
8710*4882a593Smuzhiyun 	INIT_LIST_HEAD(&ha->work_list);
8711*4882a593Smuzhiyun 
8712*4882a593Smuzhiyun 	/* Allocate dma buffers */
8713*4882a593Smuzhiyun 	if (qla4xxx_mem_alloc(ha)) {
8714*4882a593Smuzhiyun 		ql4_printk(KERN_WARNING, ha,
8715*4882a593Smuzhiyun 		    "[ERROR] Failed to allocate memory for adapter\n");
8716*4882a593Smuzhiyun 
8717*4882a593Smuzhiyun 		ret = -ENOMEM;
8718*4882a593Smuzhiyun 		goto probe_failed;
8719*4882a593Smuzhiyun 	}
8720*4882a593Smuzhiyun 
8721*4882a593Smuzhiyun 	host->cmd_per_lun = 3;
8722*4882a593Smuzhiyun 	host->max_channel = 0;
8723*4882a593Smuzhiyun 	host->max_lun = MAX_LUNS - 1;
8724*4882a593Smuzhiyun 	host->max_id = MAX_TARGETS;
8725*4882a593Smuzhiyun 	host->max_cmd_len = IOCB_MAX_CDB_LEN;
8726*4882a593Smuzhiyun 	host->can_queue = MAX_SRBS ;
8727*4882a593Smuzhiyun 	host->transportt = qla4xxx_scsi_transport;
8728*4882a593Smuzhiyun 
8729*4882a593Smuzhiyun 	pci_set_drvdata(pdev, ha);
8730*4882a593Smuzhiyun 
8731*4882a593Smuzhiyun 	ret = scsi_add_host(host, &pdev->dev);
8732*4882a593Smuzhiyun 	if (ret)
8733*4882a593Smuzhiyun 		goto probe_failed;
8734*4882a593Smuzhiyun 
8735*4882a593Smuzhiyun 	if (is_qla80XX(ha))
8736*4882a593Smuzhiyun 		qla4_8xxx_get_flash_info(ha);
8737*4882a593Smuzhiyun 
8738*4882a593Smuzhiyun 	if (is_qla8032(ha) || is_qla8042(ha)) {
8739*4882a593Smuzhiyun 		qla4_83xx_read_reset_template(ha);
8740*4882a593Smuzhiyun 		/*
8741*4882a593Smuzhiyun 		 * NOTE: If ql4dontresethba==1, set IDC_CTRL DONTRESET_BIT0.
8742*4882a593Smuzhiyun 		 * If DONRESET_BIT0 is set, drivers should not set dev_state
8743*4882a593Smuzhiyun 		 * to NEED_RESET. But if NEED_RESET is set, drivers should
8744*4882a593Smuzhiyun 		 * should honor the reset.
8745*4882a593Smuzhiyun 		 */
8746*4882a593Smuzhiyun 		if (ql4xdontresethba == 1)
8747*4882a593Smuzhiyun 			qla4_83xx_set_idc_dontreset(ha);
8748*4882a593Smuzhiyun 	}
8749*4882a593Smuzhiyun 
8750*4882a593Smuzhiyun 	/*
8751*4882a593Smuzhiyun 	 * Initialize the Host adapter request/response queues and
8752*4882a593Smuzhiyun 	 * firmware
8753*4882a593Smuzhiyun 	 * NOTE: interrupts enabled upon successful completion
8754*4882a593Smuzhiyun 	 */
8755*4882a593Smuzhiyun 	status = qla4xxx_initialize_adapter(ha, INIT_ADAPTER);
8756*4882a593Smuzhiyun 
8757*4882a593Smuzhiyun 	/* Dont retry adapter initialization if IRQ allocation failed */
8758*4882a593Smuzhiyun 	if (is_qla80XX(ha) && (status == QLA_ERROR))
8759*4882a593Smuzhiyun 		goto skip_retry_init;
8760*4882a593Smuzhiyun 
8761*4882a593Smuzhiyun 	while ((!test_bit(AF_ONLINE, &ha->flags)) &&
8762*4882a593Smuzhiyun 	    init_retry_count++ < MAX_INIT_RETRIES) {
8763*4882a593Smuzhiyun 
8764*4882a593Smuzhiyun 		if (is_qla80XX(ha)) {
8765*4882a593Smuzhiyun 			ha->isp_ops->idc_lock(ha);
8766*4882a593Smuzhiyun 			dev_state = qla4_8xxx_rd_direct(ha,
8767*4882a593Smuzhiyun 							QLA8XXX_CRB_DEV_STATE);
8768*4882a593Smuzhiyun 			ha->isp_ops->idc_unlock(ha);
8769*4882a593Smuzhiyun 			if (dev_state == QLA8XXX_DEV_FAILED) {
8770*4882a593Smuzhiyun 				ql4_printk(KERN_WARNING, ha, "%s: don't retry "
8771*4882a593Smuzhiyun 				    "initialize adapter. H/W is in failed state\n",
8772*4882a593Smuzhiyun 				    __func__);
8773*4882a593Smuzhiyun 				break;
8774*4882a593Smuzhiyun 			}
8775*4882a593Smuzhiyun 		}
8776*4882a593Smuzhiyun 		DEBUG2(printk("scsi: %s: retrying adapter initialization "
8777*4882a593Smuzhiyun 			      "(%d)\n", __func__, init_retry_count));
8778*4882a593Smuzhiyun 
8779*4882a593Smuzhiyun 		if (ha->isp_ops->reset_chip(ha) == QLA_ERROR)
8780*4882a593Smuzhiyun 			continue;
8781*4882a593Smuzhiyun 
8782*4882a593Smuzhiyun 		status = qla4xxx_initialize_adapter(ha, INIT_ADAPTER);
8783*4882a593Smuzhiyun 		if (is_qla80XX(ha) && (status == QLA_ERROR)) {
8784*4882a593Smuzhiyun 			if (qla4_8xxx_check_init_adapter_retry(ha) == QLA_ERROR)
8785*4882a593Smuzhiyun 				goto skip_retry_init;
8786*4882a593Smuzhiyun 		}
8787*4882a593Smuzhiyun 	}
8788*4882a593Smuzhiyun 
8789*4882a593Smuzhiyun skip_retry_init:
8790*4882a593Smuzhiyun 	if (!test_bit(AF_ONLINE, &ha->flags)) {
8791*4882a593Smuzhiyun 		ql4_printk(KERN_WARNING, ha, "Failed to initialize adapter\n");
8792*4882a593Smuzhiyun 
8793*4882a593Smuzhiyun 		if ((is_qla8022(ha) && ql4xdontresethba) ||
8794*4882a593Smuzhiyun 		    ((is_qla8032(ha) || is_qla8042(ha)) &&
8795*4882a593Smuzhiyun 		     qla4_83xx_idc_dontreset(ha))) {
8796*4882a593Smuzhiyun 			/* Put the device in failed state. */
8797*4882a593Smuzhiyun 			DEBUG2(printk(KERN_ERR "HW STATE: FAILED\n"));
8798*4882a593Smuzhiyun 			ha->isp_ops->idc_lock(ha);
8799*4882a593Smuzhiyun 			qla4_8xxx_wr_direct(ha, QLA8XXX_CRB_DEV_STATE,
8800*4882a593Smuzhiyun 					    QLA8XXX_DEV_FAILED);
8801*4882a593Smuzhiyun 			ha->isp_ops->idc_unlock(ha);
8802*4882a593Smuzhiyun 		}
8803*4882a593Smuzhiyun 		ret = -ENODEV;
8804*4882a593Smuzhiyun 		goto remove_host;
8805*4882a593Smuzhiyun 	}
8806*4882a593Smuzhiyun 
8807*4882a593Smuzhiyun 	/* Startup the kernel thread for this host adapter. */
8808*4882a593Smuzhiyun 	DEBUG2(printk("scsi: %s: Starting kernel thread for "
8809*4882a593Smuzhiyun 		      "qla4xxx_dpc\n", __func__));
8810*4882a593Smuzhiyun 	sprintf(buf, "qla4xxx_%lu_dpc", ha->host_no);
8811*4882a593Smuzhiyun 	ha->dpc_thread = create_singlethread_workqueue(buf);
8812*4882a593Smuzhiyun 	if (!ha->dpc_thread) {
8813*4882a593Smuzhiyun 		ql4_printk(KERN_WARNING, ha, "Unable to start DPC thread!\n");
8814*4882a593Smuzhiyun 		ret = -ENODEV;
8815*4882a593Smuzhiyun 		goto remove_host;
8816*4882a593Smuzhiyun 	}
8817*4882a593Smuzhiyun 	INIT_WORK(&ha->dpc_work, qla4xxx_do_dpc);
8818*4882a593Smuzhiyun 
8819*4882a593Smuzhiyun 	ha->task_wq = alloc_workqueue("qla4xxx_%lu_task", WQ_MEM_RECLAIM, 1,
8820*4882a593Smuzhiyun 				      ha->host_no);
8821*4882a593Smuzhiyun 	if (!ha->task_wq) {
8822*4882a593Smuzhiyun 		ql4_printk(KERN_WARNING, ha, "Unable to start task thread!\n");
8823*4882a593Smuzhiyun 		ret = -ENODEV;
8824*4882a593Smuzhiyun 		goto remove_host;
8825*4882a593Smuzhiyun 	}
8826*4882a593Smuzhiyun 
8827*4882a593Smuzhiyun 	/*
8828*4882a593Smuzhiyun 	 * For ISP-8XXX, request_irqs is called in qla4_8xxx_load_risc
8829*4882a593Smuzhiyun 	 * (which is called indirectly by qla4xxx_initialize_adapter),
8830*4882a593Smuzhiyun 	 * so that irqs will be registered after crbinit but before
8831*4882a593Smuzhiyun 	 * mbx_intr_enable.
8832*4882a593Smuzhiyun 	 */
8833*4882a593Smuzhiyun 	if (is_qla40XX(ha)) {
8834*4882a593Smuzhiyun 		ret = qla4xxx_request_irqs(ha);
8835*4882a593Smuzhiyun 		if (ret) {
8836*4882a593Smuzhiyun 			ql4_printk(KERN_WARNING, ha, "Failed to reserve "
8837*4882a593Smuzhiyun 			    "interrupt %d already in use.\n", pdev->irq);
8838*4882a593Smuzhiyun 			goto remove_host;
8839*4882a593Smuzhiyun 		}
8840*4882a593Smuzhiyun 	}
8841*4882a593Smuzhiyun 
8842*4882a593Smuzhiyun 	pci_save_state(ha->pdev);
8843*4882a593Smuzhiyun 	ha->isp_ops->enable_intrs(ha);
8844*4882a593Smuzhiyun 
8845*4882a593Smuzhiyun 	/* Start timer thread. */
8846*4882a593Smuzhiyun 	qla4xxx_start_timer(ha, 1);
8847*4882a593Smuzhiyun 
8848*4882a593Smuzhiyun 	set_bit(AF_INIT_DONE, &ha->flags);
8849*4882a593Smuzhiyun 
8850*4882a593Smuzhiyun 	qla4_8xxx_alloc_sysfs_attr(ha);
8851*4882a593Smuzhiyun 
8852*4882a593Smuzhiyun 	printk(KERN_INFO
8853*4882a593Smuzhiyun 	       " QLogic iSCSI HBA Driver version: %s\n"
8854*4882a593Smuzhiyun 	       "  QLogic ISP%04x @ %s, host#=%ld, fw=%02d.%02d.%02d.%02d\n",
8855*4882a593Smuzhiyun 	       qla4xxx_version_str, ha->pdev->device, pci_name(ha->pdev),
8856*4882a593Smuzhiyun 	       ha->host_no, ha->fw_info.fw_major, ha->fw_info.fw_minor,
8857*4882a593Smuzhiyun 	       ha->fw_info.fw_patch, ha->fw_info.fw_build);
8858*4882a593Smuzhiyun 
8859*4882a593Smuzhiyun 	/* Set the driver version */
8860*4882a593Smuzhiyun 	if (is_qla80XX(ha))
8861*4882a593Smuzhiyun 		qla4_8xxx_set_param(ha, SET_DRVR_VERSION);
8862*4882a593Smuzhiyun 
8863*4882a593Smuzhiyun 	if (qla4xxx_setup_boot_info(ha))
8864*4882a593Smuzhiyun 		ql4_printk(KERN_ERR, ha,
8865*4882a593Smuzhiyun 			   "%s: No iSCSI boot target configured\n", __func__);
8866*4882a593Smuzhiyun 
8867*4882a593Smuzhiyun 	set_bit(DPC_SYSFS_DDB_EXPORT, &ha->dpc_flags);
8868*4882a593Smuzhiyun 	/* Perform the build ddb list and login to each */
8869*4882a593Smuzhiyun 	qla4xxx_build_ddb_list(ha, INIT_ADAPTER);
8870*4882a593Smuzhiyun 	iscsi_host_for_each_session(ha->host, qla4xxx_login_flash_ddb);
8871*4882a593Smuzhiyun 	qla4xxx_wait_login_resp_boot_tgt(ha);
8872*4882a593Smuzhiyun 
8873*4882a593Smuzhiyun 	qla4xxx_create_chap_list(ha);
8874*4882a593Smuzhiyun 
8875*4882a593Smuzhiyun 	qla4xxx_create_ifaces(ha);
8876*4882a593Smuzhiyun 	return 0;
8877*4882a593Smuzhiyun 
8878*4882a593Smuzhiyun remove_host:
8879*4882a593Smuzhiyun 	scsi_remove_host(ha->host);
8880*4882a593Smuzhiyun 
8881*4882a593Smuzhiyun probe_failed:
8882*4882a593Smuzhiyun 	qla4xxx_free_adapter(ha);
8883*4882a593Smuzhiyun 
8884*4882a593Smuzhiyun probe_failed_ioconfig:
8885*4882a593Smuzhiyun 	pci_disable_pcie_error_reporting(pdev);
8886*4882a593Smuzhiyun 	scsi_host_put(ha->host);
8887*4882a593Smuzhiyun 
8888*4882a593Smuzhiyun probe_disable_device:
8889*4882a593Smuzhiyun 	pci_disable_device(pdev);
8890*4882a593Smuzhiyun 
8891*4882a593Smuzhiyun 	return ret;
8892*4882a593Smuzhiyun }
8893*4882a593Smuzhiyun 
8894*4882a593Smuzhiyun /**
8895*4882a593Smuzhiyun  * qla4xxx_prevent_other_port_reinit - prevent other port from re-initialize
8896*4882a593Smuzhiyun  * @ha: pointer to adapter structure
8897*4882a593Smuzhiyun  *
8898*4882a593Smuzhiyun  * Mark the other ISP-4xxx port to indicate that the driver is being removed,
8899*4882a593Smuzhiyun  * so that the other port will not re-initialize while in the process of
8900*4882a593Smuzhiyun  * removing the ha due to driver unload or hba hotplug.
8901*4882a593Smuzhiyun  **/
qla4xxx_prevent_other_port_reinit(struct scsi_qla_host * ha)8902*4882a593Smuzhiyun static void qla4xxx_prevent_other_port_reinit(struct scsi_qla_host *ha)
8903*4882a593Smuzhiyun {
8904*4882a593Smuzhiyun 	struct scsi_qla_host *other_ha = NULL;
8905*4882a593Smuzhiyun 	struct pci_dev *other_pdev = NULL;
8906*4882a593Smuzhiyun 	int fn = ISP4XXX_PCI_FN_2;
8907*4882a593Smuzhiyun 
8908*4882a593Smuzhiyun 	/*iscsi function numbers for ISP4xxx is 1 and 3*/
8909*4882a593Smuzhiyun 	if (PCI_FUNC(ha->pdev->devfn) & BIT_1)
8910*4882a593Smuzhiyun 		fn = ISP4XXX_PCI_FN_1;
8911*4882a593Smuzhiyun 
8912*4882a593Smuzhiyun 	other_pdev =
8913*4882a593Smuzhiyun 		pci_get_domain_bus_and_slot(pci_domain_nr(ha->pdev->bus),
8914*4882a593Smuzhiyun 		ha->pdev->bus->number, PCI_DEVFN(PCI_SLOT(ha->pdev->devfn),
8915*4882a593Smuzhiyun 		fn));
8916*4882a593Smuzhiyun 
8917*4882a593Smuzhiyun 	/* Get other_ha if other_pdev is valid and state is enable*/
8918*4882a593Smuzhiyun 	if (other_pdev) {
8919*4882a593Smuzhiyun 		if (atomic_read(&other_pdev->enable_cnt)) {
8920*4882a593Smuzhiyun 			other_ha = pci_get_drvdata(other_pdev);
8921*4882a593Smuzhiyun 			if (other_ha) {
8922*4882a593Smuzhiyun 				set_bit(AF_HA_REMOVAL, &other_ha->flags);
8923*4882a593Smuzhiyun 				DEBUG2(ql4_printk(KERN_INFO, ha, "%s: "
8924*4882a593Smuzhiyun 				    "Prevent %s reinit\n", __func__,
8925*4882a593Smuzhiyun 				    dev_name(&other_ha->pdev->dev)));
8926*4882a593Smuzhiyun 			}
8927*4882a593Smuzhiyun 		}
8928*4882a593Smuzhiyun 		pci_dev_put(other_pdev);
8929*4882a593Smuzhiyun 	}
8930*4882a593Smuzhiyun }
8931*4882a593Smuzhiyun 
qla4xxx_destroy_ddb(struct scsi_qla_host * ha,struct ddb_entry * ddb_entry)8932*4882a593Smuzhiyun static void qla4xxx_destroy_ddb(struct scsi_qla_host *ha,
8933*4882a593Smuzhiyun 		struct ddb_entry *ddb_entry)
8934*4882a593Smuzhiyun {
8935*4882a593Smuzhiyun 	struct dev_db_entry *fw_ddb_entry = NULL;
8936*4882a593Smuzhiyun 	dma_addr_t fw_ddb_entry_dma;
8937*4882a593Smuzhiyun 	unsigned long wtime;
8938*4882a593Smuzhiyun 	uint32_t ddb_state;
8939*4882a593Smuzhiyun 	int options;
8940*4882a593Smuzhiyun 	int status;
8941*4882a593Smuzhiyun 
8942*4882a593Smuzhiyun 	options = LOGOUT_OPTION_CLOSE_SESSION;
8943*4882a593Smuzhiyun 	if (qla4xxx_session_logout_ddb(ha, ddb_entry, options) == QLA_ERROR) {
8944*4882a593Smuzhiyun 		ql4_printk(KERN_ERR, ha, "%s: Logout failed\n", __func__);
8945*4882a593Smuzhiyun 		goto clear_ddb;
8946*4882a593Smuzhiyun 	}
8947*4882a593Smuzhiyun 
8948*4882a593Smuzhiyun 	fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
8949*4882a593Smuzhiyun 					  &fw_ddb_entry_dma, GFP_KERNEL);
8950*4882a593Smuzhiyun 	if (!fw_ddb_entry) {
8951*4882a593Smuzhiyun 		ql4_printk(KERN_ERR, ha,
8952*4882a593Smuzhiyun 			   "%s: Unable to allocate dma buffer\n", __func__);
8953*4882a593Smuzhiyun 		goto clear_ddb;
8954*4882a593Smuzhiyun 	}
8955*4882a593Smuzhiyun 
8956*4882a593Smuzhiyun 	wtime = jiffies + (HZ * LOGOUT_TOV);
8957*4882a593Smuzhiyun 	do {
8958*4882a593Smuzhiyun 		status = qla4xxx_get_fwddb_entry(ha, ddb_entry->fw_ddb_index,
8959*4882a593Smuzhiyun 						 fw_ddb_entry, fw_ddb_entry_dma,
8960*4882a593Smuzhiyun 						 NULL, NULL, &ddb_state, NULL,
8961*4882a593Smuzhiyun 						 NULL, NULL);
8962*4882a593Smuzhiyun 		if (status == QLA_ERROR)
8963*4882a593Smuzhiyun 			goto free_ddb;
8964*4882a593Smuzhiyun 
8965*4882a593Smuzhiyun 		if ((ddb_state == DDB_DS_NO_CONNECTION_ACTIVE) ||
8966*4882a593Smuzhiyun 		    (ddb_state == DDB_DS_SESSION_FAILED))
8967*4882a593Smuzhiyun 			goto free_ddb;
8968*4882a593Smuzhiyun 
8969*4882a593Smuzhiyun 		schedule_timeout_uninterruptible(HZ);
8970*4882a593Smuzhiyun 	} while ((time_after(wtime, jiffies)));
8971*4882a593Smuzhiyun 
8972*4882a593Smuzhiyun free_ddb:
8973*4882a593Smuzhiyun 	dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
8974*4882a593Smuzhiyun 			  fw_ddb_entry, fw_ddb_entry_dma);
8975*4882a593Smuzhiyun clear_ddb:
8976*4882a593Smuzhiyun 	qla4xxx_clear_ddb_entry(ha, ddb_entry->fw_ddb_index);
8977*4882a593Smuzhiyun }
8978*4882a593Smuzhiyun 
qla4xxx_destroy_fw_ddb_session(struct scsi_qla_host * ha)8979*4882a593Smuzhiyun static void qla4xxx_destroy_fw_ddb_session(struct scsi_qla_host *ha)
8980*4882a593Smuzhiyun {
8981*4882a593Smuzhiyun 	struct ddb_entry *ddb_entry;
8982*4882a593Smuzhiyun 	int idx;
8983*4882a593Smuzhiyun 
8984*4882a593Smuzhiyun 	for (idx = 0; idx < MAX_DDB_ENTRIES; idx++) {
8985*4882a593Smuzhiyun 
8986*4882a593Smuzhiyun 		ddb_entry = qla4xxx_lookup_ddb_by_fw_index(ha, idx);
8987*4882a593Smuzhiyun 		if ((ddb_entry != NULL) &&
8988*4882a593Smuzhiyun 		    (ddb_entry->ddb_type == FLASH_DDB)) {
8989*4882a593Smuzhiyun 
8990*4882a593Smuzhiyun 			qla4xxx_destroy_ddb(ha, ddb_entry);
8991*4882a593Smuzhiyun 			/*
8992*4882a593Smuzhiyun 			 * we have decremented the reference count of the driver
8993*4882a593Smuzhiyun 			 * when we setup the session to have the driver unload
8994*4882a593Smuzhiyun 			 * to be seamless without actually destroying the
8995*4882a593Smuzhiyun 			 * session
8996*4882a593Smuzhiyun 			 **/
8997*4882a593Smuzhiyun 			try_module_get(qla4xxx_iscsi_transport.owner);
8998*4882a593Smuzhiyun 			iscsi_destroy_endpoint(ddb_entry->conn->ep);
8999*4882a593Smuzhiyun 			qla4xxx_free_ddb(ha, ddb_entry);
9000*4882a593Smuzhiyun 			iscsi_session_teardown(ddb_entry->sess);
9001*4882a593Smuzhiyun 		}
9002*4882a593Smuzhiyun 	}
9003*4882a593Smuzhiyun }
9004*4882a593Smuzhiyun /**
9005*4882a593Smuzhiyun  * qla4xxx_remove_adapter - callback function to remove adapter.
9006*4882a593Smuzhiyun  * @pdev: PCI device pointer
9007*4882a593Smuzhiyun  **/
qla4xxx_remove_adapter(struct pci_dev * pdev)9008*4882a593Smuzhiyun static void qla4xxx_remove_adapter(struct pci_dev *pdev)
9009*4882a593Smuzhiyun {
9010*4882a593Smuzhiyun 	struct scsi_qla_host *ha;
9011*4882a593Smuzhiyun 
9012*4882a593Smuzhiyun 	/*
9013*4882a593Smuzhiyun 	 * If the PCI device is disabled then it means probe_adapter had
9014*4882a593Smuzhiyun 	 * failed and resources already cleaned up on probe_adapter exit.
9015*4882a593Smuzhiyun 	 */
9016*4882a593Smuzhiyun 	if (!pci_is_enabled(pdev))
9017*4882a593Smuzhiyun 		return;
9018*4882a593Smuzhiyun 
9019*4882a593Smuzhiyun 	ha = pci_get_drvdata(pdev);
9020*4882a593Smuzhiyun 
9021*4882a593Smuzhiyun 	if (is_qla40XX(ha))
9022*4882a593Smuzhiyun 		qla4xxx_prevent_other_port_reinit(ha);
9023*4882a593Smuzhiyun 
9024*4882a593Smuzhiyun 	/* destroy iface from sysfs */
9025*4882a593Smuzhiyun 	qla4xxx_destroy_ifaces(ha);
9026*4882a593Smuzhiyun 
9027*4882a593Smuzhiyun 	if ((!ql4xdisablesysfsboot) && ha->boot_kset)
9028*4882a593Smuzhiyun 		iscsi_boot_destroy_kset(ha->boot_kset);
9029*4882a593Smuzhiyun 
9030*4882a593Smuzhiyun 	qla4xxx_destroy_fw_ddb_session(ha);
9031*4882a593Smuzhiyun 	qla4_8xxx_free_sysfs_attr(ha);
9032*4882a593Smuzhiyun 
9033*4882a593Smuzhiyun 	qla4xxx_sysfs_ddb_remove(ha);
9034*4882a593Smuzhiyun 	scsi_remove_host(ha->host);
9035*4882a593Smuzhiyun 
9036*4882a593Smuzhiyun 	qla4xxx_free_adapter(ha);
9037*4882a593Smuzhiyun 
9038*4882a593Smuzhiyun 	scsi_host_put(ha->host);
9039*4882a593Smuzhiyun 
9040*4882a593Smuzhiyun 	pci_disable_pcie_error_reporting(pdev);
9041*4882a593Smuzhiyun 	pci_disable_device(pdev);
9042*4882a593Smuzhiyun }
9043*4882a593Smuzhiyun 
9044*4882a593Smuzhiyun /**
9045*4882a593Smuzhiyun  * qla4xxx_config_dma_addressing() - Configure OS DMA addressing method.
9046*4882a593Smuzhiyun  * @ha: HA context
9047*4882a593Smuzhiyun  */
qla4xxx_config_dma_addressing(struct scsi_qla_host * ha)9048*4882a593Smuzhiyun static void qla4xxx_config_dma_addressing(struct scsi_qla_host *ha)
9049*4882a593Smuzhiyun {
9050*4882a593Smuzhiyun 	/* Update our PCI device dma_mask for full 64 bit mask */
9051*4882a593Smuzhiyun 	if (dma_set_mask_and_coherent(&ha->pdev->dev, DMA_BIT_MASK(64))) {
9052*4882a593Smuzhiyun 		dev_dbg(&ha->pdev->dev,
9053*4882a593Smuzhiyun 			  "Failed to set 64 bit PCI consistent mask; "
9054*4882a593Smuzhiyun 			   "using 32 bit.\n");
9055*4882a593Smuzhiyun 		dma_set_mask_and_coherent(&ha->pdev->dev, DMA_BIT_MASK(32));
9056*4882a593Smuzhiyun 	}
9057*4882a593Smuzhiyun }
9058*4882a593Smuzhiyun 
qla4xxx_slave_alloc(struct scsi_device * sdev)9059*4882a593Smuzhiyun static int qla4xxx_slave_alloc(struct scsi_device *sdev)
9060*4882a593Smuzhiyun {
9061*4882a593Smuzhiyun 	struct iscsi_cls_session *cls_sess;
9062*4882a593Smuzhiyun 	struct iscsi_session *sess;
9063*4882a593Smuzhiyun 	struct ddb_entry *ddb;
9064*4882a593Smuzhiyun 	int queue_depth = QL4_DEF_QDEPTH;
9065*4882a593Smuzhiyun 
9066*4882a593Smuzhiyun 	cls_sess = starget_to_session(sdev->sdev_target);
9067*4882a593Smuzhiyun 	sess = cls_sess->dd_data;
9068*4882a593Smuzhiyun 	ddb = sess->dd_data;
9069*4882a593Smuzhiyun 
9070*4882a593Smuzhiyun 	sdev->hostdata = ddb;
9071*4882a593Smuzhiyun 
9072*4882a593Smuzhiyun 	if (ql4xmaxqdepth != 0 && ql4xmaxqdepth <= 0xffffU)
9073*4882a593Smuzhiyun 		queue_depth = ql4xmaxqdepth;
9074*4882a593Smuzhiyun 
9075*4882a593Smuzhiyun 	scsi_change_queue_depth(sdev, queue_depth);
9076*4882a593Smuzhiyun 	return 0;
9077*4882a593Smuzhiyun }
9078*4882a593Smuzhiyun 
9079*4882a593Smuzhiyun /**
9080*4882a593Smuzhiyun  * qla4xxx_del_from_active_array - returns an active srb
9081*4882a593Smuzhiyun  * @ha: Pointer to host adapter structure.
9082*4882a593Smuzhiyun  * @index: index into the active_array
9083*4882a593Smuzhiyun  *
9084*4882a593Smuzhiyun  * This routine removes and returns the srb at the specified index
9085*4882a593Smuzhiyun  **/
qla4xxx_del_from_active_array(struct scsi_qla_host * ha,uint32_t index)9086*4882a593Smuzhiyun struct srb *qla4xxx_del_from_active_array(struct scsi_qla_host *ha,
9087*4882a593Smuzhiyun     uint32_t index)
9088*4882a593Smuzhiyun {
9089*4882a593Smuzhiyun 	struct srb *srb = NULL;
9090*4882a593Smuzhiyun 	struct scsi_cmnd *cmd = NULL;
9091*4882a593Smuzhiyun 
9092*4882a593Smuzhiyun 	cmd = scsi_host_find_tag(ha->host, index);
9093*4882a593Smuzhiyun 	if (!cmd)
9094*4882a593Smuzhiyun 		return srb;
9095*4882a593Smuzhiyun 
9096*4882a593Smuzhiyun 	srb = (struct srb *)CMD_SP(cmd);
9097*4882a593Smuzhiyun 	if (!srb)
9098*4882a593Smuzhiyun 		return srb;
9099*4882a593Smuzhiyun 
9100*4882a593Smuzhiyun 	/* update counters */
9101*4882a593Smuzhiyun 	if (srb->flags & SRB_DMA_VALID) {
9102*4882a593Smuzhiyun 		ha->iocb_cnt -= srb->iocb_cnt;
9103*4882a593Smuzhiyun 		if (srb->cmd)
9104*4882a593Smuzhiyun 			srb->cmd->host_scribble =
9105*4882a593Smuzhiyun 				(unsigned char *)(unsigned long) MAX_SRBS;
9106*4882a593Smuzhiyun 	}
9107*4882a593Smuzhiyun 	return srb;
9108*4882a593Smuzhiyun }
9109*4882a593Smuzhiyun 
9110*4882a593Smuzhiyun /**
9111*4882a593Smuzhiyun  * qla4xxx_eh_wait_on_command - waits for command to be returned by firmware
9112*4882a593Smuzhiyun  * @ha: Pointer to host adapter structure.
9113*4882a593Smuzhiyun  * @cmd: Scsi Command to wait on.
9114*4882a593Smuzhiyun  *
9115*4882a593Smuzhiyun  * This routine waits for the command to be returned by the Firmware
9116*4882a593Smuzhiyun  * for some max time.
9117*4882a593Smuzhiyun  **/
qla4xxx_eh_wait_on_command(struct scsi_qla_host * ha,struct scsi_cmnd * cmd)9118*4882a593Smuzhiyun static int qla4xxx_eh_wait_on_command(struct scsi_qla_host *ha,
9119*4882a593Smuzhiyun 				      struct scsi_cmnd *cmd)
9120*4882a593Smuzhiyun {
9121*4882a593Smuzhiyun 	int done = 0;
9122*4882a593Smuzhiyun 	struct srb *rp;
9123*4882a593Smuzhiyun 	uint32_t max_wait_time = EH_WAIT_CMD_TOV;
9124*4882a593Smuzhiyun 	int ret = SUCCESS;
9125*4882a593Smuzhiyun 
9126*4882a593Smuzhiyun 	/* Dont wait on command if PCI error is being handled
9127*4882a593Smuzhiyun 	 * by PCI AER driver
9128*4882a593Smuzhiyun 	 */
9129*4882a593Smuzhiyun 	if (unlikely(pci_channel_offline(ha->pdev)) ||
9130*4882a593Smuzhiyun 	    (test_bit(AF_EEH_BUSY, &ha->flags))) {
9131*4882a593Smuzhiyun 		ql4_printk(KERN_WARNING, ha, "scsi%ld: Return from %s\n",
9132*4882a593Smuzhiyun 		    ha->host_no, __func__);
9133*4882a593Smuzhiyun 		return ret;
9134*4882a593Smuzhiyun 	}
9135*4882a593Smuzhiyun 
9136*4882a593Smuzhiyun 	do {
9137*4882a593Smuzhiyun 		/* Checking to see if its returned to OS */
9138*4882a593Smuzhiyun 		rp = (struct srb *) CMD_SP(cmd);
9139*4882a593Smuzhiyun 		if (rp == NULL) {
9140*4882a593Smuzhiyun 			done++;
9141*4882a593Smuzhiyun 			break;
9142*4882a593Smuzhiyun 		}
9143*4882a593Smuzhiyun 
9144*4882a593Smuzhiyun 		msleep(2000);
9145*4882a593Smuzhiyun 	} while (max_wait_time--);
9146*4882a593Smuzhiyun 
9147*4882a593Smuzhiyun 	return done;
9148*4882a593Smuzhiyun }
9149*4882a593Smuzhiyun 
9150*4882a593Smuzhiyun /**
9151*4882a593Smuzhiyun  * qla4xxx_wait_for_hba_online - waits for HBA to come online
9152*4882a593Smuzhiyun  * @ha: Pointer to host adapter structure
9153*4882a593Smuzhiyun  **/
qla4xxx_wait_for_hba_online(struct scsi_qla_host * ha)9154*4882a593Smuzhiyun static int qla4xxx_wait_for_hba_online(struct scsi_qla_host *ha)
9155*4882a593Smuzhiyun {
9156*4882a593Smuzhiyun 	unsigned long wait_online;
9157*4882a593Smuzhiyun 
9158*4882a593Smuzhiyun 	wait_online = jiffies + (HBA_ONLINE_TOV * HZ);
9159*4882a593Smuzhiyun 	while (time_before(jiffies, wait_online)) {
9160*4882a593Smuzhiyun 
9161*4882a593Smuzhiyun 		if (adapter_up(ha))
9162*4882a593Smuzhiyun 			return QLA_SUCCESS;
9163*4882a593Smuzhiyun 
9164*4882a593Smuzhiyun 		msleep(2000);
9165*4882a593Smuzhiyun 	}
9166*4882a593Smuzhiyun 
9167*4882a593Smuzhiyun 	return QLA_ERROR;
9168*4882a593Smuzhiyun }
9169*4882a593Smuzhiyun 
9170*4882a593Smuzhiyun /**
9171*4882a593Smuzhiyun  * qla4xxx_eh_wait_for_commands - wait for active cmds to finish.
9172*4882a593Smuzhiyun  * @ha: pointer to HBA
9173*4882a593Smuzhiyun  * @stgt: pointer to SCSI target
9174*4882a593Smuzhiyun  * @sdev: pointer to SCSI device
9175*4882a593Smuzhiyun  *
9176*4882a593Smuzhiyun  * This function waits for all outstanding commands to a lun to complete. It
9177*4882a593Smuzhiyun  * returns 0 if all pending commands are returned and 1 otherwise.
9178*4882a593Smuzhiyun  **/
qla4xxx_eh_wait_for_commands(struct scsi_qla_host * ha,struct scsi_target * stgt,struct scsi_device * sdev)9179*4882a593Smuzhiyun static int qla4xxx_eh_wait_for_commands(struct scsi_qla_host *ha,
9180*4882a593Smuzhiyun 					struct scsi_target *stgt,
9181*4882a593Smuzhiyun 					struct scsi_device *sdev)
9182*4882a593Smuzhiyun {
9183*4882a593Smuzhiyun 	int cnt;
9184*4882a593Smuzhiyun 	int status = 0;
9185*4882a593Smuzhiyun 	struct scsi_cmnd *cmd;
9186*4882a593Smuzhiyun 
9187*4882a593Smuzhiyun 	/*
9188*4882a593Smuzhiyun 	 * Waiting for all commands for the designated target or dev
9189*4882a593Smuzhiyun 	 * in the active array
9190*4882a593Smuzhiyun 	 */
9191*4882a593Smuzhiyun 	for (cnt = 0; cnt < ha->host->can_queue; cnt++) {
9192*4882a593Smuzhiyun 		cmd = scsi_host_find_tag(ha->host, cnt);
9193*4882a593Smuzhiyun 		if (cmd && stgt == scsi_target(cmd->device) &&
9194*4882a593Smuzhiyun 		    (!sdev || sdev == cmd->device)) {
9195*4882a593Smuzhiyun 			if (!qla4xxx_eh_wait_on_command(ha, cmd)) {
9196*4882a593Smuzhiyun 				status++;
9197*4882a593Smuzhiyun 				break;
9198*4882a593Smuzhiyun 			}
9199*4882a593Smuzhiyun 		}
9200*4882a593Smuzhiyun 	}
9201*4882a593Smuzhiyun 	return status;
9202*4882a593Smuzhiyun }
9203*4882a593Smuzhiyun 
9204*4882a593Smuzhiyun /**
9205*4882a593Smuzhiyun  * qla4xxx_eh_abort - callback for abort task.
9206*4882a593Smuzhiyun  * @cmd: Pointer to Linux's SCSI command structure
9207*4882a593Smuzhiyun  *
9208*4882a593Smuzhiyun  * This routine is called by the Linux OS to abort the specified
9209*4882a593Smuzhiyun  * command.
9210*4882a593Smuzhiyun  **/
qla4xxx_eh_abort(struct scsi_cmnd * cmd)9211*4882a593Smuzhiyun static int qla4xxx_eh_abort(struct scsi_cmnd *cmd)
9212*4882a593Smuzhiyun {
9213*4882a593Smuzhiyun 	struct scsi_qla_host *ha = to_qla_host(cmd->device->host);
9214*4882a593Smuzhiyun 	unsigned int id = cmd->device->id;
9215*4882a593Smuzhiyun 	uint64_t lun = cmd->device->lun;
9216*4882a593Smuzhiyun 	unsigned long flags;
9217*4882a593Smuzhiyun 	struct srb *srb = NULL;
9218*4882a593Smuzhiyun 	int ret = SUCCESS;
9219*4882a593Smuzhiyun 	int wait = 0;
9220*4882a593Smuzhiyun 	int rval;
9221*4882a593Smuzhiyun 
9222*4882a593Smuzhiyun 	ql4_printk(KERN_INFO, ha, "scsi%ld:%d:%llu: Abort command issued cmd=%p, cdb=0x%x\n",
9223*4882a593Smuzhiyun 		   ha->host_no, id, lun, cmd, cmd->cmnd[0]);
9224*4882a593Smuzhiyun 
9225*4882a593Smuzhiyun 	rval = qla4xxx_isp_check_reg(ha);
9226*4882a593Smuzhiyun 	if (rval != QLA_SUCCESS) {
9227*4882a593Smuzhiyun 		ql4_printk(KERN_INFO, ha, "PCI/Register disconnect, exiting.\n");
9228*4882a593Smuzhiyun 		return FAILED;
9229*4882a593Smuzhiyun 	}
9230*4882a593Smuzhiyun 
9231*4882a593Smuzhiyun 	spin_lock_irqsave(&ha->hardware_lock, flags);
9232*4882a593Smuzhiyun 	srb = (struct srb *) CMD_SP(cmd);
9233*4882a593Smuzhiyun 	if (!srb) {
9234*4882a593Smuzhiyun 		spin_unlock_irqrestore(&ha->hardware_lock, flags);
9235*4882a593Smuzhiyun 		ql4_printk(KERN_INFO, ha, "scsi%ld:%d:%llu: Specified command has already completed.\n",
9236*4882a593Smuzhiyun 			   ha->host_no, id, lun);
9237*4882a593Smuzhiyun 		return SUCCESS;
9238*4882a593Smuzhiyun 	}
9239*4882a593Smuzhiyun 	kref_get(&srb->srb_ref);
9240*4882a593Smuzhiyun 	spin_unlock_irqrestore(&ha->hardware_lock, flags);
9241*4882a593Smuzhiyun 
9242*4882a593Smuzhiyun 	if (qla4xxx_abort_task(ha, srb) != QLA_SUCCESS) {
9243*4882a593Smuzhiyun 		DEBUG3(printk("scsi%ld:%d:%llu: Abort_task mbx failed.\n",
9244*4882a593Smuzhiyun 		    ha->host_no, id, lun));
9245*4882a593Smuzhiyun 		ret = FAILED;
9246*4882a593Smuzhiyun 	} else {
9247*4882a593Smuzhiyun 		DEBUG3(printk("scsi%ld:%d:%llu: Abort_task mbx success.\n",
9248*4882a593Smuzhiyun 		    ha->host_no, id, lun));
9249*4882a593Smuzhiyun 		wait = 1;
9250*4882a593Smuzhiyun 	}
9251*4882a593Smuzhiyun 
9252*4882a593Smuzhiyun 	kref_put(&srb->srb_ref, qla4xxx_srb_compl);
9253*4882a593Smuzhiyun 
9254*4882a593Smuzhiyun 	/* Wait for command to complete */
9255*4882a593Smuzhiyun 	if (wait) {
9256*4882a593Smuzhiyun 		if (!qla4xxx_eh_wait_on_command(ha, cmd)) {
9257*4882a593Smuzhiyun 			DEBUG2(printk("scsi%ld:%d:%llu: Abort handler timed out\n",
9258*4882a593Smuzhiyun 			    ha->host_no, id, lun));
9259*4882a593Smuzhiyun 			ret = FAILED;
9260*4882a593Smuzhiyun 		}
9261*4882a593Smuzhiyun 	}
9262*4882a593Smuzhiyun 
9263*4882a593Smuzhiyun 	ql4_printk(KERN_INFO, ha,
9264*4882a593Smuzhiyun 	    "scsi%ld:%d:%llu: Abort command - %s\n",
9265*4882a593Smuzhiyun 	    ha->host_no, id, lun, (ret == SUCCESS) ? "succeeded" : "failed");
9266*4882a593Smuzhiyun 
9267*4882a593Smuzhiyun 	return ret;
9268*4882a593Smuzhiyun }
9269*4882a593Smuzhiyun 
9270*4882a593Smuzhiyun /**
9271*4882a593Smuzhiyun  * qla4xxx_eh_device_reset - callback for target reset.
9272*4882a593Smuzhiyun  * @cmd: Pointer to Linux's SCSI command structure
9273*4882a593Smuzhiyun  *
9274*4882a593Smuzhiyun  * This routine is called by the Linux OS to reset all luns on the
9275*4882a593Smuzhiyun  * specified target.
9276*4882a593Smuzhiyun  **/
qla4xxx_eh_device_reset(struct scsi_cmnd * cmd)9277*4882a593Smuzhiyun static int qla4xxx_eh_device_reset(struct scsi_cmnd *cmd)
9278*4882a593Smuzhiyun {
9279*4882a593Smuzhiyun 	struct scsi_qla_host *ha = to_qla_host(cmd->device->host);
9280*4882a593Smuzhiyun 	struct ddb_entry *ddb_entry = cmd->device->hostdata;
9281*4882a593Smuzhiyun 	int ret = FAILED, stat;
9282*4882a593Smuzhiyun 	int rval;
9283*4882a593Smuzhiyun 
9284*4882a593Smuzhiyun 	if (!ddb_entry)
9285*4882a593Smuzhiyun 		return ret;
9286*4882a593Smuzhiyun 
9287*4882a593Smuzhiyun 	ret = iscsi_block_scsi_eh(cmd);
9288*4882a593Smuzhiyun 	if (ret)
9289*4882a593Smuzhiyun 		return ret;
9290*4882a593Smuzhiyun 	ret = FAILED;
9291*4882a593Smuzhiyun 
9292*4882a593Smuzhiyun 	ql4_printk(KERN_INFO, ha,
9293*4882a593Smuzhiyun 		   "scsi%ld:%d:%d:%llu: DEVICE RESET ISSUED.\n", ha->host_no,
9294*4882a593Smuzhiyun 		   cmd->device->channel, cmd->device->id, cmd->device->lun);
9295*4882a593Smuzhiyun 
9296*4882a593Smuzhiyun 	DEBUG2(printk(KERN_INFO
9297*4882a593Smuzhiyun 		      "scsi%ld: DEVICE_RESET cmd=%p jiffies = 0x%lx, to=%x,"
9298*4882a593Smuzhiyun 		      "dpc_flags=%lx, status=%x allowed=%d\n", ha->host_no,
9299*4882a593Smuzhiyun 		      cmd, jiffies, cmd->request->timeout / HZ,
9300*4882a593Smuzhiyun 		      ha->dpc_flags, cmd->result, cmd->allowed));
9301*4882a593Smuzhiyun 
9302*4882a593Smuzhiyun 	rval = qla4xxx_isp_check_reg(ha);
9303*4882a593Smuzhiyun 	if (rval != QLA_SUCCESS) {
9304*4882a593Smuzhiyun 		ql4_printk(KERN_INFO, ha, "PCI/Register disconnect, exiting.\n");
9305*4882a593Smuzhiyun 		return FAILED;
9306*4882a593Smuzhiyun 	}
9307*4882a593Smuzhiyun 
9308*4882a593Smuzhiyun 	/* FIXME: wait for hba to go online */
9309*4882a593Smuzhiyun 	stat = qla4xxx_reset_lun(ha, ddb_entry, cmd->device->lun);
9310*4882a593Smuzhiyun 	if (stat != QLA_SUCCESS) {
9311*4882a593Smuzhiyun 		ql4_printk(KERN_INFO, ha, "DEVICE RESET FAILED. %d\n", stat);
9312*4882a593Smuzhiyun 		goto eh_dev_reset_done;
9313*4882a593Smuzhiyun 	}
9314*4882a593Smuzhiyun 
9315*4882a593Smuzhiyun 	if (qla4xxx_eh_wait_for_commands(ha, scsi_target(cmd->device),
9316*4882a593Smuzhiyun 					 cmd->device)) {
9317*4882a593Smuzhiyun 		ql4_printk(KERN_INFO, ha,
9318*4882a593Smuzhiyun 			   "DEVICE RESET FAILED - waiting for "
9319*4882a593Smuzhiyun 			   "commands.\n");
9320*4882a593Smuzhiyun 		goto eh_dev_reset_done;
9321*4882a593Smuzhiyun 	}
9322*4882a593Smuzhiyun 
9323*4882a593Smuzhiyun 	/* Send marker. */
9324*4882a593Smuzhiyun 	if (qla4xxx_send_marker_iocb(ha, ddb_entry, cmd->device->lun,
9325*4882a593Smuzhiyun 		MM_LUN_RESET) != QLA_SUCCESS)
9326*4882a593Smuzhiyun 		goto eh_dev_reset_done;
9327*4882a593Smuzhiyun 
9328*4882a593Smuzhiyun 	ql4_printk(KERN_INFO, ha,
9329*4882a593Smuzhiyun 		   "scsi(%ld:%d:%d:%llu): DEVICE RESET SUCCEEDED.\n",
9330*4882a593Smuzhiyun 		   ha->host_no, cmd->device->channel, cmd->device->id,
9331*4882a593Smuzhiyun 		   cmd->device->lun);
9332*4882a593Smuzhiyun 
9333*4882a593Smuzhiyun 	ret = SUCCESS;
9334*4882a593Smuzhiyun 
9335*4882a593Smuzhiyun eh_dev_reset_done:
9336*4882a593Smuzhiyun 
9337*4882a593Smuzhiyun 	return ret;
9338*4882a593Smuzhiyun }
9339*4882a593Smuzhiyun 
9340*4882a593Smuzhiyun /**
9341*4882a593Smuzhiyun  * qla4xxx_eh_target_reset - callback for target reset.
9342*4882a593Smuzhiyun  * @cmd: Pointer to Linux's SCSI command structure
9343*4882a593Smuzhiyun  *
9344*4882a593Smuzhiyun  * This routine is called by the Linux OS to reset the target.
9345*4882a593Smuzhiyun  **/
qla4xxx_eh_target_reset(struct scsi_cmnd * cmd)9346*4882a593Smuzhiyun static int qla4xxx_eh_target_reset(struct scsi_cmnd *cmd)
9347*4882a593Smuzhiyun {
9348*4882a593Smuzhiyun 	struct scsi_qla_host *ha = to_qla_host(cmd->device->host);
9349*4882a593Smuzhiyun 	struct ddb_entry *ddb_entry = cmd->device->hostdata;
9350*4882a593Smuzhiyun 	int stat, ret;
9351*4882a593Smuzhiyun 	int rval;
9352*4882a593Smuzhiyun 
9353*4882a593Smuzhiyun 	if (!ddb_entry)
9354*4882a593Smuzhiyun 		return FAILED;
9355*4882a593Smuzhiyun 
9356*4882a593Smuzhiyun 	ret = iscsi_block_scsi_eh(cmd);
9357*4882a593Smuzhiyun 	if (ret)
9358*4882a593Smuzhiyun 		return ret;
9359*4882a593Smuzhiyun 
9360*4882a593Smuzhiyun 	starget_printk(KERN_INFO, scsi_target(cmd->device),
9361*4882a593Smuzhiyun 		       "WARM TARGET RESET ISSUED.\n");
9362*4882a593Smuzhiyun 
9363*4882a593Smuzhiyun 	DEBUG2(printk(KERN_INFO
9364*4882a593Smuzhiyun 		      "scsi%ld: TARGET_DEVICE_RESET cmd=%p jiffies = 0x%lx, "
9365*4882a593Smuzhiyun 		      "to=%x,dpc_flags=%lx, status=%x allowed=%d\n",
9366*4882a593Smuzhiyun 		      ha->host_no, cmd, jiffies, cmd->request->timeout / HZ,
9367*4882a593Smuzhiyun 		      ha->dpc_flags, cmd->result, cmd->allowed));
9368*4882a593Smuzhiyun 
9369*4882a593Smuzhiyun 	rval = qla4xxx_isp_check_reg(ha);
9370*4882a593Smuzhiyun 	if (rval != QLA_SUCCESS) {
9371*4882a593Smuzhiyun 		ql4_printk(KERN_INFO, ha, "PCI/Register disconnect, exiting.\n");
9372*4882a593Smuzhiyun 		return FAILED;
9373*4882a593Smuzhiyun 	}
9374*4882a593Smuzhiyun 
9375*4882a593Smuzhiyun 	stat = qla4xxx_reset_target(ha, ddb_entry);
9376*4882a593Smuzhiyun 	if (stat != QLA_SUCCESS) {
9377*4882a593Smuzhiyun 		starget_printk(KERN_INFO, scsi_target(cmd->device),
9378*4882a593Smuzhiyun 			       "WARM TARGET RESET FAILED.\n");
9379*4882a593Smuzhiyun 		return FAILED;
9380*4882a593Smuzhiyun 	}
9381*4882a593Smuzhiyun 
9382*4882a593Smuzhiyun 	if (qla4xxx_eh_wait_for_commands(ha, scsi_target(cmd->device),
9383*4882a593Smuzhiyun 					 NULL)) {
9384*4882a593Smuzhiyun 		starget_printk(KERN_INFO, scsi_target(cmd->device),
9385*4882a593Smuzhiyun 			       "WARM TARGET DEVICE RESET FAILED - "
9386*4882a593Smuzhiyun 			       "waiting for commands.\n");
9387*4882a593Smuzhiyun 		return FAILED;
9388*4882a593Smuzhiyun 	}
9389*4882a593Smuzhiyun 
9390*4882a593Smuzhiyun 	/* Send marker. */
9391*4882a593Smuzhiyun 	if (qla4xxx_send_marker_iocb(ha, ddb_entry, cmd->device->lun,
9392*4882a593Smuzhiyun 		MM_TGT_WARM_RESET) != QLA_SUCCESS) {
9393*4882a593Smuzhiyun 		starget_printk(KERN_INFO, scsi_target(cmd->device),
9394*4882a593Smuzhiyun 			       "WARM TARGET DEVICE RESET FAILED - "
9395*4882a593Smuzhiyun 			       "marker iocb failed.\n");
9396*4882a593Smuzhiyun 		return FAILED;
9397*4882a593Smuzhiyun 	}
9398*4882a593Smuzhiyun 
9399*4882a593Smuzhiyun 	starget_printk(KERN_INFO, scsi_target(cmd->device),
9400*4882a593Smuzhiyun 		       "WARM TARGET RESET SUCCEEDED.\n");
9401*4882a593Smuzhiyun 	return SUCCESS;
9402*4882a593Smuzhiyun }
9403*4882a593Smuzhiyun 
9404*4882a593Smuzhiyun /**
9405*4882a593Smuzhiyun  * qla4xxx_is_eh_active - check if error handler is running
9406*4882a593Smuzhiyun  * @shost: Pointer to SCSI Host struct
9407*4882a593Smuzhiyun  *
9408*4882a593Smuzhiyun  * This routine finds that if reset host is called in EH
9409*4882a593Smuzhiyun  * scenario or from some application like sg_reset
9410*4882a593Smuzhiyun  **/
qla4xxx_is_eh_active(struct Scsi_Host * shost)9411*4882a593Smuzhiyun static int qla4xxx_is_eh_active(struct Scsi_Host *shost)
9412*4882a593Smuzhiyun {
9413*4882a593Smuzhiyun 	if (shost->shost_state == SHOST_RECOVERY)
9414*4882a593Smuzhiyun 		return 1;
9415*4882a593Smuzhiyun 	return 0;
9416*4882a593Smuzhiyun }
9417*4882a593Smuzhiyun 
9418*4882a593Smuzhiyun /**
9419*4882a593Smuzhiyun  * qla4xxx_eh_host_reset - kernel callback
9420*4882a593Smuzhiyun  * @cmd: Pointer to Linux's SCSI command structure
9421*4882a593Smuzhiyun  *
9422*4882a593Smuzhiyun  * This routine is invoked by the Linux kernel to perform fatal error
9423*4882a593Smuzhiyun  * recovery on the specified adapter.
9424*4882a593Smuzhiyun  **/
qla4xxx_eh_host_reset(struct scsi_cmnd * cmd)9425*4882a593Smuzhiyun static int qla4xxx_eh_host_reset(struct scsi_cmnd *cmd)
9426*4882a593Smuzhiyun {
9427*4882a593Smuzhiyun 	int return_status = FAILED;
9428*4882a593Smuzhiyun 	struct scsi_qla_host *ha;
9429*4882a593Smuzhiyun 	int rval;
9430*4882a593Smuzhiyun 
9431*4882a593Smuzhiyun 	ha = to_qla_host(cmd->device->host);
9432*4882a593Smuzhiyun 
9433*4882a593Smuzhiyun 	rval = qla4xxx_isp_check_reg(ha);
9434*4882a593Smuzhiyun 	if (rval != QLA_SUCCESS) {
9435*4882a593Smuzhiyun 		ql4_printk(KERN_INFO, ha, "PCI/Register disconnect, exiting.\n");
9436*4882a593Smuzhiyun 		return FAILED;
9437*4882a593Smuzhiyun 	}
9438*4882a593Smuzhiyun 
9439*4882a593Smuzhiyun 	if ((is_qla8032(ha) || is_qla8042(ha)) && ql4xdontresethba)
9440*4882a593Smuzhiyun 		qla4_83xx_set_idc_dontreset(ha);
9441*4882a593Smuzhiyun 
9442*4882a593Smuzhiyun 	/*
9443*4882a593Smuzhiyun 	 * For ISP8324 and ISP8042, if IDC_CTRL DONTRESET_BIT0 is set by other
9444*4882a593Smuzhiyun 	 * protocol drivers, we should not set device_state to NEED_RESET
9445*4882a593Smuzhiyun 	 */
9446*4882a593Smuzhiyun 	if (ql4xdontresethba ||
9447*4882a593Smuzhiyun 	    ((is_qla8032(ha) || is_qla8042(ha)) &&
9448*4882a593Smuzhiyun 	     qla4_83xx_idc_dontreset(ha))) {
9449*4882a593Smuzhiyun 		DEBUG2(printk("scsi%ld: %s: Don't Reset HBA\n",
9450*4882a593Smuzhiyun 		     ha->host_no, __func__));
9451*4882a593Smuzhiyun 
9452*4882a593Smuzhiyun 		/* Clear outstanding srb in queues */
9453*4882a593Smuzhiyun 		if (qla4xxx_is_eh_active(cmd->device->host))
9454*4882a593Smuzhiyun 			qla4xxx_abort_active_cmds(ha, DID_ABORT << 16);
9455*4882a593Smuzhiyun 
9456*4882a593Smuzhiyun 		return FAILED;
9457*4882a593Smuzhiyun 	}
9458*4882a593Smuzhiyun 
9459*4882a593Smuzhiyun 	ql4_printk(KERN_INFO, ha,
9460*4882a593Smuzhiyun 		   "scsi(%ld:%d:%d:%llu): HOST RESET ISSUED.\n", ha->host_no,
9461*4882a593Smuzhiyun 		   cmd->device->channel, cmd->device->id, cmd->device->lun);
9462*4882a593Smuzhiyun 
9463*4882a593Smuzhiyun 	if (qla4xxx_wait_for_hba_online(ha) != QLA_SUCCESS) {
9464*4882a593Smuzhiyun 		DEBUG2(printk("scsi%ld:%d: %s: Unable to reset host.  Adapter "
9465*4882a593Smuzhiyun 			      "DEAD.\n", ha->host_no, cmd->device->channel,
9466*4882a593Smuzhiyun 			      __func__));
9467*4882a593Smuzhiyun 
9468*4882a593Smuzhiyun 		return FAILED;
9469*4882a593Smuzhiyun 	}
9470*4882a593Smuzhiyun 
9471*4882a593Smuzhiyun 	if (!test_bit(DPC_RESET_HA, &ha->dpc_flags)) {
9472*4882a593Smuzhiyun 		if (is_qla80XX(ha))
9473*4882a593Smuzhiyun 			set_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags);
9474*4882a593Smuzhiyun 		else
9475*4882a593Smuzhiyun 			set_bit(DPC_RESET_HA, &ha->dpc_flags);
9476*4882a593Smuzhiyun 	}
9477*4882a593Smuzhiyun 
9478*4882a593Smuzhiyun 	if (qla4xxx_recover_adapter(ha) == QLA_SUCCESS)
9479*4882a593Smuzhiyun 		return_status = SUCCESS;
9480*4882a593Smuzhiyun 
9481*4882a593Smuzhiyun 	ql4_printk(KERN_INFO, ha, "HOST RESET %s.\n",
9482*4882a593Smuzhiyun 		   return_status == FAILED ? "FAILED" : "SUCCEEDED");
9483*4882a593Smuzhiyun 
9484*4882a593Smuzhiyun 	return return_status;
9485*4882a593Smuzhiyun }
9486*4882a593Smuzhiyun 
qla4xxx_context_reset(struct scsi_qla_host * ha)9487*4882a593Smuzhiyun static int qla4xxx_context_reset(struct scsi_qla_host *ha)
9488*4882a593Smuzhiyun {
9489*4882a593Smuzhiyun 	uint32_t mbox_cmd[MBOX_REG_COUNT];
9490*4882a593Smuzhiyun 	uint32_t mbox_sts[MBOX_REG_COUNT];
9491*4882a593Smuzhiyun 	struct addr_ctrl_blk_def *acb = NULL;
9492*4882a593Smuzhiyun 	uint32_t acb_len = sizeof(struct addr_ctrl_blk_def);
9493*4882a593Smuzhiyun 	int rval = QLA_SUCCESS;
9494*4882a593Smuzhiyun 	dma_addr_t acb_dma;
9495*4882a593Smuzhiyun 
9496*4882a593Smuzhiyun 	acb = dma_alloc_coherent(&ha->pdev->dev,
9497*4882a593Smuzhiyun 				 sizeof(struct addr_ctrl_blk_def),
9498*4882a593Smuzhiyun 				 &acb_dma, GFP_KERNEL);
9499*4882a593Smuzhiyun 	if (!acb) {
9500*4882a593Smuzhiyun 		ql4_printk(KERN_ERR, ha, "%s: Unable to alloc acb\n",
9501*4882a593Smuzhiyun 			   __func__);
9502*4882a593Smuzhiyun 		rval = -ENOMEM;
9503*4882a593Smuzhiyun 		goto exit_port_reset;
9504*4882a593Smuzhiyun 	}
9505*4882a593Smuzhiyun 
9506*4882a593Smuzhiyun 	memset(acb, 0, acb_len);
9507*4882a593Smuzhiyun 
9508*4882a593Smuzhiyun 	rval = qla4xxx_get_acb(ha, acb_dma, PRIMARI_ACB, acb_len);
9509*4882a593Smuzhiyun 	if (rval != QLA_SUCCESS) {
9510*4882a593Smuzhiyun 		rval = -EIO;
9511*4882a593Smuzhiyun 		goto exit_free_acb;
9512*4882a593Smuzhiyun 	}
9513*4882a593Smuzhiyun 
9514*4882a593Smuzhiyun 	rval = qla4xxx_disable_acb(ha);
9515*4882a593Smuzhiyun 	if (rval != QLA_SUCCESS) {
9516*4882a593Smuzhiyun 		rval = -EIO;
9517*4882a593Smuzhiyun 		goto exit_free_acb;
9518*4882a593Smuzhiyun 	}
9519*4882a593Smuzhiyun 
9520*4882a593Smuzhiyun 	wait_for_completion_timeout(&ha->disable_acb_comp,
9521*4882a593Smuzhiyun 				    DISABLE_ACB_TOV * HZ);
9522*4882a593Smuzhiyun 
9523*4882a593Smuzhiyun 	rval = qla4xxx_set_acb(ha, &mbox_cmd[0], &mbox_sts[0], acb_dma);
9524*4882a593Smuzhiyun 	if (rval != QLA_SUCCESS) {
9525*4882a593Smuzhiyun 		rval = -EIO;
9526*4882a593Smuzhiyun 		goto exit_free_acb;
9527*4882a593Smuzhiyun 	}
9528*4882a593Smuzhiyun 
9529*4882a593Smuzhiyun exit_free_acb:
9530*4882a593Smuzhiyun 	dma_free_coherent(&ha->pdev->dev, sizeof(struct addr_ctrl_blk_def),
9531*4882a593Smuzhiyun 			  acb, acb_dma);
9532*4882a593Smuzhiyun exit_port_reset:
9533*4882a593Smuzhiyun 	DEBUG2(ql4_printk(KERN_INFO, ha, "%s %s\n", __func__,
9534*4882a593Smuzhiyun 			  rval == QLA_SUCCESS ? "SUCCEEDED" : "FAILED"));
9535*4882a593Smuzhiyun 	return rval;
9536*4882a593Smuzhiyun }
9537*4882a593Smuzhiyun 
qla4xxx_host_reset(struct Scsi_Host * shost,int reset_type)9538*4882a593Smuzhiyun static int qla4xxx_host_reset(struct Scsi_Host *shost, int reset_type)
9539*4882a593Smuzhiyun {
9540*4882a593Smuzhiyun 	struct scsi_qla_host *ha = to_qla_host(shost);
9541*4882a593Smuzhiyun 	int rval = QLA_SUCCESS;
9542*4882a593Smuzhiyun 	uint32_t idc_ctrl;
9543*4882a593Smuzhiyun 
9544*4882a593Smuzhiyun 	if (ql4xdontresethba) {
9545*4882a593Smuzhiyun 		DEBUG2(ql4_printk(KERN_INFO, ha, "%s: Don't Reset HBA\n",
9546*4882a593Smuzhiyun 				  __func__));
9547*4882a593Smuzhiyun 		rval = -EPERM;
9548*4882a593Smuzhiyun 		goto exit_host_reset;
9549*4882a593Smuzhiyun 	}
9550*4882a593Smuzhiyun 
9551*4882a593Smuzhiyun 	if (test_bit(DPC_RESET_HA, &ha->dpc_flags))
9552*4882a593Smuzhiyun 		goto recover_adapter;
9553*4882a593Smuzhiyun 
9554*4882a593Smuzhiyun 	switch (reset_type) {
9555*4882a593Smuzhiyun 	case SCSI_ADAPTER_RESET:
9556*4882a593Smuzhiyun 		set_bit(DPC_RESET_HA, &ha->dpc_flags);
9557*4882a593Smuzhiyun 		break;
9558*4882a593Smuzhiyun 	case SCSI_FIRMWARE_RESET:
9559*4882a593Smuzhiyun 		if (!test_bit(DPC_RESET_HA, &ha->dpc_flags)) {
9560*4882a593Smuzhiyun 			if (is_qla80XX(ha))
9561*4882a593Smuzhiyun 				/* set firmware context reset */
9562*4882a593Smuzhiyun 				set_bit(DPC_RESET_HA_FW_CONTEXT,
9563*4882a593Smuzhiyun 					&ha->dpc_flags);
9564*4882a593Smuzhiyun 			else {
9565*4882a593Smuzhiyun 				rval = qla4xxx_context_reset(ha);
9566*4882a593Smuzhiyun 				goto exit_host_reset;
9567*4882a593Smuzhiyun 			}
9568*4882a593Smuzhiyun 		}
9569*4882a593Smuzhiyun 		break;
9570*4882a593Smuzhiyun 	}
9571*4882a593Smuzhiyun 
9572*4882a593Smuzhiyun recover_adapter:
9573*4882a593Smuzhiyun 	/* For ISP8324 and ISP8042 set graceful reset bit in IDC_DRV_CTRL if
9574*4882a593Smuzhiyun 	 * reset is issued by application */
9575*4882a593Smuzhiyun 	if ((is_qla8032(ha) || is_qla8042(ha)) &&
9576*4882a593Smuzhiyun 	    test_bit(DPC_RESET_HA, &ha->dpc_flags)) {
9577*4882a593Smuzhiyun 		idc_ctrl = qla4_83xx_rd_reg(ha, QLA83XX_IDC_DRV_CTRL);
9578*4882a593Smuzhiyun 		qla4_83xx_wr_reg(ha, QLA83XX_IDC_DRV_CTRL,
9579*4882a593Smuzhiyun 				 (idc_ctrl | GRACEFUL_RESET_BIT1));
9580*4882a593Smuzhiyun 	}
9581*4882a593Smuzhiyun 
9582*4882a593Smuzhiyun 	rval = qla4xxx_recover_adapter(ha);
9583*4882a593Smuzhiyun 	if (rval != QLA_SUCCESS) {
9584*4882a593Smuzhiyun 		DEBUG2(ql4_printk(KERN_INFO, ha, "%s: recover adapter fail\n",
9585*4882a593Smuzhiyun 				  __func__));
9586*4882a593Smuzhiyun 		rval = -EIO;
9587*4882a593Smuzhiyun 	}
9588*4882a593Smuzhiyun 
9589*4882a593Smuzhiyun exit_host_reset:
9590*4882a593Smuzhiyun 	return rval;
9591*4882a593Smuzhiyun }
9592*4882a593Smuzhiyun 
9593*4882a593Smuzhiyun /* PCI AER driver recovers from all correctable errors w/o
9594*4882a593Smuzhiyun  * driver intervention. For uncorrectable errors PCI AER
9595*4882a593Smuzhiyun  * driver calls the following device driver's callbacks
9596*4882a593Smuzhiyun  *
9597*4882a593Smuzhiyun  * - Fatal Errors - link_reset
9598*4882a593Smuzhiyun  * - Non-Fatal Errors - driver's error_detected() which
9599*4882a593Smuzhiyun  * returns CAN_RECOVER, NEED_RESET or DISCONNECT.
9600*4882a593Smuzhiyun  *
9601*4882a593Smuzhiyun  * PCI AER driver calls
9602*4882a593Smuzhiyun  * CAN_RECOVER - driver's mmio_enabled(), mmio_enabled()
9603*4882a593Smuzhiyun  *               returns RECOVERED or NEED_RESET if fw_hung
9604*4882a593Smuzhiyun  * NEED_RESET - driver's slot_reset()
9605*4882a593Smuzhiyun  * DISCONNECT - device is dead & cannot recover
9606*4882a593Smuzhiyun  * RECOVERED - driver's resume()
9607*4882a593Smuzhiyun  */
9608*4882a593Smuzhiyun static pci_ers_result_t
qla4xxx_pci_error_detected(struct pci_dev * pdev,pci_channel_state_t state)9609*4882a593Smuzhiyun qla4xxx_pci_error_detected(struct pci_dev *pdev, pci_channel_state_t state)
9610*4882a593Smuzhiyun {
9611*4882a593Smuzhiyun 	struct scsi_qla_host *ha = pci_get_drvdata(pdev);
9612*4882a593Smuzhiyun 
9613*4882a593Smuzhiyun 	ql4_printk(KERN_WARNING, ha, "scsi%ld: %s: error detected:state %x\n",
9614*4882a593Smuzhiyun 	    ha->host_no, __func__, state);
9615*4882a593Smuzhiyun 
9616*4882a593Smuzhiyun 	if (!is_aer_supported(ha))
9617*4882a593Smuzhiyun 		return PCI_ERS_RESULT_NONE;
9618*4882a593Smuzhiyun 
9619*4882a593Smuzhiyun 	switch (state) {
9620*4882a593Smuzhiyun 	case pci_channel_io_normal:
9621*4882a593Smuzhiyun 		clear_bit(AF_EEH_BUSY, &ha->flags);
9622*4882a593Smuzhiyun 		return PCI_ERS_RESULT_CAN_RECOVER;
9623*4882a593Smuzhiyun 	case pci_channel_io_frozen:
9624*4882a593Smuzhiyun 		set_bit(AF_EEH_BUSY, &ha->flags);
9625*4882a593Smuzhiyun 		qla4xxx_mailbox_premature_completion(ha);
9626*4882a593Smuzhiyun 		qla4xxx_free_irqs(ha);
9627*4882a593Smuzhiyun 		pci_disable_device(pdev);
9628*4882a593Smuzhiyun 		/* Return back all IOs */
9629*4882a593Smuzhiyun 		qla4xxx_abort_active_cmds(ha, DID_RESET << 16);
9630*4882a593Smuzhiyun 		return PCI_ERS_RESULT_NEED_RESET;
9631*4882a593Smuzhiyun 	case pci_channel_io_perm_failure:
9632*4882a593Smuzhiyun 		set_bit(AF_EEH_BUSY, &ha->flags);
9633*4882a593Smuzhiyun 		set_bit(AF_PCI_CHANNEL_IO_PERM_FAILURE, &ha->flags);
9634*4882a593Smuzhiyun 		qla4xxx_abort_active_cmds(ha, DID_NO_CONNECT << 16);
9635*4882a593Smuzhiyun 		return PCI_ERS_RESULT_DISCONNECT;
9636*4882a593Smuzhiyun 	}
9637*4882a593Smuzhiyun 	return PCI_ERS_RESULT_NEED_RESET;
9638*4882a593Smuzhiyun }
9639*4882a593Smuzhiyun 
9640*4882a593Smuzhiyun /**
9641*4882a593Smuzhiyun  * qla4xxx_pci_mmio_enabled() gets called if
9642*4882a593Smuzhiyun  * qla4xxx_pci_error_detected() returns PCI_ERS_RESULT_CAN_RECOVER
9643*4882a593Smuzhiyun  * and read/write to the device still works.
9644*4882a593Smuzhiyun  * @pdev: PCI device pointer
9645*4882a593Smuzhiyun  **/
9646*4882a593Smuzhiyun static pci_ers_result_t
qla4xxx_pci_mmio_enabled(struct pci_dev * pdev)9647*4882a593Smuzhiyun qla4xxx_pci_mmio_enabled(struct pci_dev *pdev)
9648*4882a593Smuzhiyun {
9649*4882a593Smuzhiyun 	struct scsi_qla_host *ha = pci_get_drvdata(pdev);
9650*4882a593Smuzhiyun 
9651*4882a593Smuzhiyun 	if (!is_aer_supported(ha))
9652*4882a593Smuzhiyun 		return PCI_ERS_RESULT_NONE;
9653*4882a593Smuzhiyun 
9654*4882a593Smuzhiyun 	return PCI_ERS_RESULT_RECOVERED;
9655*4882a593Smuzhiyun }
9656*4882a593Smuzhiyun 
qla4_8xxx_error_recovery(struct scsi_qla_host * ha)9657*4882a593Smuzhiyun static uint32_t qla4_8xxx_error_recovery(struct scsi_qla_host *ha)
9658*4882a593Smuzhiyun {
9659*4882a593Smuzhiyun 	uint32_t rval = QLA_ERROR;
9660*4882a593Smuzhiyun 	int fn;
9661*4882a593Smuzhiyun 	struct pci_dev *other_pdev = NULL;
9662*4882a593Smuzhiyun 
9663*4882a593Smuzhiyun 	ql4_printk(KERN_WARNING, ha, "scsi%ld: In %s\n", ha->host_no, __func__);
9664*4882a593Smuzhiyun 
9665*4882a593Smuzhiyun 	set_bit(DPC_RESET_ACTIVE, &ha->dpc_flags);
9666*4882a593Smuzhiyun 
9667*4882a593Smuzhiyun 	if (test_bit(AF_ONLINE, &ha->flags)) {
9668*4882a593Smuzhiyun 		clear_bit(AF_ONLINE, &ha->flags);
9669*4882a593Smuzhiyun 		clear_bit(AF_LINK_UP, &ha->flags);
9670*4882a593Smuzhiyun 		iscsi_host_for_each_session(ha->host, qla4xxx_fail_session);
9671*4882a593Smuzhiyun 		qla4xxx_process_aen(ha, FLUSH_DDB_CHANGED_AENS);
9672*4882a593Smuzhiyun 	}
9673*4882a593Smuzhiyun 
9674*4882a593Smuzhiyun 	fn = PCI_FUNC(ha->pdev->devfn);
9675*4882a593Smuzhiyun 	if (is_qla8022(ha)) {
9676*4882a593Smuzhiyun 		while (fn > 0) {
9677*4882a593Smuzhiyun 			fn--;
9678*4882a593Smuzhiyun 			ql4_printk(KERN_INFO, ha, "scsi%ld: %s: Finding PCI device at func %x\n",
9679*4882a593Smuzhiyun 				   ha->host_no, __func__, fn);
9680*4882a593Smuzhiyun 			/* Get the pci device given the domain, bus,
9681*4882a593Smuzhiyun 			 * slot/function number */
9682*4882a593Smuzhiyun 			other_pdev = pci_get_domain_bus_and_slot(
9683*4882a593Smuzhiyun 					   pci_domain_nr(ha->pdev->bus),
9684*4882a593Smuzhiyun 					   ha->pdev->bus->number,
9685*4882a593Smuzhiyun 					   PCI_DEVFN(PCI_SLOT(ha->pdev->devfn),
9686*4882a593Smuzhiyun 					   fn));
9687*4882a593Smuzhiyun 
9688*4882a593Smuzhiyun 			if (!other_pdev)
9689*4882a593Smuzhiyun 				continue;
9690*4882a593Smuzhiyun 
9691*4882a593Smuzhiyun 			if (atomic_read(&other_pdev->enable_cnt)) {
9692*4882a593Smuzhiyun 				ql4_printk(KERN_INFO, ha, "scsi%ld: %s: Found PCI func in enabled state%x\n",
9693*4882a593Smuzhiyun 					   ha->host_no, __func__, fn);
9694*4882a593Smuzhiyun 				pci_dev_put(other_pdev);
9695*4882a593Smuzhiyun 				break;
9696*4882a593Smuzhiyun 			}
9697*4882a593Smuzhiyun 			pci_dev_put(other_pdev);
9698*4882a593Smuzhiyun 		}
9699*4882a593Smuzhiyun 	} else {
9700*4882a593Smuzhiyun 		/* this case is meant for ISP83xx/ISP84xx only */
9701*4882a593Smuzhiyun 		if (qla4_83xx_can_perform_reset(ha)) {
9702*4882a593Smuzhiyun 			/* reset fn as iSCSI is going to perform the reset */
9703*4882a593Smuzhiyun 			fn = 0;
9704*4882a593Smuzhiyun 		}
9705*4882a593Smuzhiyun 	}
9706*4882a593Smuzhiyun 
9707*4882a593Smuzhiyun 	/* The first function on the card, the reset owner will
9708*4882a593Smuzhiyun 	 * start & initialize the firmware. The other functions
9709*4882a593Smuzhiyun 	 * on the card will reset the firmware context
9710*4882a593Smuzhiyun 	 */
9711*4882a593Smuzhiyun 	if (!fn) {
9712*4882a593Smuzhiyun 		ql4_printk(KERN_INFO, ha, "scsi%ld: %s: devfn being reset "
9713*4882a593Smuzhiyun 		    "0x%x is the owner\n", ha->host_no, __func__,
9714*4882a593Smuzhiyun 		    ha->pdev->devfn);
9715*4882a593Smuzhiyun 
9716*4882a593Smuzhiyun 		ha->isp_ops->idc_lock(ha);
9717*4882a593Smuzhiyun 		qla4_8xxx_wr_direct(ha, QLA8XXX_CRB_DEV_STATE,
9718*4882a593Smuzhiyun 				    QLA8XXX_DEV_COLD);
9719*4882a593Smuzhiyun 		ha->isp_ops->idc_unlock(ha);
9720*4882a593Smuzhiyun 
9721*4882a593Smuzhiyun 		rval = qla4_8xxx_update_idc_reg(ha);
9722*4882a593Smuzhiyun 		if (rval == QLA_ERROR) {
9723*4882a593Smuzhiyun 			ql4_printk(KERN_INFO, ha, "scsi%ld: %s: HW State: FAILED\n",
9724*4882a593Smuzhiyun 				   ha->host_no, __func__);
9725*4882a593Smuzhiyun 			ha->isp_ops->idc_lock(ha);
9726*4882a593Smuzhiyun 			qla4_8xxx_wr_direct(ha, QLA8XXX_CRB_DEV_STATE,
9727*4882a593Smuzhiyun 					    QLA8XXX_DEV_FAILED);
9728*4882a593Smuzhiyun 			ha->isp_ops->idc_unlock(ha);
9729*4882a593Smuzhiyun 			goto exit_error_recovery;
9730*4882a593Smuzhiyun 		}
9731*4882a593Smuzhiyun 
9732*4882a593Smuzhiyun 		clear_bit(AF_FW_RECOVERY, &ha->flags);
9733*4882a593Smuzhiyun 		rval = qla4xxx_initialize_adapter(ha, RESET_ADAPTER);
9734*4882a593Smuzhiyun 
9735*4882a593Smuzhiyun 		if (rval != QLA_SUCCESS) {
9736*4882a593Smuzhiyun 			ql4_printk(KERN_INFO, ha, "scsi%ld: %s: HW State: "
9737*4882a593Smuzhiyun 			    "FAILED\n", ha->host_no, __func__);
9738*4882a593Smuzhiyun 			qla4xxx_free_irqs(ha);
9739*4882a593Smuzhiyun 			ha->isp_ops->idc_lock(ha);
9740*4882a593Smuzhiyun 			qla4_8xxx_clear_drv_active(ha);
9741*4882a593Smuzhiyun 			qla4_8xxx_wr_direct(ha, QLA8XXX_CRB_DEV_STATE,
9742*4882a593Smuzhiyun 					    QLA8XXX_DEV_FAILED);
9743*4882a593Smuzhiyun 			ha->isp_ops->idc_unlock(ha);
9744*4882a593Smuzhiyun 		} else {
9745*4882a593Smuzhiyun 			ql4_printk(KERN_INFO, ha, "scsi%ld: %s: HW State: "
9746*4882a593Smuzhiyun 			    "READY\n", ha->host_no, __func__);
9747*4882a593Smuzhiyun 			ha->isp_ops->idc_lock(ha);
9748*4882a593Smuzhiyun 			qla4_8xxx_wr_direct(ha, QLA8XXX_CRB_DEV_STATE,
9749*4882a593Smuzhiyun 					    QLA8XXX_DEV_READY);
9750*4882a593Smuzhiyun 			/* Clear driver state register */
9751*4882a593Smuzhiyun 			qla4_8xxx_wr_direct(ha, QLA8XXX_CRB_DRV_STATE, 0);
9752*4882a593Smuzhiyun 			qla4_8xxx_set_drv_active(ha);
9753*4882a593Smuzhiyun 			ha->isp_ops->idc_unlock(ha);
9754*4882a593Smuzhiyun 			ha->isp_ops->enable_intrs(ha);
9755*4882a593Smuzhiyun 		}
9756*4882a593Smuzhiyun 	} else {
9757*4882a593Smuzhiyun 		ql4_printk(KERN_INFO, ha, "scsi%ld: %s: devfn 0x%x is not "
9758*4882a593Smuzhiyun 		    "the reset owner\n", ha->host_no, __func__,
9759*4882a593Smuzhiyun 		    ha->pdev->devfn);
9760*4882a593Smuzhiyun 		if ((qla4_8xxx_rd_direct(ha, QLA8XXX_CRB_DEV_STATE) ==
9761*4882a593Smuzhiyun 		     QLA8XXX_DEV_READY)) {
9762*4882a593Smuzhiyun 			clear_bit(AF_FW_RECOVERY, &ha->flags);
9763*4882a593Smuzhiyun 			rval = qla4xxx_initialize_adapter(ha, RESET_ADAPTER);
9764*4882a593Smuzhiyun 			if (rval == QLA_SUCCESS)
9765*4882a593Smuzhiyun 				ha->isp_ops->enable_intrs(ha);
9766*4882a593Smuzhiyun 			else
9767*4882a593Smuzhiyun 				qla4xxx_free_irqs(ha);
9768*4882a593Smuzhiyun 
9769*4882a593Smuzhiyun 			ha->isp_ops->idc_lock(ha);
9770*4882a593Smuzhiyun 			qla4_8xxx_set_drv_active(ha);
9771*4882a593Smuzhiyun 			ha->isp_ops->idc_unlock(ha);
9772*4882a593Smuzhiyun 		}
9773*4882a593Smuzhiyun 	}
9774*4882a593Smuzhiyun exit_error_recovery:
9775*4882a593Smuzhiyun 	clear_bit(DPC_RESET_ACTIVE, &ha->dpc_flags);
9776*4882a593Smuzhiyun 	return rval;
9777*4882a593Smuzhiyun }
9778*4882a593Smuzhiyun 
9779*4882a593Smuzhiyun static pci_ers_result_t
qla4xxx_pci_slot_reset(struct pci_dev * pdev)9780*4882a593Smuzhiyun qla4xxx_pci_slot_reset(struct pci_dev *pdev)
9781*4882a593Smuzhiyun {
9782*4882a593Smuzhiyun 	pci_ers_result_t ret = PCI_ERS_RESULT_DISCONNECT;
9783*4882a593Smuzhiyun 	struct scsi_qla_host *ha = pci_get_drvdata(pdev);
9784*4882a593Smuzhiyun 	int rc;
9785*4882a593Smuzhiyun 
9786*4882a593Smuzhiyun 	ql4_printk(KERN_WARNING, ha, "scsi%ld: %s: slot_reset\n",
9787*4882a593Smuzhiyun 	    ha->host_no, __func__);
9788*4882a593Smuzhiyun 
9789*4882a593Smuzhiyun 	if (!is_aer_supported(ha))
9790*4882a593Smuzhiyun 		return PCI_ERS_RESULT_NONE;
9791*4882a593Smuzhiyun 
9792*4882a593Smuzhiyun 	/* Restore the saved state of PCIe device -
9793*4882a593Smuzhiyun 	 * BAR registers, PCI Config space, PCIX, MSI,
9794*4882a593Smuzhiyun 	 * IOV states
9795*4882a593Smuzhiyun 	 */
9796*4882a593Smuzhiyun 	pci_restore_state(pdev);
9797*4882a593Smuzhiyun 
9798*4882a593Smuzhiyun 	/* pci_restore_state() clears the saved_state flag of the device
9799*4882a593Smuzhiyun 	 * save restored state which resets saved_state flag
9800*4882a593Smuzhiyun 	 */
9801*4882a593Smuzhiyun 	pci_save_state(pdev);
9802*4882a593Smuzhiyun 
9803*4882a593Smuzhiyun 	/* Initialize device or resume if in suspended state */
9804*4882a593Smuzhiyun 	rc = pci_enable_device(pdev);
9805*4882a593Smuzhiyun 	if (rc) {
9806*4882a593Smuzhiyun 		ql4_printk(KERN_WARNING, ha, "scsi%ld: %s: Can't re-enable "
9807*4882a593Smuzhiyun 		    "device after reset\n", ha->host_no, __func__);
9808*4882a593Smuzhiyun 		goto exit_slot_reset;
9809*4882a593Smuzhiyun 	}
9810*4882a593Smuzhiyun 
9811*4882a593Smuzhiyun 	ha->isp_ops->disable_intrs(ha);
9812*4882a593Smuzhiyun 
9813*4882a593Smuzhiyun 	if (is_qla80XX(ha)) {
9814*4882a593Smuzhiyun 		if (qla4_8xxx_error_recovery(ha) == QLA_SUCCESS) {
9815*4882a593Smuzhiyun 			ret = PCI_ERS_RESULT_RECOVERED;
9816*4882a593Smuzhiyun 			goto exit_slot_reset;
9817*4882a593Smuzhiyun 		} else
9818*4882a593Smuzhiyun 			goto exit_slot_reset;
9819*4882a593Smuzhiyun 	}
9820*4882a593Smuzhiyun 
9821*4882a593Smuzhiyun exit_slot_reset:
9822*4882a593Smuzhiyun 	ql4_printk(KERN_WARNING, ha, "scsi%ld: %s: Return=%x\n"
9823*4882a593Smuzhiyun 	    "device after reset\n", ha->host_no, __func__, ret);
9824*4882a593Smuzhiyun 	return ret;
9825*4882a593Smuzhiyun }
9826*4882a593Smuzhiyun 
9827*4882a593Smuzhiyun static void
qla4xxx_pci_resume(struct pci_dev * pdev)9828*4882a593Smuzhiyun qla4xxx_pci_resume(struct pci_dev *pdev)
9829*4882a593Smuzhiyun {
9830*4882a593Smuzhiyun 	struct scsi_qla_host *ha = pci_get_drvdata(pdev);
9831*4882a593Smuzhiyun 	int ret;
9832*4882a593Smuzhiyun 
9833*4882a593Smuzhiyun 	ql4_printk(KERN_WARNING, ha, "scsi%ld: %s: pci_resume\n",
9834*4882a593Smuzhiyun 	    ha->host_no, __func__);
9835*4882a593Smuzhiyun 
9836*4882a593Smuzhiyun 	ret = qla4xxx_wait_for_hba_online(ha);
9837*4882a593Smuzhiyun 	if (ret != QLA_SUCCESS) {
9838*4882a593Smuzhiyun 		ql4_printk(KERN_ERR, ha, "scsi%ld: %s: the device failed to "
9839*4882a593Smuzhiyun 		    "resume I/O from slot/link_reset\n", ha->host_no,
9840*4882a593Smuzhiyun 		     __func__);
9841*4882a593Smuzhiyun 	}
9842*4882a593Smuzhiyun 
9843*4882a593Smuzhiyun 	clear_bit(AF_EEH_BUSY, &ha->flags);
9844*4882a593Smuzhiyun }
9845*4882a593Smuzhiyun 
9846*4882a593Smuzhiyun static const struct pci_error_handlers qla4xxx_err_handler = {
9847*4882a593Smuzhiyun 	.error_detected = qla4xxx_pci_error_detected,
9848*4882a593Smuzhiyun 	.mmio_enabled = qla4xxx_pci_mmio_enabled,
9849*4882a593Smuzhiyun 	.slot_reset = qla4xxx_pci_slot_reset,
9850*4882a593Smuzhiyun 	.resume = qla4xxx_pci_resume,
9851*4882a593Smuzhiyun };
9852*4882a593Smuzhiyun 
9853*4882a593Smuzhiyun static struct pci_device_id qla4xxx_pci_tbl[] = {
9854*4882a593Smuzhiyun 	{
9855*4882a593Smuzhiyun 		.vendor		= PCI_VENDOR_ID_QLOGIC,
9856*4882a593Smuzhiyun 		.device		= PCI_DEVICE_ID_QLOGIC_ISP4010,
9857*4882a593Smuzhiyun 		.subvendor	= PCI_ANY_ID,
9858*4882a593Smuzhiyun 		.subdevice	= PCI_ANY_ID,
9859*4882a593Smuzhiyun 	},
9860*4882a593Smuzhiyun 	{
9861*4882a593Smuzhiyun 		.vendor		= PCI_VENDOR_ID_QLOGIC,
9862*4882a593Smuzhiyun 		.device		= PCI_DEVICE_ID_QLOGIC_ISP4022,
9863*4882a593Smuzhiyun 		.subvendor	= PCI_ANY_ID,
9864*4882a593Smuzhiyun 		.subdevice	= PCI_ANY_ID,
9865*4882a593Smuzhiyun 	},
9866*4882a593Smuzhiyun 	{
9867*4882a593Smuzhiyun 		.vendor		= PCI_VENDOR_ID_QLOGIC,
9868*4882a593Smuzhiyun 		.device		= PCI_DEVICE_ID_QLOGIC_ISP4032,
9869*4882a593Smuzhiyun 		.subvendor	= PCI_ANY_ID,
9870*4882a593Smuzhiyun 		.subdevice	= PCI_ANY_ID,
9871*4882a593Smuzhiyun 	},
9872*4882a593Smuzhiyun 	{
9873*4882a593Smuzhiyun 		.vendor         = PCI_VENDOR_ID_QLOGIC,
9874*4882a593Smuzhiyun 		.device         = PCI_DEVICE_ID_QLOGIC_ISP8022,
9875*4882a593Smuzhiyun 		.subvendor      = PCI_ANY_ID,
9876*4882a593Smuzhiyun 		.subdevice      = PCI_ANY_ID,
9877*4882a593Smuzhiyun 	},
9878*4882a593Smuzhiyun 	{
9879*4882a593Smuzhiyun 		.vendor		= PCI_VENDOR_ID_QLOGIC,
9880*4882a593Smuzhiyun 		.device		= PCI_DEVICE_ID_QLOGIC_ISP8324,
9881*4882a593Smuzhiyun 		.subvendor	= PCI_ANY_ID,
9882*4882a593Smuzhiyun 		.subdevice	= PCI_ANY_ID,
9883*4882a593Smuzhiyun 	},
9884*4882a593Smuzhiyun 	{
9885*4882a593Smuzhiyun 		.vendor		= PCI_VENDOR_ID_QLOGIC,
9886*4882a593Smuzhiyun 		.device		= PCI_DEVICE_ID_QLOGIC_ISP8042,
9887*4882a593Smuzhiyun 		.subvendor	= PCI_ANY_ID,
9888*4882a593Smuzhiyun 		.subdevice	= PCI_ANY_ID,
9889*4882a593Smuzhiyun 	},
9890*4882a593Smuzhiyun 	{0, 0},
9891*4882a593Smuzhiyun };
9892*4882a593Smuzhiyun MODULE_DEVICE_TABLE(pci, qla4xxx_pci_tbl);
9893*4882a593Smuzhiyun 
9894*4882a593Smuzhiyun static struct pci_driver qla4xxx_pci_driver = {
9895*4882a593Smuzhiyun 	.name		= DRIVER_NAME,
9896*4882a593Smuzhiyun 	.id_table	= qla4xxx_pci_tbl,
9897*4882a593Smuzhiyun 	.probe		= qla4xxx_probe_adapter,
9898*4882a593Smuzhiyun 	.remove		= qla4xxx_remove_adapter,
9899*4882a593Smuzhiyun 	.err_handler = &qla4xxx_err_handler,
9900*4882a593Smuzhiyun };
9901*4882a593Smuzhiyun 
qla4xxx_module_init(void)9902*4882a593Smuzhiyun static int __init qla4xxx_module_init(void)
9903*4882a593Smuzhiyun {
9904*4882a593Smuzhiyun 	int ret;
9905*4882a593Smuzhiyun 
9906*4882a593Smuzhiyun 	if (ql4xqfulltracking)
9907*4882a593Smuzhiyun 		qla4xxx_driver_template.track_queue_depth = 1;
9908*4882a593Smuzhiyun 
9909*4882a593Smuzhiyun 	/* Allocate cache for SRBs. */
9910*4882a593Smuzhiyun 	srb_cachep = kmem_cache_create("qla4xxx_srbs", sizeof(struct srb), 0,
9911*4882a593Smuzhiyun 				       SLAB_HWCACHE_ALIGN, NULL);
9912*4882a593Smuzhiyun 	if (srb_cachep == NULL) {
9913*4882a593Smuzhiyun 		printk(KERN_ERR
9914*4882a593Smuzhiyun 		       "%s: Unable to allocate SRB cache..."
9915*4882a593Smuzhiyun 		       "Failing load!\n", DRIVER_NAME);
9916*4882a593Smuzhiyun 		ret = -ENOMEM;
9917*4882a593Smuzhiyun 		goto no_srp_cache;
9918*4882a593Smuzhiyun 	}
9919*4882a593Smuzhiyun 
9920*4882a593Smuzhiyun 	/* Derive version string. */
9921*4882a593Smuzhiyun 	strcpy(qla4xxx_version_str, QLA4XXX_DRIVER_VERSION);
9922*4882a593Smuzhiyun 	if (ql4xextended_error_logging)
9923*4882a593Smuzhiyun 		strcat(qla4xxx_version_str, "-debug");
9924*4882a593Smuzhiyun 
9925*4882a593Smuzhiyun 	qla4xxx_scsi_transport =
9926*4882a593Smuzhiyun 		iscsi_register_transport(&qla4xxx_iscsi_transport);
9927*4882a593Smuzhiyun 	if (!qla4xxx_scsi_transport){
9928*4882a593Smuzhiyun 		ret = -ENODEV;
9929*4882a593Smuzhiyun 		goto release_srb_cache;
9930*4882a593Smuzhiyun 	}
9931*4882a593Smuzhiyun 
9932*4882a593Smuzhiyun 	ret = pci_register_driver(&qla4xxx_pci_driver);
9933*4882a593Smuzhiyun 	if (ret)
9934*4882a593Smuzhiyun 		goto unregister_transport;
9935*4882a593Smuzhiyun 
9936*4882a593Smuzhiyun 	printk(KERN_INFO "QLogic iSCSI HBA Driver\n");
9937*4882a593Smuzhiyun 	return 0;
9938*4882a593Smuzhiyun 
9939*4882a593Smuzhiyun unregister_transport:
9940*4882a593Smuzhiyun 	iscsi_unregister_transport(&qla4xxx_iscsi_transport);
9941*4882a593Smuzhiyun release_srb_cache:
9942*4882a593Smuzhiyun 	kmem_cache_destroy(srb_cachep);
9943*4882a593Smuzhiyun no_srp_cache:
9944*4882a593Smuzhiyun 	return ret;
9945*4882a593Smuzhiyun }
9946*4882a593Smuzhiyun 
qla4xxx_module_exit(void)9947*4882a593Smuzhiyun static void __exit qla4xxx_module_exit(void)
9948*4882a593Smuzhiyun {
9949*4882a593Smuzhiyun 	pci_unregister_driver(&qla4xxx_pci_driver);
9950*4882a593Smuzhiyun 	iscsi_unregister_transport(&qla4xxx_iscsi_transport);
9951*4882a593Smuzhiyun 	kmem_cache_destroy(srb_cachep);
9952*4882a593Smuzhiyun }
9953*4882a593Smuzhiyun 
9954*4882a593Smuzhiyun module_init(qla4xxx_module_init);
9955*4882a593Smuzhiyun module_exit(qla4xxx_module_exit);
9956*4882a593Smuzhiyun 
9957*4882a593Smuzhiyun MODULE_AUTHOR("QLogic Corporation");
9958*4882a593Smuzhiyun MODULE_DESCRIPTION("QLogic iSCSI HBA Driver");
9959*4882a593Smuzhiyun MODULE_LICENSE("GPL");
9960*4882a593Smuzhiyun MODULE_VERSION(QLA4XXX_DRIVER_VERSION);
9961