blob: fa1a3594edd5fa0f054535ce909345bed0125e25 [file] [log] [blame]
David Somayajuluafaf5a22006-09-19 10:28:00 -07001/*
2 * QLogic iSCSI HBA Driver
Vikas Chaudhary7d01d062010-12-02 22:12:51 -08003 * Copyright (c) 2003-2010 QLogic Corporation
David Somayajuluafaf5a22006-09-19 10:28:00 -07004 *
5 * See LICENSE.qla4xxx for copyright and licensing details.
6 */
7#include <linux/moduleparam.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +09008#include <linux/slab.h>
Manish Rangankar2a991c22011-07-25 13:48:55 -05009#include <linux/blkdev.h>
10#include <linux/iscsi_boot_sysfs.h>
Mike Christie13483732011-12-01 21:38:41 -060011#include <linux/inet.h>
David Somayajuluafaf5a22006-09-19 10:28:00 -070012
13#include <scsi/scsi_tcq.h>
14#include <scsi/scsicam.h>
15
16#include "ql4_def.h"
David C Somayajulubee4fe82007-05-23 18:03:32 -070017#include "ql4_version.h"
18#include "ql4_glbl.h"
19#include "ql4_dbg.h"
20#include "ql4_inline.h"
David Somayajuluafaf5a22006-09-19 10:28:00 -070021
22/*
23 * Driver version
24 */
Adrian Bunk47975472007-04-26 00:35:16 -070025static char qla4xxx_version_str[40];
David Somayajuluafaf5a22006-09-19 10:28:00 -070026
27/*
28 * SRB allocation cache
29 */
Christoph Lametere18b8902006-12-06 20:33:20 -080030static struct kmem_cache *srb_cachep;
David Somayajuluafaf5a22006-09-19 10:28:00 -070031
32/*
33 * Module parameter information and variables
34 */
Vikas Chaudharya7380a62012-02-27 03:08:56 -080035static int ql4xdisablesysfsboot = 1;
Mike Christie13483732011-12-01 21:38:41 -060036module_param(ql4xdisablesysfsboot, int, S_IRUGO | S_IWUSR);
37MODULE_PARM_DESC(ql4xdisablesysfsboot,
Karen Higginsa4e8a712012-01-11 02:44:20 -080038 " Set to disable exporting boot targets to sysfs.\n"
39 "\t\t 0 - Export boot targets\n"
40 "\t\t 1 - Do not export boot targets (Default)");
Mike Christie13483732011-12-01 21:38:41 -060041
Vikas Chaudhary3573bfb2012-02-27 03:08:57 -080042int ql4xdontresethba;
Vikas Chaudharyf4f5df22010-07-28 15:53:44 +053043module_param(ql4xdontresethba, int, S_IRUGO | S_IWUSR);
David Somayajuluafaf5a22006-09-19 10:28:00 -070044MODULE_PARM_DESC(ql4xdontresethba,
Karen Higginsa4e8a712012-01-11 02:44:20 -080045 " Don't reset the HBA for driver recovery.\n"
46 "\t\t 0 - It will reset HBA (Default)\n"
47 "\t\t 1 - It will NOT reset HBA");
David Somayajuluafaf5a22006-09-19 10:28:00 -070048
Karen Higginsa4e8a712012-01-11 02:44:20 -080049int ql4xextended_error_logging;
Vikas Chaudharyf4f5df22010-07-28 15:53:44 +053050module_param(ql4xextended_error_logging, int, S_IRUGO | S_IWUSR);
Andrew Vasquez11010fe2006-10-06 09:54:59 -070051MODULE_PARM_DESC(ql4xextended_error_logging,
Karen Higginsa4e8a712012-01-11 02:44:20 -080052 " Option to enable extended error logging.\n"
53 "\t\t 0 - no logging (Default)\n"
54 "\t\t 2 - debug logging");
David Somayajuluafaf5a22006-09-19 10:28:00 -070055
Vikas Chaudharyf4f5df22010-07-28 15:53:44 +053056int ql4xenablemsix = 1;
57module_param(ql4xenablemsix, int, S_IRUGO|S_IWUSR);
58MODULE_PARM_DESC(ql4xenablemsix,
Karen Higginsa4e8a712012-01-11 02:44:20 -080059 " Set to enable MSI or MSI-X interrupt mechanism.\n"
60 "\t\t 0 = enable INTx interrupt mechanism.\n"
61 "\t\t 1 = enable MSI-X interrupt mechanism (Default).\n"
62 "\t\t 2 = enable MSI interrupt mechanism.");
David C Somayajulu477ffb92007-01-22 12:26:11 -080063
Mike Christied510d962008-07-11 19:50:33 -050064#define QL4_DEF_QDEPTH 32
Vikas Chaudhary8bb40332011-03-21 03:34:31 -070065static int ql4xmaxqdepth = QL4_DEF_QDEPTH;
66module_param(ql4xmaxqdepth, int, S_IRUGO | S_IWUSR);
67MODULE_PARM_DESC(ql4xmaxqdepth,
Karen Higginsa4e8a712012-01-11 02:44:20 -080068 " Maximum queue depth to report for target devices.\n"
69 "\t\t Default: 32.");
Mike Christied510d962008-07-11 19:50:33 -050070
Tej Parkashf7b4aa632012-04-30 04:12:19 -070071static int ql4xqfulltracking = 1;
72module_param(ql4xqfulltracking, int, S_IRUGO | S_IWUSR);
73MODULE_PARM_DESC(ql4xqfulltracking,
74 " Enable or disable dynamic tracking and adjustment of\n"
75 "\t\t scsi device queue depth.\n"
76 "\t\t 0 - Disable.\n"
77 "\t\t 1 - Enable. (Default)");
78
Vikas Chaudhary30387272011-03-21 03:34:32 -070079static int ql4xsess_recovery_tmo = QL4_SESS_RECOVERY_TMO;
80module_param(ql4xsess_recovery_tmo, int, S_IRUGO);
81MODULE_PARM_DESC(ql4xsess_recovery_tmo,
Vikas Chaudhary3573bfb2012-02-27 03:08:57 -080082 " Target Session Recovery Timeout.\n"
Karen Higginsa4e8a712012-01-11 02:44:20 -080083 "\t\t Default: 120 sec.");
Vikas Chaudhary30387272011-03-21 03:34:32 -070084
Tej Parkash068237c82012-05-18 04:41:44 -040085int ql4xmdcapmask = 0x1F;
86module_param(ql4xmdcapmask, int, S_IRUGO);
87MODULE_PARM_DESC(ql4xmdcapmask,
88 " Set the Minidump driver capture mask level.\n"
89 "\t\t Default is 0x1F.\n"
90 "\t\t Can be set to 0x3, 0x7, 0xF, 0x1F, 0x3F, 0x7F");
91
92int ql4xenablemd = 1;
93module_param(ql4xenablemd, int, S_IRUGO | S_IWUSR);
94MODULE_PARM_DESC(ql4xenablemd,
95 " Set to enable minidump.\n"
96 "\t\t 0 - disable minidump\n"
97 "\t\t 1 - enable minidump (Default)");
98
Manish Rangankarb3a271a2011-07-25 13:48:53 -050099static int qla4xxx_wait_for_hba_online(struct scsi_qla_host *ha);
David Somayajuluafaf5a22006-09-19 10:28:00 -0700100/*
101 * SCSI host template entry points
102 */
Adrian Bunk47975472007-04-26 00:35:16 -0700103static void qla4xxx_config_dma_addressing(struct scsi_qla_host *ha);
David Somayajuluafaf5a22006-09-19 10:28:00 -0700104
105/*
106 * iSCSI template entry points
107 */
Mike Christiefca9f042012-02-27 03:08:54 -0800108static int qla4xxx_session_get_param(struct iscsi_cls_session *cls_sess,
109 enum iscsi_param param, char *buf);
David Somayajuluafaf5a22006-09-19 10:28:00 -0700110static int qla4xxx_conn_get_param(struct iscsi_cls_conn *conn,
111 enum iscsi_param param, char *buf);
Mike Christieaa1e93a2007-05-30 12:57:09 -0500112static int qla4xxx_host_get_param(struct Scsi_Host *shost,
113 enum iscsi_host_param param, char *buf);
Mike Christie00c31882011-10-06 03:56:59 -0500114static int qla4xxx_iface_set_param(struct Scsi_Host *shost, void *data,
115 uint32_t len);
Vikas Chaudharyed1086e2011-07-25 13:48:41 -0500116static int qla4xxx_get_iface_param(struct iscsi_iface *iface,
117 enum iscsi_param_type param_type,
118 int param, char *buf);
Mike Christie5c656af2009-07-15 15:02:59 -0500119static enum blk_eh_timer_return qla4xxx_eh_cmd_timed_out(struct scsi_cmnd *sc);
Manish Rangankarb3a271a2011-07-25 13:48:53 -0500120static struct iscsi_endpoint *qla4xxx_ep_connect(struct Scsi_Host *shost,
121 struct sockaddr *dst_addr,
122 int non_blocking);
123static int qla4xxx_ep_poll(struct iscsi_endpoint *ep, int timeout_ms);
124static void qla4xxx_ep_disconnect(struct iscsi_endpoint *ep);
125static int qla4xxx_get_ep_param(struct iscsi_endpoint *ep,
126 enum iscsi_param param, char *buf);
127static int qla4xxx_conn_start(struct iscsi_cls_conn *conn);
128static struct iscsi_cls_conn *
129qla4xxx_conn_create(struct iscsi_cls_session *cls_sess, uint32_t conn_idx);
130static int qla4xxx_conn_bind(struct iscsi_cls_session *cls_session,
131 struct iscsi_cls_conn *cls_conn,
132 uint64_t transport_fd, int is_leading);
133static void qla4xxx_conn_destroy(struct iscsi_cls_conn *conn);
134static struct iscsi_cls_session *
135qla4xxx_session_create(struct iscsi_endpoint *ep, uint16_t cmds_max,
136 uint16_t qdepth, uint32_t initial_cmdsn);
137static void qla4xxx_session_destroy(struct iscsi_cls_session *sess);
138static void qla4xxx_task_work(struct work_struct *wdata);
139static int qla4xxx_alloc_pdu(struct iscsi_task *, uint8_t);
140static int qla4xxx_task_xmit(struct iscsi_task *);
141static void qla4xxx_task_cleanup(struct iscsi_task *);
142static void qla4xxx_fail_session(struct iscsi_cls_session *cls_session);
143static void qla4xxx_conn_get_stats(struct iscsi_cls_conn *cls_conn,
144 struct iscsi_stats *stats);
Vikas Chaudharyc0b9d3f2012-02-13 18:30:49 +0530145static int qla4xxx_send_ping(struct Scsi_Host *shost, uint32_t iface_num,
146 uint32_t iface_type, uint32_t payload_size,
147 uint32_t pid, struct sockaddr *dst_addr);
Nilesh Javali376738a2012-02-27 03:08:52 -0800148static int qla4xxx_get_chap_list(struct Scsi_Host *shost, uint16_t chap_tbl_idx,
149 uint32_t *num_entries, char *buf);
150static int qla4xxx_delete_chap(struct Scsi_Host *shost, uint16_t chap_tbl_idx);
Vikas Chaudharyc0b9d3f2012-02-13 18:30:49 +0530151
David Somayajuluafaf5a22006-09-19 10:28:00 -0700152/*
153 * SCSI host template entry points
154 */
Jeff Garzikf2812332010-11-16 02:10:29 -0500155static int qla4xxx_queuecommand(struct Scsi_Host *h, struct scsi_cmnd *cmd);
Vikas Chaudhary09a0f712010-04-28 11:42:24 +0530156static int qla4xxx_eh_abort(struct scsi_cmnd *cmd);
David Somayajuluafaf5a22006-09-19 10:28:00 -0700157static int qla4xxx_eh_device_reset(struct scsi_cmnd *cmd);
Mike Christiece545032008-02-29 18:25:20 -0600158static int qla4xxx_eh_target_reset(struct scsi_cmnd *cmd);
David Somayajuluafaf5a22006-09-19 10:28:00 -0700159static int qla4xxx_eh_host_reset(struct scsi_cmnd *cmd);
160static int qla4xxx_slave_alloc(struct scsi_device *device);
161static int qla4xxx_slave_configure(struct scsi_device *device);
162static void qla4xxx_slave_destroy(struct scsi_device *sdev);
Al Viro587a1f12011-07-23 23:11:19 -0400163static umode_t ql4_attr_is_visible(int param_type, int param);
Vikas Chaudhary95d31262011-08-12 02:51:29 -0700164static int qla4xxx_host_reset(struct Scsi_Host *shost, int reset_type);
Tej Parkashf7b4aa632012-04-30 04:12:19 -0700165static int qla4xxx_change_queue_depth(struct scsi_device *sdev, int qdepth,
166 int reason);
David Somayajuluafaf5a22006-09-19 10:28:00 -0700167
Vikas Chaudharyf4f5df22010-07-28 15:53:44 +0530168static struct qla4_8xxx_legacy_intr_set legacy_intr[] =
169 QLA82XX_LEGACY_INTR_CONFIG;
170
David Somayajuluafaf5a22006-09-19 10:28:00 -0700171static struct scsi_host_template qla4xxx_driver_template = {
172 .module = THIS_MODULE,
173 .name = DRIVER_NAME,
174 .proc_name = DRIVER_NAME,
175 .queuecommand = qla4xxx_queuecommand,
176
Vikas Chaudhary09a0f712010-04-28 11:42:24 +0530177 .eh_abort_handler = qla4xxx_eh_abort,
David Somayajuluafaf5a22006-09-19 10:28:00 -0700178 .eh_device_reset_handler = qla4xxx_eh_device_reset,
Mike Christiece545032008-02-29 18:25:20 -0600179 .eh_target_reset_handler = qla4xxx_eh_target_reset,
David Somayajuluafaf5a22006-09-19 10:28:00 -0700180 .eh_host_reset_handler = qla4xxx_eh_host_reset,
Mike Christie5c656af2009-07-15 15:02:59 -0500181 .eh_timed_out = qla4xxx_eh_cmd_timed_out,
David Somayajuluafaf5a22006-09-19 10:28:00 -0700182
183 .slave_configure = qla4xxx_slave_configure,
184 .slave_alloc = qla4xxx_slave_alloc,
185 .slave_destroy = qla4xxx_slave_destroy,
Tej Parkashf7b4aa632012-04-30 04:12:19 -0700186 .change_queue_depth = qla4xxx_change_queue_depth,
David Somayajuluafaf5a22006-09-19 10:28:00 -0700187
188 .this_id = -1,
189 .cmd_per_lun = 3,
190 .use_clustering = ENABLE_CLUSTERING,
191 .sg_tablesize = SG_ALL,
192
193 .max_sectors = 0xFFFF,
Harish Zunjarrao7ad633c2011-05-17 23:17:11 -0700194 .shost_attrs = qla4xxx_host_attrs,
Vikas Chaudhary95d31262011-08-12 02:51:29 -0700195 .host_reset = qla4xxx_host_reset,
Vikas Chaudharya3559432011-07-25 13:48:51 -0500196 .vendor_id = SCSI_NL_VID_TYPE_PCI | PCI_VENDOR_ID_QLOGIC,
David Somayajuluafaf5a22006-09-19 10:28:00 -0700197};
198
199static struct iscsi_transport qla4xxx_iscsi_transport = {
200 .owner = THIS_MODULE,
201 .name = DRIVER_NAME,
Manish Rangankarb3a271a2011-07-25 13:48:53 -0500202 .caps = CAP_TEXT_NEGO |
203 CAP_DATA_PATH_OFFLOAD | CAP_HDRDGST |
204 CAP_DATADGST | CAP_LOGIN_OFFLOAD |
205 CAP_MULTI_R2T,
Mike Christie3128c6c2011-07-25 13:48:42 -0500206 .attr_is_visible = ql4_attr_is_visible,
Manish Rangankarb3a271a2011-07-25 13:48:53 -0500207 .create_session = qla4xxx_session_create,
208 .destroy_session = qla4xxx_session_destroy,
209 .start_conn = qla4xxx_conn_start,
210 .create_conn = qla4xxx_conn_create,
211 .bind_conn = qla4xxx_conn_bind,
212 .stop_conn = iscsi_conn_stop,
213 .destroy_conn = qla4xxx_conn_destroy,
214 .set_param = iscsi_set_param,
David Somayajuluafaf5a22006-09-19 10:28:00 -0700215 .get_conn_param = qla4xxx_conn_get_param,
Mike Christiefca9f042012-02-27 03:08:54 -0800216 .get_session_param = qla4xxx_session_get_param,
Manish Rangankarb3a271a2011-07-25 13:48:53 -0500217 .get_ep_param = qla4xxx_get_ep_param,
218 .ep_connect = qla4xxx_ep_connect,
219 .ep_poll = qla4xxx_ep_poll,
220 .ep_disconnect = qla4xxx_ep_disconnect,
221 .get_stats = qla4xxx_conn_get_stats,
222 .send_pdu = iscsi_conn_send_pdu,
223 .xmit_task = qla4xxx_task_xmit,
224 .cleanup_task = qla4xxx_task_cleanup,
225 .alloc_pdu = qla4xxx_alloc_pdu,
226
Mike Christieaa1e93a2007-05-30 12:57:09 -0500227 .get_host_param = qla4xxx_host_get_param,
Mike Christied00efe32011-07-25 13:48:38 -0500228 .set_iface_param = qla4xxx_iface_set_param,
Vikas Chaudharyed1086e2011-07-25 13:48:41 -0500229 .get_iface_param = qla4xxx_get_iface_param,
Vikas Chaudharya3559432011-07-25 13:48:51 -0500230 .bsg_request = qla4xxx_bsg_request,
Vikas Chaudharyc0b9d3f2012-02-13 18:30:49 +0530231 .send_ping = qla4xxx_send_ping,
Nilesh Javali376738a2012-02-27 03:08:52 -0800232 .get_chap = qla4xxx_get_chap_list,
233 .delete_chap = qla4xxx_delete_chap,
David Somayajuluafaf5a22006-09-19 10:28:00 -0700234};
235
236static struct scsi_transport_template *qla4xxx_scsi_transport;
237
Vikas Chaudharyc0b9d3f2012-02-13 18:30:49 +0530238static int qla4xxx_send_ping(struct Scsi_Host *shost, uint32_t iface_num,
239 uint32_t iface_type, uint32_t payload_size,
240 uint32_t pid, struct sockaddr *dst_addr)
241{
242 struct scsi_qla_host *ha = to_qla_host(shost);
243 struct sockaddr_in *addr;
244 struct sockaddr_in6 *addr6;
245 uint32_t options = 0;
246 uint8_t ipaddr[IPv6_ADDR_LEN];
247 int rval;
248
249 memset(ipaddr, 0, IPv6_ADDR_LEN);
250 /* IPv4 to IPv4 */
251 if ((iface_type == ISCSI_IFACE_TYPE_IPV4) &&
252 (dst_addr->sa_family == AF_INET)) {
253 addr = (struct sockaddr_in *)dst_addr;
254 memcpy(ipaddr, &addr->sin_addr.s_addr, IP_ADDR_LEN);
255 DEBUG2(ql4_printk(KERN_INFO, ha, "%s: IPv4 Ping src: %pI4 "
256 "dest: %pI4\n", __func__,
257 &ha->ip_config.ip_address, ipaddr));
258 rval = qla4xxx_ping_iocb(ha, options, payload_size, pid,
259 ipaddr);
260 if (rval)
261 rval = -EINVAL;
262 } else if ((iface_type == ISCSI_IFACE_TYPE_IPV6) &&
263 (dst_addr->sa_family == AF_INET6)) {
264 /* IPv6 to IPv6 */
265 addr6 = (struct sockaddr_in6 *)dst_addr;
266 memcpy(ipaddr, &addr6->sin6_addr.in6_u.u6_addr8, IPv6_ADDR_LEN);
267
268 options |= PING_IPV6_PROTOCOL_ENABLE;
269
270 /* Ping using LinkLocal address */
271 if ((iface_num == 0) || (iface_num == 1)) {
272 DEBUG2(ql4_printk(KERN_INFO, ha, "%s: LinkLocal Ping "
273 "src: %pI6 dest: %pI6\n", __func__,
274 &ha->ip_config.ipv6_link_local_addr,
275 ipaddr));
276 options |= PING_IPV6_LINKLOCAL_ADDR;
277 rval = qla4xxx_ping_iocb(ha, options, payload_size,
278 pid, ipaddr);
279 } else {
280 ql4_printk(KERN_WARNING, ha, "%s: iface num = %d "
281 "not supported\n", __func__, iface_num);
282 rval = -ENOSYS;
283 goto exit_send_ping;
284 }
285
286 /*
287 * If ping using LinkLocal address fails, try ping using
288 * IPv6 address
289 */
290 if (rval != QLA_SUCCESS) {
291 options &= ~PING_IPV6_LINKLOCAL_ADDR;
292 if (iface_num == 0) {
293 options |= PING_IPV6_ADDR0;
294 DEBUG2(ql4_printk(KERN_INFO, ha, "%s: IPv6 "
295 "Ping src: %pI6 "
296 "dest: %pI6\n", __func__,
297 &ha->ip_config.ipv6_addr0,
298 ipaddr));
299 } else if (iface_num == 1) {
300 options |= PING_IPV6_ADDR1;
301 DEBUG2(ql4_printk(KERN_INFO, ha, "%s: IPv6 "
302 "Ping src: %pI6 "
303 "dest: %pI6\n", __func__,
304 &ha->ip_config.ipv6_addr1,
305 ipaddr));
306 }
307 rval = qla4xxx_ping_iocb(ha, options, payload_size,
308 pid, ipaddr);
309 if (rval)
310 rval = -EINVAL;
311 }
312 } else
313 rval = -ENOSYS;
314exit_send_ping:
315 return rval;
316}
317
Al Viro587a1f12011-07-23 23:11:19 -0400318static umode_t ql4_attr_is_visible(int param_type, int param)
Mike Christie3128c6c2011-07-25 13:48:42 -0500319{
320 switch (param_type) {
Mike Christief27fb2e2011-07-25 13:48:45 -0500321 case ISCSI_HOST_PARAM:
322 switch (param) {
323 case ISCSI_HOST_PARAM_HWADDRESS:
324 case ISCSI_HOST_PARAM_IPADDRESS:
325 case ISCSI_HOST_PARAM_INITIATOR_NAME:
Vikas Chaudhary3254dbe2012-01-19 03:06:56 -0800326 case ISCSI_HOST_PARAM_PORT_STATE:
327 case ISCSI_HOST_PARAM_PORT_SPEED:
Mike Christief27fb2e2011-07-25 13:48:45 -0500328 return S_IRUGO;
329 default:
330 return 0;
331 }
Mike Christie3128c6c2011-07-25 13:48:42 -0500332 case ISCSI_PARAM:
333 switch (param) {
Mike Christie590134f2011-10-17 22:42:13 -0500334 case ISCSI_PARAM_PERSISTENT_ADDRESS:
335 case ISCSI_PARAM_PERSISTENT_PORT:
Mike Christie3128c6c2011-07-25 13:48:42 -0500336 case ISCSI_PARAM_CONN_ADDRESS:
337 case ISCSI_PARAM_CONN_PORT:
Mike Christie1d063c12011-07-25 13:48:43 -0500338 case ISCSI_PARAM_TARGET_NAME:
339 case ISCSI_PARAM_TPGT:
340 case ISCSI_PARAM_TARGET_ALIAS:
Manish Rangankarb3a271a2011-07-25 13:48:53 -0500341 case ISCSI_PARAM_MAX_BURST:
342 case ISCSI_PARAM_MAX_R2T:
343 case ISCSI_PARAM_FIRST_BURST:
344 case ISCSI_PARAM_MAX_RECV_DLENGTH:
345 case ISCSI_PARAM_MAX_XMIT_DLENGTH:
Mike Christiede379202011-08-14 20:42:56 -0500346 case ISCSI_PARAM_IFACE_NAME:
Mike Christiefca9f042012-02-27 03:08:54 -0800347 case ISCSI_PARAM_CHAP_OUT_IDX:
348 case ISCSI_PARAM_CHAP_IN_IDX:
349 case ISCSI_PARAM_USERNAME:
350 case ISCSI_PARAM_PASSWORD:
351 case ISCSI_PARAM_USERNAME_IN:
352 case ISCSI_PARAM_PASSWORD_IN:
Mike Christie3128c6c2011-07-25 13:48:42 -0500353 return S_IRUGO;
354 default:
355 return 0;
356 }
Mike Christieb78dbba2011-07-25 13:48:44 -0500357 case ISCSI_NET_PARAM:
358 switch (param) {
359 case ISCSI_NET_PARAM_IPV4_ADDR:
360 case ISCSI_NET_PARAM_IPV4_SUBNET:
361 case ISCSI_NET_PARAM_IPV4_GW:
362 case ISCSI_NET_PARAM_IPV4_BOOTPROTO:
363 case ISCSI_NET_PARAM_IFACE_ENABLE:
364 case ISCSI_NET_PARAM_IPV6_LINKLOCAL:
365 case ISCSI_NET_PARAM_IPV6_ADDR:
366 case ISCSI_NET_PARAM_IPV6_ROUTER:
367 case ISCSI_NET_PARAM_IPV6_ADDR_AUTOCFG:
368 case ISCSI_NET_PARAM_IPV6_LINKLOCAL_AUTOCFG:
Vikas Chaudhary6ac73e82011-07-25 13:48:49 -0500369 case ISCSI_NET_PARAM_VLAN_ID:
370 case ISCSI_NET_PARAM_VLAN_PRIORITY:
371 case ISCSI_NET_PARAM_VLAN_ENABLED:
Vikas Chaudhary943c1572011-08-01 03:26:13 -0700372 case ISCSI_NET_PARAM_MTU:
Vikas Chaudhary2ada7fc2011-08-01 03:26:19 -0700373 case ISCSI_NET_PARAM_PORT:
Mike Christieb78dbba2011-07-25 13:48:44 -0500374 return S_IRUGO;
375 default:
376 return 0;
377 }
Mike Christie3128c6c2011-07-25 13:48:42 -0500378 }
379
380 return 0;
381}
382
Nilesh Javali376738a2012-02-27 03:08:52 -0800383static int qla4xxx_get_chap_list(struct Scsi_Host *shost, uint16_t chap_tbl_idx,
384 uint32_t *num_entries, char *buf)
385{
386 struct scsi_qla_host *ha = to_qla_host(shost);
387 struct ql4_chap_table *chap_table;
388 struct iscsi_chap_rec *chap_rec;
389 int max_chap_entries = 0;
390 int valid_chap_entries = 0;
391 int ret = 0, i;
392
393 if (is_qla8022(ha))
394 max_chap_entries = (ha->hw.flt_chap_size / 2) /
395 sizeof(struct ql4_chap_table);
396 else
397 max_chap_entries = MAX_CHAP_ENTRIES_40XX;
398
399 ql4_printk(KERN_INFO, ha, "%s: num_entries = %d, CHAP idx = %d\n",
400 __func__, *num_entries, chap_tbl_idx);
401
402 if (!buf) {
403 ret = -ENOMEM;
404 goto exit_get_chap_list;
405 }
406
407 chap_rec = (struct iscsi_chap_rec *) buf;
408 mutex_lock(&ha->chap_sem);
409 for (i = chap_tbl_idx; i < max_chap_entries; i++) {
410 chap_table = (struct ql4_chap_table *)ha->chap_list + i;
411 if (chap_table->cookie !=
412 __constant_cpu_to_le16(CHAP_VALID_COOKIE))
413 continue;
414
415 chap_rec->chap_tbl_idx = i;
416 strncpy(chap_rec->username, chap_table->name,
417 ISCSI_CHAP_AUTH_NAME_MAX_LEN);
418 strncpy(chap_rec->password, chap_table->secret,
419 QL4_CHAP_MAX_SECRET_LEN);
420 chap_rec->password_length = chap_table->secret_len;
421
422 if (chap_table->flags & BIT_7) /* local */
423 chap_rec->chap_type = CHAP_TYPE_OUT;
424
425 if (chap_table->flags & BIT_6) /* peer */
426 chap_rec->chap_type = CHAP_TYPE_IN;
427
428 chap_rec++;
429
430 valid_chap_entries++;
431 if (valid_chap_entries == *num_entries)
432 break;
433 else
434 continue;
435 }
436 mutex_unlock(&ha->chap_sem);
437
438exit_get_chap_list:
439 ql4_printk(KERN_INFO, ha, "%s: Valid CHAP Entries = %d\n",
440 __func__, valid_chap_entries);
441 *num_entries = valid_chap_entries;
442 return ret;
443}
444
445static int __qla4xxx_is_chap_active(struct device *dev, void *data)
446{
447 int ret = 0;
448 uint16_t *chap_tbl_idx = (uint16_t *) data;
449 struct iscsi_cls_session *cls_session;
450 struct iscsi_session *sess;
451 struct ddb_entry *ddb_entry;
452
453 if (!iscsi_is_session_dev(dev))
454 goto exit_is_chap_active;
455
456 cls_session = iscsi_dev_to_session(dev);
457 sess = cls_session->dd_data;
458 ddb_entry = sess->dd_data;
459
460 if (iscsi_session_chkready(cls_session))
461 goto exit_is_chap_active;
462
463 if (ddb_entry->chap_tbl_idx == *chap_tbl_idx)
464 ret = 1;
465
466exit_is_chap_active:
467 return ret;
468}
469
470static int qla4xxx_is_chap_active(struct Scsi_Host *shost,
471 uint16_t chap_tbl_idx)
472{
473 int ret = 0;
474
475 ret = device_for_each_child(&shost->shost_gendev, &chap_tbl_idx,
476 __qla4xxx_is_chap_active);
477
478 return ret;
479}
480
481static int qla4xxx_delete_chap(struct Scsi_Host *shost, uint16_t chap_tbl_idx)
482{
483 struct scsi_qla_host *ha = to_qla_host(shost);
484 struct ql4_chap_table *chap_table;
485 dma_addr_t chap_dma;
486 int max_chap_entries = 0;
487 uint32_t offset = 0;
488 uint32_t chap_size;
489 int ret = 0;
490
491 chap_table = dma_pool_alloc(ha->chap_dma_pool, GFP_KERNEL, &chap_dma);
492 if (chap_table == NULL)
493 return -ENOMEM;
494
495 memset(chap_table, 0, sizeof(struct ql4_chap_table));
496
497 if (is_qla8022(ha))
498 max_chap_entries = (ha->hw.flt_chap_size / 2) /
499 sizeof(struct ql4_chap_table);
500 else
501 max_chap_entries = MAX_CHAP_ENTRIES_40XX;
502
503 if (chap_tbl_idx > max_chap_entries) {
504 ret = -EINVAL;
505 goto exit_delete_chap;
506 }
507
508 /* Check if chap index is in use.
509 * If chap is in use don't delet chap entry */
510 ret = qla4xxx_is_chap_active(shost, chap_tbl_idx);
511 if (ret) {
512 ql4_printk(KERN_INFO, ha, "CHAP entry %d is in use, cannot "
513 "delete from flash\n", chap_tbl_idx);
514 ret = -EBUSY;
515 goto exit_delete_chap;
516 }
517
518 chap_size = sizeof(struct ql4_chap_table);
519 if (is_qla40XX(ha))
520 offset = FLASH_CHAP_OFFSET | (chap_tbl_idx * chap_size);
521 else {
522 offset = FLASH_RAW_ACCESS_ADDR + (ha->hw.flt_region_chap << 2);
523 /* flt_chap_size is CHAP table size for both ports
524 * so divide it by 2 to calculate the offset for second port
525 */
526 if (ha->port_num == 1)
527 offset += (ha->hw.flt_chap_size / 2);
528 offset += (chap_tbl_idx * chap_size);
529 }
530
531 ret = qla4xxx_get_flash(ha, chap_dma, offset, chap_size);
532 if (ret != QLA_SUCCESS) {
533 ret = -EINVAL;
534 goto exit_delete_chap;
535 }
536
537 DEBUG2(ql4_printk(KERN_INFO, ha, "Chap Cookie: x%x\n",
538 __le16_to_cpu(chap_table->cookie)));
539
540 if (__le16_to_cpu(chap_table->cookie) != CHAP_VALID_COOKIE) {
541 ql4_printk(KERN_ERR, ha, "No valid chap entry found\n");
542 goto exit_delete_chap;
543 }
544
545 chap_table->cookie = __constant_cpu_to_le16(0xFFFF);
546
547 offset = FLASH_CHAP_OFFSET |
548 (chap_tbl_idx * sizeof(struct ql4_chap_table));
549 ret = qla4xxx_set_flash(ha, chap_dma, offset, chap_size,
550 FLASH_OPT_RMW_COMMIT);
551 if (ret == QLA_SUCCESS && ha->chap_list) {
552 mutex_lock(&ha->chap_sem);
553 /* Update ha chap_list cache */
554 memcpy((struct ql4_chap_table *)ha->chap_list + chap_tbl_idx,
555 chap_table, sizeof(struct ql4_chap_table));
556 mutex_unlock(&ha->chap_sem);
557 }
558 if (ret != QLA_SUCCESS)
559 ret = -EINVAL;
560
561exit_delete_chap:
562 dma_pool_free(ha->chap_dma_pool, chap_table, chap_dma);
563 return ret;
564}
565
Vikas Chaudharyed1086e2011-07-25 13:48:41 -0500566static int qla4xxx_get_iface_param(struct iscsi_iface *iface,
567 enum iscsi_param_type param_type,
568 int param, char *buf)
569{
570 struct Scsi_Host *shost = iscsi_iface_to_shost(iface);
571 struct scsi_qla_host *ha = to_qla_host(shost);
572 int len = -ENOSYS;
573
574 if (param_type != ISCSI_NET_PARAM)
575 return -ENOSYS;
576
577 switch (param) {
578 case ISCSI_NET_PARAM_IPV4_ADDR:
579 len = sprintf(buf, "%pI4\n", &ha->ip_config.ip_address);
580 break;
581 case ISCSI_NET_PARAM_IPV4_SUBNET:
582 len = sprintf(buf, "%pI4\n", &ha->ip_config.subnet_mask);
583 break;
584 case ISCSI_NET_PARAM_IPV4_GW:
585 len = sprintf(buf, "%pI4\n", &ha->ip_config.gateway);
586 break;
587 case ISCSI_NET_PARAM_IFACE_ENABLE:
588 if (iface->iface_type == ISCSI_IFACE_TYPE_IPV4)
589 len = sprintf(buf, "%s\n",
590 (ha->ip_config.ipv4_options &
591 IPOPT_IPV4_PROTOCOL_ENABLE) ?
592 "enabled" : "disabled");
593 else if (iface->iface_type == ISCSI_IFACE_TYPE_IPV6)
594 len = sprintf(buf, "%s\n",
595 (ha->ip_config.ipv6_options &
596 IPV6_OPT_IPV6_PROTOCOL_ENABLE) ?
597 "enabled" : "disabled");
598 break;
599 case ISCSI_NET_PARAM_IPV4_BOOTPROTO:
600 len = sprintf(buf, "%s\n",
601 (ha->ip_config.tcp_options & TCPOPT_DHCP_ENABLE) ?
602 "dhcp" : "static");
603 break;
604 case ISCSI_NET_PARAM_IPV6_ADDR:
605 if (iface->iface_num == 0)
606 len = sprintf(buf, "%pI6\n", &ha->ip_config.ipv6_addr0);
607 if (iface->iface_num == 1)
608 len = sprintf(buf, "%pI6\n", &ha->ip_config.ipv6_addr1);
609 break;
610 case ISCSI_NET_PARAM_IPV6_LINKLOCAL:
611 len = sprintf(buf, "%pI6\n",
612 &ha->ip_config.ipv6_link_local_addr);
613 break;
614 case ISCSI_NET_PARAM_IPV6_ROUTER:
615 len = sprintf(buf, "%pI6\n",
616 &ha->ip_config.ipv6_default_router_addr);
617 break;
618 case ISCSI_NET_PARAM_IPV6_ADDR_AUTOCFG:
619 len = sprintf(buf, "%s\n",
620 (ha->ip_config.ipv6_addl_options &
621 IPV6_ADDOPT_NEIGHBOR_DISCOVERY_ADDR_ENABLE) ?
622 "nd" : "static");
623 break;
624 case ISCSI_NET_PARAM_IPV6_LINKLOCAL_AUTOCFG:
625 len = sprintf(buf, "%s\n",
626 (ha->ip_config.ipv6_addl_options &
627 IPV6_ADDOPT_AUTOCONFIG_LINK_LOCAL_ADDR) ?
628 "auto" : "static");
629 break;
Vikas Chaudhary6ac73e82011-07-25 13:48:49 -0500630 case ISCSI_NET_PARAM_VLAN_ID:
631 if (iface->iface_type == ISCSI_IFACE_TYPE_IPV4)
632 len = sprintf(buf, "%d\n",
633 (ha->ip_config.ipv4_vlan_tag &
634 ISCSI_MAX_VLAN_ID));
635 else if (iface->iface_type == ISCSI_IFACE_TYPE_IPV6)
636 len = sprintf(buf, "%d\n",
637 (ha->ip_config.ipv6_vlan_tag &
638 ISCSI_MAX_VLAN_ID));
639 break;
640 case ISCSI_NET_PARAM_VLAN_PRIORITY:
641 if (iface->iface_type == ISCSI_IFACE_TYPE_IPV4)
642 len = sprintf(buf, "%d\n",
643 ((ha->ip_config.ipv4_vlan_tag >> 13) &
644 ISCSI_MAX_VLAN_PRIORITY));
645 else if (iface->iface_type == ISCSI_IFACE_TYPE_IPV6)
646 len = sprintf(buf, "%d\n",
647 ((ha->ip_config.ipv6_vlan_tag >> 13) &
648 ISCSI_MAX_VLAN_PRIORITY));
649 break;
650 case ISCSI_NET_PARAM_VLAN_ENABLED:
651 if (iface->iface_type == ISCSI_IFACE_TYPE_IPV4)
652 len = sprintf(buf, "%s\n",
653 (ha->ip_config.ipv4_options &
654 IPOPT_VLAN_TAGGING_ENABLE) ?
655 "enabled" : "disabled");
656 else if (iface->iface_type == ISCSI_IFACE_TYPE_IPV6)
657 len = sprintf(buf, "%s\n",
658 (ha->ip_config.ipv6_options &
659 IPV6_OPT_VLAN_TAGGING_ENABLE) ?
660 "enabled" : "disabled");
661 break;
Vikas Chaudhary943c1572011-08-01 03:26:13 -0700662 case ISCSI_NET_PARAM_MTU:
663 len = sprintf(buf, "%d\n", ha->ip_config.eth_mtu_size);
664 break;
Vikas Chaudhary2ada7fc2011-08-01 03:26:19 -0700665 case ISCSI_NET_PARAM_PORT:
666 if (iface->iface_type == ISCSI_IFACE_TYPE_IPV4)
667 len = sprintf(buf, "%d\n", ha->ip_config.ipv4_port);
668 else if (iface->iface_type == ISCSI_IFACE_TYPE_IPV6)
669 len = sprintf(buf, "%d\n", ha->ip_config.ipv6_port);
670 break;
Vikas Chaudharyed1086e2011-07-25 13:48:41 -0500671 default:
672 len = -ENOSYS;
673 }
674
675 return len;
676}
677
Manish Rangankarb3a271a2011-07-25 13:48:53 -0500678static struct iscsi_endpoint *
679qla4xxx_ep_connect(struct Scsi_Host *shost, struct sockaddr *dst_addr,
680 int non_blocking)
681{
682 int ret;
683 struct iscsi_endpoint *ep;
684 struct qla_endpoint *qla_ep;
685 struct scsi_qla_host *ha;
686 struct sockaddr_in *addr;
687 struct sockaddr_in6 *addr6;
688
689 DEBUG2(printk(KERN_INFO "Func: %s\n", __func__));
690 if (!shost) {
691 ret = -ENXIO;
692 printk(KERN_ERR "%s: shost is NULL\n",
693 __func__);
694 return ERR_PTR(ret);
695 }
696
697 ha = iscsi_host_priv(shost);
698
699 ep = iscsi_create_endpoint(sizeof(struct qla_endpoint));
700 if (!ep) {
701 ret = -ENOMEM;
702 return ERR_PTR(ret);
703 }
704
705 qla_ep = ep->dd_data;
706 memset(qla_ep, 0, sizeof(struct qla_endpoint));
707 if (dst_addr->sa_family == AF_INET) {
708 memcpy(&qla_ep->dst_addr, dst_addr, sizeof(struct sockaddr_in));
709 addr = (struct sockaddr_in *)&qla_ep->dst_addr;
710 DEBUG2(ql4_printk(KERN_INFO, ha, "%s: %pI4\n", __func__,
711 (char *)&addr->sin_addr));
712 } else if (dst_addr->sa_family == AF_INET6) {
713 memcpy(&qla_ep->dst_addr, dst_addr,
714 sizeof(struct sockaddr_in6));
715 addr6 = (struct sockaddr_in6 *)&qla_ep->dst_addr;
716 DEBUG2(ql4_printk(KERN_INFO, ha, "%s: %pI6\n", __func__,
717 (char *)&addr6->sin6_addr));
718 }
719
720 qla_ep->host = shost;
721
722 return ep;
723}
724
725static int qla4xxx_ep_poll(struct iscsi_endpoint *ep, int timeout_ms)
726{
727 struct qla_endpoint *qla_ep;
728 struct scsi_qla_host *ha;
729 int ret = 0;
730
731 DEBUG2(printk(KERN_INFO "Func: %s\n", __func__));
732 qla_ep = ep->dd_data;
733 ha = to_qla_host(qla_ep->host);
734
Mike Christie13483732011-12-01 21:38:41 -0600735 if (adapter_up(ha) && !test_bit(AF_BUILD_DDB_LIST, &ha->flags))
Manish Rangankarb3a271a2011-07-25 13:48:53 -0500736 ret = 1;
737
738 return ret;
739}
740
741static void qla4xxx_ep_disconnect(struct iscsi_endpoint *ep)
742{
743 DEBUG2(printk(KERN_INFO "Func: %s\n", __func__));
744 iscsi_destroy_endpoint(ep);
745}
746
747static int qla4xxx_get_ep_param(struct iscsi_endpoint *ep,
748 enum iscsi_param param,
749 char *buf)
750{
751 struct qla_endpoint *qla_ep = ep->dd_data;
752 struct sockaddr *dst_addr;
753
754 DEBUG2(printk(KERN_INFO "Func: %s\n", __func__));
755
756 switch (param) {
757 case ISCSI_PARAM_CONN_PORT:
758 case ISCSI_PARAM_CONN_ADDRESS:
759 if (!qla_ep)
760 return -ENOTCONN;
761
762 dst_addr = (struct sockaddr *)&qla_ep->dst_addr;
763 if (!dst_addr)
764 return -ENOTCONN;
765
766 return iscsi_conn_get_addr_param((struct sockaddr_storage *)
767 &qla_ep->dst_addr, param, buf);
768 default:
769 return -ENOSYS;
770 }
771}
772
773static void qla4xxx_conn_get_stats(struct iscsi_cls_conn *cls_conn,
774 struct iscsi_stats *stats)
775{
776 struct iscsi_session *sess;
777 struct iscsi_cls_session *cls_sess;
778 struct ddb_entry *ddb_entry;
779 struct scsi_qla_host *ha;
780 struct ql_iscsi_stats *ql_iscsi_stats;
781 int stats_size;
782 int ret;
783 dma_addr_t iscsi_stats_dma;
784
785 DEBUG2(printk(KERN_INFO "Func: %s\n", __func__));
786
787 cls_sess = iscsi_conn_to_session(cls_conn);
788 sess = cls_sess->dd_data;
789 ddb_entry = sess->dd_data;
790 ha = ddb_entry->ha;
791
792 stats_size = PAGE_ALIGN(sizeof(struct ql_iscsi_stats));
793 /* Allocate memory */
794 ql_iscsi_stats = dma_alloc_coherent(&ha->pdev->dev, stats_size,
795 &iscsi_stats_dma, GFP_KERNEL);
796 if (!ql_iscsi_stats) {
797 ql4_printk(KERN_ERR, ha,
798 "Unable to allocate memory for iscsi stats\n");
799 goto exit_get_stats;
800 }
801
802 ret = qla4xxx_get_mgmt_data(ha, ddb_entry->fw_ddb_index, stats_size,
803 iscsi_stats_dma);
804 if (ret != QLA_SUCCESS) {
805 ql4_printk(KERN_ERR, ha,
806 "Unable to retreive iscsi stats\n");
807 goto free_stats;
808 }
809
810 /* octets */
811 stats->txdata_octets = le64_to_cpu(ql_iscsi_stats->tx_data_octets);
812 stats->rxdata_octets = le64_to_cpu(ql_iscsi_stats->rx_data_octets);
813 /* xmit pdus */
814 stats->noptx_pdus = le32_to_cpu(ql_iscsi_stats->tx_nopout_pdus);
815 stats->scsicmd_pdus = le32_to_cpu(ql_iscsi_stats->tx_scsi_cmd_pdus);
816 stats->tmfcmd_pdus = le32_to_cpu(ql_iscsi_stats->tx_tmf_cmd_pdus);
817 stats->login_pdus = le32_to_cpu(ql_iscsi_stats->tx_login_cmd_pdus);
818 stats->text_pdus = le32_to_cpu(ql_iscsi_stats->tx_text_cmd_pdus);
819 stats->dataout_pdus = le32_to_cpu(ql_iscsi_stats->tx_scsi_write_pdus);
820 stats->logout_pdus = le32_to_cpu(ql_iscsi_stats->tx_logout_cmd_pdus);
821 stats->snack_pdus = le32_to_cpu(ql_iscsi_stats->tx_snack_req_pdus);
822 /* recv pdus */
823 stats->noprx_pdus = le32_to_cpu(ql_iscsi_stats->rx_nopin_pdus);
824 stats->scsirsp_pdus = le32_to_cpu(ql_iscsi_stats->rx_scsi_resp_pdus);
825 stats->tmfrsp_pdus = le32_to_cpu(ql_iscsi_stats->rx_tmf_resp_pdus);
826 stats->textrsp_pdus = le32_to_cpu(ql_iscsi_stats->rx_text_resp_pdus);
827 stats->datain_pdus = le32_to_cpu(ql_iscsi_stats->rx_scsi_read_pdus);
828 stats->logoutrsp_pdus =
829 le32_to_cpu(ql_iscsi_stats->rx_logout_resp_pdus);
830 stats->r2t_pdus = le32_to_cpu(ql_iscsi_stats->rx_r2t_pdus);
831 stats->async_pdus = le32_to_cpu(ql_iscsi_stats->rx_async_pdus);
832 stats->rjt_pdus = le32_to_cpu(ql_iscsi_stats->rx_reject_pdus);
833
834free_stats:
835 dma_free_coherent(&ha->pdev->dev, stats_size, ql_iscsi_stats,
836 iscsi_stats_dma);
837exit_get_stats:
838 return;
839}
840
Mike Christie5c656af2009-07-15 15:02:59 -0500841static enum blk_eh_timer_return qla4xxx_eh_cmd_timed_out(struct scsi_cmnd *sc)
842{
843 struct iscsi_cls_session *session;
Manish Rangankarb3a271a2011-07-25 13:48:53 -0500844 struct iscsi_session *sess;
845 unsigned long flags;
846 enum blk_eh_timer_return ret = BLK_EH_NOT_HANDLED;
Mike Christie5c656af2009-07-15 15:02:59 -0500847
848 session = starget_to_session(scsi_target(sc->device));
Manish Rangankarb3a271a2011-07-25 13:48:53 -0500849 sess = session->dd_data;
Mike Christie5c656af2009-07-15 15:02:59 -0500850
Manish Rangankarb3a271a2011-07-25 13:48:53 -0500851 spin_lock_irqsave(&session->lock, flags);
852 if (session->state == ISCSI_SESSION_FAILED)
853 ret = BLK_EH_RESET_TIMER;
854 spin_unlock_irqrestore(&session->lock, flags);
Mike Christie5c656af2009-07-15 15:02:59 -0500855
Manish Rangankarb3a271a2011-07-25 13:48:53 -0500856 return ret;
David Somayajuluafaf5a22006-09-19 10:28:00 -0700857}
858
Vikas Chaudhary3254dbe2012-01-19 03:06:56 -0800859static void qla4xxx_set_port_speed(struct Scsi_Host *shost)
860{
861 struct scsi_qla_host *ha = to_qla_host(shost);
Vikas Chaudharye16d1662012-03-02 01:55:31 -0800862 struct iscsi_cls_host *ihost = shost->shost_data;
Vikas Chaudhary3254dbe2012-01-19 03:06:56 -0800863 uint32_t speed = ISCSI_PORT_SPEED_UNKNOWN;
864
865 qla4xxx_get_firmware_state(ha);
866
867 switch (ha->addl_fw_state & 0x0F00) {
868 case FW_ADDSTATE_LINK_SPEED_10MBPS:
869 speed = ISCSI_PORT_SPEED_10MBPS;
870 break;
871 case FW_ADDSTATE_LINK_SPEED_100MBPS:
872 speed = ISCSI_PORT_SPEED_100MBPS;
873 break;
874 case FW_ADDSTATE_LINK_SPEED_1GBPS:
875 speed = ISCSI_PORT_SPEED_1GBPS;
876 break;
877 case FW_ADDSTATE_LINK_SPEED_10GBPS:
878 speed = ISCSI_PORT_SPEED_10GBPS;
879 break;
880 }
881 ihost->port_speed = speed;
882}
883
884static void qla4xxx_set_port_state(struct Scsi_Host *shost)
885{
886 struct scsi_qla_host *ha = to_qla_host(shost);
Vikas Chaudharye16d1662012-03-02 01:55:31 -0800887 struct iscsi_cls_host *ihost = shost->shost_data;
Vikas Chaudhary3254dbe2012-01-19 03:06:56 -0800888 uint32_t state = ISCSI_PORT_STATE_DOWN;
889
890 if (test_bit(AF_LINK_UP, &ha->flags))
891 state = ISCSI_PORT_STATE_UP;
892
893 ihost->port_state = state;
894}
895
Mike Christieaa1e93a2007-05-30 12:57:09 -0500896static int qla4xxx_host_get_param(struct Scsi_Host *shost,
897 enum iscsi_host_param param, char *buf)
898{
899 struct scsi_qla_host *ha = to_qla_host(shost);
900 int len;
901
902 switch (param) {
903 case ISCSI_HOST_PARAM_HWADDRESS:
Michael Chan7ffc49a2007-12-24 21:28:09 -0800904 len = sysfs_format_mac(buf, ha->my_mac, MAC_ADDR_LEN);
Mike Christieaa1e93a2007-05-30 12:57:09 -0500905 break;
Mike Christie22236962007-05-30 12:57:24 -0500906 case ISCSI_HOST_PARAM_IPADDRESS:
Vikas Chaudhary2bab08f2011-07-25 13:48:39 -0500907 len = sprintf(buf, "%pI4\n", &ha->ip_config.ip_address);
Mike Christie22236962007-05-30 12:57:24 -0500908 break;
Mike Christie8ad57812007-05-30 12:57:13 -0500909 case ISCSI_HOST_PARAM_INITIATOR_NAME:
Mike Christie22236962007-05-30 12:57:24 -0500910 len = sprintf(buf, "%s\n", ha->name_string);
Mike Christie8ad57812007-05-30 12:57:13 -0500911 break;
Vikas Chaudhary3254dbe2012-01-19 03:06:56 -0800912 case ISCSI_HOST_PARAM_PORT_STATE:
913 qla4xxx_set_port_state(shost);
914 len = sprintf(buf, "%s\n", iscsi_get_port_state_name(shost));
915 break;
916 case ISCSI_HOST_PARAM_PORT_SPEED:
917 qla4xxx_set_port_speed(shost);
918 len = sprintf(buf, "%s\n", iscsi_get_port_speed_name(shost));
919 break;
Mike Christieaa1e93a2007-05-30 12:57:09 -0500920 default:
921 return -ENOSYS;
922 }
923
924 return len;
925}
926
Vikas Chaudharyed1086e2011-07-25 13:48:41 -0500927static void qla4xxx_create_ipv4_iface(struct scsi_qla_host *ha)
928{
929 if (ha->iface_ipv4)
930 return;
931
932 /* IPv4 */
933 ha->iface_ipv4 = iscsi_create_iface(ha->host,
934 &qla4xxx_iscsi_transport,
935 ISCSI_IFACE_TYPE_IPV4, 0, 0);
936 if (!ha->iface_ipv4)
937 ql4_printk(KERN_ERR, ha, "Could not create IPv4 iSCSI "
938 "iface0.\n");
939}
940
941static void qla4xxx_create_ipv6_iface(struct scsi_qla_host *ha)
942{
943 if (!ha->iface_ipv6_0)
944 /* IPv6 iface-0 */
945 ha->iface_ipv6_0 = iscsi_create_iface(ha->host,
946 &qla4xxx_iscsi_transport,
947 ISCSI_IFACE_TYPE_IPV6, 0,
948 0);
949 if (!ha->iface_ipv6_0)
950 ql4_printk(KERN_ERR, ha, "Could not create IPv6 iSCSI "
951 "iface0.\n");
952
953 if (!ha->iface_ipv6_1)
954 /* IPv6 iface-1 */
955 ha->iface_ipv6_1 = iscsi_create_iface(ha->host,
956 &qla4xxx_iscsi_transport,
957 ISCSI_IFACE_TYPE_IPV6, 1,
958 0);
959 if (!ha->iface_ipv6_1)
960 ql4_printk(KERN_ERR, ha, "Could not create IPv6 iSCSI "
961 "iface1.\n");
962}
963
964static void qla4xxx_create_ifaces(struct scsi_qla_host *ha)
965{
966 if (ha->ip_config.ipv4_options & IPOPT_IPV4_PROTOCOL_ENABLE)
967 qla4xxx_create_ipv4_iface(ha);
968
969 if (ha->ip_config.ipv6_options & IPV6_OPT_IPV6_PROTOCOL_ENABLE)
970 qla4xxx_create_ipv6_iface(ha);
971}
972
973static void qla4xxx_destroy_ipv4_iface(struct scsi_qla_host *ha)
974{
975 if (ha->iface_ipv4) {
976 iscsi_destroy_iface(ha->iface_ipv4);
977 ha->iface_ipv4 = NULL;
978 }
979}
980
981static void qla4xxx_destroy_ipv6_iface(struct scsi_qla_host *ha)
982{
983 if (ha->iface_ipv6_0) {
984 iscsi_destroy_iface(ha->iface_ipv6_0);
985 ha->iface_ipv6_0 = NULL;
986 }
987 if (ha->iface_ipv6_1) {
988 iscsi_destroy_iface(ha->iface_ipv6_1);
989 ha->iface_ipv6_1 = NULL;
990 }
991}
992
993static void qla4xxx_destroy_ifaces(struct scsi_qla_host *ha)
994{
995 qla4xxx_destroy_ipv4_iface(ha);
996 qla4xxx_destroy_ipv6_iface(ha);
997}
998
Mike Christied00efe32011-07-25 13:48:38 -0500999static void qla4xxx_set_ipv6(struct scsi_qla_host *ha,
1000 struct iscsi_iface_param_info *iface_param,
1001 struct addr_ctrl_blk *init_fw_cb)
1002{
1003 /*
1004 * iface_num 0 is valid for IPv6 Addr, linklocal, router, autocfg.
1005 * iface_num 1 is valid only for IPv6 Addr.
1006 */
1007 switch (iface_param->param) {
1008 case ISCSI_NET_PARAM_IPV6_ADDR:
1009 if (iface_param->iface_num & 0x1)
1010 /* IPv6 Addr 1 */
1011 memcpy(init_fw_cb->ipv6_addr1, iface_param->value,
1012 sizeof(init_fw_cb->ipv6_addr1));
1013 else
1014 /* IPv6 Addr 0 */
1015 memcpy(init_fw_cb->ipv6_addr0, iface_param->value,
1016 sizeof(init_fw_cb->ipv6_addr0));
1017 break;
1018 case ISCSI_NET_PARAM_IPV6_LINKLOCAL:
1019 if (iface_param->iface_num & 0x1)
1020 break;
1021 memcpy(init_fw_cb->ipv6_if_id, &iface_param->value[8],
1022 sizeof(init_fw_cb->ipv6_if_id));
1023 break;
1024 case ISCSI_NET_PARAM_IPV6_ROUTER:
1025 if (iface_param->iface_num & 0x1)
1026 break;
1027 memcpy(init_fw_cb->ipv6_dflt_rtr_addr, iface_param->value,
1028 sizeof(init_fw_cb->ipv6_dflt_rtr_addr));
1029 break;
1030 case ISCSI_NET_PARAM_IPV6_ADDR_AUTOCFG:
1031 /* Autocfg applies to even interface */
1032 if (iface_param->iface_num & 0x1)
1033 break;
1034
1035 if (iface_param->value[0] == ISCSI_IPV6_AUTOCFG_DISABLE)
1036 init_fw_cb->ipv6_addtl_opts &=
1037 cpu_to_le16(
1038 ~IPV6_ADDOPT_NEIGHBOR_DISCOVERY_ADDR_ENABLE);
1039 else if (iface_param->value[0] == ISCSI_IPV6_AUTOCFG_ND_ENABLE)
1040 init_fw_cb->ipv6_addtl_opts |=
1041 cpu_to_le16(
1042 IPV6_ADDOPT_NEIGHBOR_DISCOVERY_ADDR_ENABLE);
1043 else
1044 ql4_printk(KERN_ERR, ha, "Invalid autocfg setting for "
1045 "IPv6 addr\n");
1046 break;
1047 case ISCSI_NET_PARAM_IPV6_LINKLOCAL_AUTOCFG:
1048 /* Autocfg applies to even interface */
1049 if (iface_param->iface_num & 0x1)
1050 break;
1051
1052 if (iface_param->value[0] ==
1053 ISCSI_IPV6_LINKLOCAL_AUTOCFG_ENABLE)
1054 init_fw_cb->ipv6_addtl_opts |= cpu_to_le16(
1055 IPV6_ADDOPT_AUTOCONFIG_LINK_LOCAL_ADDR);
1056 else if (iface_param->value[0] ==
1057 ISCSI_IPV6_LINKLOCAL_AUTOCFG_DISABLE)
1058 init_fw_cb->ipv6_addtl_opts &= cpu_to_le16(
1059 ~IPV6_ADDOPT_AUTOCONFIG_LINK_LOCAL_ADDR);
1060 else
1061 ql4_printk(KERN_ERR, ha, "Invalid autocfg setting for "
1062 "IPv6 linklocal addr\n");
1063 break;
1064 case ISCSI_NET_PARAM_IPV6_ROUTER_AUTOCFG:
1065 /* Autocfg applies to even interface */
1066 if (iface_param->iface_num & 0x1)
1067 break;
1068
1069 if (iface_param->value[0] == ISCSI_IPV6_ROUTER_AUTOCFG_ENABLE)
1070 memset(init_fw_cb->ipv6_dflt_rtr_addr, 0,
1071 sizeof(init_fw_cb->ipv6_dflt_rtr_addr));
1072 break;
1073 case ISCSI_NET_PARAM_IFACE_ENABLE:
Vikas Chaudharyed1086e2011-07-25 13:48:41 -05001074 if (iface_param->value[0] == ISCSI_IFACE_ENABLE) {
Mike Christied00efe32011-07-25 13:48:38 -05001075 init_fw_cb->ipv6_opts |=
1076 cpu_to_le16(IPV6_OPT_IPV6_PROTOCOL_ENABLE);
Vikas Chaudharyed1086e2011-07-25 13:48:41 -05001077 qla4xxx_create_ipv6_iface(ha);
1078 } else {
Mike Christied00efe32011-07-25 13:48:38 -05001079 init_fw_cb->ipv6_opts &=
1080 cpu_to_le16(~IPV6_OPT_IPV6_PROTOCOL_ENABLE &
1081 0xFFFF);
Vikas Chaudharyed1086e2011-07-25 13:48:41 -05001082 qla4xxx_destroy_ipv6_iface(ha);
1083 }
Mike Christied00efe32011-07-25 13:48:38 -05001084 break;
Mike Christie2d636732011-10-11 17:55:11 -05001085 case ISCSI_NET_PARAM_VLAN_TAG:
Mike Christied00efe32011-07-25 13:48:38 -05001086 if (iface_param->len != sizeof(init_fw_cb->ipv6_vlan_tag))
1087 break;
Vikas Chaudhary6ac73e82011-07-25 13:48:49 -05001088 init_fw_cb->ipv6_vlan_tag =
1089 cpu_to_be16(*(uint16_t *)iface_param->value);
1090 break;
1091 case ISCSI_NET_PARAM_VLAN_ENABLED:
1092 if (iface_param->value[0] == ISCSI_VLAN_ENABLE)
1093 init_fw_cb->ipv6_opts |=
1094 cpu_to_le16(IPV6_OPT_VLAN_TAGGING_ENABLE);
1095 else
1096 init_fw_cb->ipv6_opts &=
1097 cpu_to_le16(~IPV6_OPT_VLAN_TAGGING_ENABLE);
Mike Christied00efe32011-07-25 13:48:38 -05001098 break;
Vikas Chaudhary943c1572011-08-01 03:26:13 -07001099 case ISCSI_NET_PARAM_MTU:
1100 init_fw_cb->eth_mtu_size =
1101 cpu_to_le16(*(uint16_t *)iface_param->value);
1102 break;
Vikas Chaudhary2ada7fc2011-08-01 03:26:19 -07001103 case ISCSI_NET_PARAM_PORT:
1104 /* Autocfg applies to even interface */
1105 if (iface_param->iface_num & 0x1)
1106 break;
1107
1108 init_fw_cb->ipv6_port =
1109 cpu_to_le16(*(uint16_t *)iface_param->value);
1110 break;
Mike Christied00efe32011-07-25 13:48:38 -05001111 default:
1112 ql4_printk(KERN_ERR, ha, "Unknown IPv6 param = %d\n",
1113 iface_param->param);
1114 break;
1115 }
1116}
1117
1118static void qla4xxx_set_ipv4(struct scsi_qla_host *ha,
1119 struct iscsi_iface_param_info *iface_param,
1120 struct addr_ctrl_blk *init_fw_cb)
1121{
1122 switch (iface_param->param) {
1123 case ISCSI_NET_PARAM_IPV4_ADDR:
1124 memcpy(init_fw_cb->ipv4_addr, iface_param->value,
1125 sizeof(init_fw_cb->ipv4_addr));
1126 break;
1127 case ISCSI_NET_PARAM_IPV4_SUBNET:
1128 memcpy(init_fw_cb->ipv4_subnet, iface_param->value,
1129 sizeof(init_fw_cb->ipv4_subnet));
1130 break;
1131 case ISCSI_NET_PARAM_IPV4_GW:
1132 memcpy(init_fw_cb->ipv4_gw_addr, iface_param->value,
1133 sizeof(init_fw_cb->ipv4_gw_addr));
1134 break;
1135 case ISCSI_NET_PARAM_IPV4_BOOTPROTO:
1136 if (iface_param->value[0] == ISCSI_BOOTPROTO_DHCP)
1137 init_fw_cb->ipv4_tcp_opts |=
1138 cpu_to_le16(TCPOPT_DHCP_ENABLE);
1139 else if (iface_param->value[0] == ISCSI_BOOTPROTO_STATIC)
1140 init_fw_cb->ipv4_tcp_opts &=
1141 cpu_to_le16(~TCPOPT_DHCP_ENABLE);
1142 else
1143 ql4_printk(KERN_ERR, ha, "Invalid IPv4 bootproto\n");
1144 break;
1145 case ISCSI_NET_PARAM_IFACE_ENABLE:
Vikas Chaudharyed1086e2011-07-25 13:48:41 -05001146 if (iface_param->value[0] == ISCSI_IFACE_ENABLE) {
Mike Christied00efe32011-07-25 13:48:38 -05001147 init_fw_cb->ipv4_ip_opts |=
Vikas Chaudhary2bab08f2011-07-25 13:48:39 -05001148 cpu_to_le16(IPOPT_IPV4_PROTOCOL_ENABLE);
Vikas Chaudharyed1086e2011-07-25 13:48:41 -05001149 qla4xxx_create_ipv4_iface(ha);
1150 } else {
Mike Christied00efe32011-07-25 13:48:38 -05001151 init_fw_cb->ipv4_ip_opts &=
Vikas Chaudhary2bab08f2011-07-25 13:48:39 -05001152 cpu_to_le16(~IPOPT_IPV4_PROTOCOL_ENABLE &
Mike Christied00efe32011-07-25 13:48:38 -05001153 0xFFFF);
Vikas Chaudharyed1086e2011-07-25 13:48:41 -05001154 qla4xxx_destroy_ipv4_iface(ha);
1155 }
Mike Christied00efe32011-07-25 13:48:38 -05001156 break;
Mike Christie2d636732011-10-11 17:55:11 -05001157 case ISCSI_NET_PARAM_VLAN_TAG:
Mike Christied00efe32011-07-25 13:48:38 -05001158 if (iface_param->len != sizeof(init_fw_cb->ipv4_vlan_tag))
1159 break;
Vikas Chaudhary6ac73e82011-07-25 13:48:49 -05001160 init_fw_cb->ipv4_vlan_tag =
1161 cpu_to_be16(*(uint16_t *)iface_param->value);
1162 break;
1163 case ISCSI_NET_PARAM_VLAN_ENABLED:
1164 if (iface_param->value[0] == ISCSI_VLAN_ENABLE)
1165 init_fw_cb->ipv4_ip_opts |=
1166 cpu_to_le16(IPOPT_VLAN_TAGGING_ENABLE);
1167 else
1168 init_fw_cb->ipv4_ip_opts &=
1169 cpu_to_le16(~IPOPT_VLAN_TAGGING_ENABLE);
Mike Christied00efe32011-07-25 13:48:38 -05001170 break;
Vikas Chaudhary943c1572011-08-01 03:26:13 -07001171 case ISCSI_NET_PARAM_MTU:
1172 init_fw_cb->eth_mtu_size =
1173 cpu_to_le16(*(uint16_t *)iface_param->value);
1174 break;
Vikas Chaudhary2ada7fc2011-08-01 03:26:19 -07001175 case ISCSI_NET_PARAM_PORT:
1176 init_fw_cb->ipv4_port =
1177 cpu_to_le16(*(uint16_t *)iface_param->value);
1178 break;
Mike Christied00efe32011-07-25 13:48:38 -05001179 default:
1180 ql4_printk(KERN_ERR, ha, "Unknown IPv4 param = %d\n",
1181 iface_param->param);
1182 break;
1183 }
1184}
1185
1186static void
1187qla4xxx_initcb_to_acb(struct addr_ctrl_blk *init_fw_cb)
1188{
1189 struct addr_ctrl_blk_def *acb;
1190 acb = (struct addr_ctrl_blk_def *)init_fw_cb;
1191 memset(acb->reserved1, 0, sizeof(acb->reserved1));
1192 memset(acb->reserved2, 0, sizeof(acb->reserved2));
1193 memset(acb->reserved3, 0, sizeof(acb->reserved3));
1194 memset(acb->reserved4, 0, sizeof(acb->reserved4));
1195 memset(acb->reserved5, 0, sizeof(acb->reserved5));
1196 memset(acb->reserved6, 0, sizeof(acb->reserved6));
1197 memset(acb->reserved7, 0, sizeof(acb->reserved7));
1198 memset(acb->reserved8, 0, sizeof(acb->reserved8));
1199 memset(acb->reserved9, 0, sizeof(acb->reserved9));
1200 memset(acb->reserved10, 0, sizeof(acb->reserved10));
1201 memset(acb->reserved11, 0, sizeof(acb->reserved11));
1202 memset(acb->reserved12, 0, sizeof(acb->reserved12));
1203 memset(acb->reserved13, 0, sizeof(acb->reserved13));
1204 memset(acb->reserved14, 0, sizeof(acb->reserved14));
1205 memset(acb->reserved15, 0, sizeof(acb->reserved15));
1206}
1207
1208static int
Mike Christie00c31882011-10-06 03:56:59 -05001209qla4xxx_iface_set_param(struct Scsi_Host *shost, void *data, uint32_t len)
Mike Christied00efe32011-07-25 13:48:38 -05001210{
1211 struct scsi_qla_host *ha = to_qla_host(shost);
1212 int rval = 0;
1213 struct iscsi_iface_param_info *iface_param = NULL;
1214 struct addr_ctrl_blk *init_fw_cb = NULL;
1215 dma_addr_t init_fw_cb_dma;
1216 uint32_t mbox_cmd[MBOX_REG_COUNT];
1217 uint32_t mbox_sts[MBOX_REG_COUNT];
Mike Christie00c31882011-10-06 03:56:59 -05001218 uint32_t rem = len;
1219 struct nlattr *attr;
Mike Christied00efe32011-07-25 13:48:38 -05001220
1221 init_fw_cb = dma_alloc_coherent(&ha->pdev->dev,
1222 sizeof(struct addr_ctrl_blk),
1223 &init_fw_cb_dma, GFP_KERNEL);
1224 if (!init_fw_cb) {
1225 ql4_printk(KERN_ERR, ha, "%s: Unable to alloc init_cb\n",
1226 __func__);
1227 return -ENOMEM;
1228 }
1229
1230 memset(init_fw_cb, 0, sizeof(struct addr_ctrl_blk));
1231 memset(&mbox_cmd, 0, sizeof(mbox_cmd));
1232 memset(&mbox_sts, 0, sizeof(mbox_sts));
1233
1234 if (qla4xxx_get_ifcb(ha, &mbox_cmd[0], &mbox_sts[0], init_fw_cb_dma)) {
1235 ql4_printk(KERN_ERR, ha, "%s: get ifcb failed\n", __func__);
1236 rval = -EIO;
1237 goto exit_init_fw_cb;
1238 }
1239
Mike Christie00c31882011-10-06 03:56:59 -05001240 nla_for_each_attr(attr, data, len, rem) {
1241 iface_param = nla_data(attr);
Mike Christied00efe32011-07-25 13:48:38 -05001242
1243 if (iface_param->param_type != ISCSI_NET_PARAM)
1244 continue;
1245
1246 switch (iface_param->iface_type) {
1247 case ISCSI_IFACE_TYPE_IPV4:
1248 switch (iface_param->iface_num) {
1249 case 0:
1250 qla4xxx_set_ipv4(ha, iface_param, init_fw_cb);
1251 break;
1252 default:
1253 /* Cannot have more than one IPv4 interface */
1254 ql4_printk(KERN_ERR, ha, "Invalid IPv4 iface "
1255 "number = %d\n",
1256 iface_param->iface_num);
1257 break;
1258 }
1259 break;
1260 case ISCSI_IFACE_TYPE_IPV6:
1261 switch (iface_param->iface_num) {
1262 case 0:
1263 case 1:
1264 qla4xxx_set_ipv6(ha, iface_param, init_fw_cb);
1265 break;
1266 default:
1267 /* Cannot have more than two IPv6 interface */
1268 ql4_printk(KERN_ERR, ha, "Invalid IPv6 iface "
1269 "number = %d\n",
1270 iface_param->iface_num);
1271 break;
1272 }
1273 break;
1274 default:
1275 ql4_printk(KERN_ERR, ha, "Invalid iface type\n");
1276 break;
1277 }
Mike Christied00efe32011-07-25 13:48:38 -05001278 }
1279
1280 init_fw_cb->cookie = cpu_to_le32(0x11BEAD5A);
1281
1282 rval = qla4xxx_set_flash(ha, init_fw_cb_dma, FLASH_SEGMENT_IFCB,
1283 sizeof(struct addr_ctrl_blk),
1284 FLASH_OPT_RMW_COMMIT);
1285 if (rval != QLA_SUCCESS) {
1286 ql4_printk(KERN_ERR, ha, "%s: set flash mbx failed\n",
1287 __func__);
1288 rval = -EIO;
1289 goto exit_init_fw_cb;
1290 }
1291
Vikas Chaudharyce505f92011-12-01 22:42:10 -08001292 rval = qla4xxx_disable_acb(ha);
1293 if (rval != QLA_SUCCESS) {
1294 ql4_printk(KERN_ERR, ha, "%s: disable acb mbx failed\n",
1295 __func__);
1296 rval = -EIO;
1297 goto exit_init_fw_cb;
1298 }
1299
1300 wait_for_completion_timeout(&ha->disable_acb_comp,
1301 DISABLE_ACB_TOV * HZ);
Mike Christied00efe32011-07-25 13:48:38 -05001302
1303 qla4xxx_initcb_to_acb(init_fw_cb);
1304
1305 rval = qla4xxx_set_acb(ha, &mbox_cmd[0], &mbox_sts[0], init_fw_cb_dma);
1306 if (rval != QLA_SUCCESS) {
1307 ql4_printk(KERN_ERR, ha, "%s: set acb mbx failed\n",
1308 __func__);
1309 rval = -EIO;
1310 goto exit_init_fw_cb;
1311 }
1312
1313 memset(init_fw_cb, 0, sizeof(struct addr_ctrl_blk));
1314 qla4xxx_update_local_ifcb(ha, &mbox_cmd[0], &mbox_sts[0], init_fw_cb,
1315 init_fw_cb_dma);
1316
1317exit_init_fw_cb:
1318 dma_free_coherent(&ha->pdev->dev, sizeof(struct addr_ctrl_blk),
1319 init_fw_cb, init_fw_cb_dma);
1320
1321 return rval;
1322}
1323
Mike Christiefca9f042012-02-27 03:08:54 -08001324static int qla4xxx_session_get_param(struct iscsi_cls_session *cls_sess,
1325 enum iscsi_param param, char *buf)
1326{
1327 struct iscsi_session *sess = cls_sess->dd_data;
1328 struct ddb_entry *ddb_entry = sess->dd_data;
1329 struct scsi_qla_host *ha = ddb_entry->ha;
1330 int rval, len;
1331 uint16_t idx;
1332
1333 switch (param) {
1334 case ISCSI_PARAM_CHAP_IN_IDX:
1335 rval = qla4xxx_get_chap_index(ha, sess->username_in,
1336 sess->password_in, BIDI_CHAP,
1337 &idx);
1338 if (rval)
1339 return -EINVAL;
1340
1341 len = sprintf(buf, "%hu\n", idx);
1342 break;
1343 case ISCSI_PARAM_CHAP_OUT_IDX:
1344 rval = qla4xxx_get_chap_index(ha, sess->username,
1345 sess->password, LOCAL_CHAP,
1346 &idx);
1347 if (rval)
1348 return -EINVAL;
1349
1350 len = sprintf(buf, "%hu\n", idx);
1351 break;
1352 default:
1353 return iscsi_session_get_param(cls_sess, param, buf);
1354 }
1355
1356 return len;
1357}
1358
Manish Rangankarb3a271a2011-07-25 13:48:53 -05001359static int qla4xxx_conn_get_param(struct iscsi_cls_conn *cls_conn,
David Somayajuluafaf5a22006-09-19 10:28:00 -07001360 enum iscsi_param param, char *buf)
1361{
Manish Rangankarb3a271a2011-07-25 13:48:53 -05001362 struct iscsi_conn *conn;
1363 struct qla_conn *qla_conn;
1364 struct sockaddr *dst_addr;
1365 int len = 0;
David Somayajuluafaf5a22006-09-19 10:28:00 -07001366
Manish Rangankarb3a271a2011-07-25 13:48:53 -05001367 conn = cls_conn->dd_data;
1368 qla_conn = conn->dd_data;
Manish Rangankard46bdeb2012-08-07 07:57:13 -04001369 dst_addr = (struct sockaddr *)&qla_conn->qla_ep->dst_addr;
David Somayajuluafaf5a22006-09-19 10:28:00 -07001370
1371 switch (param) {
1372 case ISCSI_PARAM_CONN_PORT:
David Somayajuluafaf5a22006-09-19 10:28:00 -07001373 case ISCSI_PARAM_CONN_ADDRESS:
Manish Rangankarb3a271a2011-07-25 13:48:53 -05001374 return iscsi_conn_get_addr_param((struct sockaddr_storage *)
1375 dst_addr, param, buf);
David Somayajuluafaf5a22006-09-19 10:28:00 -07001376 default:
Manish Rangankarb3a271a2011-07-25 13:48:53 -05001377 return iscsi_conn_get_param(cls_conn, param, buf);
David Somayajuluafaf5a22006-09-19 10:28:00 -07001378 }
1379
1380 return len;
Manish Rangankarb3a271a2011-07-25 13:48:53 -05001381
David Somayajuluafaf5a22006-09-19 10:28:00 -07001382}
1383
Mike Christie13483732011-12-01 21:38:41 -06001384int qla4xxx_get_ddb_index(struct scsi_qla_host *ha, uint16_t *ddb_index)
1385{
1386 uint32_t mbx_sts = 0;
1387 uint16_t tmp_ddb_index;
1388 int ret;
1389
1390get_ddb_index:
1391 tmp_ddb_index = find_first_zero_bit(ha->ddb_idx_map, MAX_DDB_ENTRIES);
1392
1393 if (tmp_ddb_index >= MAX_DDB_ENTRIES) {
1394 DEBUG2(ql4_printk(KERN_INFO, ha,
1395 "Free DDB index not available\n"));
1396 ret = QLA_ERROR;
1397 goto exit_get_ddb_index;
1398 }
1399
1400 if (test_and_set_bit(tmp_ddb_index, ha->ddb_idx_map))
1401 goto get_ddb_index;
1402
1403 DEBUG2(ql4_printk(KERN_INFO, ha,
1404 "Found a free DDB index at %d\n", tmp_ddb_index));
1405 ret = qla4xxx_req_ddb_entry(ha, tmp_ddb_index, &mbx_sts);
1406 if (ret == QLA_ERROR) {
1407 if (mbx_sts == MBOX_STS_COMMAND_ERROR) {
1408 ql4_printk(KERN_INFO, ha,
1409 "DDB index = %d not available trying next\n",
1410 tmp_ddb_index);
1411 goto get_ddb_index;
1412 }
1413 DEBUG2(ql4_printk(KERN_INFO, ha,
1414 "Free FW DDB not available\n"));
1415 }
1416
1417 *ddb_index = tmp_ddb_index;
1418
1419exit_get_ddb_index:
1420 return ret;
1421}
1422
1423static int qla4xxx_match_ipaddress(struct scsi_qla_host *ha,
1424 struct ddb_entry *ddb_entry,
1425 char *existing_ipaddr,
1426 char *user_ipaddr)
1427{
1428 uint8_t dst_ipaddr[IPv6_ADDR_LEN];
1429 char formatted_ipaddr[DDB_IPADDR_LEN];
1430 int status = QLA_SUCCESS, ret = 0;
1431
1432 if (ddb_entry->fw_ddb_entry.options & DDB_OPT_IPV6_DEVICE) {
1433 ret = in6_pton(user_ipaddr, strlen(user_ipaddr), dst_ipaddr,
1434 '\0', NULL);
1435 if (ret == 0) {
1436 status = QLA_ERROR;
1437 goto out_match;
1438 }
1439 ret = sprintf(formatted_ipaddr, "%pI6", dst_ipaddr);
1440 } else {
1441 ret = in4_pton(user_ipaddr, strlen(user_ipaddr), dst_ipaddr,
1442 '\0', NULL);
1443 if (ret == 0) {
1444 status = QLA_ERROR;
1445 goto out_match;
1446 }
1447 ret = sprintf(formatted_ipaddr, "%pI4", dst_ipaddr);
1448 }
1449
1450 if (strcmp(existing_ipaddr, formatted_ipaddr))
1451 status = QLA_ERROR;
1452
1453out_match:
1454 return status;
1455}
1456
1457static int qla4xxx_match_fwdb_session(struct scsi_qla_host *ha,
1458 struct iscsi_cls_conn *cls_conn)
1459{
1460 int idx = 0, max_ddbs, rval;
1461 struct iscsi_cls_session *cls_sess = iscsi_conn_to_session(cls_conn);
1462 struct iscsi_session *sess, *existing_sess;
1463 struct iscsi_conn *conn, *existing_conn;
1464 struct ddb_entry *ddb_entry;
1465
1466 sess = cls_sess->dd_data;
1467 conn = cls_conn->dd_data;
1468
1469 if (sess->targetname == NULL ||
1470 conn->persistent_address == NULL ||
1471 conn->persistent_port == 0)
1472 return QLA_ERROR;
1473
1474 max_ddbs = is_qla40XX(ha) ? MAX_DEV_DB_ENTRIES_40XX :
1475 MAX_DEV_DB_ENTRIES;
1476
1477 for (idx = 0; idx < max_ddbs; idx++) {
1478 ddb_entry = qla4xxx_lookup_ddb_by_fw_index(ha, idx);
1479 if (ddb_entry == NULL)
1480 continue;
1481
1482 if (ddb_entry->ddb_type != FLASH_DDB)
1483 continue;
1484
1485 existing_sess = ddb_entry->sess->dd_data;
1486 existing_conn = ddb_entry->conn->dd_data;
1487
1488 if (existing_sess->targetname == NULL ||
1489 existing_conn->persistent_address == NULL ||
1490 existing_conn->persistent_port == 0)
1491 continue;
1492
1493 DEBUG2(ql4_printk(KERN_INFO, ha,
1494 "IQN = %s User IQN = %s\n",
1495 existing_sess->targetname,
1496 sess->targetname));
1497
1498 DEBUG2(ql4_printk(KERN_INFO, ha,
1499 "IP = %s User IP = %s\n",
1500 existing_conn->persistent_address,
1501 conn->persistent_address));
1502
1503 DEBUG2(ql4_printk(KERN_INFO, ha,
1504 "Port = %d User Port = %d\n",
1505 existing_conn->persistent_port,
1506 conn->persistent_port));
1507
1508 if (strcmp(existing_sess->targetname, sess->targetname))
1509 continue;
1510 rval = qla4xxx_match_ipaddress(ha, ddb_entry,
1511 existing_conn->persistent_address,
1512 conn->persistent_address);
1513 if (rval == QLA_ERROR)
1514 continue;
1515 if (existing_conn->persistent_port != conn->persistent_port)
1516 continue;
1517 break;
1518 }
1519
1520 if (idx == max_ddbs)
1521 return QLA_ERROR;
1522
1523 DEBUG2(ql4_printk(KERN_INFO, ha,
1524 "Match found in fwdb sessions\n"));
1525 return QLA_SUCCESS;
1526}
1527
Manish Rangankarb3a271a2011-07-25 13:48:53 -05001528static struct iscsi_cls_session *
1529qla4xxx_session_create(struct iscsi_endpoint *ep,
1530 uint16_t cmds_max, uint16_t qdepth,
1531 uint32_t initial_cmdsn)
1532{
1533 struct iscsi_cls_session *cls_sess;
1534 struct scsi_qla_host *ha;
1535 struct qla_endpoint *qla_ep;
1536 struct ddb_entry *ddb_entry;
Mike Christie13483732011-12-01 21:38:41 -06001537 uint16_t ddb_index;
Manish Rangankarb3a271a2011-07-25 13:48:53 -05001538 struct iscsi_session *sess;
1539 struct sockaddr *dst_addr;
1540 int ret;
1541
1542 DEBUG2(printk(KERN_INFO "Func: %s\n", __func__));
1543 if (!ep) {
1544 printk(KERN_ERR "qla4xxx: missing ep.\n");
1545 return NULL;
1546 }
1547
1548 qla_ep = ep->dd_data;
1549 dst_addr = (struct sockaddr *)&qla_ep->dst_addr;
1550 ha = to_qla_host(qla_ep->host);
Manish Rangankar736cf362011-10-07 16:55:46 -07001551
Mike Christie13483732011-12-01 21:38:41 -06001552 ret = qla4xxx_get_ddb_index(ha, &ddb_index);
1553 if (ret == QLA_ERROR)
Manish Rangankarb3a271a2011-07-25 13:48:53 -05001554 return NULL;
Manish Rangankarb3a271a2011-07-25 13:48:53 -05001555
1556 cls_sess = iscsi_session_setup(&qla4xxx_iscsi_transport, qla_ep->host,
1557 cmds_max, sizeof(struct ddb_entry),
1558 sizeof(struct ql4_task_data),
1559 initial_cmdsn, ddb_index);
1560 if (!cls_sess)
1561 return NULL;
1562
1563 sess = cls_sess->dd_data;
1564 ddb_entry = sess->dd_data;
1565 ddb_entry->fw_ddb_index = ddb_index;
1566 ddb_entry->fw_ddb_device_state = DDB_DS_NO_CONNECTION_ACTIVE;
1567 ddb_entry->ha = ha;
1568 ddb_entry->sess = cls_sess;
Mike Christie13483732011-12-01 21:38:41 -06001569 ddb_entry->unblock_sess = qla4xxx_unblock_ddb;
1570 ddb_entry->ddb_change = qla4xxx_ddb_change;
Manish Rangankarb3a271a2011-07-25 13:48:53 -05001571 cls_sess->recovery_tmo = ql4xsess_recovery_tmo;
1572 ha->fw_ddb_index_map[ddb_entry->fw_ddb_index] = ddb_entry;
1573 ha->tot_ddbs++;
1574
1575 return cls_sess;
1576}
1577
1578static void qla4xxx_session_destroy(struct iscsi_cls_session *cls_sess)
1579{
1580 struct iscsi_session *sess;
1581 struct ddb_entry *ddb_entry;
1582 struct scsi_qla_host *ha;
Manish Rangankar90599b62012-04-23 22:32:34 -07001583 unsigned long flags, wtime;
1584 struct dev_db_entry *fw_ddb_entry = NULL;
1585 dma_addr_t fw_ddb_entry_dma;
1586 uint32_t ddb_state;
1587 int ret;
Manish Rangankarb3a271a2011-07-25 13:48:53 -05001588
1589 DEBUG2(printk(KERN_INFO "Func: %s\n", __func__));
1590 sess = cls_sess->dd_data;
1591 ddb_entry = sess->dd_data;
1592 ha = ddb_entry->ha;
1593
Manish Rangankar90599b62012-04-23 22:32:34 -07001594 fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
1595 &fw_ddb_entry_dma, GFP_KERNEL);
1596 if (!fw_ddb_entry) {
1597 ql4_printk(KERN_ERR, ha,
1598 "%s: Unable to allocate dma buffer\n", __func__);
1599 goto destroy_session;
1600 }
1601
1602 wtime = jiffies + (HZ * LOGOUT_TOV);
1603 do {
1604 ret = qla4xxx_get_fwddb_entry(ha, ddb_entry->fw_ddb_index,
1605 fw_ddb_entry, fw_ddb_entry_dma,
1606 NULL, NULL, &ddb_state, NULL,
1607 NULL, NULL);
1608 if (ret == QLA_ERROR)
1609 goto destroy_session;
1610
1611 if ((ddb_state == DDB_DS_NO_CONNECTION_ACTIVE) ||
1612 (ddb_state == DDB_DS_SESSION_FAILED))
1613 goto destroy_session;
1614
1615 schedule_timeout_uninterruptible(HZ);
1616 } while ((time_after(wtime, jiffies)));
1617
1618destroy_session:
Manish Rangankar736cf362011-10-07 16:55:46 -07001619 qla4xxx_clear_ddb_entry(ha, ddb_entry->fw_ddb_index);
1620
Manish Rangankarb3a271a2011-07-25 13:48:53 -05001621 spin_lock_irqsave(&ha->hardware_lock, flags);
1622 qla4xxx_free_ddb(ha, ddb_entry);
1623 spin_unlock_irqrestore(&ha->hardware_lock, flags);
Manish Rangankar90599b62012-04-23 22:32:34 -07001624
Manish Rangankarb3a271a2011-07-25 13:48:53 -05001625 iscsi_session_teardown(cls_sess);
Manish Rangankar90599b62012-04-23 22:32:34 -07001626
1627 if (fw_ddb_entry)
1628 dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
1629 fw_ddb_entry, fw_ddb_entry_dma);
Manish Rangankarb3a271a2011-07-25 13:48:53 -05001630}
1631
Manish Rangankarb3a271a2011-07-25 13:48:53 -05001632static struct iscsi_cls_conn *
1633qla4xxx_conn_create(struct iscsi_cls_session *cls_sess, uint32_t conn_idx)
1634{
1635 struct iscsi_cls_conn *cls_conn;
1636 struct iscsi_session *sess;
1637 struct ddb_entry *ddb_entry;
1638
1639 DEBUG2(printk(KERN_INFO "Func: %s\n", __func__));
1640 cls_conn = iscsi_conn_setup(cls_sess, sizeof(struct qla_conn),
1641 conn_idx);
Mike Christieff1d0312011-12-01 21:38:43 -06001642 if (!cls_conn)
1643 return NULL;
1644
Manish Rangankarb3a271a2011-07-25 13:48:53 -05001645 sess = cls_sess->dd_data;
1646 ddb_entry = sess->dd_data;
1647 ddb_entry->conn = cls_conn;
1648
1649 return cls_conn;
1650}
1651
1652static int qla4xxx_conn_bind(struct iscsi_cls_session *cls_session,
1653 struct iscsi_cls_conn *cls_conn,
1654 uint64_t transport_fd, int is_leading)
1655{
1656 struct iscsi_conn *conn;
1657 struct qla_conn *qla_conn;
1658 struct iscsi_endpoint *ep;
1659
1660 DEBUG2(printk(KERN_INFO "Func: %s\n", __func__));
1661
1662 if (iscsi_conn_bind(cls_session, cls_conn, is_leading))
1663 return -EINVAL;
1664 ep = iscsi_lookup_endpoint(transport_fd);
1665 conn = cls_conn->dd_data;
1666 qla_conn = conn->dd_data;
1667 qla_conn->qla_ep = ep->dd_data;
1668 return 0;
1669}
1670
1671static int qla4xxx_conn_start(struct iscsi_cls_conn *cls_conn)
1672{
1673 struct iscsi_cls_session *cls_sess = iscsi_conn_to_session(cls_conn);
1674 struct iscsi_session *sess;
1675 struct ddb_entry *ddb_entry;
1676 struct scsi_qla_host *ha;
Mike Christie13483732011-12-01 21:38:41 -06001677 struct dev_db_entry *fw_ddb_entry = NULL;
Manish Rangankarb3a271a2011-07-25 13:48:53 -05001678 dma_addr_t fw_ddb_entry_dma;
Manish Rangankarb3a271a2011-07-25 13:48:53 -05001679 uint32_t mbx_sts = 0;
1680 int ret = 0;
1681 int status = QLA_SUCCESS;
1682
1683 DEBUG2(printk(KERN_INFO "Func: %s\n", __func__));
1684 sess = cls_sess->dd_data;
1685 ddb_entry = sess->dd_data;
1686 ha = ddb_entry->ha;
1687
Mike Christie13483732011-12-01 21:38:41 -06001688 /* Check if we have matching FW DDB, if yes then do not
1689 * login to this target. This could cause target to logout previous
1690 * connection
1691 */
1692 ret = qla4xxx_match_fwdb_session(ha, cls_conn);
1693 if (ret == QLA_SUCCESS) {
1694 ql4_printk(KERN_INFO, ha,
1695 "Session already exist in FW.\n");
1696 ret = -EEXIST;
1697 goto exit_conn_start;
1698 }
1699
Manish Rangankarb3a271a2011-07-25 13:48:53 -05001700 fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
1701 &fw_ddb_entry_dma, GFP_KERNEL);
1702 if (!fw_ddb_entry) {
1703 ql4_printk(KERN_ERR, ha,
1704 "%s: Unable to allocate dma buffer\n", __func__);
Mike Christie13483732011-12-01 21:38:41 -06001705 ret = -ENOMEM;
1706 goto exit_conn_start;
Manish Rangankarb3a271a2011-07-25 13:48:53 -05001707 }
1708
1709 ret = qla4xxx_set_param_ddbentry(ha, ddb_entry, cls_conn, &mbx_sts);
1710 if (ret) {
1711 /* If iscsid is stopped and started then no need to do
1712 * set param again since ddb state will be already
1713 * active and FW does not allow set ddb to an
1714 * active session.
1715 */
1716 if (mbx_sts)
1717 if (ddb_entry->fw_ddb_device_state ==
Manish Rangankarf922da72011-10-07 16:55:49 -07001718 DDB_DS_SESSION_ACTIVE) {
Mike Christie13483732011-12-01 21:38:41 -06001719 ddb_entry->unblock_sess(ddb_entry->sess);
Manish Rangankarb3a271a2011-07-25 13:48:53 -05001720 goto exit_set_param;
Manish Rangankarf922da72011-10-07 16:55:49 -07001721 }
Manish Rangankarb3a271a2011-07-25 13:48:53 -05001722
1723 ql4_printk(KERN_ERR, ha, "%s: Failed set param for index[%d]\n",
1724 __func__, ddb_entry->fw_ddb_index);
1725 goto exit_conn_start;
1726 }
1727
1728 status = qla4xxx_conn_open(ha, ddb_entry->fw_ddb_index);
1729 if (status == QLA_ERROR) {
Manish Rangankar0e7e8502011-07-25 13:48:54 -05001730 ql4_printk(KERN_ERR, ha, "%s: Login failed: %s\n", __func__,
1731 sess->targetname);
Manish Rangankarb3a271a2011-07-25 13:48:53 -05001732 ret = -EINVAL;
1733 goto exit_conn_start;
1734 }
1735
Manish Rangankar98270ab2011-10-07 16:55:47 -07001736 if (ddb_entry->fw_ddb_device_state == DDB_DS_NO_CONNECTION_ACTIVE)
1737 ddb_entry->fw_ddb_device_state = DDB_DS_LOGIN_IN_PROCESS;
1738
1739 DEBUG2(printk(KERN_INFO "%s: DDB state [%d]\n", __func__,
1740 ddb_entry->fw_ddb_device_state));
Manish Rangankarb3a271a2011-07-25 13:48:53 -05001741
1742exit_set_param:
Manish Rangankarb3a271a2011-07-25 13:48:53 -05001743 ret = 0;
1744
1745exit_conn_start:
Mike Christie13483732011-12-01 21:38:41 -06001746 if (fw_ddb_entry)
1747 dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
1748 fw_ddb_entry, fw_ddb_entry_dma);
Manish Rangankarb3a271a2011-07-25 13:48:53 -05001749 return ret;
1750}
1751
1752static void qla4xxx_conn_destroy(struct iscsi_cls_conn *cls_conn)
1753{
1754 struct iscsi_cls_session *cls_sess = iscsi_conn_to_session(cls_conn);
1755 struct iscsi_session *sess;
1756 struct scsi_qla_host *ha;
1757 struct ddb_entry *ddb_entry;
1758 int options;
1759
1760 DEBUG2(printk(KERN_INFO "Func: %s\n", __func__));
1761 sess = cls_sess->dd_data;
1762 ddb_entry = sess->dd_data;
1763 ha = ddb_entry->ha;
1764
1765 options = LOGOUT_OPTION_CLOSE_SESSION;
1766 if (qla4xxx_session_logout_ddb(ha, ddb_entry, options) == QLA_ERROR)
1767 ql4_printk(KERN_ERR, ha, "%s: Logout failed\n", __func__);
Manish Rangankarb3a271a2011-07-25 13:48:53 -05001768}
1769
1770static void qla4xxx_task_work(struct work_struct *wdata)
1771{
1772 struct ql4_task_data *task_data;
1773 struct scsi_qla_host *ha;
1774 struct passthru_status *sts;
1775 struct iscsi_task *task;
1776 struct iscsi_hdr *hdr;
1777 uint8_t *data;
1778 uint32_t data_len;
1779 struct iscsi_conn *conn;
1780 int hdr_len;
1781 itt_t itt;
1782
1783 task_data = container_of(wdata, struct ql4_task_data, task_work);
1784 ha = task_data->ha;
1785 task = task_data->task;
1786 sts = &task_data->sts;
1787 hdr_len = sizeof(struct iscsi_hdr);
1788
1789 DEBUG3(printk(KERN_INFO "Status returned\n"));
1790 DEBUG3(qla4xxx_dump_buffer(sts, 64));
1791 DEBUG3(printk(KERN_INFO "Response buffer"));
1792 DEBUG3(qla4xxx_dump_buffer(task_data->resp_buffer, 64));
1793
1794 conn = task->conn;
1795
1796 switch (sts->completionStatus) {
1797 case PASSTHRU_STATUS_COMPLETE:
1798 hdr = (struct iscsi_hdr *)task_data->resp_buffer;
1799 /* Assign back the itt in hdr, until we use the PREASSIGN_TAG */
1800 itt = sts->handle;
1801 hdr->itt = itt;
1802 data = task_data->resp_buffer + hdr_len;
1803 data_len = task_data->resp_len - hdr_len;
1804 iscsi_complete_pdu(conn, hdr, data, data_len);
1805 break;
1806 default:
1807 ql4_printk(KERN_ERR, ha, "Passthru failed status = 0x%x\n",
1808 sts->completionStatus);
1809 break;
1810 }
1811 return;
1812}
1813
1814static int qla4xxx_alloc_pdu(struct iscsi_task *task, uint8_t opcode)
1815{
1816 struct ql4_task_data *task_data;
1817 struct iscsi_session *sess;
1818 struct ddb_entry *ddb_entry;
1819 struct scsi_qla_host *ha;
1820 int hdr_len;
1821
1822 sess = task->conn->session;
1823 ddb_entry = sess->dd_data;
1824 ha = ddb_entry->ha;
1825 task_data = task->dd_data;
1826 memset(task_data, 0, sizeof(struct ql4_task_data));
1827
1828 if (task->sc) {
1829 ql4_printk(KERN_INFO, ha,
1830 "%s: SCSI Commands not implemented\n", __func__);
1831 return -EINVAL;
1832 }
1833
1834 hdr_len = sizeof(struct iscsi_hdr);
1835 task_data->ha = ha;
1836 task_data->task = task;
1837
1838 if (task->data_count) {
1839 task_data->data_dma = dma_map_single(&ha->pdev->dev, task->data,
1840 task->data_count,
1841 PCI_DMA_TODEVICE);
1842 }
1843
1844 DEBUG2(ql4_printk(KERN_INFO, ha, "%s: MaxRecvLen %u, iscsi hrd %d\n",
1845 __func__, task->conn->max_recv_dlength, hdr_len));
1846
Manish Rangankar69ca2162011-10-07 16:55:50 -07001847 task_data->resp_len = task->conn->max_recv_dlength + hdr_len;
Manish Rangankarb3a271a2011-07-25 13:48:53 -05001848 task_data->resp_buffer = dma_alloc_coherent(&ha->pdev->dev,
1849 task_data->resp_len,
1850 &task_data->resp_dma,
1851 GFP_ATOMIC);
1852 if (!task_data->resp_buffer)
1853 goto exit_alloc_pdu;
1854
Manish Rangankar69ca2162011-10-07 16:55:50 -07001855 task_data->req_len = task->data_count + hdr_len;
Manish Rangankarb3a271a2011-07-25 13:48:53 -05001856 task_data->req_buffer = dma_alloc_coherent(&ha->pdev->dev,
Manish Rangankar69ca2162011-10-07 16:55:50 -07001857 task_data->req_len,
Manish Rangankarb3a271a2011-07-25 13:48:53 -05001858 &task_data->req_dma,
1859 GFP_ATOMIC);
1860 if (!task_data->req_buffer)
1861 goto exit_alloc_pdu;
1862
1863 task->hdr = task_data->req_buffer;
1864
1865 INIT_WORK(&task_data->task_work, qla4xxx_task_work);
1866
1867 return 0;
1868
1869exit_alloc_pdu:
1870 if (task_data->resp_buffer)
1871 dma_free_coherent(&ha->pdev->dev, task_data->resp_len,
1872 task_data->resp_buffer, task_data->resp_dma);
1873
1874 if (task_data->req_buffer)
Manish Rangankar69ca2162011-10-07 16:55:50 -07001875 dma_free_coherent(&ha->pdev->dev, task_data->req_len,
Manish Rangankarb3a271a2011-07-25 13:48:53 -05001876 task_data->req_buffer, task_data->req_dma);
1877 return -ENOMEM;
1878}
1879
1880static void qla4xxx_task_cleanup(struct iscsi_task *task)
1881{
1882 struct ql4_task_data *task_data;
1883 struct iscsi_session *sess;
1884 struct ddb_entry *ddb_entry;
1885 struct scsi_qla_host *ha;
1886 int hdr_len;
1887
1888 hdr_len = sizeof(struct iscsi_hdr);
1889 sess = task->conn->session;
1890 ddb_entry = sess->dd_data;
1891 ha = ddb_entry->ha;
1892 task_data = task->dd_data;
1893
1894 if (task->data_count) {
1895 dma_unmap_single(&ha->pdev->dev, task_data->data_dma,
1896 task->data_count, PCI_DMA_TODEVICE);
1897 }
1898
1899 DEBUG2(ql4_printk(KERN_INFO, ha, "%s: MaxRecvLen %u, iscsi hrd %d\n",
1900 __func__, task->conn->max_recv_dlength, hdr_len));
1901
1902 dma_free_coherent(&ha->pdev->dev, task_data->resp_len,
1903 task_data->resp_buffer, task_data->resp_dma);
Manish Rangankar69ca2162011-10-07 16:55:50 -07001904 dma_free_coherent(&ha->pdev->dev, task_data->req_len,
Manish Rangankarb3a271a2011-07-25 13:48:53 -05001905 task_data->req_buffer, task_data->req_dma);
1906 return;
1907}
1908
1909static int qla4xxx_task_xmit(struct iscsi_task *task)
1910{
1911 struct scsi_cmnd *sc = task->sc;
1912 struct iscsi_session *sess = task->conn->session;
1913 struct ddb_entry *ddb_entry = sess->dd_data;
1914 struct scsi_qla_host *ha = ddb_entry->ha;
1915
1916 if (!sc)
1917 return qla4xxx_send_passthru0(task);
1918
1919 ql4_printk(KERN_INFO, ha, "%s: scsi cmd xmit not implemented\n",
1920 __func__);
1921 return -ENOSYS;
1922}
1923
Mike Christie13483732011-12-01 21:38:41 -06001924static void qla4xxx_copy_fwddb_param(struct scsi_qla_host *ha,
1925 struct dev_db_entry *fw_ddb_entry,
1926 struct iscsi_cls_session *cls_sess,
1927 struct iscsi_cls_conn *cls_conn)
1928{
1929 int buflen = 0;
1930 struct iscsi_session *sess;
Nilesh Javali376738a2012-02-27 03:08:52 -08001931 struct ddb_entry *ddb_entry;
Mike Christie13483732011-12-01 21:38:41 -06001932 struct iscsi_conn *conn;
1933 char ip_addr[DDB_IPADDR_LEN];
1934 uint16_t options = 0;
1935
1936 sess = cls_sess->dd_data;
Nilesh Javali376738a2012-02-27 03:08:52 -08001937 ddb_entry = sess->dd_data;
Mike Christie13483732011-12-01 21:38:41 -06001938 conn = cls_conn->dd_data;
1939
Nilesh Javali376738a2012-02-27 03:08:52 -08001940 ddb_entry->chap_tbl_idx = le16_to_cpu(fw_ddb_entry->chap_tbl_idx);
1941
Mike Christie13483732011-12-01 21:38:41 -06001942 conn->max_recv_dlength = BYTE_UNITS *
1943 le16_to_cpu(fw_ddb_entry->iscsi_max_rcv_data_seg_len);
1944
1945 conn->max_xmit_dlength = BYTE_UNITS *
1946 le16_to_cpu(fw_ddb_entry->iscsi_max_snd_data_seg_len);
1947
1948 sess->initial_r2t_en =
1949 (BIT_10 & le16_to_cpu(fw_ddb_entry->iscsi_options));
1950
1951 sess->max_r2t = le16_to_cpu(fw_ddb_entry->iscsi_max_outsnd_r2t);
1952
1953 sess->imm_data_en = (BIT_11 & le16_to_cpu(fw_ddb_entry->iscsi_options));
1954
1955 sess->first_burst = BYTE_UNITS *
1956 le16_to_cpu(fw_ddb_entry->iscsi_first_burst_len);
1957
1958 sess->max_burst = BYTE_UNITS *
1959 le16_to_cpu(fw_ddb_entry->iscsi_max_burst_len);
1960
1961 sess->time2wait = le16_to_cpu(fw_ddb_entry->iscsi_def_time2wait);
1962
1963 sess->time2retain = le16_to_cpu(fw_ddb_entry->iscsi_def_time2retain);
1964
1965 conn->persistent_port = le16_to_cpu(fw_ddb_entry->port);
1966
1967 sess->tpgt = le32_to_cpu(fw_ddb_entry->tgt_portal_grp);
1968
1969 options = le16_to_cpu(fw_ddb_entry->options);
1970 if (options & DDB_OPT_IPV6_DEVICE)
1971 sprintf(ip_addr, "%pI6", fw_ddb_entry->ip_addr);
1972 else
1973 sprintf(ip_addr, "%pI4", fw_ddb_entry->ip_addr);
1974
1975 iscsi_set_param(cls_conn, ISCSI_PARAM_TARGET_NAME,
1976 (char *)fw_ddb_entry->iscsi_name, buflen);
1977 iscsi_set_param(cls_conn, ISCSI_PARAM_INITIATOR_NAME,
1978 (char *)ha->name_string, buflen);
1979 iscsi_set_param(cls_conn, ISCSI_PARAM_PERSISTENT_ADDRESS,
1980 (char *)ip_addr, buflen);
Vikas Chaudhary6c1b8782012-01-19 03:06:54 -08001981 iscsi_set_param(cls_conn, ISCSI_PARAM_TARGET_ALIAS,
1982 (char *)fw_ddb_entry->iscsi_alias, buflen);
Mike Christie13483732011-12-01 21:38:41 -06001983}
1984
1985void qla4xxx_update_session_conn_fwddb_param(struct scsi_qla_host *ha,
1986 struct ddb_entry *ddb_entry)
1987{
1988 struct iscsi_cls_session *cls_sess;
1989 struct iscsi_cls_conn *cls_conn;
1990 uint32_t ddb_state;
1991 dma_addr_t fw_ddb_entry_dma;
1992 struct dev_db_entry *fw_ddb_entry;
1993
1994 fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
1995 &fw_ddb_entry_dma, GFP_KERNEL);
1996 if (!fw_ddb_entry) {
1997 ql4_printk(KERN_ERR, ha,
1998 "%s: Unable to allocate dma buffer\n", __func__);
1999 goto exit_session_conn_fwddb_param;
2000 }
2001
2002 if (qla4xxx_get_fwddb_entry(ha, ddb_entry->fw_ddb_index, fw_ddb_entry,
2003 fw_ddb_entry_dma, NULL, NULL, &ddb_state,
2004 NULL, NULL, NULL) == QLA_ERROR) {
2005 DEBUG2(ql4_printk(KERN_ERR, ha, "scsi%ld: %s: failed "
2006 "get_ddb_entry for fw_ddb_index %d\n",
2007 ha->host_no, __func__,
2008 ddb_entry->fw_ddb_index));
2009 goto exit_session_conn_fwddb_param;
2010 }
2011
2012 cls_sess = ddb_entry->sess;
2013
2014 cls_conn = ddb_entry->conn;
2015
2016 /* Update params */
2017 qla4xxx_copy_fwddb_param(ha, fw_ddb_entry, cls_sess, cls_conn);
2018
2019exit_session_conn_fwddb_param:
2020 if (fw_ddb_entry)
2021 dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
2022 fw_ddb_entry, fw_ddb_entry_dma);
2023}
2024
Manish Rangankarb3a271a2011-07-25 13:48:53 -05002025void qla4xxx_update_session_conn_param(struct scsi_qla_host *ha,
2026 struct ddb_entry *ddb_entry)
2027{
2028 struct iscsi_cls_session *cls_sess;
2029 struct iscsi_cls_conn *cls_conn;
2030 struct iscsi_session *sess;
2031 struct iscsi_conn *conn;
2032 uint32_t ddb_state;
2033 dma_addr_t fw_ddb_entry_dma;
2034 struct dev_db_entry *fw_ddb_entry;
2035
2036 fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
2037 &fw_ddb_entry_dma, GFP_KERNEL);
2038 if (!fw_ddb_entry) {
2039 ql4_printk(KERN_ERR, ha,
2040 "%s: Unable to allocate dma buffer\n", __func__);
Mike Christie13483732011-12-01 21:38:41 -06002041 goto exit_session_conn_param;
Manish Rangankarb3a271a2011-07-25 13:48:53 -05002042 }
2043
2044 if (qla4xxx_get_fwddb_entry(ha, ddb_entry->fw_ddb_index, fw_ddb_entry,
2045 fw_ddb_entry_dma, NULL, NULL, &ddb_state,
2046 NULL, NULL, NULL) == QLA_ERROR) {
2047 DEBUG2(ql4_printk(KERN_ERR, ha, "scsi%ld: %s: failed "
2048 "get_ddb_entry for fw_ddb_index %d\n",
2049 ha->host_no, __func__,
2050 ddb_entry->fw_ddb_index));
Mike Christie13483732011-12-01 21:38:41 -06002051 goto exit_session_conn_param;
Manish Rangankarb3a271a2011-07-25 13:48:53 -05002052 }
2053
2054 cls_sess = ddb_entry->sess;
2055 sess = cls_sess->dd_data;
2056
2057 cls_conn = ddb_entry->conn;
2058 conn = cls_conn->dd_data;
2059
Mike Christie13483732011-12-01 21:38:41 -06002060 /* Update timers after login */
2061 ddb_entry->default_relogin_timeout =
Nilesh Javalic28eaac2011-12-18 21:40:44 -08002062 (le16_to_cpu(fw_ddb_entry->def_timeout) > LOGIN_TOV) &&
2063 (le16_to_cpu(fw_ddb_entry->def_timeout) < LOGIN_TOV * 10) ?
2064 le16_to_cpu(fw_ddb_entry->def_timeout) : LOGIN_TOV;
Mike Christie13483732011-12-01 21:38:41 -06002065 ddb_entry->default_time2wait =
2066 le16_to_cpu(fw_ddb_entry->iscsi_def_time2wait);
2067
Manish Rangankarb3a271a2011-07-25 13:48:53 -05002068 /* Update params */
Nilesh Javali376738a2012-02-27 03:08:52 -08002069 ddb_entry->chap_tbl_idx = le16_to_cpu(fw_ddb_entry->chap_tbl_idx);
Manish Rangankarb3a271a2011-07-25 13:48:53 -05002070 conn->max_recv_dlength = BYTE_UNITS *
2071 le16_to_cpu(fw_ddb_entry->iscsi_max_rcv_data_seg_len);
2072
2073 conn->max_xmit_dlength = BYTE_UNITS *
2074 le16_to_cpu(fw_ddb_entry->iscsi_max_snd_data_seg_len);
2075
2076 sess->initial_r2t_en =
2077 (BIT_10 & le16_to_cpu(fw_ddb_entry->iscsi_options));
2078
2079 sess->max_r2t = le16_to_cpu(fw_ddb_entry->iscsi_max_outsnd_r2t);
2080
2081 sess->imm_data_en = (BIT_11 & le16_to_cpu(fw_ddb_entry->iscsi_options));
2082
2083 sess->first_burst = BYTE_UNITS *
2084 le16_to_cpu(fw_ddb_entry->iscsi_first_burst_len);
2085
2086 sess->max_burst = BYTE_UNITS *
2087 le16_to_cpu(fw_ddb_entry->iscsi_max_burst_len);
2088
2089 sess->time2wait = le16_to_cpu(fw_ddb_entry->iscsi_def_time2wait);
2090
2091 sess->time2retain = le16_to_cpu(fw_ddb_entry->iscsi_def_time2retain);
2092
2093 sess->tpgt = le32_to_cpu(fw_ddb_entry->tgt_portal_grp);
2094
2095 memcpy(sess->initiatorname, ha->name_string,
2096 min(sizeof(ha->name_string), sizeof(sess->initiatorname)));
Mike Christie13483732011-12-01 21:38:41 -06002097
Vikas Chaudhary6c1b8782012-01-19 03:06:54 -08002098 iscsi_set_param(cls_conn, ISCSI_PARAM_TARGET_ALIAS,
2099 (char *)fw_ddb_entry->iscsi_alias, 0);
2100
Mike Christie13483732011-12-01 21:38:41 -06002101exit_session_conn_param:
2102 if (fw_ddb_entry)
2103 dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
2104 fw_ddb_entry, fw_ddb_entry_dma);
Manish Rangankarb3a271a2011-07-25 13:48:53 -05002105}
2106
David Somayajuluafaf5a22006-09-19 10:28:00 -07002107/*
2108 * Timer routines
2109 */
2110
2111static void qla4xxx_start_timer(struct scsi_qla_host *ha, void *func,
2112 unsigned long interval)
2113{
2114 DEBUG(printk("scsi: %s: Starting timer thread for adapter %d\n",
2115 __func__, ha->host->host_no));
2116 init_timer(&ha->timer);
2117 ha->timer.expires = jiffies + interval * HZ;
2118 ha->timer.data = (unsigned long)ha;
2119 ha->timer.function = (void (*)(unsigned long))func;
2120 add_timer(&ha->timer);
2121 ha->timer_active = 1;
2122}
2123
2124static void qla4xxx_stop_timer(struct scsi_qla_host *ha)
2125{
2126 del_timer_sync(&ha->timer);
2127 ha->timer_active = 0;
2128}
2129
2130/***
Manish Rangankarb3a271a2011-07-25 13:48:53 -05002131 * qla4xxx_mark_device_missing - blocks the session
2132 * @cls_session: Pointer to the session to be blocked
David Somayajuluafaf5a22006-09-19 10:28:00 -07002133 * @ddb_entry: Pointer to device database entry
2134 *
Vikas Chaudharyf4f5df22010-07-28 15:53:44 +05302135 * This routine marks a device missing and close connection.
David Somayajuluafaf5a22006-09-19 10:28:00 -07002136 **/
Manish Rangankarb3a271a2011-07-25 13:48:53 -05002137void qla4xxx_mark_device_missing(struct iscsi_cls_session *cls_session)
David Somayajuluafaf5a22006-09-19 10:28:00 -07002138{
Manish Rangankarb3a271a2011-07-25 13:48:53 -05002139 iscsi_block_session(cls_session);
David Somayajuluafaf5a22006-09-19 10:28:00 -07002140}
2141
Vikas Chaudharyf4f5df22010-07-28 15:53:44 +05302142/**
2143 * qla4xxx_mark_all_devices_missing - mark all devices as missing.
2144 * @ha: Pointer to host adapter structure.
2145 *
2146 * This routine marks a device missing and resets the relogin retry count.
2147 **/
2148void qla4xxx_mark_all_devices_missing(struct scsi_qla_host *ha)
2149{
Manish Rangankarb3a271a2011-07-25 13:48:53 -05002150 iscsi_host_for_each_session(ha->host, qla4xxx_mark_device_missing);
Vikas Chaudharyf4f5df22010-07-28 15:53:44 +05302151}
2152
David Somayajuluafaf5a22006-09-19 10:28:00 -07002153static struct srb* qla4xxx_get_new_srb(struct scsi_qla_host *ha,
2154 struct ddb_entry *ddb_entry,
Vikas Chaudhary8f0722c2011-05-17 23:17:10 -07002155 struct scsi_cmnd *cmd)
David Somayajuluafaf5a22006-09-19 10:28:00 -07002156{
2157 struct srb *srb;
2158
2159 srb = mempool_alloc(ha->srb_mempool, GFP_ATOMIC);
2160 if (!srb)
2161 return srb;
2162
Vikas Chaudhary09a0f712010-04-28 11:42:24 +05302163 kref_init(&srb->srb_ref);
David Somayajuluafaf5a22006-09-19 10:28:00 -07002164 srb->ha = ha;
2165 srb->ddb = ddb_entry;
2166 srb->cmd = cmd;
2167 srb->flags = 0;
Vikas Chaudhary53698872010-04-28 11:41:59 +05302168 CMD_SP(cmd) = (void *)srb;
David Somayajuluafaf5a22006-09-19 10:28:00 -07002169
2170 return srb;
2171}
2172
2173static void qla4xxx_srb_free_dma(struct scsi_qla_host *ha, struct srb *srb)
2174{
2175 struct scsi_cmnd *cmd = srb->cmd;
2176
2177 if (srb->flags & SRB_DMA_VALID) {
FUJITA Tomonori5f7186c2007-05-26 14:08:20 +09002178 scsi_dma_unmap(cmd);
David Somayajuluafaf5a22006-09-19 10:28:00 -07002179 srb->flags &= ~SRB_DMA_VALID;
2180 }
Vikas Chaudhary53698872010-04-28 11:41:59 +05302181 CMD_SP(cmd) = NULL;
David Somayajuluafaf5a22006-09-19 10:28:00 -07002182}
2183
Vikas Chaudhary09a0f712010-04-28 11:42:24 +05302184void qla4xxx_srb_compl(struct kref *ref)
David Somayajuluafaf5a22006-09-19 10:28:00 -07002185{
Vikas Chaudhary09a0f712010-04-28 11:42:24 +05302186 struct srb *srb = container_of(ref, struct srb, srb_ref);
David Somayajuluafaf5a22006-09-19 10:28:00 -07002187 struct scsi_cmnd *cmd = srb->cmd;
Vikas Chaudhary09a0f712010-04-28 11:42:24 +05302188 struct scsi_qla_host *ha = srb->ha;
David Somayajuluafaf5a22006-09-19 10:28:00 -07002189
2190 qla4xxx_srb_free_dma(ha, srb);
2191
2192 mempool_free(srb, ha->srb_mempool);
2193
2194 cmd->scsi_done(cmd);
2195}
2196
2197/**
2198 * qla4xxx_queuecommand - scsi layer issues scsi command to driver.
Vikas Chaudhary8f0722c2011-05-17 23:17:10 -07002199 * @host: scsi host
David Somayajuluafaf5a22006-09-19 10:28:00 -07002200 * @cmd: Pointer to Linux's SCSI command structure
David Somayajuluafaf5a22006-09-19 10:28:00 -07002201 *
2202 * Remarks:
2203 * This routine is invoked by Linux to send a SCSI command to the driver.
2204 * The mid-level driver tries to ensure that queuecommand never gets
2205 * invoked concurrently with itself or the interrupt handler (although
2206 * the interrupt handler may call this routine as part of request-
2207 * completion handling). Unfortunely, it sometimes calls the scheduler
2208 * in interrupt context which is a big NO! NO!.
2209 **/
Vikas Chaudhary8f0722c2011-05-17 23:17:10 -07002210static int qla4xxx_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd)
David Somayajuluafaf5a22006-09-19 10:28:00 -07002211{
Vikas Chaudhary8f0722c2011-05-17 23:17:10 -07002212 struct scsi_qla_host *ha = to_qla_host(host);
David Somayajuluafaf5a22006-09-19 10:28:00 -07002213 struct ddb_entry *ddb_entry = cmd->device->hostdata;
Mike Christie7fb19212008-01-31 13:36:45 -06002214 struct iscsi_cls_session *sess = ddb_entry->sess;
David Somayajuluafaf5a22006-09-19 10:28:00 -07002215 struct srb *srb;
2216 int rval;
2217
Lalit Chandivade2232be02010-07-30 14:38:47 +05302218 if (test_bit(AF_EEH_BUSY, &ha->flags)) {
2219 if (test_bit(AF_PCI_CHANNEL_IO_PERM_FAILURE, &ha->flags))
2220 cmd->result = DID_NO_CONNECT << 16;
2221 else
2222 cmd->result = DID_REQUEUE << 16;
2223 goto qc_fail_command;
2224 }
2225
Mike Christie7fb19212008-01-31 13:36:45 -06002226 if (!sess) {
2227 cmd->result = DID_IMM_RETRY << 16;
2228 goto qc_fail_command;
2229 }
2230
2231 rval = iscsi_session_chkready(sess);
2232 if (rval) {
2233 cmd->result = rval;
2234 goto qc_fail_command;
2235 }
2236
Vikas Chaudharyf4f5df22010-07-28 15:53:44 +05302237 if (test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags) ||
2238 test_bit(DPC_RESET_ACTIVE, &ha->dpc_flags) ||
2239 test_bit(DPC_RESET_HA, &ha->dpc_flags) ||
2240 test_bit(DPC_HA_UNRECOVERABLE, &ha->dpc_flags) ||
2241 test_bit(DPC_HA_NEED_QUIESCENT, &ha->dpc_flags) ||
2242 !test_bit(AF_ONLINE, &ha->flags) ||
Manish Rangankarb3a271a2011-07-25 13:48:53 -05002243 !test_bit(AF_LINK_UP, &ha->flags) ||
Vikas Chaudharyf4f5df22010-07-28 15:53:44 +05302244 test_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags))
David C Somayajulu477ffb92007-01-22 12:26:11 -08002245 goto qc_host_busy;
2246
Vikas Chaudhary8f0722c2011-05-17 23:17:10 -07002247 srb = qla4xxx_get_new_srb(ha, ddb_entry, cmd);
David Somayajuluafaf5a22006-09-19 10:28:00 -07002248 if (!srb)
Vikas Chaudhary8f0722c2011-05-17 23:17:10 -07002249 goto qc_host_busy;
David Somayajuluafaf5a22006-09-19 10:28:00 -07002250
2251 rval = qla4xxx_send_command_to_isp(ha, srb);
2252 if (rval != QLA_SUCCESS)
2253 goto qc_host_busy_free_sp;
2254
David Somayajuluafaf5a22006-09-19 10:28:00 -07002255 return 0;
2256
2257qc_host_busy_free_sp:
2258 qla4xxx_srb_free_dma(ha, srb);
2259 mempool_free(srb, ha->srb_mempool);
2260
David Somayajuluafaf5a22006-09-19 10:28:00 -07002261qc_host_busy:
2262 return SCSI_MLQUEUE_HOST_BUSY;
2263
2264qc_fail_command:
Vikas Chaudhary8f0722c2011-05-17 23:17:10 -07002265 cmd->scsi_done(cmd);
David Somayajuluafaf5a22006-09-19 10:28:00 -07002266
2267 return 0;
2268}
2269
2270/**
2271 * qla4xxx_mem_free - frees memory allocated to adapter
2272 * @ha: Pointer to host adapter structure.
2273 *
2274 * Frees memory previously allocated by qla4xxx_mem_alloc
2275 **/
2276static void qla4xxx_mem_free(struct scsi_qla_host *ha)
2277{
2278 if (ha->queues)
2279 dma_free_coherent(&ha->pdev->dev, ha->queues_len, ha->queues,
2280 ha->queues_dma);
2281
Tej Parkash068237c82012-05-18 04:41:44 -04002282 if (ha->fw_dump)
2283 vfree(ha->fw_dump);
2284
David Somayajuluafaf5a22006-09-19 10:28:00 -07002285 ha->queues_len = 0;
2286 ha->queues = NULL;
2287 ha->queues_dma = 0;
2288 ha->request_ring = NULL;
2289 ha->request_dma = 0;
2290 ha->response_ring = NULL;
2291 ha->response_dma = 0;
2292 ha->shadow_regs = NULL;
2293 ha->shadow_regs_dma = 0;
Tej Parkash068237c82012-05-18 04:41:44 -04002294 ha->fw_dump = NULL;
2295 ha->fw_dump_size = 0;
David Somayajuluafaf5a22006-09-19 10:28:00 -07002296
2297 /* Free srb pool. */
2298 if (ha->srb_mempool)
2299 mempool_destroy(ha->srb_mempool);
2300
2301 ha->srb_mempool = NULL;
2302
Manish Rangankarb3a271a2011-07-25 13:48:53 -05002303 if (ha->chap_dma_pool)
2304 dma_pool_destroy(ha->chap_dma_pool);
2305
Lalit Chandivade45494152011-10-07 16:55:42 -07002306 if (ha->chap_list)
2307 vfree(ha->chap_list);
2308 ha->chap_list = NULL;
2309
Mike Christie13483732011-12-01 21:38:41 -06002310 if (ha->fw_ddb_dma_pool)
2311 dma_pool_destroy(ha->fw_ddb_dma_pool);
2312
David Somayajuluafaf5a22006-09-19 10:28:00 -07002313 /* release io space registers */
Vikas Chaudharyf4f5df22010-07-28 15:53:44 +05302314 if (is_qla8022(ha)) {
2315 if (ha->nx_pcibase)
2316 iounmap(
2317 (struct device_reg_82xx __iomem *)ha->nx_pcibase);
Vikas Chaudharyf4f5df22010-07-28 15:53:44 +05302318 } else if (ha->reg)
David Somayajuluafaf5a22006-09-19 10:28:00 -07002319 iounmap(ha->reg);
2320 pci_release_regions(ha->pdev);
2321}
2322
2323/**
2324 * qla4xxx_mem_alloc - allocates memory for use by adapter.
2325 * @ha: Pointer to host adapter structure
2326 *
2327 * Allocates DMA memory for request and response queues. Also allocates memory
2328 * for srbs.
2329 **/
2330static int qla4xxx_mem_alloc(struct scsi_qla_host *ha)
2331{
2332 unsigned long align;
2333
2334 /* Allocate contiguous block of DMA memory for queues. */
2335 ha->queues_len = ((REQUEST_QUEUE_DEPTH * QUEUE_SIZE) +
2336 (RESPONSE_QUEUE_DEPTH * QUEUE_SIZE) +
2337 sizeof(struct shadow_regs) +
2338 MEM_ALIGN_VALUE +
2339 (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1);
2340 ha->queues = dma_alloc_coherent(&ha->pdev->dev, ha->queues_len,
2341 &ha->queues_dma, GFP_KERNEL);
2342 if (ha->queues == NULL) {
Vikas Chaudharyc2660df2010-07-10 14:51:02 +05302343 ql4_printk(KERN_WARNING, ha,
2344 "Memory Allocation failed - queues.\n");
David Somayajuluafaf5a22006-09-19 10:28:00 -07002345
2346 goto mem_alloc_error_exit;
2347 }
2348 memset(ha->queues, 0, ha->queues_len);
2349
2350 /*
2351 * As per RISC alignment requirements -- the bus-address must be a
2352 * multiple of the request-ring size (in bytes).
2353 */
2354 align = 0;
2355 if ((unsigned long)ha->queues_dma & (MEM_ALIGN_VALUE - 1))
2356 align = MEM_ALIGN_VALUE - ((unsigned long)ha->queues_dma &
2357 (MEM_ALIGN_VALUE - 1));
2358
2359 /* Update request and response queue pointers. */
2360 ha->request_dma = ha->queues_dma + align;
2361 ha->request_ring = (struct queue_entry *) (ha->queues + align);
2362 ha->response_dma = ha->queues_dma + align +
2363 (REQUEST_QUEUE_DEPTH * QUEUE_SIZE);
2364 ha->response_ring = (struct queue_entry *) (ha->queues + align +
2365 (REQUEST_QUEUE_DEPTH *
2366 QUEUE_SIZE));
2367 ha->shadow_regs_dma = ha->queues_dma + align +
2368 (REQUEST_QUEUE_DEPTH * QUEUE_SIZE) +
2369 (RESPONSE_QUEUE_DEPTH * QUEUE_SIZE);
2370 ha->shadow_regs = (struct shadow_regs *) (ha->queues + align +
2371 (REQUEST_QUEUE_DEPTH *
2372 QUEUE_SIZE) +
2373 (RESPONSE_QUEUE_DEPTH *
2374 QUEUE_SIZE));
2375
2376 /* Allocate memory for srb pool. */
2377 ha->srb_mempool = mempool_create(SRB_MIN_REQ, mempool_alloc_slab,
2378 mempool_free_slab, srb_cachep);
2379 if (ha->srb_mempool == NULL) {
Vikas Chaudharyc2660df2010-07-10 14:51:02 +05302380 ql4_printk(KERN_WARNING, ha,
2381 "Memory Allocation failed - SRB Pool.\n");
David Somayajuluafaf5a22006-09-19 10:28:00 -07002382
2383 goto mem_alloc_error_exit;
2384 }
2385
Manish Rangankarb3a271a2011-07-25 13:48:53 -05002386 ha->chap_dma_pool = dma_pool_create("ql4_chap", &ha->pdev->dev,
2387 CHAP_DMA_BLOCK_SIZE, 8, 0);
2388
2389 if (ha->chap_dma_pool == NULL) {
2390 ql4_printk(KERN_WARNING, ha,
2391 "%s: chap_dma_pool allocation failed..\n", __func__);
2392 goto mem_alloc_error_exit;
2393 }
2394
Mike Christie13483732011-12-01 21:38:41 -06002395 ha->fw_ddb_dma_pool = dma_pool_create("ql4_fw_ddb", &ha->pdev->dev,
2396 DDB_DMA_BLOCK_SIZE, 8, 0);
2397
2398 if (ha->fw_ddb_dma_pool == NULL) {
2399 ql4_printk(KERN_WARNING, ha,
2400 "%s: fw_ddb_dma_pool allocation failed..\n",
2401 __func__);
2402 goto mem_alloc_error_exit;
2403 }
2404
David Somayajuluafaf5a22006-09-19 10:28:00 -07002405 return QLA_SUCCESS;
2406
2407mem_alloc_error_exit:
2408 qla4xxx_mem_free(ha);
2409 return QLA_ERROR;
2410}
2411
2412/**
Mike Hernandez4f770832012-01-11 02:44:15 -08002413 * qla4_8xxx_check_temp - Check the ISP82XX temperature.
2414 * @ha: adapter block pointer.
2415 *
2416 * Note: The caller should not hold the idc lock.
2417 **/
2418static int qla4_8xxx_check_temp(struct scsi_qla_host *ha)
2419{
2420 uint32_t temp, temp_state, temp_val;
2421 int status = QLA_SUCCESS;
2422
2423 temp = qla4_8xxx_rd_32(ha, CRB_TEMP_STATE);
2424
2425 temp_state = qla82xx_get_temp_state(temp);
2426 temp_val = qla82xx_get_temp_val(temp);
2427
2428 if (temp_state == QLA82XX_TEMP_PANIC) {
2429 ql4_printk(KERN_WARNING, ha, "Device temperature %d degrees C"
2430 " exceeds maximum allowed. Hardware has been shut"
2431 " down.\n", temp_val);
2432 status = QLA_ERROR;
2433 } else if (temp_state == QLA82XX_TEMP_WARN) {
2434 if (ha->temperature == QLA82XX_TEMP_NORMAL)
2435 ql4_printk(KERN_WARNING, ha, "Device temperature %d"
2436 " degrees C exceeds operating range."
2437 " Immediate action needed.\n", temp_val);
2438 } else {
2439 if (ha->temperature == QLA82XX_TEMP_WARN)
2440 ql4_printk(KERN_INFO, ha, "Device temperature is"
2441 " now %d degrees C in normal range.\n",
2442 temp_val);
2443 }
2444 ha->temperature = temp_state;
2445 return status;
2446}
2447
2448/**
Vikas Chaudharyf4f5df22010-07-28 15:53:44 +05302449 * qla4_8xxx_check_fw_alive - Check firmware health
2450 * @ha: Pointer to host adapter structure.
2451 *
2452 * Context: Interrupt
2453 **/
Shyam Sunder9ee91a32011-12-01 22:42:13 -08002454static int qla4_8xxx_check_fw_alive(struct scsi_qla_host *ha)
Vikas Chaudharyf4f5df22010-07-28 15:53:44 +05302455{
Shyam Sunder9ee91a32011-12-01 22:42:13 -08002456 uint32_t fw_heartbeat_counter;
2457 int status = QLA_SUCCESS;
Vikas Chaudharyf4f5df22010-07-28 15:53:44 +05302458
2459 fw_heartbeat_counter = qla4_8xxx_rd_32(ha, QLA82XX_PEG_ALIVE_COUNTER);
Lalit Chandivade2232be02010-07-30 14:38:47 +05302460 /* If PEG_ALIVE_COUNTER is 0xffffffff, AER/EEH is in progress, ignore */
2461 if (fw_heartbeat_counter == 0xffffffff) {
2462 DEBUG2(printk(KERN_WARNING "scsi%ld: %s: Device in frozen "
2463 "state, QLA82XX_PEG_ALIVE_COUNTER is 0xffffffff\n",
2464 ha->host_no, __func__));
Shyam Sunder9ee91a32011-12-01 22:42:13 -08002465 return status;
Lalit Chandivade2232be02010-07-30 14:38:47 +05302466 }
Vikas Chaudharyf4f5df22010-07-28 15:53:44 +05302467
2468 if (ha->fw_heartbeat_counter == fw_heartbeat_counter) {
2469 ha->seconds_since_last_heartbeat++;
2470 /* FW not alive after 2 seconds */
2471 if (ha->seconds_since_last_heartbeat == 2) {
2472 ha->seconds_since_last_heartbeat = 0;
Vikas Chaudhary68d92eb2011-05-17 23:17:05 -07002473
2474 ql4_printk(KERN_INFO, ha,
2475 "scsi(%ld): %s, Dumping hw/fw registers:\n "
2476 " PEG_HALT_STATUS1: 0x%x, PEG_HALT_STATUS2:"
2477 " 0x%x,\n PEG_NET_0_PC: 0x%x, PEG_NET_1_PC:"
2478 " 0x%x,\n PEG_NET_2_PC: 0x%x, PEG_NET_3_PC:"
2479 " 0x%x,\n PEG_NET_4_PC: 0x%x\n",
Shyam Sunder9ee91a32011-12-01 22:42:13 -08002480 ha->host_no, __func__,
2481 qla4_8xxx_rd_32(ha,
2482 QLA82XX_PEG_HALT_STATUS1),
Vikas Chaudhary68d92eb2011-05-17 23:17:05 -07002483 qla4_8xxx_rd_32(ha,
2484 QLA82XX_PEG_HALT_STATUS2),
2485 qla4_8xxx_rd_32(ha, QLA82XX_CRB_PEG_NET_0 +
2486 0x3c),
2487 qla4_8xxx_rd_32(ha, QLA82XX_CRB_PEG_NET_1 +
2488 0x3c),
2489 qla4_8xxx_rd_32(ha, QLA82XX_CRB_PEG_NET_2 +
2490 0x3c),
2491 qla4_8xxx_rd_32(ha, QLA82XX_CRB_PEG_NET_3 +
2492 0x3c),
2493 qla4_8xxx_rd_32(ha, QLA82XX_CRB_PEG_NET_4 +
2494 0x3c));
Shyam Sunder9ee91a32011-12-01 22:42:13 -08002495 status = QLA_ERROR;
Vikas Chaudharyf4f5df22010-07-28 15:53:44 +05302496 }
Lalit Chandivade99457d72010-10-06 22:49:32 -07002497 } else
2498 ha->seconds_since_last_heartbeat = 0;
2499
Vikas Chaudharyf4f5df22010-07-28 15:53:44 +05302500 ha->fw_heartbeat_counter = fw_heartbeat_counter;
Shyam Sunder9ee91a32011-12-01 22:42:13 -08002501 return status;
Vikas Chaudharyf4f5df22010-07-28 15:53:44 +05302502}
2503
2504/**
2505 * qla4_8xxx_watchdog - Poll dev state
2506 * @ha: Pointer to host adapter structure.
2507 *
2508 * Context: Interrupt
2509 **/
2510void qla4_8xxx_watchdog(struct scsi_qla_host *ha)
2511{
Shyam Sunder9ee91a32011-12-01 22:42:13 -08002512 uint32_t dev_state, halt_status;
Vikas Chaudharyf4f5df22010-07-28 15:53:44 +05302513
2514 /* don't poll if reset is going on */
Lalit Chandivaded56a1f72010-12-02 22:12:45 -08002515 if (!(test_bit(DPC_RESET_ACTIVE, &ha->dpc_flags) ||
2516 test_bit(DPC_RESET_HA, &ha->dpc_flags) ||
Vikas Chaudhary977f46a2011-05-17 23:17:08 -07002517 test_bit(DPC_RETRY_RESET_HA, &ha->dpc_flags))) {
Shyam Sunder9ee91a32011-12-01 22:42:13 -08002518 dev_state = qla4_8xxx_rd_32(ha, QLA82XX_CRB_DEV_STATE);
Mike Hernandez4f770832012-01-11 02:44:15 -08002519
2520 if (qla4_8xxx_check_temp(ha)) {
Giridhar Malavalie6bd0eb2012-01-11 02:44:16 -08002521 ql4_printk(KERN_INFO, ha, "disabling pause"
2522 " transmit on port 0 & 1.\n");
2523 qla4_8xxx_wr_32(ha, QLA82XX_CRB_NIU + 0x98,
2524 CRB_NIU_XG_PAUSE_CTL_P0 |
2525 CRB_NIU_XG_PAUSE_CTL_P1);
Mike Hernandez4f770832012-01-11 02:44:15 -08002526 set_bit(DPC_HA_UNRECOVERABLE, &ha->dpc_flags);
2527 qla4xxx_wake_dpc(ha);
2528 } else if (dev_state == QLA82XX_DEV_NEED_RESET &&
Vikas Chaudharyf4f5df22010-07-28 15:53:44 +05302529 !test_bit(DPC_RESET_HA, &ha->dpc_flags)) {
Vikas Chaudhary3930b8c2010-12-02 22:12:47 -08002530 if (!ql4xdontresethba) {
2531 ql4_printk(KERN_INFO, ha, "%s: HW State: "
2532 "NEED RESET!\n", __func__);
2533 set_bit(DPC_RESET_HA, &ha->dpc_flags);
2534 qla4xxx_wake_dpc(ha);
Vikas Chaudhary3930b8c2010-12-02 22:12:47 -08002535 }
Vikas Chaudharyf4f5df22010-07-28 15:53:44 +05302536 } else if (dev_state == QLA82XX_DEV_NEED_QUIESCENT &&
2537 !test_bit(DPC_HA_NEED_QUIESCENT, &ha->dpc_flags)) {
Vikas Chaudhary3930b8c2010-12-02 22:12:47 -08002538 ql4_printk(KERN_INFO, ha, "%s: HW State: NEED QUIES!\n",
2539 __func__);
Vikas Chaudharyf4f5df22010-07-28 15:53:44 +05302540 set_bit(DPC_HA_NEED_QUIESCENT, &ha->dpc_flags);
2541 qla4xxx_wake_dpc(ha);
2542 } else {
2543 /* Check firmware health */
Shyam Sunder9ee91a32011-12-01 22:42:13 -08002544 if (qla4_8xxx_check_fw_alive(ha)) {
Giridhar Malavalie6bd0eb2012-01-11 02:44:16 -08002545 ql4_printk(KERN_INFO, ha, "disabling pause"
2546 " transmit on port 0 & 1.\n");
2547 qla4_8xxx_wr_32(ha, QLA82XX_CRB_NIU + 0x98,
2548 CRB_NIU_XG_PAUSE_CTL_P0 |
2549 CRB_NIU_XG_PAUSE_CTL_P1);
Shyam Sunder9ee91a32011-12-01 22:42:13 -08002550 halt_status = qla4_8xxx_rd_32(ha,
2551 QLA82XX_PEG_HALT_STATUS1);
2552
Vikas Chaudhary46801ba2012-02-13 18:30:45 +05302553 if (QLA82XX_FWERROR_CODE(halt_status) == 0x67)
Nilesh Javali527c8b22012-01-11 02:44:17 -08002554 ql4_printk(KERN_ERR, ha, "%s:"
2555 " Firmware aborted with"
2556 " error code 0x00006700."
2557 " Device is being reset\n",
2558 __func__);
2559
Shyam Sunder9ee91a32011-12-01 22:42:13 -08002560 /* Since we cannot change dev_state in interrupt
2561 * context, set appropriate DPC flag then wakeup
2562 * DPC */
2563 if (halt_status & HALT_STATUS_UNRECOVERABLE)
2564 set_bit(DPC_HA_UNRECOVERABLE,
2565 &ha->dpc_flags);
2566 else {
2567 ql4_printk(KERN_INFO, ha, "%s: detect "
2568 "abort needed!\n", __func__);
2569 set_bit(DPC_RESET_HA, &ha->dpc_flags);
2570 }
2571 qla4xxx_mailbox_premature_completion(ha);
2572 qla4xxx_wake_dpc(ha);
2573 }
Vikas Chaudharyf4f5df22010-07-28 15:53:44 +05302574 }
2575 }
2576}
2577
Lalit Chandivade4a4bc2e2011-12-16 01:58:55 -08002578static void qla4xxx_check_relogin_flash_ddb(struct iscsi_cls_session *cls_sess)
Mike Christie13483732011-12-01 21:38:41 -06002579{
2580 struct iscsi_session *sess;
2581 struct ddb_entry *ddb_entry;
2582 struct scsi_qla_host *ha;
2583
2584 sess = cls_sess->dd_data;
2585 ddb_entry = sess->dd_data;
2586 ha = ddb_entry->ha;
2587
2588 if (!(ddb_entry->ddb_type == FLASH_DDB))
2589 return;
2590
2591 if (adapter_up(ha) && !test_bit(DF_RELOGIN, &ddb_entry->flags) &&
2592 !iscsi_is_session_online(cls_sess)) {
2593 if (atomic_read(&ddb_entry->retry_relogin_timer) !=
2594 INVALID_ENTRY) {
2595 if (atomic_read(&ddb_entry->retry_relogin_timer) ==
2596 0) {
2597 atomic_set(&ddb_entry->retry_relogin_timer,
2598 INVALID_ENTRY);
2599 set_bit(DPC_RELOGIN_DEVICE, &ha->dpc_flags);
2600 set_bit(DF_RELOGIN, &ddb_entry->flags);
2601 DEBUG2(ql4_printk(KERN_INFO, ha,
2602 "%s: index [%d] login device\n",
2603 __func__, ddb_entry->fw_ddb_index));
2604 } else
2605 atomic_dec(&ddb_entry->retry_relogin_timer);
2606 }
2607 }
2608
2609 /* Wait for relogin to timeout */
2610 if (atomic_read(&ddb_entry->relogin_timer) &&
2611 (atomic_dec_and_test(&ddb_entry->relogin_timer) != 0)) {
2612 /*
2613 * If the relogin times out and the device is
2614 * still NOT ONLINE then try and relogin again.
2615 */
2616 if (!iscsi_is_session_online(cls_sess)) {
2617 /* Reset retry relogin timer */
2618 atomic_inc(&ddb_entry->relogin_retry_count);
2619 DEBUG2(ql4_printk(KERN_INFO, ha,
2620 "%s: index[%d] relogin timed out-retrying"
2621 " relogin (%d), retry (%d)\n", __func__,
2622 ddb_entry->fw_ddb_index,
2623 atomic_read(&ddb_entry->relogin_retry_count),
2624 ddb_entry->default_time2wait + 4));
2625 set_bit(DPC_RELOGIN_DEVICE, &ha->dpc_flags);
2626 atomic_set(&ddb_entry->retry_relogin_timer,
2627 ddb_entry->default_time2wait + 4);
2628 }
2629 }
2630}
2631
Vikas Chaudharyf4f5df22010-07-28 15:53:44 +05302632/**
David Somayajuluafaf5a22006-09-19 10:28:00 -07002633 * qla4xxx_timer - checks every second for work to do.
2634 * @ha: Pointer to host adapter structure.
2635 **/
2636static void qla4xxx_timer(struct scsi_qla_host *ha)
2637{
David Somayajuluafaf5a22006-09-19 10:28:00 -07002638 int start_dpc = 0;
Lalit Chandivade2232be02010-07-30 14:38:47 +05302639 uint16_t w;
2640
Mike Christie13483732011-12-01 21:38:41 -06002641 iscsi_host_for_each_session(ha->host, qla4xxx_check_relogin_flash_ddb);
2642
Lalit Chandivade2232be02010-07-30 14:38:47 +05302643 /* If we are in the middle of AER/EEH processing
2644 * skip any processing and reschedule the timer
2645 */
2646 if (test_bit(AF_EEH_BUSY, &ha->flags)) {
2647 mod_timer(&ha->timer, jiffies + HZ);
2648 return;
2649 }
2650
2651 /* Hardware read to trigger an EEH error during mailbox waits. */
2652 if (!pci_channel_offline(ha->pdev))
2653 pci_read_config_word(ha->pdev, PCI_VENDOR_ID, &w);
David Somayajuluafaf5a22006-09-19 10:28:00 -07002654
Vikas Chaudharyf4f5df22010-07-28 15:53:44 +05302655 if (is_qla8022(ha)) {
2656 qla4_8xxx_watchdog(ha);
2657 }
2658
Vikas Chaudharyf4f5df22010-07-28 15:53:44 +05302659 if (!is_qla8022(ha)) {
2660 /* Check for heartbeat interval. */
2661 if (ha->firmware_options & FWOPT_HEARTBEAT_ENABLE &&
2662 ha->heartbeat_interval != 0) {
2663 ha->seconds_since_last_heartbeat++;
2664 if (ha->seconds_since_last_heartbeat >
2665 ha->heartbeat_interval + 2)
2666 set_bit(DPC_RESET_HA, &ha->dpc_flags);
2667 }
David Somayajuluafaf5a22006-09-19 10:28:00 -07002668 }
2669
Vikas Chaudharyff884432011-08-29 23:43:02 +05302670 /* Process any deferred work. */
2671 if (!list_empty(&ha->work_list))
2672 start_dpc++;
2673
David Somayajuluafaf5a22006-09-19 10:28:00 -07002674 /* Wakeup the dpc routine for this adapter, if needed. */
Lalit Chandivade1b468072011-05-17 23:17:09 -07002675 if (start_dpc ||
David Somayajuluafaf5a22006-09-19 10:28:00 -07002676 test_bit(DPC_RESET_HA, &ha->dpc_flags) ||
2677 test_bit(DPC_RETRY_RESET_HA, &ha->dpc_flags) ||
2678 test_bit(DPC_RELOGIN_DEVICE, &ha->dpc_flags) ||
Vikas Chaudharyf4f5df22010-07-28 15:53:44 +05302679 test_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags) ||
David Somayajuluafaf5a22006-09-19 10:28:00 -07002680 test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags) ||
2681 test_bit(DPC_GET_DHCP_IP_ADDR, &ha->dpc_flags) ||
Vikas Chaudhary065aa1b2010-04-28 11:38:11 +05302682 test_bit(DPC_LINK_CHANGED, &ha->dpc_flags) ||
Vikas Chaudharyf4f5df22010-07-28 15:53:44 +05302683 test_bit(DPC_HA_UNRECOVERABLE, &ha->dpc_flags) ||
2684 test_bit(DPC_HA_NEED_QUIESCENT, &ha->dpc_flags) ||
Lalit Chandivade1b468072011-05-17 23:17:09 -07002685 test_bit(DPC_AEN, &ha->dpc_flags)) {
David Somayajuluafaf5a22006-09-19 10:28:00 -07002686 DEBUG2(printk("scsi%ld: %s: scheduling dpc routine"
2687 " - dpc flags = 0x%lx\n",
2688 ha->host_no, __func__, ha->dpc_flags));
Vikas Chaudharyf4f5df22010-07-28 15:53:44 +05302689 qla4xxx_wake_dpc(ha);
David Somayajuluafaf5a22006-09-19 10:28:00 -07002690 }
2691
2692 /* Reschedule timer thread to call us back in one second */
2693 mod_timer(&ha->timer, jiffies + HZ);
2694
2695 DEBUG2(ha->seconds_since_last_intr++);
2696}
2697
2698/**
2699 * qla4xxx_cmd_wait - waits for all outstanding commands to complete
2700 * @ha: Pointer to host adapter structure.
2701 *
2702 * This routine stalls the driver until all outstanding commands are returned.
2703 * Caller must release the Hardware Lock prior to calling this routine.
2704 **/
2705static int qla4xxx_cmd_wait(struct scsi_qla_host *ha)
2706{
2707 uint32_t index = 0;
David Somayajuluafaf5a22006-09-19 10:28:00 -07002708 unsigned long flags;
2709 struct scsi_cmnd *cmd;
David Somayajuluafaf5a22006-09-19 10:28:00 -07002710
Vikas Chaudharyf4f5df22010-07-28 15:53:44 +05302711 unsigned long wtime = jiffies + (WAIT_CMD_TOV * HZ);
2712
2713 DEBUG2(ql4_printk(KERN_INFO, ha, "Wait up to %d seconds for cmds to "
2714 "complete\n", WAIT_CMD_TOV));
2715
2716 while (!time_after_eq(jiffies, wtime)) {
David Somayajuluafaf5a22006-09-19 10:28:00 -07002717 spin_lock_irqsave(&ha->hardware_lock, flags);
2718 /* Find a command that hasn't completed. */
2719 for (index = 0; index < ha->host->can_queue; index++) {
2720 cmd = scsi_host_find_tag(ha->host, index);
Mike Christiea1e00632010-10-26 05:45:30 -07002721 /*
2722 * We cannot just check if the index is valid,
2723 * becase if we are run from the scsi eh, then
2724 * the scsi/block layer is going to prevent
2725 * the tag from being released.
2726 */
2727 if (cmd != NULL && CMD_SP(cmd))
David Somayajuluafaf5a22006-09-19 10:28:00 -07002728 break;
2729 }
2730 spin_unlock_irqrestore(&ha->hardware_lock, flags);
2731
2732 /* If No Commands are pending, wait is complete */
Vikas Chaudharyf4f5df22010-07-28 15:53:44 +05302733 if (index == ha->host->can_queue)
2734 return QLA_SUCCESS;
David Somayajuluafaf5a22006-09-19 10:28:00 -07002735
Vikas Chaudharyf4f5df22010-07-28 15:53:44 +05302736 msleep(1000);
2737 }
2738 /* If we timed out on waiting for commands to come back
2739 * return ERROR. */
2740 return QLA_ERROR;
David Somayajuluafaf5a22006-09-19 10:28:00 -07002741}
2742
Vikas Chaudharyf4f5df22010-07-28 15:53:44 +05302743int qla4xxx_hw_reset(struct scsi_qla_host *ha)
David Somayajuluafaf5a22006-09-19 10:28:00 -07002744{
David Somayajuluafaf5a22006-09-19 10:28:00 -07002745 uint32_t ctrl_status;
David C Somayajulu477ffb92007-01-22 12:26:11 -08002746 unsigned long flags = 0;
2747
2748 DEBUG2(printk(KERN_ERR "scsi%ld: %s\n", ha->host_no, __func__));
David Somayajuluafaf5a22006-09-19 10:28:00 -07002749
Vikas Chaudharyf4f5df22010-07-28 15:53:44 +05302750 if (ql4xxx_lock_drvr_wait(ha) != QLA_SUCCESS)
2751 return QLA_ERROR;
2752
David Somayajuluafaf5a22006-09-19 10:28:00 -07002753 spin_lock_irqsave(&ha->hardware_lock, flags);
2754
2755 /*
2756 * If the SCSI Reset Interrupt bit is set, clear it.
2757 * Otherwise, the Soft Reset won't work.
2758 */
2759 ctrl_status = readw(&ha->reg->ctrl_status);
2760 if ((ctrl_status & CSR_SCSI_RESET_INTR) != 0)
2761 writel(set_rmask(CSR_SCSI_RESET_INTR), &ha->reg->ctrl_status);
2762
2763 /* Issue Soft Reset */
2764 writel(set_rmask(CSR_SOFT_RESET), &ha->reg->ctrl_status);
2765 readl(&ha->reg->ctrl_status);
2766
2767 spin_unlock_irqrestore(&ha->hardware_lock, flags);
Vikas Chaudharyf4f5df22010-07-28 15:53:44 +05302768 return QLA_SUCCESS;
David C Somayajulu477ffb92007-01-22 12:26:11 -08002769}
2770
2771/**
2772 * qla4xxx_soft_reset - performs soft reset.
2773 * @ha: Pointer to host adapter structure.
2774 **/
2775int qla4xxx_soft_reset(struct scsi_qla_host *ha)
2776{
2777 uint32_t max_wait_time;
2778 unsigned long flags = 0;
Vikas Chaudharyf931c532010-10-06 22:48:07 -07002779 int status;
David C Somayajulu477ffb92007-01-22 12:26:11 -08002780 uint32_t ctrl_status;
2781
Vikas Chaudharyf931c532010-10-06 22:48:07 -07002782 status = qla4xxx_hw_reset(ha);
2783 if (status != QLA_SUCCESS)
2784 return status;
David Somayajuluafaf5a22006-09-19 10:28:00 -07002785
Vikas Chaudharyf931c532010-10-06 22:48:07 -07002786 status = QLA_ERROR;
David Somayajuluafaf5a22006-09-19 10:28:00 -07002787 /* Wait until the Network Reset Intr bit is cleared */
2788 max_wait_time = RESET_INTR_TOV;
2789 do {
2790 spin_lock_irqsave(&ha->hardware_lock, flags);
2791 ctrl_status = readw(&ha->reg->ctrl_status);
2792 spin_unlock_irqrestore(&ha->hardware_lock, flags);
2793
2794 if ((ctrl_status & CSR_NET_RESET_INTR) == 0)
2795 break;
2796
2797 msleep(1000);
2798 } while ((--max_wait_time));
2799
2800 if ((ctrl_status & CSR_NET_RESET_INTR) != 0) {
2801 DEBUG2(printk(KERN_WARNING
2802 "scsi%ld: Network Reset Intr not cleared by "
2803 "Network function, clearing it now!\n",
2804 ha->host_no));
2805 spin_lock_irqsave(&ha->hardware_lock, flags);
2806 writel(set_rmask(CSR_NET_RESET_INTR), &ha->reg->ctrl_status);
2807 readl(&ha->reg->ctrl_status);
2808 spin_unlock_irqrestore(&ha->hardware_lock, flags);
2809 }
2810
2811 /* Wait until the firmware tells us the Soft Reset is done */
2812 max_wait_time = SOFT_RESET_TOV;
2813 do {
2814 spin_lock_irqsave(&ha->hardware_lock, flags);
2815 ctrl_status = readw(&ha->reg->ctrl_status);
2816 spin_unlock_irqrestore(&ha->hardware_lock, flags);
2817
2818 if ((ctrl_status & CSR_SOFT_RESET) == 0) {
2819 status = QLA_SUCCESS;
2820 break;
2821 }
2822
2823 msleep(1000);
2824 } while ((--max_wait_time));
2825
2826 /*
2827 * Also, make sure that the SCSI Reset Interrupt bit has been cleared
2828 * after the soft reset has taken place.
2829 */
2830 spin_lock_irqsave(&ha->hardware_lock, flags);
2831 ctrl_status = readw(&ha->reg->ctrl_status);
2832 if ((ctrl_status & CSR_SCSI_RESET_INTR) != 0) {
2833 writel(set_rmask(CSR_SCSI_RESET_INTR), &ha->reg->ctrl_status);
2834 readl(&ha->reg->ctrl_status);
2835 }
2836 spin_unlock_irqrestore(&ha->hardware_lock, flags);
2837
2838 /* If soft reset fails then most probably the bios on other
2839 * function is also enabled.
2840 * Since the initialization is sequential the other fn
2841 * wont be able to acknowledge the soft reset.
2842 * Issue a force soft reset to workaround this scenario.
2843 */
2844 if (max_wait_time == 0) {
2845 /* Issue Force Soft Reset */
2846 spin_lock_irqsave(&ha->hardware_lock, flags);
2847 writel(set_rmask(CSR_FORCE_SOFT_RESET), &ha->reg->ctrl_status);
2848 readl(&ha->reg->ctrl_status);
2849 spin_unlock_irqrestore(&ha->hardware_lock, flags);
2850 /* Wait until the firmware tells us the Soft Reset is done */
2851 max_wait_time = SOFT_RESET_TOV;
2852 do {
2853 spin_lock_irqsave(&ha->hardware_lock, flags);
2854 ctrl_status = readw(&ha->reg->ctrl_status);
2855 spin_unlock_irqrestore(&ha->hardware_lock, flags);
2856
2857 if ((ctrl_status & CSR_FORCE_SOFT_RESET) == 0) {
2858 status = QLA_SUCCESS;
2859 break;
2860 }
2861
2862 msleep(1000);
2863 } while ((--max_wait_time));
2864 }
2865
2866 return status;
2867}
2868
2869/**
Vikas Chaudharyf4f5df22010-07-28 15:53:44 +05302870 * qla4xxx_abort_active_cmds - returns all outstanding i/o requests to O.S.
David Somayajuluafaf5a22006-09-19 10:28:00 -07002871 * @ha: Pointer to host adapter structure.
Vikas Chaudharyf4f5df22010-07-28 15:53:44 +05302872 * @res: returned scsi status
David Somayajuluafaf5a22006-09-19 10:28:00 -07002873 *
2874 * This routine is called just prior to a HARD RESET to return all
2875 * outstanding commands back to the Operating System.
2876 * Caller should make sure that the following locks are released
2877 * before this calling routine: Hardware lock, and io_request_lock.
2878 **/
Vikas Chaudharyf4f5df22010-07-28 15:53:44 +05302879static void qla4xxx_abort_active_cmds(struct scsi_qla_host *ha, int res)
David Somayajuluafaf5a22006-09-19 10:28:00 -07002880{
2881 struct srb *srb;
2882 int i;
2883 unsigned long flags;
2884
2885 spin_lock_irqsave(&ha->hardware_lock, flags);
2886 for (i = 0; i < ha->host->can_queue; i++) {
2887 srb = qla4xxx_del_from_active_array(ha, i);
2888 if (srb != NULL) {
Vikas Chaudharyf4f5df22010-07-28 15:53:44 +05302889 srb->cmd->result = res;
Vikas Chaudhary09a0f712010-04-28 11:42:24 +05302890 kref_put(&srb->srb_ref, qla4xxx_srb_compl);
David Somayajuluafaf5a22006-09-19 10:28:00 -07002891 }
2892 }
2893 spin_unlock_irqrestore(&ha->hardware_lock, flags);
David Somayajuluafaf5a22006-09-19 10:28:00 -07002894}
2895
Vikas Chaudharyf4f5df22010-07-28 15:53:44 +05302896void qla4xxx_dead_adapter_cleanup(struct scsi_qla_host *ha)
2897{
2898 clear_bit(AF_ONLINE, &ha->flags);
2899
2900 /* Disable the board */
2901 ql4_printk(KERN_INFO, ha, "Disabling the board\n");
Vikas Chaudharyf4f5df22010-07-28 15:53:44 +05302902
2903 qla4xxx_abort_active_cmds(ha, DID_NO_CONNECT << 16);
2904 qla4xxx_mark_all_devices_missing(ha);
2905 clear_bit(AF_INIT_DONE, &ha->flags);
2906}
2907
Manish Rangankarb3a271a2011-07-25 13:48:53 -05002908static void qla4xxx_fail_session(struct iscsi_cls_session *cls_session)
2909{
2910 struct iscsi_session *sess;
2911 struct ddb_entry *ddb_entry;
2912
2913 sess = cls_session->dd_data;
2914 ddb_entry = sess->dd_data;
2915 ddb_entry->fw_ddb_device_state = DDB_DS_SESSION_FAILED;
Mike Christie13483732011-12-01 21:38:41 -06002916
2917 if (ddb_entry->ddb_type == FLASH_DDB)
2918 iscsi_block_session(ddb_entry->sess);
2919 else
2920 iscsi_session_failure(cls_session->dd_data,
2921 ISCSI_ERR_CONN_FAILED);
Manish Rangankarb3a271a2011-07-25 13:48:53 -05002922}
2923
David Somayajuluafaf5a22006-09-19 10:28:00 -07002924/**
David Somayajuluafaf5a22006-09-19 10:28:00 -07002925 * qla4xxx_recover_adapter - recovers adapter after a fatal error
2926 * @ha: Pointer to host adapter structure.
David Somayajuluafaf5a22006-09-19 10:28:00 -07002927 **/
Vikas Chaudharyf4f5df22010-07-28 15:53:44 +05302928static int qla4xxx_recover_adapter(struct scsi_qla_host *ha)
David Somayajuluafaf5a22006-09-19 10:28:00 -07002929{
Vikas Chaudharyf4f5df22010-07-28 15:53:44 +05302930 int status = QLA_ERROR;
2931 uint8_t reset_chip = 0;
Sarang Radke8e0f3a62011-12-01 22:42:09 -08002932 uint32_t dev_state;
Shyam Sunder9ee91a32011-12-01 22:42:13 -08002933 unsigned long wait;
David Somayajuluafaf5a22006-09-19 10:28:00 -07002934
2935 /* Stall incoming I/O until we are done */
Vikas Chaudharyf4f5df22010-07-28 15:53:44 +05302936 scsi_block_requests(ha->host);
David Somayajuluafaf5a22006-09-19 10:28:00 -07002937 clear_bit(AF_ONLINE, &ha->flags);
Manish Rangankarb3a271a2011-07-25 13:48:53 -05002938 clear_bit(AF_LINK_UP, &ha->flags);
Mike Christie50a29ae2008-03-04 13:26:53 -06002939
Vikas Chaudharyf4f5df22010-07-28 15:53:44 +05302940 DEBUG2(ql4_printk(KERN_INFO, ha, "%s: adapter OFFLINE\n", __func__));
David Somayajuluafaf5a22006-09-19 10:28:00 -07002941
Vikas Chaudharyf4f5df22010-07-28 15:53:44 +05302942 set_bit(DPC_RESET_ACTIVE, &ha->dpc_flags);
David Somayajuluafaf5a22006-09-19 10:28:00 -07002943
Manish Rangankarb3a271a2011-07-25 13:48:53 -05002944 iscsi_host_for_each_session(ha->host, qla4xxx_fail_session);
2945
Vikas Chaudharyf4f5df22010-07-28 15:53:44 +05302946 if (test_bit(DPC_RESET_HA, &ha->dpc_flags))
2947 reset_chip = 1;
David Somayajuluafaf5a22006-09-19 10:28:00 -07002948
Vikas Chaudharyf4f5df22010-07-28 15:53:44 +05302949 /* For the DPC_RESET_HA_INTR case (ISP-4xxx specific)
2950 * do not reset adapter, jump to initialize_adapter */
2951 if (test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags)) {
2952 status = QLA_SUCCESS;
2953 goto recover_ha_init_adapter;
David Somayajuluafaf5a22006-09-19 10:28:00 -07002954 }
2955
Vikas Chaudharyf4f5df22010-07-28 15:53:44 +05302956 /* For the ISP-82xx adapter, issue a stop_firmware if invoked
2957 * from eh_host_reset or ioctl module */
2958 if (is_qla8022(ha) && !reset_chip &&
2959 test_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags)) {
2960
2961 DEBUG2(ql4_printk(KERN_INFO, ha,
2962 "scsi%ld: %s - Performing stop_firmware...\n",
2963 ha->host_no, __func__));
2964 status = ha->isp_ops->reset_firmware(ha);
2965 if (status == QLA_SUCCESS) {
Nilesh Javali2bd1e2be2010-10-06 22:49:20 -07002966 if (!test_bit(AF_FW_RECOVERY, &ha->flags))
2967 qla4xxx_cmd_wait(ha);
Vikas Chaudharyf4f5df22010-07-28 15:53:44 +05302968 ha->isp_ops->disable_intrs(ha);
2969 qla4xxx_process_aen(ha, FLUSH_DDB_CHANGED_AENS);
2970 qla4xxx_abort_active_cmds(ha, DID_RESET << 16);
2971 } else {
2972 /* If the stop_firmware fails then
2973 * reset the entire chip */
2974 reset_chip = 1;
2975 clear_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags);
2976 set_bit(DPC_RESET_HA, &ha->dpc_flags);
2977 }
2978 }
2979
2980 /* Issue full chip reset if recovering from a catastrophic error,
2981 * or if stop_firmware fails for ISP-82xx.
2982 * This is the default case for ISP-4xxx */
2983 if (!is_qla8022(ha) || reset_chip) {
Shyam Sunder9ee91a32011-12-01 22:42:13 -08002984 if (!is_qla8022(ha))
2985 goto chip_reset;
2986
2987 /* Check if 82XX firmware is alive or not
2988 * We may have arrived here from NEED_RESET
2989 * detection only */
2990 if (test_bit(AF_FW_RECOVERY, &ha->flags))
2991 goto chip_reset;
2992
2993 wait = jiffies + (FW_ALIVE_WAIT_TOV * HZ);
2994 while (time_before(jiffies, wait)) {
2995 if (qla4_8xxx_check_fw_alive(ha)) {
2996 qla4xxx_mailbox_premature_completion(ha);
2997 break;
2998 }
2999
3000 set_current_state(TASK_UNINTERRUPTIBLE);
3001 schedule_timeout(HZ);
3002 }
3003
Nilesh Javali2bd1e2be2010-10-06 22:49:20 -07003004 if (!test_bit(AF_FW_RECOVERY, &ha->flags))
3005 qla4xxx_cmd_wait(ha);
Shyam Sunder9ee91a32011-12-01 22:42:13 -08003006chip_reset:
Vikas Chaudharyf4f5df22010-07-28 15:53:44 +05303007 qla4xxx_process_aen(ha, FLUSH_DDB_CHANGED_AENS);
3008 qla4xxx_abort_active_cmds(ha, DID_RESET << 16);
3009 DEBUG2(ql4_printk(KERN_INFO, ha,
3010 "scsi%ld: %s - Performing chip reset..\n",
3011 ha->host_no, __func__));
3012 status = ha->isp_ops->reset_chip(ha);
3013 }
3014
3015 /* Flush any pending ddb changed AENs */
3016 qla4xxx_process_aen(ha, FLUSH_DDB_CHANGED_AENS);
3017
3018recover_ha_init_adapter:
3019 /* Upon successful firmware/chip reset, re-initialize the adapter */
3020 if (status == QLA_SUCCESS) {
3021 /* For ISP-4xxx, force function 1 to always initialize
3022 * before function 3 to prevent both funcions from
3023 * stepping on top of the other */
3024 if (!is_qla8022(ha) && (ha->mac_index == 3))
3025 ssleep(6);
3026
3027 /* NOTE: AF_ONLINE flag set upon successful completion of
3028 * qla4xxx_initialize_adapter */
Mike Christie13483732011-12-01 21:38:41 -06003029 status = qla4xxx_initialize_adapter(ha, RESET_ADAPTER);
Vikas Chaudharyf4f5df22010-07-28 15:53:44 +05303030 }
3031
3032 /* Retry failed adapter initialization, if necessary
3033 * Do not retry initialize_adapter for RESET_HA_INTR (ISP-4xxx specific)
3034 * case to prevent ping-pong resets between functions */
3035 if (!test_bit(AF_ONLINE, &ha->flags) &&
3036 !test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags)) {
David Somayajuluafaf5a22006-09-19 10:28:00 -07003037 /* Adapter initialization failed, see if we can retry
Vikas Chaudharyf4f5df22010-07-28 15:53:44 +05303038 * resetting the ha.
3039 * Since we don't want to block the DPC for too long
3040 * with multiple resets in the same thread,
3041 * utilize DPC to retry */
Sarang Radke8e0f3a62011-12-01 22:42:09 -08003042 if (is_qla8022(ha)) {
3043 qla4_8xxx_idc_lock(ha);
3044 dev_state = qla4_8xxx_rd_32(ha, QLA82XX_CRB_DEV_STATE);
3045 qla4_8xxx_idc_unlock(ha);
3046 if (dev_state == QLA82XX_DEV_FAILED) {
3047 ql4_printk(KERN_INFO, ha, "%s: don't retry "
3048 "recover adapter. H/W is in Failed "
3049 "state\n", __func__);
3050 qla4xxx_dead_adapter_cleanup(ha);
3051 clear_bit(DPC_RETRY_RESET_HA, &ha->dpc_flags);
3052 clear_bit(DPC_RESET_HA, &ha->dpc_flags);
3053 clear_bit(DPC_RESET_HA_FW_CONTEXT,
3054 &ha->dpc_flags);
3055 status = QLA_ERROR;
3056
3057 goto exit_recover;
3058 }
3059 }
3060
David Somayajuluafaf5a22006-09-19 10:28:00 -07003061 if (!test_bit(DPC_RETRY_RESET_HA, &ha->dpc_flags)) {
3062 ha->retry_reset_ha_cnt = MAX_RESET_HA_RETRIES;
3063 DEBUG2(printk("scsi%ld: recover adapter - retrying "
3064 "(%d) more times\n", ha->host_no,
3065 ha->retry_reset_ha_cnt));
3066 set_bit(DPC_RETRY_RESET_HA, &ha->dpc_flags);
3067 status = QLA_ERROR;
3068 } else {
3069 if (ha->retry_reset_ha_cnt > 0) {
3070 /* Schedule another Reset HA--DPC will retry */
3071 ha->retry_reset_ha_cnt--;
3072 DEBUG2(printk("scsi%ld: recover adapter - "
3073 "retry remaining %d\n",
3074 ha->host_no,
3075 ha->retry_reset_ha_cnt));
3076 status = QLA_ERROR;
3077 }
3078
3079 if (ha->retry_reset_ha_cnt == 0) {
3080 /* Recover adapter retries have been exhausted.
3081 * Adapter DEAD */
3082 DEBUG2(printk("scsi%ld: recover adapter "
3083 "failed - board disabled\n",
3084 ha->host_no));
Vikas Chaudharyf4f5df22010-07-28 15:53:44 +05303085 qla4xxx_dead_adapter_cleanup(ha);
David Somayajuluafaf5a22006-09-19 10:28:00 -07003086 clear_bit(DPC_RETRY_RESET_HA, &ha->dpc_flags);
3087 clear_bit(DPC_RESET_HA, &ha->dpc_flags);
Vikas Chaudharyf4f5df22010-07-28 15:53:44 +05303088 clear_bit(DPC_RESET_HA_FW_CONTEXT,
David Somayajuluafaf5a22006-09-19 10:28:00 -07003089 &ha->dpc_flags);
3090 status = QLA_ERROR;
3091 }
3092 }
3093 } else {
3094 clear_bit(DPC_RESET_HA, &ha->dpc_flags);
Vikas Chaudharyf4f5df22010-07-28 15:53:44 +05303095 clear_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags);
David Somayajuluafaf5a22006-09-19 10:28:00 -07003096 clear_bit(DPC_RETRY_RESET_HA, &ha->dpc_flags);
3097 }
3098
Sarang Radke8e0f3a62011-12-01 22:42:09 -08003099exit_recover:
David Somayajuluafaf5a22006-09-19 10:28:00 -07003100 ha->adapter_error_count++;
3101
Vikas Chaudharyf4f5df22010-07-28 15:53:44 +05303102 if (test_bit(AF_ONLINE, &ha->flags))
3103 ha->isp_ops->enable_intrs(ha);
David Somayajuluafaf5a22006-09-19 10:28:00 -07003104
Vikas Chaudharyf4f5df22010-07-28 15:53:44 +05303105 scsi_unblock_requests(ha->host);
3106
3107 clear_bit(DPC_RESET_ACTIVE, &ha->dpc_flags);
3108 DEBUG2(printk("scsi%ld: recover adapter: %s\n", ha->host_no,
Lucas De Marchi25985ed2011-03-30 22:57:33 -03003109 status == QLA_ERROR ? "FAILED" : "SUCCEEDED"));
Vikas Chaudharyf4f5df22010-07-28 15:53:44 +05303110
David Somayajuluafaf5a22006-09-19 10:28:00 -07003111 return status;
3112}
3113
Manish Rangankarb3a271a2011-07-25 13:48:53 -05003114static void qla4xxx_relogin_devices(struct iscsi_cls_session *cls_session)
Vikas Chaudhary2d7924e2011-03-21 03:34:33 -07003115{
Manish Rangankarb3a271a2011-07-25 13:48:53 -05003116 struct iscsi_session *sess;
3117 struct ddb_entry *ddb_entry;
3118 struct scsi_qla_host *ha;
Vikas Chaudhary2d7924e2011-03-21 03:34:33 -07003119
Manish Rangankarb3a271a2011-07-25 13:48:53 -05003120 sess = cls_session->dd_data;
3121 ddb_entry = sess->dd_data;
3122 ha = ddb_entry->ha;
3123 if (!iscsi_is_session_online(cls_session)) {
3124 if (ddb_entry->fw_ddb_device_state == DDB_DS_SESSION_ACTIVE) {
3125 ql4_printk(KERN_INFO, ha, "scsi%ld: %s: ddb[%d]"
3126 " unblock session\n", ha->host_no, __func__,
3127 ddb_entry->fw_ddb_index);
3128 iscsi_unblock_session(ddb_entry->sess);
3129 } else {
3130 /* Trigger relogin */
Mike Christie13483732011-12-01 21:38:41 -06003131 if (ddb_entry->ddb_type == FLASH_DDB) {
3132 if (!test_bit(DF_RELOGIN, &ddb_entry->flags))
3133 qla4xxx_arm_relogin_timer(ddb_entry);
3134 } else
3135 iscsi_session_failure(cls_session->dd_data,
3136 ISCSI_ERR_CONN_FAILED);
Vikas Chaudhary2d7924e2011-03-21 03:34:33 -07003137 }
3138 }
3139}
3140
Mike Christie13483732011-12-01 21:38:41 -06003141int qla4xxx_unblock_flash_ddb(struct iscsi_cls_session *cls_session)
3142{
3143 struct iscsi_session *sess;
3144 struct ddb_entry *ddb_entry;
3145 struct scsi_qla_host *ha;
3146
3147 sess = cls_session->dd_data;
3148 ddb_entry = sess->dd_data;
3149 ha = ddb_entry->ha;
3150 ql4_printk(KERN_INFO, ha, "scsi%ld: %s: ddb[%d]"
3151 " unblock session\n", ha->host_no, __func__,
3152 ddb_entry->fw_ddb_index);
3153
3154 iscsi_unblock_session(ddb_entry->sess);
3155
3156 /* Start scan target */
3157 if (test_bit(AF_ONLINE, &ha->flags)) {
3158 ql4_printk(KERN_INFO, ha, "scsi%ld: %s: ddb[%d]"
3159 " start scan\n", ha->host_no, __func__,
3160 ddb_entry->fw_ddb_index);
3161 scsi_queue_work(ha->host, &ddb_entry->sess->scan_work);
3162 }
3163 return QLA_SUCCESS;
3164}
3165
3166int qla4xxx_unblock_ddb(struct iscsi_cls_session *cls_session)
3167{
3168 struct iscsi_session *sess;
3169 struct ddb_entry *ddb_entry;
3170 struct scsi_qla_host *ha;
Manish Rangankar80c53e62012-08-07 07:57:15 -04003171 int status = QLA_SUCCESS;
Mike Christie13483732011-12-01 21:38:41 -06003172
3173 sess = cls_session->dd_data;
3174 ddb_entry = sess->dd_data;
3175 ha = ddb_entry->ha;
3176 ql4_printk(KERN_INFO, ha, "scsi%ld: %s: ddb[%d]"
3177 " unblock user space session\n", ha->host_no, __func__,
3178 ddb_entry->fw_ddb_index);
Mike Christie13483732011-12-01 21:38:41 -06003179
Manish Rangankar80c53e62012-08-07 07:57:15 -04003180 if (!iscsi_is_session_online(cls_session)) {
3181 iscsi_conn_start(ddb_entry->conn);
3182 iscsi_conn_login_event(ddb_entry->conn,
3183 ISCSI_CONN_STATE_LOGGED_IN);
3184 } else {
3185 ql4_printk(KERN_INFO, ha,
3186 "scsi%ld: %s: ddb[%d] session [%d] already logged in\n",
3187 ha->host_no, __func__, ddb_entry->fw_ddb_index,
3188 cls_session->sid);
3189 status = QLA_ERROR;
3190 }
3191
3192 return status;
Mike Christie13483732011-12-01 21:38:41 -06003193}
3194
Manish Rangankarb3a271a2011-07-25 13:48:53 -05003195static void qla4xxx_relogin_all_devices(struct scsi_qla_host *ha)
3196{
3197 iscsi_host_for_each_session(ha->host, qla4xxx_relogin_devices);
3198}
3199
Mike Christie13483732011-12-01 21:38:41 -06003200static void qla4xxx_relogin_flash_ddb(struct iscsi_cls_session *cls_sess)
3201{
3202 uint16_t relogin_timer;
3203 struct iscsi_session *sess;
3204 struct ddb_entry *ddb_entry;
3205 struct scsi_qla_host *ha;
3206
3207 sess = cls_sess->dd_data;
3208 ddb_entry = sess->dd_data;
3209 ha = ddb_entry->ha;
3210
3211 relogin_timer = max(ddb_entry->default_relogin_timeout,
3212 (uint16_t)RELOGIN_TOV);
3213 atomic_set(&ddb_entry->relogin_timer, relogin_timer);
3214
3215 DEBUG2(ql4_printk(KERN_INFO, ha,
3216 "scsi%ld: Relogin index [%d]. TOV=%d\n", ha->host_no,
3217 ddb_entry->fw_ddb_index, relogin_timer));
3218
3219 qla4xxx_login_flash_ddb(cls_sess);
3220}
3221
3222static void qla4xxx_dpc_relogin(struct iscsi_cls_session *cls_sess)
3223{
3224 struct iscsi_session *sess;
3225 struct ddb_entry *ddb_entry;
3226 struct scsi_qla_host *ha;
3227
3228 sess = cls_sess->dd_data;
3229 ddb_entry = sess->dd_data;
3230 ha = ddb_entry->ha;
3231
3232 if (!(ddb_entry->ddb_type == FLASH_DDB))
3233 return;
3234
3235 if (test_and_clear_bit(DF_RELOGIN, &ddb_entry->flags) &&
3236 !iscsi_is_session_online(cls_sess)) {
3237 DEBUG2(ql4_printk(KERN_INFO, ha,
3238 "relogin issued\n"));
3239 qla4xxx_relogin_flash_ddb(cls_sess);
3240 }
3241}
3242
Vikas Chaudharyf4f5df22010-07-28 15:53:44 +05303243void qla4xxx_wake_dpc(struct scsi_qla_host *ha)
3244{
Lalit Chandivade1b468072011-05-17 23:17:09 -07003245 if (ha->dpc_thread)
Vikas Chaudharyf4f5df22010-07-28 15:53:44 +05303246 queue_work(ha->dpc_thread, &ha->dpc_work);
Vikas Chaudharyf4f5df22010-07-28 15:53:44 +05303247}
3248
Vikas Chaudharyff884432011-08-29 23:43:02 +05303249static struct qla4_work_evt *
3250qla4xxx_alloc_work(struct scsi_qla_host *ha, uint32_t data_size,
3251 enum qla4_work_type type)
3252{
3253 struct qla4_work_evt *e;
3254 uint32_t size = sizeof(struct qla4_work_evt) + data_size;
3255
3256 e = kzalloc(size, GFP_ATOMIC);
3257 if (!e)
3258 return NULL;
3259
3260 INIT_LIST_HEAD(&e->list);
3261 e->type = type;
3262 return e;
3263}
3264
3265static void qla4xxx_post_work(struct scsi_qla_host *ha,
3266 struct qla4_work_evt *e)
3267{
3268 unsigned long flags;
3269
3270 spin_lock_irqsave(&ha->work_lock, flags);
3271 list_add_tail(&e->list, &ha->work_list);
3272 spin_unlock_irqrestore(&ha->work_lock, flags);
3273 qla4xxx_wake_dpc(ha);
3274}
3275
3276int qla4xxx_post_aen_work(struct scsi_qla_host *ha,
3277 enum iscsi_host_event_code aen_code,
3278 uint32_t data_size, uint8_t *data)
3279{
3280 struct qla4_work_evt *e;
3281
3282 e = qla4xxx_alloc_work(ha, data_size, QLA4_EVENT_AEN);
3283 if (!e)
3284 return QLA_ERROR;
3285
3286 e->u.aen.code = aen_code;
3287 e->u.aen.data_size = data_size;
3288 memcpy(e->u.aen.data, data, data_size);
3289
3290 qla4xxx_post_work(ha, e);
3291
3292 return QLA_SUCCESS;
3293}
3294
Vikas Chaudharyc0b9d3f2012-02-13 18:30:49 +05303295int qla4xxx_post_ping_evt_work(struct scsi_qla_host *ha,
3296 uint32_t status, uint32_t pid,
3297 uint32_t data_size, uint8_t *data)
3298{
3299 struct qla4_work_evt *e;
3300
3301 e = qla4xxx_alloc_work(ha, data_size, QLA4_EVENT_PING_STATUS);
3302 if (!e)
3303 return QLA_ERROR;
3304
3305 e->u.ping.status = status;
3306 e->u.ping.pid = pid;
3307 e->u.ping.data_size = data_size;
3308 memcpy(e->u.ping.data, data, data_size);
3309
3310 qla4xxx_post_work(ha, e);
3311
3312 return QLA_SUCCESS;
3313}
3314
Vikas Chaudharya7380a62012-02-27 03:08:56 -08003315static void qla4xxx_do_work(struct scsi_qla_host *ha)
Vikas Chaudharyff884432011-08-29 23:43:02 +05303316{
3317 struct qla4_work_evt *e, *tmp;
3318 unsigned long flags;
3319 LIST_HEAD(work);
3320
3321 spin_lock_irqsave(&ha->work_lock, flags);
3322 list_splice_init(&ha->work_list, &work);
3323 spin_unlock_irqrestore(&ha->work_lock, flags);
3324
3325 list_for_each_entry_safe(e, tmp, &work, list) {
3326 list_del_init(&e->list);
3327
3328 switch (e->type) {
3329 case QLA4_EVENT_AEN:
3330 iscsi_post_host_event(ha->host_no,
3331 &qla4xxx_iscsi_transport,
3332 e->u.aen.code,
3333 e->u.aen.data_size,
3334 e->u.aen.data);
3335 break;
Vikas Chaudharyc0b9d3f2012-02-13 18:30:49 +05303336 case QLA4_EVENT_PING_STATUS:
3337 iscsi_ping_comp_event(ha->host_no,
3338 &qla4xxx_iscsi_transport,
3339 e->u.ping.status,
3340 e->u.ping.pid,
3341 e->u.ping.data_size,
3342 e->u.ping.data);
3343 break;
Vikas Chaudharyff884432011-08-29 23:43:02 +05303344 default:
3345 ql4_printk(KERN_WARNING, ha, "event type: 0x%x not "
3346 "supported", e->type);
3347 }
3348 kfree(e);
3349 }
3350}
3351
David Somayajuluafaf5a22006-09-19 10:28:00 -07003352/**
3353 * qla4xxx_do_dpc - dpc routine
3354 * @data: in our case pointer to adapter structure
3355 *
3356 * This routine is a task that is schedule by the interrupt handler
3357 * to perform the background processing for interrupts. We put it
3358 * on a task queue that is consumed whenever the scheduler runs; that's
3359 * so you can do anything (i.e. put the process to sleep etc). In fact,
3360 * the mid-level tries to sleep when it reaches the driver threshold
3361 * "host->can_queue". This can cause a panic if we were in our interrupt code.
3362 **/
David Howellsc4028952006-11-22 14:57:56 +00003363static void qla4xxx_do_dpc(struct work_struct *work)
David Somayajuluafaf5a22006-09-19 10:28:00 -07003364{
David Howellsc4028952006-11-22 14:57:56 +00003365 struct scsi_qla_host *ha =
3366 container_of(work, struct scsi_qla_host, dpc_work);
David C Somayajulu477ffb92007-01-22 12:26:11 -08003367 int status = QLA_ERROR;
David Somayajuluafaf5a22006-09-19 10:28:00 -07003368
David C Somayajuluf26b9042006-11-15 16:41:09 -08003369 DEBUG2(printk("scsi%ld: %s: DPC handler waking up."
Vikas Chaudharyf4f5df22010-07-28 15:53:44 +05303370 "flags = 0x%08lx, dpc_flags = 0x%08lx\n",
3371 ha->host_no, __func__, ha->flags, ha->dpc_flags))
David Somayajuluafaf5a22006-09-19 10:28:00 -07003372
3373 /* Initialization not yet finished. Don't do anything yet. */
3374 if (!test_bit(AF_INIT_DONE, &ha->flags))
Lalit Chandivade1b468072011-05-17 23:17:09 -07003375 return;
David Somayajuluafaf5a22006-09-19 10:28:00 -07003376
Lalit Chandivade2232be02010-07-30 14:38:47 +05303377 if (test_bit(AF_EEH_BUSY, &ha->flags)) {
3378 DEBUG2(printk(KERN_INFO "scsi%ld: %s: flags = %lx\n",
3379 ha->host_no, __func__, ha->flags));
Lalit Chandivade1b468072011-05-17 23:17:09 -07003380 return;
Lalit Chandivade2232be02010-07-30 14:38:47 +05303381 }
3382
Vikas Chaudharyff884432011-08-29 23:43:02 +05303383 /* post events to application */
3384 qla4xxx_do_work(ha);
3385
Vikas Chaudharyf4f5df22010-07-28 15:53:44 +05303386 if (is_qla8022(ha)) {
3387 if (test_bit(DPC_HA_UNRECOVERABLE, &ha->dpc_flags)) {
3388 qla4_8xxx_idc_lock(ha);
3389 qla4_8xxx_wr_32(ha, QLA82XX_CRB_DEV_STATE,
3390 QLA82XX_DEV_FAILED);
3391 qla4_8xxx_idc_unlock(ha);
3392 ql4_printk(KERN_INFO, ha, "HW State: FAILED\n");
3393 qla4_8xxx_device_state_handler(ha);
3394 }
3395 if (test_and_clear_bit(DPC_HA_NEED_QUIESCENT, &ha->dpc_flags)) {
3396 qla4_8xxx_need_qsnt_handler(ha);
3397 }
3398 }
3399
3400 if (!test_bit(DPC_RESET_ACTIVE, &ha->dpc_flags) &&
3401 (test_bit(DPC_RESET_HA, &ha->dpc_flags) ||
David Somayajuluafaf5a22006-09-19 10:28:00 -07003402 test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags) ||
Vikas Chaudharyf4f5df22010-07-28 15:53:44 +05303403 test_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags))) {
3404 if (ql4xdontresethba) {
3405 DEBUG2(printk("scsi%ld: %s: Don't Reset HBA\n",
3406 ha->host_no, __func__));
3407 clear_bit(DPC_RESET_HA, &ha->dpc_flags);
3408 clear_bit(DPC_RESET_HA_INTR, &ha->dpc_flags);
3409 clear_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags);
3410 goto dpc_post_reset_ha;
3411 }
3412 if (test_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags) ||
3413 test_bit(DPC_RESET_HA, &ha->dpc_flags))
3414 qla4xxx_recover_adapter(ha);
David Somayajuluafaf5a22006-09-19 10:28:00 -07003415
David C Somayajulu477ffb92007-01-22 12:26:11 -08003416 if (test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags)) {
David Somayajuluafaf5a22006-09-19 10:28:00 -07003417 uint8_t wait_time = RESET_INTR_TOV;
David Somayajuluafaf5a22006-09-19 10:28:00 -07003418
David Somayajuluafaf5a22006-09-19 10:28:00 -07003419 while ((readw(&ha->reg->ctrl_status) &
3420 (CSR_SOFT_RESET | CSR_FORCE_SOFT_RESET)) != 0) {
3421 if (--wait_time == 0)
3422 break;
David Somayajuluafaf5a22006-09-19 10:28:00 -07003423 msleep(1000);
David Somayajuluafaf5a22006-09-19 10:28:00 -07003424 }
David Somayajuluafaf5a22006-09-19 10:28:00 -07003425 if (wait_time == 0)
3426 DEBUG2(printk("scsi%ld: %s: SR|FSR "
3427 "bit not cleared-- resetting\n",
3428 ha->host_no, __func__));
Vikas Chaudharyf4f5df22010-07-28 15:53:44 +05303429 qla4xxx_abort_active_cmds(ha, DID_RESET << 16);
David C Somayajulu477ffb92007-01-22 12:26:11 -08003430 if (ql4xxx_lock_drvr_wait(ha) == QLA_SUCCESS) {
3431 qla4xxx_process_aen(ha, FLUSH_DDB_CHANGED_AENS);
Vikas Chaudharyf4f5df22010-07-28 15:53:44 +05303432 status = qla4xxx_recover_adapter(ha);
David C Somayajulu477ffb92007-01-22 12:26:11 -08003433 }
3434 clear_bit(DPC_RESET_HA_INTR, &ha->dpc_flags);
3435 if (status == QLA_SUCCESS)
Vikas Chaudharyf4f5df22010-07-28 15:53:44 +05303436 ha->isp_ops->enable_intrs(ha);
David Somayajuluafaf5a22006-09-19 10:28:00 -07003437 }
3438 }
3439
Vikas Chaudharyf4f5df22010-07-28 15:53:44 +05303440dpc_post_reset_ha:
David Somayajuluafaf5a22006-09-19 10:28:00 -07003441 /* ---- process AEN? --- */
3442 if (test_and_clear_bit(DPC_AEN, &ha->dpc_flags))
3443 qla4xxx_process_aen(ha, PROCESS_ALL_AENS);
3444
3445 /* ---- Get DHCP IP Address? --- */
3446 if (test_and_clear_bit(DPC_GET_DHCP_IP_ADDR, &ha->dpc_flags))
3447 qla4xxx_get_dhcp_ip_address(ha);
3448
Mike Christie13483732011-12-01 21:38:41 -06003449 /* ---- relogin device? --- */
3450 if (adapter_up(ha) &&
3451 test_and_clear_bit(DPC_RELOGIN_DEVICE, &ha->dpc_flags)) {
3452 iscsi_host_for_each_session(ha->host, qla4xxx_dpc_relogin);
3453 }
3454
Vikas Chaudhary065aa1b2010-04-28 11:38:11 +05303455 /* ---- link change? --- */
3456 if (test_and_clear_bit(DPC_LINK_CHANGED, &ha->dpc_flags)) {
3457 if (!test_bit(AF_LINK_UP, &ha->flags)) {
3458 /* ---- link down? --- */
Vikas Chaudhary2d7924e2011-03-21 03:34:33 -07003459 qla4xxx_mark_all_devices_missing(ha);
Vikas Chaudhary065aa1b2010-04-28 11:38:11 +05303460 } else {
3461 /* ---- link up? --- *
3462 * F/W will auto login to all devices ONLY ONCE after
3463 * link up during driver initialization and runtime
3464 * fatal error recovery. Therefore, the driver must
3465 * manually relogin to devices when recovering from
3466 * connection failures, logouts, expired KATO, etc. */
Mike Christie13483732011-12-01 21:38:41 -06003467 if (test_and_clear_bit(AF_BUILD_DDB_LIST, &ha->flags)) {
3468 qla4xxx_build_ddb_list(ha, ha->is_reset);
3469 iscsi_host_for_each_session(ha->host,
3470 qla4xxx_login_flash_ddb);
3471 } else
3472 qla4xxx_relogin_all_devices(ha);
Vikas Chaudhary065aa1b2010-04-28 11:38:11 +05303473 }
3474 }
David Somayajuluafaf5a22006-09-19 10:28:00 -07003475}
3476
3477/**
3478 * qla4xxx_free_adapter - release the adapter
3479 * @ha: pointer to adapter structure
3480 **/
3481static void qla4xxx_free_adapter(struct scsi_qla_host *ha)
3482{
Sarang Radke8a288962011-12-06 02:34:10 -08003483 qla4xxx_abort_active_cmds(ha, DID_NO_CONNECT << 16);
David Somayajuluafaf5a22006-09-19 10:28:00 -07003484
3485 if (test_bit(AF_INTERRUPTS_ON, &ha->flags)) {
3486 /* Turn-off interrupts on the card. */
Vikas Chaudharyf4f5df22010-07-28 15:53:44 +05303487 ha->isp_ops->disable_intrs(ha);
David Somayajuluafaf5a22006-09-19 10:28:00 -07003488 }
3489
David Somayajuluafaf5a22006-09-19 10:28:00 -07003490 /* Remove timer thread, if present */
3491 if (ha->timer_active)
3492 qla4xxx_stop_timer(ha);
3493
Vikas Chaudharyf4f5df22010-07-28 15:53:44 +05303494 /* Kill the kernel thread for this host */
3495 if (ha->dpc_thread)
3496 destroy_workqueue(ha->dpc_thread);
3497
Manish Rangankarb3a271a2011-07-25 13:48:53 -05003498 /* Kill the kernel thread for this host */
3499 if (ha->task_wq)
3500 destroy_workqueue(ha->task_wq);
3501
Vikas Chaudharyf4f5df22010-07-28 15:53:44 +05303502 /* Put firmware in known state */
3503 ha->isp_ops->reset_firmware(ha);
3504
3505 if (is_qla8022(ha)) {
3506 qla4_8xxx_idc_lock(ha);
3507 qla4_8xxx_clear_drv_active(ha);
3508 qla4_8xxx_idc_unlock(ha);
3509 }
3510
David Somayajuluafaf5a22006-09-19 10:28:00 -07003511 /* Detach interrupts */
3512 if (test_and_clear_bit(AF_IRQ_ATTACHED, &ha->flags))
Vikas Chaudharyf4f5df22010-07-28 15:53:44 +05303513 qla4xxx_free_irqs(ha);
David Somayajuluafaf5a22006-09-19 10:28:00 -07003514
David C Somayajulubee4fe82007-05-23 18:03:32 -07003515 /* free extra memory */
3516 qla4xxx_mem_free(ha);
Vikas Chaudharyf4f5df22010-07-28 15:53:44 +05303517}
David C Somayajulubee4fe82007-05-23 18:03:32 -07003518
Vikas Chaudharyf4f5df22010-07-28 15:53:44 +05303519int qla4_8xxx_iospace_config(struct scsi_qla_host *ha)
3520{
3521 int status = 0;
Vikas Chaudharyf4f5df22010-07-28 15:53:44 +05303522 unsigned long mem_base, mem_len, db_base, db_len;
3523 struct pci_dev *pdev = ha->pdev;
David Somayajuluafaf5a22006-09-19 10:28:00 -07003524
Vikas Chaudharyf4f5df22010-07-28 15:53:44 +05303525 status = pci_request_regions(pdev, DRIVER_NAME);
3526 if (status) {
3527 printk(KERN_WARNING
3528 "scsi(%ld) Failed to reserve PIO regions (%s) "
3529 "status=%d\n", ha->host_no, pci_name(pdev), status);
3530 goto iospace_error_exit;
3531 }
3532
Vikas Chaudharyf4f5df22010-07-28 15:53:44 +05303533 DEBUG2(printk(KERN_INFO "%s: revision-id=%d\n",
Sergei Shtylyov7d7311c2012-03-14 22:04:30 +03003534 __func__, pdev->revision));
3535 ha->revision_id = pdev->revision;
Vikas Chaudharyf4f5df22010-07-28 15:53:44 +05303536
3537 /* remap phys address */
3538 mem_base = pci_resource_start(pdev, 0); /* 0 is for BAR 0 */
3539 mem_len = pci_resource_len(pdev, 0);
3540 DEBUG2(printk(KERN_INFO "%s: ioremap from %lx a size of %lx\n",
3541 __func__, mem_base, mem_len));
3542
3543 /* mapping of pcibase pointer */
3544 ha->nx_pcibase = (unsigned long)ioremap(mem_base, mem_len);
3545 if (!ha->nx_pcibase) {
3546 printk(KERN_ERR
3547 "cannot remap MMIO (%s), aborting\n", pci_name(pdev));
3548 pci_release_regions(ha->pdev);
3549 goto iospace_error_exit;
3550 }
3551
3552 /* Mapping of IO base pointer, door bell read and write pointer */
3553
3554 /* mapping of IO base pointer */
3555 ha->qla4_8xxx_reg =
3556 (struct device_reg_82xx __iomem *)((uint8_t *)ha->nx_pcibase +
3557 0xbc000 + (ha->pdev->devfn << 11));
3558
3559 db_base = pci_resource_start(pdev, 4); /* doorbell is on bar 4 */
3560 db_len = pci_resource_len(pdev, 4);
3561
Shyam Sundar2657c802010-10-06 22:50:29 -07003562 ha->nx_db_wr_ptr = (ha->pdev->devfn == 4 ? QLA82XX_CAM_RAM_DB1 :
3563 QLA82XX_CAM_RAM_DB2);
Vikas Chaudharyf4f5df22010-07-28 15:53:44 +05303564
Shyam Sundar2657c802010-10-06 22:50:29 -07003565 return 0;
Vikas Chaudharyf4f5df22010-07-28 15:53:44 +05303566iospace_error_exit:
3567 return -ENOMEM;
David Somayajuluafaf5a22006-09-19 10:28:00 -07003568}
3569
3570/***
3571 * qla4xxx_iospace_config - maps registers
3572 * @ha: pointer to adapter structure
3573 *
3574 * This routines maps HBA's registers from the pci address space
3575 * into the kernel virtual address space for memory mapped i/o.
3576 **/
Vikas Chaudharyf4f5df22010-07-28 15:53:44 +05303577int qla4xxx_iospace_config(struct scsi_qla_host *ha)
David Somayajuluafaf5a22006-09-19 10:28:00 -07003578{
3579 unsigned long pio, pio_len, pio_flags;
3580 unsigned long mmio, mmio_len, mmio_flags;
3581
3582 pio = pci_resource_start(ha->pdev, 0);
3583 pio_len = pci_resource_len(ha->pdev, 0);
3584 pio_flags = pci_resource_flags(ha->pdev, 0);
3585 if (pio_flags & IORESOURCE_IO) {
3586 if (pio_len < MIN_IOBASE_LEN) {
Vikas Chaudharyc2660df2010-07-10 14:51:02 +05303587 ql4_printk(KERN_WARNING, ha,
David Somayajuluafaf5a22006-09-19 10:28:00 -07003588 "Invalid PCI I/O region size\n");
3589 pio = 0;
3590 }
3591 } else {
Vikas Chaudharyc2660df2010-07-10 14:51:02 +05303592 ql4_printk(KERN_WARNING, ha, "region #0 not a PIO resource\n");
David Somayajuluafaf5a22006-09-19 10:28:00 -07003593 pio = 0;
3594 }
3595
3596 /* Use MMIO operations for all accesses. */
3597 mmio = pci_resource_start(ha->pdev, 1);
3598 mmio_len = pci_resource_len(ha->pdev, 1);
3599 mmio_flags = pci_resource_flags(ha->pdev, 1);
3600
3601 if (!(mmio_flags & IORESOURCE_MEM)) {
Vikas Chaudharyc2660df2010-07-10 14:51:02 +05303602 ql4_printk(KERN_ERR, ha,
3603 "region #0 not an MMIO resource, aborting\n");
David Somayajuluafaf5a22006-09-19 10:28:00 -07003604
3605 goto iospace_error_exit;
3606 }
Vikas Chaudharyc2660df2010-07-10 14:51:02 +05303607
David Somayajuluafaf5a22006-09-19 10:28:00 -07003608 if (mmio_len < MIN_IOBASE_LEN) {
Vikas Chaudharyc2660df2010-07-10 14:51:02 +05303609 ql4_printk(KERN_ERR, ha,
3610 "Invalid PCI mem region size, aborting\n");
David Somayajuluafaf5a22006-09-19 10:28:00 -07003611 goto iospace_error_exit;
3612 }
3613
3614 if (pci_request_regions(ha->pdev, DRIVER_NAME)) {
Vikas Chaudharyc2660df2010-07-10 14:51:02 +05303615 ql4_printk(KERN_WARNING, ha,
3616 "Failed to reserve PIO/MMIO regions\n");
David Somayajuluafaf5a22006-09-19 10:28:00 -07003617
3618 goto iospace_error_exit;
3619 }
3620
3621 ha->pio_address = pio;
3622 ha->pio_length = pio_len;
3623 ha->reg = ioremap(mmio, MIN_IOBASE_LEN);
3624 if (!ha->reg) {
Vikas Chaudharyc2660df2010-07-10 14:51:02 +05303625 ql4_printk(KERN_ERR, ha,
3626 "cannot remap MMIO, aborting\n");
David Somayajuluafaf5a22006-09-19 10:28:00 -07003627
3628 goto iospace_error_exit;
3629 }
3630
3631 return 0;
3632
3633iospace_error_exit:
3634 return -ENOMEM;
3635}
3636
Vikas Chaudharyf4f5df22010-07-28 15:53:44 +05303637static struct isp_operations qla4xxx_isp_ops = {
3638 .iospace_config = qla4xxx_iospace_config,
3639 .pci_config = qla4xxx_pci_config,
3640 .disable_intrs = qla4xxx_disable_intrs,
3641 .enable_intrs = qla4xxx_enable_intrs,
3642 .start_firmware = qla4xxx_start_firmware,
3643 .intr_handler = qla4xxx_intr_handler,
3644 .interrupt_service_routine = qla4xxx_interrupt_service_routine,
3645 .reset_chip = qla4xxx_soft_reset,
3646 .reset_firmware = qla4xxx_hw_reset,
3647 .queue_iocb = qla4xxx_queue_iocb,
3648 .complete_iocb = qla4xxx_complete_iocb,
3649 .rd_shdw_req_q_out = qla4xxx_rd_shdw_req_q_out,
3650 .rd_shdw_rsp_q_in = qla4xxx_rd_shdw_rsp_q_in,
3651 .get_sys_info = qla4xxx_get_sys_info,
3652};
3653
3654static struct isp_operations qla4_8xxx_isp_ops = {
3655 .iospace_config = qla4_8xxx_iospace_config,
3656 .pci_config = qla4_8xxx_pci_config,
3657 .disable_intrs = qla4_8xxx_disable_intrs,
3658 .enable_intrs = qla4_8xxx_enable_intrs,
3659 .start_firmware = qla4_8xxx_load_risc,
3660 .intr_handler = qla4_8xxx_intr_handler,
3661 .interrupt_service_routine = qla4_8xxx_interrupt_service_routine,
3662 .reset_chip = qla4_8xxx_isp_reset,
3663 .reset_firmware = qla4_8xxx_stop_firmware,
3664 .queue_iocb = qla4_8xxx_queue_iocb,
3665 .complete_iocb = qla4_8xxx_complete_iocb,
3666 .rd_shdw_req_q_out = qla4_8xxx_rd_shdw_req_q_out,
3667 .rd_shdw_rsp_q_in = qla4_8xxx_rd_shdw_rsp_q_in,
3668 .get_sys_info = qla4_8xxx_get_sys_info,
3669};
3670
3671uint16_t qla4xxx_rd_shdw_req_q_out(struct scsi_qla_host *ha)
3672{
3673 return (uint16_t)le32_to_cpu(ha->shadow_regs->req_q_out);
3674}
3675
3676uint16_t qla4_8xxx_rd_shdw_req_q_out(struct scsi_qla_host *ha)
3677{
3678 return (uint16_t)le32_to_cpu(readl(&ha->qla4_8xxx_reg->req_q_out));
3679}
3680
3681uint16_t qla4xxx_rd_shdw_rsp_q_in(struct scsi_qla_host *ha)
3682{
3683 return (uint16_t)le32_to_cpu(ha->shadow_regs->rsp_q_in);
3684}
3685
3686uint16_t qla4_8xxx_rd_shdw_rsp_q_in(struct scsi_qla_host *ha)
3687{
3688 return (uint16_t)le32_to_cpu(readl(&ha->qla4_8xxx_reg->rsp_q_in));
3689}
3690
Manish Rangankar2a991c22011-07-25 13:48:55 -05003691static ssize_t qla4xxx_show_boot_eth_info(void *data, int type, char *buf)
3692{
3693 struct scsi_qla_host *ha = data;
3694 char *str = buf;
3695 int rc;
3696
3697 switch (type) {
3698 case ISCSI_BOOT_ETH_FLAGS:
3699 rc = sprintf(str, "%d\n", SYSFS_FLAG_FW_SEL_BOOT);
3700 break;
3701 case ISCSI_BOOT_ETH_INDEX:
3702 rc = sprintf(str, "0\n");
3703 break;
3704 case ISCSI_BOOT_ETH_MAC:
3705 rc = sysfs_format_mac(str, ha->my_mac,
3706 MAC_ADDR_LEN);
3707 break;
3708 default:
3709 rc = -ENOSYS;
3710 break;
3711 }
3712 return rc;
3713}
3714
Al Viro587a1f12011-07-23 23:11:19 -04003715static umode_t qla4xxx_eth_get_attr_visibility(void *data, int type)
Manish Rangankar2a991c22011-07-25 13:48:55 -05003716{
3717 int rc;
3718
3719 switch (type) {
3720 case ISCSI_BOOT_ETH_FLAGS:
3721 case ISCSI_BOOT_ETH_MAC:
3722 case ISCSI_BOOT_ETH_INDEX:
3723 rc = S_IRUGO;
3724 break;
3725 default:
3726 rc = 0;
3727 break;
3728 }
3729 return rc;
3730}
3731
3732static ssize_t qla4xxx_show_boot_ini_info(void *data, int type, char *buf)
3733{
3734 struct scsi_qla_host *ha = data;
3735 char *str = buf;
3736 int rc;
3737
3738 switch (type) {
3739 case ISCSI_BOOT_INI_INITIATOR_NAME:
3740 rc = sprintf(str, "%s\n", ha->name_string);
3741 break;
3742 default:
3743 rc = -ENOSYS;
3744 break;
3745 }
3746 return rc;
3747}
3748
Al Viro587a1f12011-07-23 23:11:19 -04003749static umode_t qla4xxx_ini_get_attr_visibility(void *data, int type)
Manish Rangankar2a991c22011-07-25 13:48:55 -05003750{
3751 int rc;
3752
3753 switch (type) {
3754 case ISCSI_BOOT_INI_INITIATOR_NAME:
3755 rc = S_IRUGO;
3756 break;
3757 default:
3758 rc = 0;
3759 break;
3760 }
3761 return rc;
3762}
3763
3764static ssize_t
3765qla4xxx_show_boot_tgt_info(struct ql4_boot_session_info *boot_sess, int type,
3766 char *buf)
3767{
3768 struct ql4_conn_info *boot_conn = &boot_sess->conn_list[0];
3769 char *str = buf;
3770 int rc;
3771
3772 switch (type) {
3773 case ISCSI_BOOT_TGT_NAME:
3774 rc = sprintf(buf, "%s\n", (char *)&boot_sess->target_name);
3775 break;
3776 case ISCSI_BOOT_TGT_IP_ADDR:
3777 if (boot_sess->conn_list[0].dest_ipaddr.ip_type == 0x1)
3778 rc = sprintf(buf, "%pI4\n",
3779 &boot_conn->dest_ipaddr.ip_address);
3780 else
3781 rc = sprintf(str, "%pI6\n",
3782 &boot_conn->dest_ipaddr.ip_address);
3783 break;
3784 case ISCSI_BOOT_TGT_PORT:
3785 rc = sprintf(str, "%d\n", boot_conn->dest_port);
3786 break;
3787 case ISCSI_BOOT_TGT_CHAP_NAME:
3788 rc = sprintf(str, "%.*s\n",
3789 boot_conn->chap.target_chap_name_length,
3790 (char *)&boot_conn->chap.target_chap_name);
3791 break;
3792 case ISCSI_BOOT_TGT_CHAP_SECRET:
3793 rc = sprintf(str, "%.*s\n",
3794 boot_conn->chap.target_secret_length,
3795 (char *)&boot_conn->chap.target_secret);
3796 break;
3797 case ISCSI_BOOT_TGT_REV_CHAP_NAME:
3798 rc = sprintf(str, "%.*s\n",
3799 boot_conn->chap.intr_chap_name_length,
3800 (char *)&boot_conn->chap.intr_chap_name);
3801 break;
3802 case ISCSI_BOOT_TGT_REV_CHAP_SECRET:
3803 rc = sprintf(str, "%.*s\n",
3804 boot_conn->chap.intr_secret_length,
3805 (char *)&boot_conn->chap.intr_secret);
3806 break;
3807 case ISCSI_BOOT_TGT_FLAGS:
3808 rc = sprintf(str, "%d\n", SYSFS_FLAG_FW_SEL_BOOT);
3809 break;
3810 case ISCSI_BOOT_TGT_NIC_ASSOC:
3811 rc = sprintf(str, "0\n");
3812 break;
3813 default:
3814 rc = -ENOSYS;
3815 break;
3816 }
3817 return rc;
3818}
3819
3820static ssize_t qla4xxx_show_boot_tgt_pri_info(void *data, int type, char *buf)
3821{
3822 struct scsi_qla_host *ha = data;
3823 struct ql4_boot_session_info *boot_sess = &(ha->boot_tgt.boot_pri_sess);
3824
3825 return qla4xxx_show_boot_tgt_info(boot_sess, type, buf);
3826}
3827
3828static ssize_t qla4xxx_show_boot_tgt_sec_info(void *data, int type, char *buf)
3829{
3830 struct scsi_qla_host *ha = data;
3831 struct ql4_boot_session_info *boot_sess = &(ha->boot_tgt.boot_sec_sess);
3832
3833 return qla4xxx_show_boot_tgt_info(boot_sess, type, buf);
3834}
3835
Al Viro587a1f12011-07-23 23:11:19 -04003836static umode_t qla4xxx_tgt_get_attr_visibility(void *data, int type)
Manish Rangankar2a991c22011-07-25 13:48:55 -05003837{
3838 int rc;
3839
3840 switch (type) {
3841 case ISCSI_BOOT_TGT_NAME:
3842 case ISCSI_BOOT_TGT_IP_ADDR:
3843 case ISCSI_BOOT_TGT_PORT:
3844 case ISCSI_BOOT_TGT_CHAP_NAME:
3845 case ISCSI_BOOT_TGT_CHAP_SECRET:
3846 case ISCSI_BOOT_TGT_REV_CHAP_NAME:
3847 case ISCSI_BOOT_TGT_REV_CHAP_SECRET:
3848 case ISCSI_BOOT_TGT_NIC_ASSOC:
3849 case ISCSI_BOOT_TGT_FLAGS:
3850 rc = S_IRUGO;
3851 break;
3852 default:
3853 rc = 0;
3854 break;
3855 }
3856 return rc;
3857}
3858
3859static void qla4xxx_boot_release(void *data)
3860{
3861 struct scsi_qla_host *ha = data;
3862
3863 scsi_host_put(ha->host);
3864}
3865
3866static int get_fw_boot_info(struct scsi_qla_host *ha, uint16_t ddb_index[])
3867{
3868 dma_addr_t buf_dma;
3869 uint32_t addr, pri_addr, sec_addr;
3870 uint32_t offset;
3871 uint16_t func_num;
3872 uint8_t val;
3873 uint8_t *buf = NULL;
3874 size_t size = 13 * sizeof(uint8_t);
3875 int ret = QLA_SUCCESS;
3876
3877 func_num = PCI_FUNC(ha->pdev->devfn);
3878
Manish Rangankar0d5b36b2011-10-07 16:55:51 -07003879 ql4_printk(KERN_INFO, ha, "%s: Get FW boot info for 0x%x func %d\n",
3880 __func__, ha->pdev->device, func_num);
Manish Rangankar2a991c22011-07-25 13:48:55 -05003881
Manish Rangankar0d5b36b2011-10-07 16:55:51 -07003882 if (is_qla40XX(ha)) {
Manish Rangankar2a991c22011-07-25 13:48:55 -05003883 if (func_num == 1) {
3884 addr = NVRAM_PORT0_BOOT_MODE;
3885 pri_addr = NVRAM_PORT0_BOOT_PRI_TGT;
3886 sec_addr = NVRAM_PORT0_BOOT_SEC_TGT;
3887 } else if (func_num == 3) {
3888 addr = NVRAM_PORT1_BOOT_MODE;
3889 pri_addr = NVRAM_PORT1_BOOT_PRI_TGT;
3890 sec_addr = NVRAM_PORT1_BOOT_SEC_TGT;
3891 } else {
3892 ret = QLA_ERROR;
3893 goto exit_boot_info;
3894 }
3895
3896 /* Check Boot Mode */
3897 val = rd_nvram_byte(ha, addr);
3898 if (!(val & 0x07)) {
Manish Rangankare8fb00e2012-02-13 18:30:43 +05303899 DEBUG2(ql4_printk(KERN_INFO, ha, "%s: Adapter boot "
3900 "options : 0x%x\n", __func__, val));
Manish Rangankar2a991c22011-07-25 13:48:55 -05003901 ret = QLA_ERROR;
3902 goto exit_boot_info;
3903 }
3904
3905 /* get primary valid target index */
3906 val = rd_nvram_byte(ha, pri_addr);
3907 if (val & BIT_7)
3908 ddb_index[0] = (val & 0x7f);
Manish Rangankar2a991c22011-07-25 13:48:55 -05003909
3910 /* get secondary valid target index */
3911 val = rd_nvram_byte(ha, sec_addr);
3912 if (val & BIT_7)
3913 ddb_index[1] = (val & 0x7f);
Manish Rangankar2a991c22011-07-25 13:48:55 -05003914
3915 } else if (is_qla8022(ha)) {
3916 buf = dma_alloc_coherent(&ha->pdev->dev, size,
3917 &buf_dma, GFP_KERNEL);
3918 if (!buf) {
3919 DEBUG2(ql4_printk(KERN_ERR, ha,
3920 "%s: Unable to allocate dma buffer\n",
3921 __func__));
3922 ret = QLA_ERROR;
3923 goto exit_boot_info;
3924 }
3925
3926 if (ha->port_num == 0)
3927 offset = BOOT_PARAM_OFFSET_PORT0;
3928 else if (ha->port_num == 1)
3929 offset = BOOT_PARAM_OFFSET_PORT1;
3930 else {
3931 ret = QLA_ERROR;
3932 goto exit_boot_info_free;
3933 }
3934 addr = FLASH_RAW_ACCESS_ADDR + (ha->hw.flt_iscsi_param * 4) +
3935 offset;
3936 if (qla4xxx_get_flash(ha, buf_dma, addr,
3937 13 * sizeof(uint8_t)) != QLA_SUCCESS) {
3938 DEBUG2(ql4_printk(KERN_ERR, ha, "scsi%ld: %s: Get Flash"
Petr Uzel0bd7f842012-02-24 16:32:59 +01003939 " failed\n", ha->host_no, __func__));
Manish Rangankar2a991c22011-07-25 13:48:55 -05003940 ret = QLA_ERROR;
3941 goto exit_boot_info_free;
3942 }
3943 /* Check Boot Mode */
3944 if (!(buf[1] & 0x07)) {
Manish Rangankare8fb00e2012-02-13 18:30:43 +05303945 DEBUG2(ql4_printk(KERN_INFO, ha, "Firmware boot options"
3946 " : 0x%x\n", buf[1]));
Manish Rangankar2a991c22011-07-25 13:48:55 -05003947 ret = QLA_ERROR;
3948 goto exit_boot_info_free;
3949 }
3950
3951 /* get primary valid target index */
3952 if (buf[2] & BIT_7)
3953 ddb_index[0] = buf[2] & 0x7f;
Manish Rangankar2a991c22011-07-25 13:48:55 -05003954
3955 /* get secondary valid target index */
3956 if (buf[11] & BIT_7)
3957 ddb_index[1] = buf[11] & 0x7f;
Manish Rangankar2a991c22011-07-25 13:48:55 -05003958 } else {
3959 ret = QLA_ERROR;
3960 goto exit_boot_info;
3961 }
3962
3963 DEBUG2(ql4_printk(KERN_INFO, ha, "%s: Primary target ID %d, Secondary"
3964 " target ID %d\n", __func__, ddb_index[0],
3965 ddb_index[1]));
3966
3967exit_boot_info_free:
3968 dma_free_coherent(&ha->pdev->dev, size, buf, buf_dma);
3969exit_boot_info:
Lalit Chandivade20e835b2012-02-13 18:30:42 +05303970 ha->pri_ddb_idx = ddb_index[0];
3971 ha->sec_ddb_idx = ddb_index[1];
Manish Rangankar2a991c22011-07-25 13:48:55 -05003972 return ret;
3973}
3974
Lalit Chandivade28deb452011-10-07 16:55:44 -07003975/**
3976 * qla4xxx_get_bidi_chap - Get a BIDI CHAP user and password
3977 * @ha: pointer to adapter structure
3978 * @username: CHAP username to be returned
3979 * @password: CHAP password to be returned
3980 *
3981 * If a boot entry has BIDI CHAP enabled then we need to set the BIDI CHAP
3982 * user and password in the sysfs entry in /sys/firmware/iscsi_boot#/.
3983 * So from the CHAP cache find the first BIDI CHAP entry and set it
3984 * to the boot record in sysfs.
3985 **/
3986static int qla4xxx_get_bidi_chap(struct scsi_qla_host *ha, char *username,
3987 char *password)
3988{
3989 int i, ret = -EINVAL;
3990 int max_chap_entries = 0;
3991 struct ql4_chap_table *chap_table;
3992
3993 if (is_qla8022(ha))
3994 max_chap_entries = (ha->hw.flt_chap_size / 2) /
3995 sizeof(struct ql4_chap_table);
3996 else
3997 max_chap_entries = MAX_CHAP_ENTRIES_40XX;
3998
3999 if (!ha->chap_list) {
4000 ql4_printk(KERN_ERR, ha, "Do not have CHAP table cache\n");
4001 return ret;
4002 }
4003
4004 mutex_lock(&ha->chap_sem);
4005 for (i = 0; i < max_chap_entries; i++) {
4006 chap_table = (struct ql4_chap_table *)ha->chap_list + i;
4007 if (chap_table->cookie !=
4008 __constant_cpu_to_le16(CHAP_VALID_COOKIE)) {
4009 continue;
4010 }
4011
4012 if (chap_table->flags & BIT_7) /* local */
4013 continue;
4014
4015 if (!(chap_table->flags & BIT_6)) /* Not BIDI */
4016 continue;
4017
4018 strncpy(password, chap_table->secret, QL4_CHAP_MAX_SECRET_LEN);
4019 strncpy(username, chap_table->name, QL4_CHAP_MAX_NAME_LEN);
4020 ret = 0;
4021 break;
4022 }
4023 mutex_unlock(&ha->chap_sem);
4024
4025 return ret;
4026}
4027
4028
Manish Rangankar2a991c22011-07-25 13:48:55 -05004029static int qla4xxx_get_boot_target(struct scsi_qla_host *ha,
4030 struct ql4_boot_session_info *boot_sess,
4031 uint16_t ddb_index)
4032{
4033 struct ql4_conn_info *boot_conn = &boot_sess->conn_list[0];
4034 struct dev_db_entry *fw_ddb_entry;
4035 dma_addr_t fw_ddb_entry_dma;
4036 uint16_t idx;
4037 uint16_t options;
4038 int ret = QLA_SUCCESS;
4039
4040 fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
4041 &fw_ddb_entry_dma, GFP_KERNEL);
4042 if (!fw_ddb_entry) {
4043 DEBUG2(ql4_printk(KERN_ERR, ha,
4044 "%s: Unable to allocate dma buffer.\n",
4045 __func__));
4046 ret = QLA_ERROR;
4047 return ret;
4048 }
4049
4050 if (qla4xxx_bootdb_by_index(ha, fw_ddb_entry,
4051 fw_ddb_entry_dma, ddb_index)) {
Manish Rangankare8fb00e2012-02-13 18:30:43 +05304052 DEBUG2(ql4_printk(KERN_INFO, ha, "%s: No Flash DDB found at "
4053 "index [%d]\n", __func__, ddb_index));
Manish Rangankar2a991c22011-07-25 13:48:55 -05004054 ret = QLA_ERROR;
4055 goto exit_boot_target;
4056 }
4057
4058 /* Update target name and IP from DDB */
4059 memcpy(boot_sess->target_name, fw_ddb_entry->iscsi_name,
4060 min(sizeof(boot_sess->target_name),
4061 sizeof(fw_ddb_entry->iscsi_name)));
4062
4063 options = le16_to_cpu(fw_ddb_entry->options);
4064 if (options & DDB_OPT_IPV6_DEVICE) {
4065 memcpy(&boot_conn->dest_ipaddr.ip_address,
4066 &fw_ddb_entry->ip_addr[0], IPv6_ADDR_LEN);
4067 } else {
4068 boot_conn->dest_ipaddr.ip_type = 0x1;
4069 memcpy(&boot_conn->dest_ipaddr.ip_address,
4070 &fw_ddb_entry->ip_addr[0], IP_ADDR_LEN);
4071 }
4072
4073 boot_conn->dest_port = le16_to_cpu(fw_ddb_entry->port);
4074
4075 /* update chap information */
4076 idx = __le16_to_cpu(fw_ddb_entry->chap_tbl_idx);
4077
4078 if (BIT_7 & le16_to_cpu(fw_ddb_entry->iscsi_options)) {
4079
4080 DEBUG2(ql4_printk(KERN_INFO, ha, "Setting chap\n"));
4081
4082 ret = qla4xxx_get_chap(ha, (char *)&boot_conn->chap.
4083 target_chap_name,
4084 (char *)&boot_conn->chap.target_secret,
4085 idx);
4086 if (ret) {
4087 ql4_printk(KERN_ERR, ha, "Failed to set chap\n");
4088 ret = QLA_ERROR;
4089 goto exit_boot_target;
4090 }
4091
4092 boot_conn->chap.target_chap_name_length = QL4_CHAP_MAX_NAME_LEN;
4093 boot_conn->chap.target_secret_length = QL4_CHAP_MAX_SECRET_LEN;
4094 }
4095
4096 if (BIT_4 & le16_to_cpu(fw_ddb_entry->iscsi_options)) {
4097
4098 DEBUG2(ql4_printk(KERN_INFO, ha, "Setting BIDI chap\n"));
4099
Lalit Chandivade28deb452011-10-07 16:55:44 -07004100 ret = qla4xxx_get_bidi_chap(ha,
4101 (char *)&boot_conn->chap.intr_chap_name,
4102 (char *)&boot_conn->chap.intr_secret);
4103
Manish Rangankar2a991c22011-07-25 13:48:55 -05004104 if (ret) {
4105 ql4_printk(KERN_ERR, ha, "Failed to set BIDI chap\n");
4106 ret = QLA_ERROR;
4107 goto exit_boot_target;
4108 }
4109
4110 boot_conn->chap.intr_chap_name_length = QL4_CHAP_MAX_NAME_LEN;
4111 boot_conn->chap.intr_secret_length = QL4_CHAP_MAX_SECRET_LEN;
4112 }
4113
4114exit_boot_target:
4115 dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
4116 fw_ddb_entry, fw_ddb_entry_dma);
4117 return ret;
4118}
4119
4120static int qla4xxx_get_boot_info(struct scsi_qla_host *ha)
4121{
4122 uint16_t ddb_index[2];
Lalit Chandivade8de5b952011-10-07 16:55:43 -07004123 int ret = QLA_ERROR;
4124 int rval;
Manish Rangankar2a991c22011-07-25 13:48:55 -05004125
4126 memset(ddb_index, 0, sizeof(ddb_index));
Lalit Chandivade8de5b952011-10-07 16:55:43 -07004127 ddb_index[0] = 0xffff;
4128 ddb_index[1] = 0xffff;
Manish Rangankar2a991c22011-07-25 13:48:55 -05004129 ret = get_fw_boot_info(ha, ddb_index);
4130 if (ret != QLA_SUCCESS) {
Manish Rangankare8fb00e2012-02-13 18:30:43 +05304131 DEBUG2(ql4_printk(KERN_INFO, ha,
4132 "%s: No boot target configured.\n", __func__));
Manish Rangankar2a991c22011-07-25 13:48:55 -05004133 return ret;
4134 }
4135
Mike Christie13483732011-12-01 21:38:41 -06004136 if (ql4xdisablesysfsboot)
4137 return QLA_SUCCESS;
4138
Lalit Chandivade8de5b952011-10-07 16:55:43 -07004139 if (ddb_index[0] == 0xffff)
4140 goto sec_target;
4141
4142 rval = qla4xxx_get_boot_target(ha, &(ha->boot_tgt.boot_pri_sess),
Manish Rangankar2a991c22011-07-25 13:48:55 -05004143 ddb_index[0]);
Lalit Chandivade8de5b952011-10-07 16:55:43 -07004144 if (rval != QLA_SUCCESS) {
Manish Rangankare8fb00e2012-02-13 18:30:43 +05304145 DEBUG2(ql4_printk(KERN_INFO, ha, "%s: Primary boot target not "
4146 "configured\n", __func__));
Lalit Chandivade8de5b952011-10-07 16:55:43 -07004147 } else
4148 ret = QLA_SUCCESS;
Manish Rangankar2a991c22011-07-25 13:48:55 -05004149
Lalit Chandivade8de5b952011-10-07 16:55:43 -07004150sec_target:
4151 if (ddb_index[1] == 0xffff)
4152 goto exit_get_boot_info;
4153
4154 rval = qla4xxx_get_boot_target(ha, &(ha->boot_tgt.boot_sec_sess),
Manish Rangankar2a991c22011-07-25 13:48:55 -05004155 ddb_index[1]);
Lalit Chandivade8de5b952011-10-07 16:55:43 -07004156 if (rval != QLA_SUCCESS) {
Manish Rangankare8fb00e2012-02-13 18:30:43 +05304157 DEBUG2(ql4_printk(KERN_INFO, ha, "%s: Secondary boot target not"
4158 " configured\n", __func__));
Lalit Chandivade8de5b952011-10-07 16:55:43 -07004159 } else
4160 ret = QLA_SUCCESS;
4161
4162exit_get_boot_info:
Manish Rangankar2a991c22011-07-25 13:48:55 -05004163 return ret;
4164}
4165
4166static int qla4xxx_setup_boot_info(struct scsi_qla_host *ha)
4167{
4168 struct iscsi_boot_kobj *boot_kobj;
4169
4170 if (qla4xxx_get_boot_info(ha) != QLA_SUCCESS)
Mike Christie13483732011-12-01 21:38:41 -06004171 return QLA_ERROR;
4172
4173 if (ql4xdisablesysfsboot) {
4174 ql4_printk(KERN_INFO, ha,
Petr Uzel0bd7f842012-02-24 16:32:59 +01004175 "%s: syfsboot disabled - driver will trigger login "
Mike Christie13483732011-12-01 21:38:41 -06004176 "and publish session for discovery .\n", __func__);
4177 return QLA_SUCCESS;
4178 }
4179
Manish Rangankar2a991c22011-07-25 13:48:55 -05004180
4181 ha->boot_kset = iscsi_boot_create_host_kset(ha->host->host_no);
4182 if (!ha->boot_kset)
4183 goto kset_free;
4184
4185 if (!scsi_host_get(ha->host))
4186 goto kset_free;
4187 boot_kobj = iscsi_boot_create_target(ha->boot_kset, 0, ha,
4188 qla4xxx_show_boot_tgt_pri_info,
4189 qla4xxx_tgt_get_attr_visibility,
4190 qla4xxx_boot_release);
4191 if (!boot_kobj)
4192 goto put_host;
4193
4194 if (!scsi_host_get(ha->host))
4195 goto kset_free;
4196 boot_kobj = iscsi_boot_create_target(ha->boot_kset, 1, ha,
4197 qla4xxx_show_boot_tgt_sec_info,
4198 qla4xxx_tgt_get_attr_visibility,
4199 qla4xxx_boot_release);
4200 if (!boot_kobj)
4201 goto put_host;
4202
4203 if (!scsi_host_get(ha->host))
4204 goto kset_free;
4205 boot_kobj = iscsi_boot_create_initiator(ha->boot_kset, 0, ha,
4206 qla4xxx_show_boot_ini_info,
4207 qla4xxx_ini_get_attr_visibility,
4208 qla4xxx_boot_release);
4209 if (!boot_kobj)
4210 goto put_host;
4211
4212 if (!scsi_host_get(ha->host))
4213 goto kset_free;
4214 boot_kobj = iscsi_boot_create_ethernet(ha->boot_kset, 0, ha,
4215 qla4xxx_show_boot_eth_info,
4216 qla4xxx_eth_get_attr_visibility,
4217 qla4xxx_boot_release);
4218 if (!boot_kobj)
4219 goto put_host;
4220
Mike Christie13483732011-12-01 21:38:41 -06004221 return QLA_SUCCESS;
Manish Rangankar2a991c22011-07-25 13:48:55 -05004222
4223put_host:
4224 scsi_host_put(ha->host);
4225kset_free:
4226 iscsi_boot_destroy_kset(ha->boot_kset);
4227 return -ENOMEM;
4228}
4229
Lalit Chandivade45494152011-10-07 16:55:42 -07004230
4231/**
4232 * qla4xxx_create chap_list - Create CHAP list from FLASH
4233 * @ha: pointer to adapter structure
4234 *
4235 * Read flash and make a list of CHAP entries, during login when a CHAP entry
4236 * is received, it will be checked in this list. If entry exist then the CHAP
4237 * entry index is set in the DDB. If CHAP entry does not exist in this list
4238 * then a new entry is added in FLASH in CHAP table and the index obtained is
4239 * used in the DDB.
4240 **/
4241static void qla4xxx_create_chap_list(struct scsi_qla_host *ha)
4242{
4243 int rval = 0;
4244 uint8_t *chap_flash_data = NULL;
4245 uint32_t offset;
4246 dma_addr_t chap_dma;
4247 uint32_t chap_size = 0;
4248
4249 if (is_qla40XX(ha))
4250 chap_size = MAX_CHAP_ENTRIES_40XX *
4251 sizeof(struct ql4_chap_table);
4252 else /* Single region contains CHAP info for both
4253 * ports which is divided into half for each port.
4254 */
4255 chap_size = ha->hw.flt_chap_size / 2;
4256
4257 chap_flash_data = dma_alloc_coherent(&ha->pdev->dev, chap_size,
4258 &chap_dma, GFP_KERNEL);
4259 if (!chap_flash_data) {
4260 ql4_printk(KERN_ERR, ha, "No memory for chap_flash_data\n");
4261 return;
4262 }
4263 if (is_qla40XX(ha))
4264 offset = FLASH_CHAP_OFFSET;
4265 else {
4266 offset = FLASH_RAW_ACCESS_ADDR + (ha->hw.flt_region_chap << 2);
4267 if (ha->port_num == 1)
4268 offset += chap_size;
4269 }
4270
4271 rval = qla4xxx_get_flash(ha, chap_dma, offset, chap_size);
4272 if (rval != QLA_SUCCESS)
4273 goto exit_chap_list;
4274
4275 if (ha->chap_list == NULL)
4276 ha->chap_list = vmalloc(chap_size);
4277 if (ha->chap_list == NULL) {
4278 ql4_printk(KERN_ERR, ha, "No memory for ha->chap_list\n");
4279 goto exit_chap_list;
4280 }
4281
4282 memcpy(ha->chap_list, chap_flash_data, chap_size);
4283
4284exit_chap_list:
4285 dma_free_coherent(&ha->pdev->dev, chap_size,
4286 chap_flash_data, chap_dma);
Lalit Chandivade45494152011-10-07 16:55:42 -07004287}
4288
Mike Christie13483732011-12-01 21:38:41 -06004289static void qla4xxx_get_param_ddb(struct ddb_entry *ddb_entry,
4290 struct ql4_tuple_ddb *tddb)
4291{
4292 struct scsi_qla_host *ha;
4293 struct iscsi_cls_session *cls_sess;
4294 struct iscsi_cls_conn *cls_conn;
4295 struct iscsi_session *sess;
4296 struct iscsi_conn *conn;
4297
4298 DEBUG2(printk(KERN_INFO "Func: %s\n", __func__));
4299 ha = ddb_entry->ha;
4300 cls_sess = ddb_entry->sess;
4301 sess = cls_sess->dd_data;
4302 cls_conn = ddb_entry->conn;
4303 conn = cls_conn->dd_data;
4304
4305 tddb->tpgt = sess->tpgt;
4306 tddb->port = conn->persistent_port;
4307 strncpy(tddb->iscsi_name, sess->targetname, ISCSI_NAME_SIZE);
4308 strncpy(tddb->ip_addr, conn->persistent_address, DDB_IPADDR_LEN);
4309}
4310
4311static void qla4xxx_convert_param_ddb(struct dev_db_entry *fw_ddb_entry,
Vikas Chaudhary1cb78d72012-06-14 06:35:48 -04004312 struct ql4_tuple_ddb *tddb,
4313 uint8_t *flash_isid)
Mike Christie13483732011-12-01 21:38:41 -06004314{
4315 uint16_t options = 0;
4316
4317 tddb->tpgt = le32_to_cpu(fw_ddb_entry->tgt_portal_grp);
4318 memcpy(&tddb->iscsi_name[0], &fw_ddb_entry->iscsi_name[0],
4319 min(sizeof(tddb->iscsi_name), sizeof(fw_ddb_entry->iscsi_name)));
4320
4321 options = le16_to_cpu(fw_ddb_entry->options);
4322 if (options & DDB_OPT_IPV6_DEVICE)
4323 sprintf(tddb->ip_addr, "%pI6", fw_ddb_entry->ip_addr);
4324 else
4325 sprintf(tddb->ip_addr, "%pI4", fw_ddb_entry->ip_addr);
4326
4327 tddb->port = le16_to_cpu(fw_ddb_entry->port);
Vikas Chaudhary1cb78d72012-06-14 06:35:48 -04004328
4329 if (flash_isid == NULL)
4330 memcpy(&tddb->isid[0], &fw_ddb_entry->isid[0],
4331 sizeof(tddb->isid));
4332 else
4333 memcpy(&tddb->isid[0], &flash_isid[0], sizeof(tddb->isid));
Mike Christie13483732011-12-01 21:38:41 -06004334}
4335
4336static int qla4xxx_compare_tuple_ddb(struct scsi_qla_host *ha,
4337 struct ql4_tuple_ddb *old_tddb,
Manish Rangankar173269e2012-02-27 03:08:55 -08004338 struct ql4_tuple_ddb *new_tddb,
4339 uint8_t is_isid_compare)
Mike Christie13483732011-12-01 21:38:41 -06004340{
4341 if (strcmp(old_tddb->iscsi_name, new_tddb->iscsi_name))
4342 return QLA_ERROR;
4343
4344 if (strcmp(old_tddb->ip_addr, new_tddb->ip_addr))
4345 return QLA_ERROR;
4346
4347 if (old_tddb->port != new_tddb->port)
4348 return QLA_ERROR;
4349
Manish Rangankar173269e2012-02-27 03:08:55 -08004350 /* For multi sessions, driver generates the ISID, so do not compare
4351 * ISID in reset path since it would be a comparision between the
4352 * driver generated ISID and firmware generated ISID. This could
4353 * lead to adding duplicated DDBs in the list as driver generated
4354 * ISID would not match firmware generated ISID.
4355 */
4356 if (is_isid_compare) {
4357 DEBUG2(ql4_printk(KERN_INFO, ha, "%s: old ISID [%02x%02x%02x"
4358 "%02x%02x%02x] New ISID [%02x%02x%02x%02x%02x%02x]\n",
4359 __func__, old_tddb->isid[5], old_tddb->isid[4],
4360 old_tddb->isid[3], old_tddb->isid[2], old_tddb->isid[1],
4361 old_tddb->isid[0], new_tddb->isid[5], new_tddb->isid[4],
4362 new_tddb->isid[3], new_tddb->isid[2], new_tddb->isid[1],
4363 new_tddb->isid[0]));
4364
4365 if (memcmp(&old_tddb->isid[0], &new_tddb->isid[0],
4366 sizeof(old_tddb->isid)))
4367 return QLA_ERROR;
4368 }
4369
Mike Christie13483732011-12-01 21:38:41 -06004370 DEBUG2(ql4_printk(KERN_INFO, ha,
4371 "Match Found, fw[%d,%d,%s,%s], [%d,%d,%s,%s]",
4372 old_tddb->port, old_tddb->tpgt, old_tddb->ip_addr,
4373 old_tddb->iscsi_name, new_tddb->port, new_tddb->tpgt,
4374 new_tddb->ip_addr, new_tddb->iscsi_name));
4375
4376 return QLA_SUCCESS;
4377}
4378
4379static int qla4xxx_is_session_exists(struct scsi_qla_host *ha,
4380 struct dev_db_entry *fw_ddb_entry)
4381{
4382 struct ddb_entry *ddb_entry;
4383 struct ql4_tuple_ddb *fw_tddb = NULL;
4384 struct ql4_tuple_ddb *tmp_tddb = NULL;
4385 int idx;
4386 int ret = QLA_ERROR;
4387
4388 fw_tddb = vzalloc(sizeof(*fw_tddb));
4389 if (!fw_tddb) {
4390 DEBUG2(ql4_printk(KERN_WARNING, ha,
4391 "Memory Allocation failed.\n"));
4392 ret = QLA_SUCCESS;
4393 goto exit_check;
4394 }
4395
4396 tmp_tddb = vzalloc(sizeof(*tmp_tddb));
4397 if (!tmp_tddb) {
4398 DEBUG2(ql4_printk(KERN_WARNING, ha,
4399 "Memory Allocation failed.\n"));
4400 ret = QLA_SUCCESS;
4401 goto exit_check;
4402 }
4403
Vikas Chaudhary1cb78d72012-06-14 06:35:48 -04004404 qla4xxx_convert_param_ddb(fw_ddb_entry, fw_tddb, NULL);
Mike Christie13483732011-12-01 21:38:41 -06004405
4406 for (idx = 0; idx < MAX_DDB_ENTRIES; idx++) {
4407 ddb_entry = qla4xxx_lookup_ddb_by_fw_index(ha, idx);
4408 if (ddb_entry == NULL)
4409 continue;
4410
4411 qla4xxx_get_param_ddb(ddb_entry, tmp_tddb);
Manish Rangankar173269e2012-02-27 03:08:55 -08004412 if (!qla4xxx_compare_tuple_ddb(ha, fw_tddb, tmp_tddb, false)) {
Mike Christie13483732011-12-01 21:38:41 -06004413 ret = QLA_SUCCESS; /* found */
4414 goto exit_check;
4415 }
4416 }
4417
4418exit_check:
4419 if (fw_tddb)
4420 vfree(fw_tddb);
4421 if (tmp_tddb)
4422 vfree(tmp_tddb);
4423 return ret;
4424}
4425
Vikas Chaudhary1cb78d72012-06-14 06:35:48 -04004426/**
4427 * qla4xxx_check_existing_isid - check if target with same isid exist
4428 * in target list
4429 * @list_nt: list of target
4430 * @isid: isid to check
4431 *
4432 * This routine return QLA_SUCCESS if target with same isid exist
4433 **/
4434static int qla4xxx_check_existing_isid(struct list_head *list_nt, uint8_t *isid)
4435{
4436 struct qla_ddb_index *nt_ddb_idx, *nt_ddb_idx_tmp;
4437 struct dev_db_entry *fw_ddb_entry;
4438
4439 list_for_each_entry_safe(nt_ddb_idx, nt_ddb_idx_tmp, list_nt, list) {
4440 fw_ddb_entry = &nt_ddb_idx->fw_ddb;
4441
4442 if (memcmp(&fw_ddb_entry->isid[0], &isid[0],
4443 sizeof(nt_ddb_idx->fw_ddb.isid)) == 0) {
4444 return QLA_SUCCESS;
4445 }
4446 }
4447 return QLA_ERROR;
4448}
4449
4450/**
4451 * qla4xxx_update_isid - compare ddbs and updated isid
4452 * @ha: Pointer to host adapter structure.
4453 * @list_nt: list of nt target
4454 * @fw_ddb_entry: firmware ddb entry
4455 *
4456 * This routine update isid if ddbs have same iqn, same isid and
4457 * different IP addr.
4458 * Return QLA_SUCCESS if isid is updated.
4459 **/
4460static int qla4xxx_update_isid(struct scsi_qla_host *ha,
4461 struct list_head *list_nt,
4462 struct dev_db_entry *fw_ddb_entry)
4463{
4464 uint8_t base_value, i;
4465
4466 base_value = fw_ddb_entry->isid[1] & 0x1f;
4467 for (i = 0; i < 8; i++) {
4468 fw_ddb_entry->isid[1] = (base_value | (i << 5));
4469 if (qla4xxx_check_existing_isid(list_nt, fw_ddb_entry->isid))
4470 break;
4471 }
4472
4473 if (!qla4xxx_check_existing_isid(list_nt, fw_ddb_entry->isid))
4474 return QLA_ERROR;
4475
4476 return QLA_SUCCESS;
4477}
4478
4479/**
4480 * qla4xxx_should_update_isid - check if isid need to update
4481 * @ha: Pointer to host adapter structure.
4482 * @old_tddb: ddb tuple
4483 * @new_tddb: ddb tuple
4484 *
4485 * Return QLA_SUCCESS if different IP, different PORT, same iqn,
4486 * same isid
4487 **/
4488static int qla4xxx_should_update_isid(struct scsi_qla_host *ha,
4489 struct ql4_tuple_ddb *old_tddb,
4490 struct ql4_tuple_ddb *new_tddb)
4491{
4492 if (strcmp(old_tddb->ip_addr, new_tddb->ip_addr) == 0) {
4493 /* Same ip */
4494 if (old_tddb->port == new_tddb->port)
4495 return QLA_ERROR;
4496 }
4497
4498 if (strcmp(old_tddb->iscsi_name, new_tddb->iscsi_name))
4499 /* different iqn */
4500 return QLA_ERROR;
4501
4502 if (memcmp(&old_tddb->isid[0], &new_tddb->isid[0],
4503 sizeof(old_tddb->isid)))
4504 /* different isid */
4505 return QLA_ERROR;
4506
4507 return QLA_SUCCESS;
4508}
4509
4510/**
4511 * qla4xxx_is_flash_ddb_exists - check if fw_ddb_entry already exists in list_nt
4512 * @ha: Pointer to host adapter structure.
4513 * @list_nt: list of nt target.
4514 * @fw_ddb_entry: firmware ddb entry.
4515 *
4516 * This routine check if fw_ddb_entry already exists in list_nt to avoid
4517 * duplicate ddb in list_nt.
4518 * Return QLA_SUCCESS if duplicate ddb exit in list_nl.
4519 * Note: This function also update isid of DDB if required.
4520 **/
4521
Mike Christie13483732011-12-01 21:38:41 -06004522static int qla4xxx_is_flash_ddb_exists(struct scsi_qla_host *ha,
4523 struct list_head *list_nt,
4524 struct dev_db_entry *fw_ddb_entry)
4525{
4526 struct qla_ddb_index *nt_ddb_idx, *nt_ddb_idx_tmp;
4527 struct ql4_tuple_ddb *fw_tddb = NULL;
4528 struct ql4_tuple_ddb *tmp_tddb = NULL;
Vikas Chaudhary1cb78d72012-06-14 06:35:48 -04004529 int rval, ret = QLA_ERROR;
Mike Christie13483732011-12-01 21:38:41 -06004530
4531 fw_tddb = vzalloc(sizeof(*fw_tddb));
4532 if (!fw_tddb) {
4533 DEBUG2(ql4_printk(KERN_WARNING, ha,
4534 "Memory Allocation failed.\n"));
4535 ret = QLA_SUCCESS;
4536 goto exit_check;
4537 }
4538
4539 tmp_tddb = vzalloc(sizeof(*tmp_tddb));
4540 if (!tmp_tddb) {
4541 DEBUG2(ql4_printk(KERN_WARNING, ha,
4542 "Memory Allocation failed.\n"));
4543 ret = QLA_SUCCESS;
4544 goto exit_check;
4545 }
4546
Vikas Chaudhary1cb78d72012-06-14 06:35:48 -04004547 qla4xxx_convert_param_ddb(fw_ddb_entry, fw_tddb, NULL);
Mike Christie13483732011-12-01 21:38:41 -06004548
4549 list_for_each_entry_safe(nt_ddb_idx, nt_ddb_idx_tmp, list_nt, list) {
Vikas Chaudhary1cb78d72012-06-14 06:35:48 -04004550 qla4xxx_convert_param_ddb(&nt_ddb_idx->fw_ddb, tmp_tddb,
4551 nt_ddb_idx->flash_isid);
4552 ret = qla4xxx_compare_tuple_ddb(ha, fw_tddb, tmp_tddb, true);
4553 /* found duplicate ddb */
4554 if (ret == QLA_SUCCESS)
4555 goto exit_check;
4556 }
4557
4558 list_for_each_entry_safe(nt_ddb_idx, nt_ddb_idx_tmp, list_nt, list) {
4559 qla4xxx_convert_param_ddb(&nt_ddb_idx->fw_ddb, tmp_tddb, NULL);
4560
4561 ret = qla4xxx_should_update_isid(ha, tmp_tddb, fw_tddb);
4562 if (ret == QLA_SUCCESS) {
4563 rval = qla4xxx_update_isid(ha, list_nt, fw_ddb_entry);
4564 if (rval == QLA_SUCCESS)
4565 ret = QLA_ERROR;
4566 else
4567 ret = QLA_SUCCESS;
4568
Mike Christie13483732011-12-01 21:38:41 -06004569 goto exit_check;
4570 }
4571 }
4572
4573exit_check:
4574 if (fw_tddb)
4575 vfree(fw_tddb);
4576 if (tmp_tddb)
4577 vfree(tmp_tddb);
4578 return ret;
4579}
4580
Lalit Chandivade4a4bc2e2011-12-16 01:58:55 -08004581static void qla4xxx_free_ddb_list(struct list_head *list_ddb)
Mike Christie13483732011-12-01 21:38:41 -06004582{
Lalit Chandivade4a4bc2e2011-12-16 01:58:55 -08004583 struct qla_ddb_index *ddb_idx, *ddb_idx_tmp;
Mike Christie13483732011-12-01 21:38:41 -06004584
Lalit Chandivade4a4bc2e2011-12-16 01:58:55 -08004585 list_for_each_entry_safe(ddb_idx, ddb_idx_tmp, list_ddb, list) {
4586 list_del_init(&ddb_idx->list);
4587 vfree(ddb_idx);
Mike Christie13483732011-12-01 21:38:41 -06004588 }
Mike Christie13483732011-12-01 21:38:41 -06004589}
4590
4591static struct iscsi_endpoint *qla4xxx_get_ep_fwdb(struct scsi_qla_host *ha,
4592 struct dev_db_entry *fw_ddb_entry)
4593{
4594 struct iscsi_endpoint *ep;
4595 struct sockaddr_in *addr;
4596 struct sockaddr_in6 *addr6;
4597 struct sockaddr *dst_addr;
4598 char *ip;
4599
4600 /* TODO: need to destroy on unload iscsi_endpoint*/
4601 dst_addr = vmalloc(sizeof(*dst_addr));
4602 if (!dst_addr)
4603 return NULL;
4604
4605 if (fw_ddb_entry->options & DDB_OPT_IPV6_DEVICE) {
4606 dst_addr->sa_family = AF_INET6;
4607 addr6 = (struct sockaddr_in6 *)dst_addr;
4608 ip = (char *)&addr6->sin6_addr;
4609 memcpy(ip, fw_ddb_entry->ip_addr, IPv6_ADDR_LEN);
4610 addr6->sin6_port = htons(le16_to_cpu(fw_ddb_entry->port));
4611
4612 } else {
4613 dst_addr->sa_family = AF_INET;
4614 addr = (struct sockaddr_in *)dst_addr;
4615 ip = (char *)&addr->sin_addr;
4616 memcpy(ip, fw_ddb_entry->ip_addr, IP_ADDR_LEN);
4617 addr->sin_port = htons(le16_to_cpu(fw_ddb_entry->port));
4618 }
4619
4620 ep = qla4xxx_ep_connect(ha->host, dst_addr, 0);
4621 vfree(dst_addr);
4622 return ep;
4623}
4624
4625static int qla4xxx_verify_boot_idx(struct scsi_qla_host *ha, uint16_t idx)
4626{
4627 if (ql4xdisablesysfsboot)
4628 return QLA_SUCCESS;
4629 if (idx == ha->pri_ddb_idx || idx == ha->sec_ddb_idx)
4630 return QLA_ERROR;
4631 return QLA_SUCCESS;
4632}
4633
4634static void qla4xxx_setup_flash_ddb_entry(struct scsi_qla_host *ha,
4635 struct ddb_entry *ddb_entry)
4636{
Nilesh Javalic28eaac2011-12-18 21:40:44 -08004637 uint16_t def_timeout;
4638
Mike Christie13483732011-12-01 21:38:41 -06004639 ddb_entry->ddb_type = FLASH_DDB;
4640 ddb_entry->fw_ddb_index = INVALID_ENTRY;
4641 ddb_entry->fw_ddb_device_state = DDB_DS_NO_CONNECTION_ACTIVE;
4642 ddb_entry->ha = ha;
4643 ddb_entry->unblock_sess = qla4xxx_unblock_flash_ddb;
4644 ddb_entry->ddb_change = qla4xxx_flash_ddb_change;
4645
4646 atomic_set(&ddb_entry->retry_relogin_timer, INVALID_ENTRY);
4647 atomic_set(&ddb_entry->relogin_timer, 0);
4648 atomic_set(&ddb_entry->relogin_retry_count, 0);
Nilesh Javalic28eaac2011-12-18 21:40:44 -08004649 def_timeout = le16_to_cpu(ddb_entry->fw_ddb_entry.def_timeout);
Mike Christie13483732011-12-01 21:38:41 -06004650 ddb_entry->default_relogin_timeout =
Nilesh Javalic28eaac2011-12-18 21:40:44 -08004651 (def_timeout > LOGIN_TOV) && (def_timeout < LOGIN_TOV * 10) ?
4652 def_timeout : LOGIN_TOV;
Mike Christie13483732011-12-01 21:38:41 -06004653 ddb_entry->default_time2wait =
4654 le16_to_cpu(ddb_entry->fw_ddb_entry.iscsi_def_time2wait);
4655}
4656
4657static void qla4xxx_wait_for_ip_configuration(struct scsi_qla_host *ha)
4658{
4659 uint32_t idx = 0;
4660 uint32_t ip_idx[IP_ADDR_COUNT] = {0, 1, 2, 3}; /* 4 IP interfaces */
4661 uint32_t sts[MBOX_REG_COUNT];
4662 uint32_t ip_state;
4663 unsigned long wtime;
4664 int ret;
4665
4666 wtime = jiffies + (HZ * IP_CONFIG_TOV);
4667 do {
4668 for (idx = 0; idx < IP_ADDR_COUNT; idx++) {
4669 if (ip_idx[idx] == -1)
4670 continue;
4671
4672 ret = qla4xxx_get_ip_state(ha, 0, ip_idx[idx], sts);
4673
4674 if (ret == QLA_ERROR) {
4675 ip_idx[idx] = -1;
4676 continue;
4677 }
4678
4679 ip_state = (sts[1] & IP_STATE_MASK) >> IP_STATE_SHIFT;
4680
4681 DEBUG2(ql4_printk(KERN_INFO, ha,
4682 "Waiting for IP state for idx = %d, state = 0x%x\n",
4683 ip_idx[idx], ip_state));
4684 if (ip_state == IP_ADDRSTATE_UNCONFIGURED ||
4685 ip_state == IP_ADDRSTATE_INVALID ||
4686 ip_state == IP_ADDRSTATE_PREFERRED ||
4687 ip_state == IP_ADDRSTATE_DEPRICATED ||
4688 ip_state == IP_ADDRSTATE_DISABLING)
4689 ip_idx[idx] = -1;
Mike Christie13483732011-12-01 21:38:41 -06004690 }
4691
4692 /* Break if all IP states checked */
4693 if ((ip_idx[0] == -1) &&
4694 (ip_idx[1] == -1) &&
4695 (ip_idx[2] == -1) &&
4696 (ip_idx[3] == -1))
4697 break;
4698 schedule_timeout_uninterruptible(HZ);
4699 } while (time_after(wtime, jiffies));
4700}
4701
Lalit Chandivade4a4bc2e2011-12-16 01:58:55 -08004702static void qla4xxx_build_st_list(struct scsi_qla_host *ha,
4703 struct list_head *list_st)
Mike Christie13483732011-12-01 21:38:41 -06004704{
Lalit Chandivade4a4bc2e2011-12-16 01:58:55 -08004705 struct qla_ddb_index *st_ddb_idx;
Mike Christie13483732011-12-01 21:38:41 -06004706 int max_ddbs;
Lalit Chandivade4a4bc2e2011-12-16 01:58:55 -08004707 int fw_idx_size;
4708 struct dev_db_entry *fw_ddb_entry;
4709 dma_addr_t fw_ddb_dma;
Mike Christie13483732011-12-01 21:38:41 -06004710 int ret;
4711 uint32_t idx = 0, next_idx = 0;
4712 uint32_t state = 0, conn_err = 0;
Lalit Chandivade4a4bc2e2011-12-16 01:58:55 -08004713 uint16_t conn_id = 0;
Mike Christie13483732011-12-01 21:38:41 -06004714
4715 fw_ddb_entry = dma_pool_alloc(ha->fw_ddb_dma_pool, GFP_KERNEL,
4716 &fw_ddb_dma);
4717 if (fw_ddb_entry == NULL) {
4718 DEBUG2(ql4_printk(KERN_ERR, ha, "Out of memory\n"));
Lalit Chandivade4a4bc2e2011-12-16 01:58:55 -08004719 goto exit_st_list;
Mike Christie13483732011-12-01 21:38:41 -06004720 }
4721
Lalit Chandivade4a4bc2e2011-12-16 01:58:55 -08004722 max_ddbs = is_qla40XX(ha) ? MAX_DEV_DB_ENTRIES_40XX :
4723 MAX_DEV_DB_ENTRIES;
Mike Christie13483732011-12-01 21:38:41 -06004724 fw_idx_size = sizeof(struct qla_ddb_index);
4725
4726 for (idx = 0; idx < max_ddbs; idx = next_idx) {
Lalit Chandivade4a4bc2e2011-12-16 01:58:55 -08004727 ret = qla4xxx_get_fwddb_entry(ha, idx, fw_ddb_entry, fw_ddb_dma,
4728 NULL, &next_idx, &state,
4729 &conn_err, NULL, &conn_id);
Mike Christie13483732011-12-01 21:38:41 -06004730 if (ret == QLA_ERROR)
4731 break;
4732
Lalit Chandivade981c9822012-02-13 18:30:41 +05304733 /* Ignore DDB if invalid state (unassigned) */
4734 if (state == DDB_DS_UNASSIGNED)
4735 goto continue_next_st;
4736
Mike Christie13483732011-12-01 21:38:41 -06004737 /* Check if ST, add to the list_st */
4738 if (strlen((char *) fw_ddb_entry->iscsi_name) != 0)
4739 goto continue_next_st;
4740
4741 st_ddb_idx = vzalloc(fw_idx_size);
4742 if (!st_ddb_idx)
4743 break;
4744
4745 st_ddb_idx->fw_ddb_idx = idx;
4746
Lalit Chandivade4a4bc2e2011-12-16 01:58:55 -08004747 list_add_tail(&st_ddb_idx->list, list_st);
Mike Christie13483732011-12-01 21:38:41 -06004748continue_next_st:
4749 if (next_idx == 0)
4750 break;
4751 }
4752
Lalit Chandivade4a4bc2e2011-12-16 01:58:55 -08004753exit_st_list:
4754 if (fw_ddb_entry)
4755 dma_pool_free(ha->fw_ddb_dma_pool, fw_ddb_entry, fw_ddb_dma);
4756}
4757
4758/**
4759 * qla4xxx_remove_failed_ddb - Remove inactive or failed ddb from list
4760 * @ha: pointer to adapter structure
4761 * @list_ddb: List from which failed ddb to be removed
4762 *
4763 * Iterate over the list of DDBs and find and remove DDBs that are either in
4764 * no connection active state or failed state
4765 **/
4766static void qla4xxx_remove_failed_ddb(struct scsi_qla_host *ha,
4767 struct list_head *list_ddb)
4768{
4769 struct qla_ddb_index *ddb_idx, *ddb_idx_tmp;
4770 uint32_t next_idx = 0;
4771 uint32_t state = 0, conn_err = 0;
4772 int ret;
4773
4774 list_for_each_entry_safe(ddb_idx, ddb_idx_tmp, list_ddb, list) {
4775 ret = qla4xxx_get_fwddb_entry(ha, ddb_idx->fw_ddb_idx,
4776 NULL, 0, NULL, &next_idx, &state,
4777 &conn_err, NULL, NULL);
4778 if (ret == QLA_ERROR)
4779 continue;
4780
4781 if (state == DDB_DS_NO_CONNECTION_ACTIVE ||
4782 state == DDB_DS_SESSION_FAILED) {
4783 list_del_init(&ddb_idx->list);
4784 vfree(ddb_idx);
4785 }
4786 }
4787}
4788
4789static int qla4xxx_sess_conn_setup(struct scsi_qla_host *ha,
4790 struct dev_db_entry *fw_ddb_entry,
4791 int is_reset)
4792{
4793 struct iscsi_cls_session *cls_sess;
4794 struct iscsi_session *sess;
4795 struct iscsi_cls_conn *cls_conn;
4796 struct iscsi_endpoint *ep;
4797 uint16_t cmds_max = 32;
4798 uint16_t conn_id = 0;
4799 uint32_t initial_cmdsn = 0;
4800 int ret = QLA_SUCCESS;
4801
4802 struct ddb_entry *ddb_entry = NULL;
4803
4804 /* Create session object, with INVALID_ENTRY,
4805 * the targer_id would get set when we issue the login
4806 */
4807 cls_sess = iscsi_session_setup(&qla4xxx_iscsi_transport, ha->host,
4808 cmds_max, sizeof(struct ddb_entry),
4809 sizeof(struct ql4_task_data),
4810 initial_cmdsn, INVALID_ENTRY);
4811 if (!cls_sess) {
4812 ret = QLA_ERROR;
4813 goto exit_setup;
4814 }
4815
4816 /*
4817 * so calling module_put function to decrement the
4818 * reference count.
4819 **/
4820 module_put(qla4xxx_iscsi_transport.owner);
4821 sess = cls_sess->dd_data;
4822 ddb_entry = sess->dd_data;
4823 ddb_entry->sess = cls_sess;
4824
4825 cls_sess->recovery_tmo = ql4xsess_recovery_tmo;
4826 memcpy(&ddb_entry->fw_ddb_entry, fw_ddb_entry,
4827 sizeof(struct dev_db_entry));
4828
4829 qla4xxx_setup_flash_ddb_entry(ha, ddb_entry);
4830
4831 cls_conn = iscsi_conn_setup(cls_sess, sizeof(struct qla_conn), conn_id);
4832
4833 if (!cls_conn) {
4834 ret = QLA_ERROR;
4835 goto exit_setup;
4836 }
4837
4838 ddb_entry->conn = cls_conn;
4839
4840 /* Setup ep, for displaying attributes in sysfs */
4841 ep = qla4xxx_get_ep_fwdb(ha, fw_ddb_entry);
4842 if (ep) {
4843 ep->conn = cls_conn;
4844 cls_conn->ep = ep;
4845 } else {
4846 DEBUG2(ql4_printk(KERN_ERR, ha, "Unable to get ep\n"));
4847 ret = QLA_ERROR;
4848 goto exit_setup;
4849 }
4850
4851 /* Update sess/conn params */
4852 qla4xxx_copy_fwddb_param(ha, fw_ddb_entry, cls_sess, cls_conn);
4853
4854 if (is_reset == RESET_ADAPTER) {
4855 iscsi_block_session(cls_sess);
4856 /* Use the relogin path to discover new devices
4857 * by short-circuting the logic of setting
4858 * timer to relogin - instead set the flags
4859 * to initiate login right away.
4860 */
4861 set_bit(DPC_RELOGIN_DEVICE, &ha->dpc_flags);
4862 set_bit(DF_RELOGIN, &ddb_entry->flags);
4863 }
4864
4865exit_setup:
4866 return ret;
4867}
4868
4869static void qla4xxx_build_nt_list(struct scsi_qla_host *ha,
4870 struct list_head *list_nt, int is_reset)
4871{
4872 struct dev_db_entry *fw_ddb_entry;
4873 dma_addr_t fw_ddb_dma;
4874 int max_ddbs;
4875 int fw_idx_size;
4876 int ret;
4877 uint32_t idx = 0, next_idx = 0;
4878 uint32_t state = 0, conn_err = 0;
4879 uint16_t conn_id = 0;
4880 struct qla_ddb_index *nt_ddb_idx;
4881
4882 fw_ddb_entry = dma_pool_alloc(ha->fw_ddb_dma_pool, GFP_KERNEL,
4883 &fw_ddb_dma);
4884 if (fw_ddb_entry == NULL) {
4885 DEBUG2(ql4_printk(KERN_ERR, ha, "Out of memory\n"));
4886 goto exit_nt_list;
4887 }
4888 max_ddbs = is_qla40XX(ha) ? MAX_DEV_DB_ENTRIES_40XX :
4889 MAX_DEV_DB_ENTRIES;
4890 fw_idx_size = sizeof(struct qla_ddb_index);
4891
4892 for (idx = 0; idx < max_ddbs; idx = next_idx) {
4893 ret = qla4xxx_get_fwddb_entry(ha, idx, fw_ddb_entry, fw_ddb_dma,
4894 NULL, &next_idx, &state,
4895 &conn_err, NULL, &conn_id);
4896 if (ret == QLA_ERROR)
4897 break;
4898
4899 if (qla4xxx_verify_boot_idx(ha, idx) != QLA_SUCCESS)
4900 goto continue_next_nt;
4901
4902 /* Check if NT, then add to list it */
4903 if (strlen((char *) fw_ddb_entry->iscsi_name) == 0)
4904 goto continue_next_nt;
4905
4906 if (!(state == DDB_DS_NO_CONNECTION_ACTIVE ||
4907 state == DDB_DS_SESSION_FAILED))
4908 goto continue_next_nt;
4909
4910 DEBUG2(ql4_printk(KERN_INFO, ha,
4911 "Adding DDB to session = 0x%x\n", idx));
4912 if (is_reset == INIT_ADAPTER) {
4913 nt_ddb_idx = vmalloc(fw_idx_size);
4914 if (!nt_ddb_idx)
4915 break;
4916
4917 nt_ddb_idx->fw_ddb_idx = idx;
4918
Vikas Chaudhary1cb78d72012-06-14 06:35:48 -04004919 /* Copy original isid as it may get updated in function
4920 * qla4xxx_update_isid(). We need original isid in
4921 * function qla4xxx_compare_tuple_ddb to find duplicate
4922 * target */
4923 memcpy(&nt_ddb_idx->flash_isid[0],
4924 &fw_ddb_entry->isid[0],
4925 sizeof(nt_ddb_idx->flash_isid));
Lalit Chandivade4a4bc2e2011-12-16 01:58:55 -08004926
Vikas Chaudhary1cb78d72012-06-14 06:35:48 -04004927 ret = qla4xxx_is_flash_ddb_exists(ha, list_nt,
4928 fw_ddb_entry);
4929 if (ret == QLA_SUCCESS) {
4930 /* free nt_ddb_idx and do not add to list_nt */
Lalit Chandivade4a4bc2e2011-12-16 01:58:55 -08004931 vfree(nt_ddb_idx);
4932 goto continue_next_nt;
4933 }
Vikas Chaudhary1cb78d72012-06-14 06:35:48 -04004934
4935 /* Copy updated isid */
4936 memcpy(&nt_ddb_idx->fw_ddb, fw_ddb_entry,
4937 sizeof(struct dev_db_entry));
4938
Lalit Chandivade4a4bc2e2011-12-16 01:58:55 -08004939 list_add_tail(&nt_ddb_idx->list, list_nt);
4940 } else if (is_reset == RESET_ADAPTER) {
4941 if (qla4xxx_is_session_exists(ha, fw_ddb_entry) ==
4942 QLA_SUCCESS)
4943 goto continue_next_nt;
4944 }
4945
4946 ret = qla4xxx_sess_conn_setup(ha, fw_ddb_entry, is_reset);
4947 if (ret == QLA_ERROR)
4948 goto exit_nt_list;
4949
4950continue_next_nt:
4951 if (next_idx == 0)
4952 break;
4953 }
4954
4955exit_nt_list:
4956 if (fw_ddb_entry)
4957 dma_pool_free(ha->fw_ddb_dma_pool, fw_ddb_entry, fw_ddb_dma);
4958}
4959
4960/**
4961 * qla4xxx_build_ddb_list - Build ddb list and setup sessions
4962 * @ha: pointer to adapter structure
4963 * @is_reset: Is this init path or reset path
4964 *
4965 * Create a list of sendtargets (st) from firmware DDBs, issue send targets
4966 * using connection open, then create the list of normal targets (nt)
4967 * from firmware DDBs. Based on the list of nt setup session and connection
4968 * objects.
4969 **/
4970void qla4xxx_build_ddb_list(struct scsi_qla_host *ha, int is_reset)
4971{
4972 uint16_t tmo = 0;
4973 struct list_head list_st, list_nt;
4974 struct qla_ddb_index *st_ddb_idx, *st_ddb_idx_tmp;
4975 unsigned long wtime;
4976
4977 if (!test_bit(AF_LINK_UP, &ha->flags)) {
4978 set_bit(AF_BUILD_DDB_LIST, &ha->flags);
4979 ha->is_reset = is_reset;
4980 return;
4981 }
4982
4983 INIT_LIST_HEAD(&list_st);
4984 INIT_LIST_HEAD(&list_nt);
4985
4986 qla4xxx_build_st_list(ha, &list_st);
4987
Mike Christie13483732011-12-01 21:38:41 -06004988 /* Before issuing conn open mbox, ensure all IPs states are configured
4989 * Note, conn open fails if IPs are not configured
4990 */
4991 qla4xxx_wait_for_ip_configuration(ha);
4992
4993 /* Go thru the STs and fire the sendtargets by issuing conn open mbx */
4994 list_for_each_entry_safe(st_ddb_idx, st_ddb_idx_tmp, &list_st, list) {
4995 qla4xxx_conn_open(ha, st_ddb_idx->fw_ddb_idx);
4996 }
4997
4998 /* Wait to ensure all sendtargets are done for min 12 sec wait */
Nilesh Javalic28eaac2011-12-18 21:40:44 -08004999 tmo = ((ha->def_timeout > LOGIN_TOV) &&
5000 (ha->def_timeout < LOGIN_TOV * 10) ?
5001 ha->def_timeout : LOGIN_TOV);
5002
Mike Christie13483732011-12-01 21:38:41 -06005003 DEBUG2(ql4_printk(KERN_INFO, ha,
5004 "Default time to wait for build ddb %d\n", tmo));
5005
5006 wtime = jiffies + (HZ * tmo);
5007 do {
Nilesh Javalif1f2e602011-12-16 01:58:57 -08005008 if (list_empty(&list_st))
5009 break;
5010
Lalit Chandivade4a4bc2e2011-12-16 01:58:55 -08005011 qla4xxx_remove_failed_ddb(ha, &list_st);
Mike Christie13483732011-12-01 21:38:41 -06005012 schedule_timeout_uninterruptible(HZ / 10);
5013 } while (time_after(wtime, jiffies));
5014
5015 /* Free up the sendtargets list */
Lalit Chandivade4a4bc2e2011-12-16 01:58:55 -08005016 qla4xxx_free_ddb_list(&list_st);
Mike Christie13483732011-12-01 21:38:41 -06005017
Lalit Chandivade4a4bc2e2011-12-16 01:58:55 -08005018 qla4xxx_build_nt_list(ha, &list_nt, is_reset);
Mike Christie13483732011-12-01 21:38:41 -06005019
Lalit Chandivade4a4bc2e2011-12-16 01:58:55 -08005020 qla4xxx_free_ddb_list(&list_nt);
Mike Christie13483732011-12-01 21:38:41 -06005021
5022 qla4xxx_free_ddb_index(ha);
5023}
5024
David Somayajuluafaf5a22006-09-19 10:28:00 -07005025/**
5026 * qla4xxx_probe_adapter - callback function to probe HBA
5027 * @pdev: pointer to pci_dev structure
5028 * @pci_device_id: pointer to pci_device entry
5029 *
5030 * This routine will probe for Qlogic 4xxx iSCSI host adapters.
5031 * It returns zero if successful. It also initializes all data necessary for
5032 * the driver.
5033 **/
5034static int __devinit qla4xxx_probe_adapter(struct pci_dev *pdev,
5035 const struct pci_device_id *ent)
5036{
5037 int ret = -ENODEV, status;
5038 struct Scsi_Host *host;
5039 struct scsi_qla_host *ha;
David Somayajuluafaf5a22006-09-19 10:28:00 -07005040 uint8_t init_retry_count = 0;
5041 char buf[34];
Vikas Chaudharyf4f5df22010-07-28 15:53:44 +05305042 struct qla4_8xxx_legacy_intr_set *nx_legacy_intr;
Prasanna Mumbaif9880e72011-03-21 03:34:26 -07005043 uint32_t dev_state;
David Somayajuluafaf5a22006-09-19 10:28:00 -07005044
5045 if (pci_enable_device(pdev))
5046 return -1;
5047
Manish Rangankarb3a271a2011-07-25 13:48:53 -05005048 host = iscsi_host_alloc(&qla4xxx_driver_template, sizeof(*ha), 0);
David Somayajuluafaf5a22006-09-19 10:28:00 -07005049 if (host == NULL) {
5050 printk(KERN_WARNING
5051 "qla4xxx: Couldn't allocate host from scsi layer!\n");
5052 goto probe_disable_device;
5053 }
5054
5055 /* Clear our data area */
Manish Rangankarb3a271a2011-07-25 13:48:53 -05005056 ha = to_qla_host(host);
David Somayajuluafaf5a22006-09-19 10:28:00 -07005057 memset(ha, 0, sizeof(*ha));
5058
5059 /* Save the information from PCI BIOS. */
5060 ha->pdev = pdev;
5061 ha->host = host;
5062 ha->host_no = host->host_no;
5063
Lalit Chandivade2232be02010-07-30 14:38:47 +05305064 pci_enable_pcie_error_reporting(pdev);
5065
Vikas Chaudharyf4f5df22010-07-28 15:53:44 +05305066 /* Setup Runtime configurable options */
5067 if (is_qla8022(ha)) {
5068 ha->isp_ops = &qla4_8xxx_isp_ops;
5069 rwlock_init(&ha->hw_lock);
5070 ha->qdr_sn_window = -1;
5071 ha->ddr_mn_window = -1;
5072 ha->curr_window = 255;
5073 ha->func_num = PCI_FUNC(ha->pdev->devfn);
5074 nx_legacy_intr = &legacy_intr[ha->func_num];
5075 ha->nx_legacy_intr.int_vec_bit = nx_legacy_intr->int_vec_bit;
5076 ha->nx_legacy_intr.tgt_status_reg =
5077 nx_legacy_intr->tgt_status_reg;
5078 ha->nx_legacy_intr.tgt_mask_reg = nx_legacy_intr->tgt_mask_reg;
5079 ha->nx_legacy_intr.pci_int_reg = nx_legacy_intr->pci_int_reg;
5080 } else {
5081 ha->isp_ops = &qla4xxx_isp_ops;
5082 }
5083
Lalit Chandivade2232be02010-07-30 14:38:47 +05305084 /* Set EEH reset type to fundamental if required by hba */
5085 if (is_qla8022(ha))
5086 pdev->needs_freset = 1;
5087
David Somayajuluafaf5a22006-09-19 10:28:00 -07005088 /* Configure PCI I/O space. */
Vikas Chaudharyf4f5df22010-07-28 15:53:44 +05305089 ret = ha->isp_ops->iospace_config(ha);
David Somayajuluafaf5a22006-09-19 10:28:00 -07005090 if (ret)
Vikas Chaudharyf4f5df22010-07-28 15:53:44 +05305091 goto probe_failed_ioconfig;
David Somayajuluafaf5a22006-09-19 10:28:00 -07005092
Vikas Chaudharyc2660df2010-07-10 14:51:02 +05305093 ql4_printk(KERN_INFO, ha, "Found an ISP%04x, irq %d, iobase 0x%p\n",
David Somayajuluafaf5a22006-09-19 10:28:00 -07005094 pdev->device, pdev->irq, ha->reg);
5095
5096 qla4xxx_config_dma_addressing(ha);
5097
5098 /* Initialize lists and spinlocks. */
David Somayajuluafaf5a22006-09-19 10:28:00 -07005099 INIT_LIST_HEAD(&ha->free_srb_q);
5100
5101 mutex_init(&ha->mbox_sem);
Lalit Chandivade45494152011-10-07 16:55:42 -07005102 mutex_init(&ha->chap_sem);
Vikas Chaudharyf4f5df22010-07-28 15:53:44 +05305103 init_completion(&ha->mbx_intr_comp);
Vikas Chaudhary95d31262011-08-12 02:51:29 -07005104 init_completion(&ha->disable_acb_comp);
David Somayajuluafaf5a22006-09-19 10:28:00 -07005105
5106 spin_lock_init(&ha->hardware_lock);
Vikas Chaudhary8e9157c2012-08-22 07:45:24 -04005107 spin_lock_init(&ha->work_lock);
David Somayajuluafaf5a22006-09-19 10:28:00 -07005108
Vikas Chaudharyff884432011-08-29 23:43:02 +05305109 /* Initialize work list */
5110 INIT_LIST_HEAD(&ha->work_list);
5111
David Somayajuluafaf5a22006-09-19 10:28:00 -07005112 /* Allocate dma buffers */
5113 if (qla4xxx_mem_alloc(ha)) {
Vikas Chaudharyc2660df2010-07-10 14:51:02 +05305114 ql4_printk(KERN_WARNING, ha,
5115 "[ERROR] Failed to allocate memory for adapter\n");
David Somayajuluafaf5a22006-09-19 10:28:00 -07005116
5117 ret = -ENOMEM;
5118 goto probe_failed;
5119 }
5120
Manish Rangankarb3a271a2011-07-25 13:48:53 -05005121 host->cmd_per_lun = 3;
5122 host->max_channel = 0;
5123 host->max_lun = MAX_LUNS - 1;
5124 host->max_id = MAX_TARGETS;
5125 host->max_cmd_len = IOCB_MAX_CDB_LEN;
5126 host->can_queue = MAX_SRBS ;
5127 host->transportt = qla4xxx_scsi_transport;
5128
5129 ret = scsi_init_shared_tag_map(host, MAX_SRBS);
5130 if (ret) {
5131 ql4_printk(KERN_WARNING, ha,
5132 "%s: scsi_init_shared_tag_map failed\n", __func__);
5133 goto probe_failed;
5134 }
5135
5136 pci_set_drvdata(pdev, ha);
5137
5138 ret = scsi_add_host(host, &pdev->dev);
5139 if (ret)
5140 goto probe_failed;
5141
Vikas Chaudharyf4f5df22010-07-28 15:53:44 +05305142 if (is_qla8022(ha))
5143 (void) qla4_8xxx_get_flash_info(ha);
5144
David Somayajuluafaf5a22006-09-19 10:28:00 -07005145 /*
5146 * Initialize the Host adapter request/response queues and
5147 * firmware
5148 * NOTE: interrupts enabled upon successful completion
5149 */
Mike Christie13483732011-12-01 21:38:41 -06005150 status = qla4xxx_initialize_adapter(ha, INIT_ADAPTER);
Vikas Chaudharyf4f5df22010-07-28 15:53:44 +05305151 while ((!test_bit(AF_ONLINE, &ha->flags)) &&
5152 init_retry_count++ < MAX_INIT_RETRIES) {
Prasanna Mumbaif9880e72011-03-21 03:34:26 -07005153
5154 if (is_qla8022(ha)) {
5155 qla4_8xxx_idc_lock(ha);
5156 dev_state = qla4_8xxx_rd_32(ha, QLA82XX_CRB_DEV_STATE);
5157 qla4_8xxx_idc_unlock(ha);
5158 if (dev_state == QLA82XX_DEV_FAILED) {
5159 ql4_printk(KERN_WARNING, ha, "%s: don't retry "
5160 "initialize adapter. H/W is in failed state\n",
5161 __func__);
5162 break;
5163 }
5164 }
David Somayajuluafaf5a22006-09-19 10:28:00 -07005165 DEBUG2(printk("scsi: %s: retrying adapter initialization "
5166 "(%d)\n", __func__, init_retry_count));
Vikas Chaudharyf4f5df22010-07-28 15:53:44 +05305167
5168 if (ha->isp_ops->reset_chip(ha) == QLA_ERROR)
5169 continue;
5170
Mike Christie13483732011-12-01 21:38:41 -06005171 status = qla4xxx_initialize_adapter(ha, INIT_ADAPTER);
David Somayajuluafaf5a22006-09-19 10:28:00 -07005172 }
Vikas Chaudharyf4f5df22010-07-28 15:53:44 +05305173
5174 if (!test_bit(AF_ONLINE, &ha->flags)) {
Vikas Chaudharyc2660df2010-07-10 14:51:02 +05305175 ql4_printk(KERN_WARNING, ha, "Failed to initialize adapter\n");
David Somayajuluafaf5a22006-09-19 10:28:00 -07005176
Lalit Chandivadefe998522010-12-02 22:12:36 -08005177 if (is_qla8022(ha) && ql4xdontresethba) {
5178 /* Put the device in failed state. */
5179 DEBUG2(printk(KERN_ERR "HW STATE: FAILED\n"));
5180 qla4_8xxx_idc_lock(ha);
5181 qla4_8xxx_wr_32(ha, QLA82XX_CRB_DEV_STATE,
5182 QLA82XX_DEV_FAILED);
5183 qla4_8xxx_idc_unlock(ha);
5184 }
David Somayajuluafaf5a22006-09-19 10:28:00 -07005185 ret = -ENODEV;
Manish Rangankarb3a271a2011-07-25 13:48:53 -05005186 goto remove_host;
David Somayajuluafaf5a22006-09-19 10:28:00 -07005187 }
5188
David Somayajuluafaf5a22006-09-19 10:28:00 -07005189 /* Startup the kernel thread for this host adapter. */
5190 DEBUG2(printk("scsi: %s: Starting kernel thread for "
5191 "qla4xxx_dpc\n", __func__));
5192 sprintf(buf, "qla4xxx_%lu_dpc", ha->host_no);
5193 ha->dpc_thread = create_singlethread_workqueue(buf);
5194 if (!ha->dpc_thread) {
Vikas Chaudharyc2660df2010-07-10 14:51:02 +05305195 ql4_printk(KERN_WARNING, ha, "Unable to start DPC thread!\n");
David Somayajuluafaf5a22006-09-19 10:28:00 -07005196 ret = -ENODEV;
Manish Rangankarb3a271a2011-07-25 13:48:53 -05005197 goto remove_host;
David Somayajuluafaf5a22006-09-19 10:28:00 -07005198 }
David Howellsc4028952006-11-22 14:57:56 +00005199 INIT_WORK(&ha->dpc_work, qla4xxx_do_dpc);
David Somayajuluafaf5a22006-09-19 10:28:00 -07005200
Manish Rangankarb3a271a2011-07-25 13:48:53 -05005201 sprintf(buf, "qla4xxx_%lu_task", ha->host_no);
5202 ha->task_wq = alloc_workqueue(buf, WQ_MEM_RECLAIM, 1);
5203 if (!ha->task_wq) {
5204 ql4_printk(KERN_WARNING, ha, "Unable to start task thread!\n");
5205 ret = -ENODEV;
5206 goto remove_host;
5207 }
5208
Vikas Chaudharyf4f5df22010-07-28 15:53:44 +05305209 /* For ISP-82XX, request_irqs is called in qla4_8xxx_load_risc
5210 * (which is called indirectly by qla4xxx_initialize_adapter),
5211 * so that irqs will be registered after crbinit but before
5212 * mbx_intr_enable.
5213 */
5214 if (!is_qla8022(ha)) {
5215 ret = qla4xxx_request_irqs(ha);
5216 if (ret) {
5217 ql4_printk(KERN_WARNING, ha, "Failed to reserve "
5218 "interrupt %d already in use.\n", pdev->irq);
Manish Rangankarb3a271a2011-07-25 13:48:53 -05005219 goto remove_host;
Vikas Chaudharyf4f5df22010-07-28 15:53:44 +05305220 }
David Somayajuluafaf5a22006-09-19 10:28:00 -07005221 }
David Somayajuluafaf5a22006-09-19 10:28:00 -07005222
Lalit Chandivade2232be02010-07-30 14:38:47 +05305223 pci_save_state(ha->pdev);
Vikas Chaudharyf4f5df22010-07-28 15:53:44 +05305224 ha->isp_ops->enable_intrs(ha);
David Somayajuluafaf5a22006-09-19 10:28:00 -07005225
5226 /* Start timer thread. */
5227 qla4xxx_start_timer(ha, qla4xxx_timer, 1);
5228
5229 set_bit(AF_INIT_DONE, &ha->flags);
5230
Tej Parkash068237c82012-05-18 04:41:44 -04005231 qla4_8xxx_alloc_sysfs_attr(ha);
5232
David Somayajuluafaf5a22006-09-19 10:28:00 -07005233 printk(KERN_INFO
5234 " QLogic iSCSI HBA Driver version: %s\n"
5235 " QLogic ISP%04x @ %s, host#=%ld, fw=%02d.%02d.%02d.%02d\n",
5236 qla4xxx_version_str, ha->pdev->device, pci_name(ha->pdev),
5237 ha->host_no, ha->firmware_version[0], ha->firmware_version[1],
5238 ha->patch_number, ha->build_number);
Vikas Chaudharyed1086e2011-07-25 13:48:41 -05005239
Manish Rangankar2a991c22011-07-25 13:48:55 -05005240 if (qla4xxx_setup_boot_info(ha))
Vikas Chaudhary3573bfb2012-02-27 03:08:57 -08005241 ql4_printk(KERN_ERR, ha,
5242 "%s: No iSCSI boot target configured\n", __func__);
Manish Rangankar2a991c22011-07-25 13:48:55 -05005243
Mike Christie13483732011-12-01 21:38:41 -06005244 /* Perform the build ddb list and login to each */
5245 qla4xxx_build_ddb_list(ha, INIT_ADAPTER);
5246 iscsi_host_for_each_session(ha->host, qla4xxx_login_flash_ddb);
5247
5248 qla4xxx_create_chap_list(ha);
5249
Vikas Chaudharyed1086e2011-07-25 13:48:41 -05005250 qla4xxx_create_ifaces(ha);
David Somayajuluafaf5a22006-09-19 10:28:00 -07005251 return 0;
5252
Manish Rangankarb3a271a2011-07-25 13:48:53 -05005253remove_host:
5254 scsi_remove_host(ha->host);
5255
David Somayajuluafaf5a22006-09-19 10:28:00 -07005256probe_failed:
5257 qla4xxx_free_adapter(ha);
Vikas Chaudharyf4f5df22010-07-28 15:53:44 +05305258
5259probe_failed_ioconfig:
Lalit Chandivade2232be02010-07-30 14:38:47 +05305260 pci_disable_pcie_error_reporting(pdev);
David Somayajuluafaf5a22006-09-19 10:28:00 -07005261 scsi_host_put(ha->host);
5262
5263probe_disable_device:
5264 pci_disable_device(pdev);
5265
5266 return ret;
5267}
5268
5269/**
Karen Higgins7eece5a2011-03-21 03:34:29 -07005270 * qla4xxx_prevent_other_port_reinit - prevent other port from re-initialize
5271 * @ha: pointer to adapter structure
5272 *
5273 * Mark the other ISP-4xxx port to indicate that the driver is being removed,
5274 * so that the other port will not re-initialize while in the process of
5275 * removing the ha due to driver unload or hba hotplug.
5276 **/
5277static void qla4xxx_prevent_other_port_reinit(struct scsi_qla_host *ha)
5278{
5279 struct scsi_qla_host *other_ha = NULL;
5280 struct pci_dev *other_pdev = NULL;
5281 int fn = ISP4XXX_PCI_FN_2;
5282
5283 /*iscsi function numbers for ISP4xxx is 1 and 3*/
5284 if (PCI_FUNC(ha->pdev->devfn) & BIT_1)
5285 fn = ISP4XXX_PCI_FN_1;
5286
5287 other_pdev =
5288 pci_get_domain_bus_and_slot(pci_domain_nr(ha->pdev->bus),
5289 ha->pdev->bus->number, PCI_DEVFN(PCI_SLOT(ha->pdev->devfn),
5290 fn));
5291
5292 /* Get other_ha if other_pdev is valid and state is enable*/
5293 if (other_pdev) {
5294 if (atomic_read(&other_pdev->enable_cnt)) {
5295 other_ha = pci_get_drvdata(other_pdev);
5296 if (other_ha) {
5297 set_bit(AF_HA_REMOVAL, &other_ha->flags);
5298 DEBUG2(ql4_printk(KERN_INFO, ha, "%s: "
5299 "Prevent %s reinit\n", __func__,
5300 dev_name(&other_ha->pdev->dev)));
5301 }
5302 }
5303 pci_dev_put(other_pdev);
5304 }
5305}
5306
Mike Christie13483732011-12-01 21:38:41 -06005307static void qla4xxx_destroy_fw_ddb_session(struct scsi_qla_host *ha)
5308{
5309 struct ddb_entry *ddb_entry;
5310 int options;
5311 int idx;
5312
5313 for (idx = 0; idx < MAX_DDB_ENTRIES; idx++) {
5314
5315 ddb_entry = qla4xxx_lookup_ddb_by_fw_index(ha, idx);
5316 if ((ddb_entry != NULL) &&
5317 (ddb_entry->ddb_type == FLASH_DDB)) {
5318
5319 options = LOGOUT_OPTION_CLOSE_SESSION;
5320 if (qla4xxx_session_logout_ddb(ha, ddb_entry, options)
5321 == QLA_ERROR)
5322 ql4_printk(KERN_ERR, ha, "%s: Logout failed\n",
5323 __func__);
5324
5325 qla4xxx_clear_ddb_entry(ha, ddb_entry->fw_ddb_index);
5326 /*
5327 * we have decremented the reference count of the driver
5328 * when we setup the session to have the driver unload
5329 * to be seamless without actually destroying the
5330 * session
5331 **/
5332 try_module_get(qla4xxx_iscsi_transport.owner);
5333 iscsi_destroy_endpoint(ddb_entry->conn->ep);
5334 qla4xxx_free_ddb(ha, ddb_entry);
5335 iscsi_session_teardown(ddb_entry->sess);
5336 }
5337 }
5338}
Karen Higgins7eece5a2011-03-21 03:34:29 -07005339/**
David Somayajuluafaf5a22006-09-19 10:28:00 -07005340 * qla4xxx_remove_adapter - calback function to remove adapter.
5341 * @pci_dev: PCI device pointer
5342 **/
5343static void __devexit qla4xxx_remove_adapter(struct pci_dev *pdev)
5344{
5345 struct scsi_qla_host *ha;
5346
5347 ha = pci_get_drvdata(pdev);
5348
Karen Higgins7eece5a2011-03-21 03:34:29 -07005349 if (!is_qla8022(ha))
5350 qla4xxx_prevent_other_port_reinit(ha);
David C Somayajulubee4fe82007-05-23 18:03:32 -07005351
Vikas Chaudharyed1086e2011-07-25 13:48:41 -05005352 /* destroy iface from sysfs */
5353 qla4xxx_destroy_ifaces(ha);
5354
Mike Christie13483732011-12-01 21:38:41 -06005355 if ((!ql4xdisablesysfsboot) && ha->boot_kset)
Manish Rangankar2a991c22011-07-25 13:48:55 -05005356 iscsi_boot_destroy_kset(ha->boot_kset);
5357
Mike Christie13483732011-12-01 21:38:41 -06005358 qla4xxx_destroy_fw_ddb_session(ha);
Tej Parkash068237c82012-05-18 04:41:44 -04005359 qla4_8xxx_free_sysfs_attr(ha);
Mike Christie13483732011-12-01 21:38:41 -06005360
David Somayajuluafaf5a22006-09-19 10:28:00 -07005361 scsi_remove_host(ha->host);
5362
5363 qla4xxx_free_adapter(ha);
5364
5365 scsi_host_put(ha->host);
5366
Lalit Chandivade2232be02010-07-30 14:38:47 +05305367 pci_disable_pcie_error_reporting(pdev);
Vikas Chaudharyf4f5df22010-07-28 15:53:44 +05305368 pci_disable_device(pdev);
David Somayajuluafaf5a22006-09-19 10:28:00 -07005369 pci_set_drvdata(pdev, NULL);
5370}
5371
5372/**
5373 * qla4xxx_config_dma_addressing() - Configure OS DMA addressing method.
5374 * @ha: HA context
5375 *
5376 * At exit, the @ha's flags.enable_64bit_addressing set to indicated
5377 * supported addressing method.
5378 */
Adrian Bunk47975472007-04-26 00:35:16 -07005379static void qla4xxx_config_dma_addressing(struct scsi_qla_host *ha)
David Somayajuluafaf5a22006-09-19 10:28:00 -07005380{
5381 int retval;
5382
5383 /* Update our PCI device dma_mask for full 64 bit mask */
Yang Hongyang6a355282009-04-06 19:01:13 -07005384 if (pci_set_dma_mask(ha->pdev, DMA_BIT_MASK(64)) == 0) {
5385 if (pci_set_consistent_dma_mask(ha->pdev, DMA_BIT_MASK(64))) {
David Somayajuluafaf5a22006-09-19 10:28:00 -07005386 dev_dbg(&ha->pdev->dev,
5387 "Failed to set 64 bit PCI consistent mask; "
5388 "using 32 bit.\n");
5389 retval = pci_set_consistent_dma_mask(ha->pdev,
Yang Hongyang284901a2009-04-06 19:01:15 -07005390 DMA_BIT_MASK(32));
David Somayajuluafaf5a22006-09-19 10:28:00 -07005391 }
5392 } else
Yang Hongyang284901a2009-04-06 19:01:15 -07005393 retval = pci_set_dma_mask(ha->pdev, DMA_BIT_MASK(32));
David Somayajuluafaf5a22006-09-19 10:28:00 -07005394}
5395
5396static int qla4xxx_slave_alloc(struct scsi_device *sdev)
5397{
Manish Rangankarb3a271a2011-07-25 13:48:53 -05005398 struct iscsi_cls_session *cls_sess;
5399 struct iscsi_session *sess;
5400 struct ddb_entry *ddb;
Vikas Chaudhary8bb40332011-03-21 03:34:31 -07005401 int queue_depth = QL4_DEF_QDEPTH;
David Somayajuluafaf5a22006-09-19 10:28:00 -07005402
Manish Rangankarb3a271a2011-07-25 13:48:53 -05005403 cls_sess = starget_to_session(sdev->sdev_target);
5404 sess = cls_sess->dd_data;
5405 ddb = sess->dd_data;
5406
David Somayajuluafaf5a22006-09-19 10:28:00 -07005407 sdev->hostdata = ddb;
5408 sdev->tagged_supported = 1;
Vikas Chaudhary8bb40332011-03-21 03:34:31 -07005409
5410 if (ql4xmaxqdepth != 0 && ql4xmaxqdepth <= 0xffffU)
5411 queue_depth = ql4xmaxqdepth;
5412
5413 scsi_activate_tcq(sdev, queue_depth);
David Somayajuluafaf5a22006-09-19 10:28:00 -07005414 return 0;
5415}
5416
5417static int qla4xxx_slave_configure(struct scsi_device *sdev)
5418{
5419 sdev->tagged_supported = 1;
5420 return 0;
5421}
5422
5423static void qla4xxx_slave_destroy(struct scsi_device *sdev)
5424{
5425 scsi_deactivate_tcq(sdev, 1);
5426}
5427
Tej Parkashf7b4aa632012-04-30 04:12:19 -07005428static int qla4xxx_change_queue_depth(struct scsi_device *sdev, int qdepth,
5429 int reason)
5430{
5431 if (!ql4xqfulltracking)
5432 return -EOPNOTSUPP;
5433
5434 return iscsi_change_queue_depth(sdev, qdepth, reason);
5435}
5436
David Somayajuluafaf5a22006-09-19 10:28:00 -07005437/**
5438 * qla4xxx_del_from_active_array - returns an active srb
5439 * @ha: Pointer to host adapter structure.
Anand Gadiyarfd589a82009-07-16 17:13:03 +02005440 * @index: index into the active_array
David Somayajuluafaf5a22006-09-19 10:28:00 -07005441 *
5442 * This routine removes and returns the srb at the specified index
5443 **/
Vikas Chaudharyf4f5df22010-07-28 15:53:44 +05305444struct srb *qla4xxx_del_from_active_array(struct scsi_qla_host *ha,
5445 uint32_t index)
David Somayajuluafaf5a22006-09-19 10:28:00 -07005446{
5447 struct srb *srb = NULL;
Vikas Chaudhary53698872010-04-28 11:41:59 +05305448 struct scsi_cmnd *cmd = NULL;
David Somayajuluafaf5a22006-09-19 10:28:00 -07005449
Vikas Chaudhary53698872010-04-28 11:41:59 +05305450 cmd = scsi_host_find_tag(ha->host, index);
5451 if (!cmd)
David Somayajuluafaf5a22006-09-19 10:28:00 -07005452 return srb;
5453
Vikas Chaudhary53698872010-04-28 11:41:59 +05305454 srb = (struct srb *)CMD_SP(cmd);
5455 if (!srb)
David Somayajuluafaf5a22006-09-19 10:28:00 -07005456 return srb;
5457
5458 /* update counters */
5459 if (srb->flags & SRB_DMA_VALID) {
5460 ha->req_q_count += srb->iocb_cnt;
5461 ha->iocb_cnt -= srb->iocb_cnt;
5462 if (srb->cmd)
Vikas Chaudhary53698872010-04-28 11:41:59 +05305463 srb->cmd->host_scribble =
5464 (unsigned char *)(unsigned long) MAX_SRBS;
David Somayajuluafaf5a22006-09-19 10:28:00 -07005465 }
5466 return srb;
5467}
5468
5469/**
David Somayajuluafaf5a22006-09-19 10:28:00 -07005470 * qla4xxx_eh_wait_on_command - waits for command to be returned by firmware
Vikas Chaudhary09a0f712010-04-28 11:42:24 +05305471 * @ha: Pointer to host adapter structure.
David Somayajuluafaf5a22006-09-19 10:28:00 -07005472 * @cmd: Scsi Command to wait on.
5473 *
5474 * This routine waits for the command to be returned by the Firmware
5475 * for some max time.
5476 **/
5477static int qla4xxx_eh_wait_on_command(struct scsi_qla_host *ha,
5478 struct scsi_cmnd *cmd)
5479{
5480 int done = 0;
5481 struct srb *rp;
5482 uint32_t max_wait_time = EH_WAIT_CMD_TOV;
Lalit Chandivade2232be02010-07-30 14:38:47 +05305483 int ret = SUCCESS;
5484
5485 /* Dont wait on command if PCI error is being handled
5486 * by PCI AER driver
5487 */
5488 if (unlikely(pci_channel_offline(ha->pdev)) ||
5489 (test_bit(AF_EEH_BUSY, &ha->flags))) {
5490 ql4_printk(KERN_WARNING, ha, "scsi%ld: Return from %s\n",
5491 ha->host_no, __func__);
5492 return ret;
5493 }
David Somayajuluafaf5a22006-09-19 10:28:00 -07005494
5495 do {
5496 /* Checking to see if its returned to OS */
Vikas Chaudhary53698872010-04-28 11:41:59 +05305497 rp = (struct srb *) CMD_SP(cmd);
David Somayajuluafaf5a22006-09-19 10:28:00 -07005498 if (rp == NULL) {
5499 done++;
5500 break;
5501 }
5502
5503 msleep(2000);
5504 } while (max_wait_time--);
5505
5506 return done;
5507}
5508
5509/**
5510 * qla4xxx_wait_for_hba_online - waits for HBA to come online
5511 * @ha: Pointer to host adapter structure
5512 **/
5513static int qla4xxx_wait_for_hba_online(struct scsi_qla_host *ha)
5514{
5515 unsigned long wait_online;
5516
Vikas Chaudharyf581a3f2010-10-06 22:47:48 -07005517 wait_online = jiffies + (HBA_ONLINE_TOV * HZ);
David Somayajuluafaf5a22006-09-19 10:28:00 -07005518 while (time_before(jiffies, wait_online)) {
5519
5520 if (adapter_up(ha))
5521 return QLA_SUCCESS;
David Somayajuluafaf5a22006-09-19 10:28:00 -07005522
5523 msleep(2000);
5524 }
5525
5526 return QLA_ERROR;
5527}
5528
5529/**
Mike Christiece545032008-02-29 18:25:20 -06005530 * qla4xxx_eh_wait_for_commands - wait for active cmds to finish.
Anand Gadiyarfd589a82009-07-16 17:13:03 +02005531 * @ha: pointer to HBA
David Somayajuluafaf5a22006-09-19 10:28:00 -07005532 * @t: target id
5533 * @l: lun id
5534 *
5535 * This function waits for all outstanding commands to a lun to complete. It
5536 * returns 0 if all pending commands are returned and 1 otherwise.
5537 **/
Mike Christiece545032008-02-29 18:25:20 -06005538static int qla4xxx_eh_wait_for_commands(struct scsi_qla_host *ha,
5539 struct scsi_target *stgt,
5540 struct scsi_device *sdev)
David Somayajuluafaf5a22006-09-19 10:28:00 -07005541{
5542 int cnt;
5543 int status = 0;
5544 struct scsi_cmnd *cmd;
5545
5546 /*
Mike Christiece545032008-02-29 18:25:20 -06005547 * Waiting for all commands for the designated target or dev
5548 * in the active array
David Somayajuluafaf5a22006-09-19 10:28:00 -07005549 */
5550 for (cnt = 0; cnt < ha->host->can_queue; cnt++) {
5551 cmd = scsi_host_find_tag(ha->host, cnt);
Mike Christiece545032008-02-29 18:25:20 -06005552 if (cmd && stgt == scsi_target(cmd->device) &&
5553 (!sdev || sdev == cmd->device)) {
David Somayajuluafaf5a22006-09-19 10:28:00 -07005554 if (!qla4xxx_eh_wait_on_command(ha, cmd)) {
5555 status++;
5556 break;
5557 }
5558 }
5559 }
5560 return status;
5561}
5562
5563/**
Vikas Chaudhary09a0f712010-04-28 11:42:24 +05305564 * qla4xxx_eh_abort - callback for abort task.
5565 * @cmd: Pointer to Linux's SCSI command structure
5566 *
5567 * This routine is called by the Linux OS to abort the specified
5568 * command.
5569 **/
5570static int qla4xxx_eh_abort(struct scsi_cmnd *cmd)
5571{
5572 struct scsi_qla_host *ha = to_qla_host(cmd->device->host);
5573 unsigned int id = cmd->device->id;
5574 unsigned int lun = cmd->device->lun;
Mike Christie92b3e5b2010-10-06 22:51:17 -07005575 unsigned long flags;
Vikas Chaudhary09a0f712010-04-28 11:42:24 +05305576 struct srb *srb = NULL;
5577 int ret = SUCCESS;
5578 int wait = 0;
5579
Vikas Chaudharyc2660df2010-07-10 14:51:02 +05305580 ql4_printk(KERN_INFO, ha,
Christoph Hellwig5cd049a2011-04-04 09:42:14 -04005581 "scsi%ld:%d:%d: Abort command issued cmd=%p\n",
5582 ha->host_no, id, lun, cmd);
Vikas Chaudhary09a0f712010-04-28 11:42:24 +05305583
Mike Christie92b3e5b2010-10-06 22:51:17 -07005584 spin_lock_irqsave(&ha->hardware_lock, flags);
Vikas Chaudhary09a0f712010-04-28 11:42:24 +05305585 srb = (struct srb *) CMD_SP(cmd);
Mike Christie92b3e5b2010-10-06 22:51:17 -07005586 if (!srb) {
5587 spin_unlock_irqrestore(&ha->hardware_lock, flags);
Vikas Chaudhary09a0f712010-04-28 11:42:24 +05305588 return SUCCESS;
Mike Christie92b3e5b2010-10-06 22:51:17 -07005589 }
Vikas Chaudhary09a0f712010-04-28 11:42:24 +05305590 kref_get(&srb->srb_ref);
Mike Christie92b3e5b2010-10-06 22:51:17 -07005591 spin_unlock_irqrestore(&ha->hardware_lock, flags);
Vikas Chaudhary09a0f712010-04-28 11:42:24 +05305592
5593 if (qla4xxx_abort_task(ha, srb) != QLA_SUCCESS) {
5594 DEBUG3(printk("scsi%ld:%d:%d: Abort_task mbx failed.\n",
5595 ha->host_no, id, lun));
5596 ret = FAILED;
5597 } else {
5598 DEBUG3(printk("scsi%ld:%d:%d: Abort_task mbx success.\n",
5599 ha->host_no, id, lun));
5600 wait = 1;
5601 }
5602
5603 kref_put(&srb->srb_ref, qla4xxx_srb_compl);
5604
5605 /* Wait for command to complete */
5606 if (wait) {
5607 if (!qla4xxx_eh_wait_on_command(ha, cmd)) {
5608 DEBUG2(printk("scsi%ld:%d:%d: Abort handler timed out\n",
5609 ha->host_no, id, lun));
5610 ret = FAILED;
5611 }
5612 }
5613
Vikas Chaudharyc2660df2010-07-10 14:51:02 +05305614 ql4_printk(KERN_INFO, ha,
Vikas Chaudhary09a0f712010-04-28 11:42:24 +05305615 "scsi%ld:%d:%d: Abort command - %s\n",
Lucas De Marchi25985ed2011-03-30 22:57:33 -03005616 ha->host_no, id, lun, (ret == SUCCESS) ? "succeeded" : "failed");
Vikas Chaudhary09a0f712010-04-28 11:42:24 +05305617
5618 return ret;
5619}
5620
5621/**
David Somayajuluafaf5a22006-09-19 10:28:00 -07005622 * qla4xxx_eh_device_reset - callback for target reset.
5623 * @cmd: Pointer to Linux's SCSI command structure
5624 *
5625 * This routine is called by the Linux OS to reset all luns on the
5626 * specified target.
5627 **/
5628static int qla4xxx_eh_device_reset(struct scsi_cmnd *cmd)
5629{
5630 struct scsi_qla_host *ha = to_qla_host(cmd->device->host);
5631 struct ddb_entry *ddb_entry = cmd->device->hostdata;
David Somayajuluafaf5a22006-09-19 10:28:00 -07005632 int ret = FAILED, stat;
5633
Karen Higgins612f73482009-07-15 15:03:01 -05005634 if (!ddb_entry)
David Somayajuluafaf5a22006-09-19 10:28:00 -07005635 return ret;
5636
Mike Christiec01be6d2010-07-22 16:59:49 +05305637 ret = iscsi_block_scsi_eh(cmd);
5638 if (ret)
5639 return ret;
5640 ret = FAILED;
5641
Vikas Chaudharyc2660df2010-07-10 14:51:02 +05305642 ql4_printk(KERN_INFO, ha,
David Somayajuluafaf5a22006-09-19 10:28:00 -07005643 "scsi%ld:%d:%d:%d: DEVICE RESET ISSUED.\n", ha->host_no,
5644 cmd->device->channel, cmd->device->id, cmd->device->lun);
5645
5646 DEBUG2(printk(KERN_INFO
5647 "scsi%ld: DEVICE_RESET cmd=%p jiffies = 0x%lx, to=%x,"
5648 "dpc_flags=%lx, status=%x allowed=%d\n", ha->host_no,
Jens Axboe242f9dc2008-09-14 05:55:09 -07005649 cmd, jiffies, cmd->request->timeout / HZ,
David Somayajuluafaf5a22006-09-19 10:28:00 -07005650 ha->dpc_flags, cmd->result, cmd->allowed));
5651
5652 /* FIXME: wait for hba to go online */
5653 stat = qla4xxx_reset_lun(ha, ddb_entry, cmd->device->lun);
5654 if (stat != QLA_SUCCESS) {
Vikas Chaudharyc2660df2010-07-10 14:51:02 +05305655 ql4_printk(KERN_INFO, ha, "DEVICE RESET FAILED. %d\n", stat);
David Somayajuluafaf5a22006-09-19 10:28:00 -07005656 goto eh_dev_reset_done;
5657 }
5658
Mike Christiece545032008-02-29 18:25:20 -06005659 if (qla4xxx_eh_wait_for_commands(ha, scsi_target(cmd->device),
5660 cmd->device)) {
Vikas Chaudharyc2660df2010-07-10 14:51:02 +05305661 ql4_printk(KERN_INFO, ha,
Mike Christiece545032008-02-29 18:25:20 -06005662 "DEVICE RESET FAILED - waiting for "
5663 "commands.\n");
5664 goto eh_dev_reset_done;
David Somayajuluafaf5a22006-09-19 10:28:00 -07005665 }
5666
David C Somayajulu9d562912008-03-19 11:23:03 -07005667 /* Send marker. */
5668 if (qla4xxx_send_marker_iocb(ha, ddb_entry, cmd->device->lun,
5669 MM_LUN_RESET) != QLA_SUCCESS)
5670 goto eh_dev_reset_done;
5671
Vikas Chaudharyc2660df2010-07-10 14:51:02 +05305672 ql4_printk(KERN_INFO, ha,
David Somayajuluafaf5a22006-09-19 10:28:00 -07005673 "scsi(%ld:%d:%d:%d): DEVICE RESET SUCCEEDED.\n",
5674 ha->host_no, cmd->device->channel, cmd->device->id,
5675 cmd->device->lun);
5676
5677 ret = SUCCESS;
5678
5679eh_dev_reset_done:
5680
5681 return ret;
5682}
5683
5684/**
Mike Christiece545032008-02-29 18:25:20 -06005685 * qla4xxx_eh_target_reset - callback for target reset.
5686 * @cmd: Pointer to Linux's SCSI command structure
5687 *
5688 * This routine is called by the Linux OS to reset the target.
5689 **/
5690static int qla4xxx_eh_target_reset(struct scsi_cmnd *cmd)
5691{
5692 struct scsi_qla_host *ha = to_qla_host(cmd->device->host);
5693 struct ddb_entry *ddb_entry = cmd->device->hostdata;
Mike Christiec01be6d2010-07-22 16:59:49 +05305694 int stat, ret;
Mike Christiece545032008-02-29 18:25:20 -06005695
5696 if (!ddb_entry)
5697 return FAILED;
5698
Mike Christiec01be6d2010-07-22 16:59:49 +05305699 ret = iscsi_block_scsi_eh(cmd);
5700 if (ret)
5701 return ret;
5702
Mike Christiece545032008-02-29 18:25:20 -06005703 starget_printk(KERN_INFO, scsi_target(cmd->device),
5704 "WARM TARGET RESET ISSUED.\n");
5705
5706 DEBUG2(printk(KERN_INFO
5707 "scsi%ld: TARGET_DEVICE_RESET cmd=%p jiffies = 0x%lx, "
5708 "to=%x,dpc_flags=%lx, status=%x allowed=%d\n",
Jens Axboe242f9dc2008-09-14 05:55:09 -07005709 ha->host_no, cmd, jiffies, cmd->request->timeout / HZ,
Mike Christiece545032008-02-29 18:25:20 -06005710 ha->dpc_flags, cmd->result, cmd->allowed));
5711
5712 stat = qla4xxx_reset_target(ha, ddb_entry);
5713 if (stat != QLA_SUCCESS) {
5714 starget_printk(KERN_INFO, scsi_target(cmd->device),
5715 "WARM TARGET RESET FAILED.\n");
5716 return FAILED;
5717 }
5718
Mike Christiece545032008-02-29 18:25:20 -06005719 if (qla4xxx_eh_wait_for_commands(ha, scsi_target(cmd->device),
5720 NULL)) {
5721 starget_printk(KERN_INFO, scsi_target(cmd->device),
5722 "WARM TARGET DEVICE RESET FAILED - "
5723 "waiting for commands.\n");
5724 return FAILED;
5725 }
5726
David C Somayajulu9d562912008-03-19 11:23:03 -07005727 /* Send marker. */
5728 if (qla4xxx_send_marker_iocb(ha, ddb_entry, cmd->device->lun,
5729 MM_TGT_WARM_RESET) != QLA_SUCCESS) {
5730 starget_printk(KERN_INFO, scsi_target(cmd->device),
5731 "WARM TARGET DEVICE RESET FAILED - "
5732 "marker iocb failed.\n");
5733 return FAILED;
5734 }
5735
Mike Christiece545032008-02-29 18:25:20 -06005736 starget_printk(KERN_INFO, scsi_target(cmd->device),
5737 "WARM TARGET RESET SUCCEEDED.\n");
5738 return SUCCESS;
5739}
5740
5741/**
Sarang Radke8a288962011-12-06 02:34:10 -08005742 * qla4xxx_is_eh_active - check if error handler is running
5743 * @shost: Pointer to SCSI Host struct
5744 *
5745 * This routine finds that if reset host is called in EH
5746 * scenario or from some application like sg_reset
5747 **/
5748static int qla4xxx_is_eh_active(struct Scsi_Host *shost)
5749{
5750 if (shost->shost_state == SHOST_RECOVERY)
5751 return 1;
5752 return 0;
5753}
5754
5755/**
David Somayajuluafaf5a22006-09-19 10:28:00 -07005756 * qla4xxx_eh_host_reset - kernel callback
5757 * @cmd: Pointer to Linux's SCSI command structure
5758 *
5759 * This routine is invoked by the Linux kernel to perform fatal error
5760 * recovery on the specified adapter.
5761 **/
5762static int qla4xxx_eh_host_reset(struct scsi_cmnd *cmd)
5763{
5764 int return_status = FAILED;
5765 struct scsi_qla_host *ha;
5766
Manish Rangankarb3a271a2011-07-25 13:48:53 -05005767 ha = to_qla_host(cmd->device->host);
David Somayajuluafaf5a22006-09-19 10:28:00 -07005768
Vikas Chaudharyf4f5df22010-07-28 15:53:44 +05305769 if (ql4xdontresethba) {
5770 DEBUG2(printk("scsi%ld: %s: Don't Reset HBA\n",
5771 ha->host_no, __func__));
Sarang Radke8a288962011-12-06 02:34:10 -08005772
5773 /* Clear outstanding srb in queues */
5774 if (qla4xxx_is_eh_active(cmd->device->host))
5775 qla4xxx_abort_active_cmds(ha, DID_ABORT << 16);
5776
Vikas Chaudharyf4f5df22010-07-28 15:53:44 +05305777 return FAILED;
5778 }
5779
Vikas Chaudharyc2660df2010-07-10 14:51:02 +05305780 ql4_printk(KERN_INFO, ha,
Karen Higginsdca05c42009-07-15 15:03:00 -05005781 "scsi(%ld:%d:%d:%d): HOST RESET ISSUED.\n", ha->host_no,
David Somayajuluafaf5a22006-09-19 10:28:00 -07005782 cmd->device->channel, cmd->device->id, cmd->device->lun);
5783
5784 if (qla4xxx_wait_for_hba_online(ha) != QLA_SUCCESS) {
5785 DEBUG2(printk("scsi%ld:%d: %s: Unable to reset host. Adapter "
5786 "DEAD.\n", ha->host_no, cmd->device->channel,
5787 __func__));
5788
5789 return FAILED;
5790 }
5791
Vikas Chaudharyf4f5df22010-07-28 15:53:44 +05305792 if (!test_bit(DPC_RESET_HA, &ha->dpc_flags)) {
5793 if (is_qla8022(ha))
5794 set_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags);
5795 else
5796 set_bit(DPC_RESET_HA, &ha->dpc_flags);
5797 }
Mike Christie50a29ae2008-03-04 13:26:53 -06005798
Vikas Chaudharyf4f5df22010-07-28 15:53:44 +05305799 if (qla4xxx_recover_adapter(ha) == QLA_SUCCESS)
David Somayajuluafaf5a22006-09-19 10:28:00 -07005800 return_status = SUCCESS;
David Somayajuluafaf5a22006-09-19 10:28:00 -07005801
Vikas Chaudharyc2660df2010-07-10 14:51:02 +05305802 ql4_printk(KERN_INFO, ha, "HOST RESET %s.\n",
Lucas De Marchi25985ed2011-03-30 22:57:33 -03005803 return_status == FAILED ? "FAILED" : "SUCCEEDED");
David Somayajuluafaf5a22006-09-19 10:28:00 -07005804
5805 return return_status;
5806}
5807
Vikas Chaudhary95d31262011-08-12 02:51:29 -07005808static int qla4xxx_context_reset(struct scsi_qla_host *ha)
5809{
5810 uint32_t mbox_cmd[MBOX_REG_COUNT];
5811 uint32_t mbox_sts[MBOX_REG_COUNT];
5812 struct addr_ctrl_blk_def *acb = NULL;
5813 uint32_t acb_len = sizeof(struct addr_ctrl_blk_def);
5814 int rval = QLA_SUCCESS;
5815 dma_addr_t acb_dma;
5816
5817 acb = dma_alloc_coherent(&ha->pdev->dev,
5818 sizeof(struct addr_ctrl_blk_def),
5819 &acb_dma, GFP_KERNEL);
5820 if (!acb) {
5821 ql4_printk(KERN_ERR, ha, "%s: Unable to alloc acb\n",
5822 __func__);
5823 rval = -ENOMEM;
5824 goto exit_port_reset;
5825 }
5826
5827 memset(acb, 0, acb_len);
5828
5829 rval = qla4xxx_get_acb(ha, acb_dma, PRIMARI_ACB, acb_len);
5830 if (rval != QLA_SUCCESS) {
5831 rval = -EIO;
5832 goto exit_free_acb;
5833 }
5834
5835 rval = qla4xxx_disable_acb(ha);
5836 if (rval != QLA_SUCCESS) {
5837 rval = -EIO;
5838 goto exit_free_acb;
5839 }
5840
5841 wait_for_completion_timeout(&ha->disable_acb_comp,
5842 DISABLE_ACB_TOV * HZ);
5843
5844 rval = qla4xxx_set_acb(ha, &mbox_cmd[0], &mbox_sts[0], acb_dma);
5845 if (rval != QLA_SUCCESS) {
5846 rval = -EIO;
5847 goto exit_free_acb;
5848 }
5849
5850exit_free_acb:
5851 dma_free_coherent(&ha->pdev->dev, sizeof(struct addr_ctrl_blk_def),
5852 acb, acb_dma);
5853exit_port_reset:
5854 DEBUG2(ql4_printk(KERN_INFO, ha, "%s %s\n", __func__,
5855 rval == QLA_SUCCESS ? "SUCCEEDED" : "FAILED"));
5856 return rval;
5857}
5858
5859static int qla4xxx_host_reset(struct Scsi_Host *shost, int reset_type)
5860{
5861 struct scsi_qla_host *ha = to_qla_host(shost);
5862 int rval = QLA_SUCCESS;
5863
5864 if (ql4xdontresethba) {
5865 DEBUG2(ql4_printk(KERN_INFO, ha, "%s: Don't Reset HBA\n",
5866 __func__));
5867 rval = -EPERM;
5868 goto exit_host_reset;
5869 }
5870
5871 rval = qla4xxx_wait_for_hba_online(ha);
5872 if (rval != QLA_SUCCESS) {
5873 DEBUG2(ql4_printk(KERN_INFO, ha, "%s: Unable to reset host "
5874 "adapter\n", __func__));
5875 rval = -EIO;
5876 goto exit_host_reset;
5877 }
5878
5879 if (test_bit(DPC_RESET_HA, &ha->dpc_flags))
5880 goto recover_adapter;
5881
5882 switch (reset_type) {
5883 case SCSI_ADAPTER_RESET:
5884 set_bit(DPC_RESET_HA, &ha->dpc_flags);
5885 break;
5886 case SCSI_FIRMWARE_RESET:
5887 if (!test_bit(DPC_RESET_HA, &ha->dpc_flags)) {
5888 if (is_qla8022(ha))
5889 /* set firmware context reset */
5890 set_bit(DPC_RESET_HA_FW_CONTEXT,
5891 &ha->dpc_flags);
5892 else {
5893 rval = qla4xxx_context_reset(ha);
5894 goto exit_host_reset;
5895 }
5896 }
5897 break;
5898 }
5899
5900recover_adapter:
5901 rval = qla4xxx_recover_adapter(ha);
5902 if (rval != QLA_SUCCESS) {
5903 DEBUG2(ql4_printk(KERN_INFO, ha, "%s: recover adapter fail\n",
5904 __func__));
5905 rval = -EIO;
5906 }
5907
5908exit_host_reset:
5909 return rval;
5910}
5911
Lalit Chandivade2232be02010-07-30 14:38:47 +05305912/* PCI AER driver recovers from all correctable errors w/o
5913 * driver intervention. For uncorrectable errors PCI AER
5914 * driver calls the following device driver's callbacks
5915 *
5916 * - Fatal Errors - link_reset
5917 * - Non-Fatal Errors - driver's pci_error_detected() which
5918 * returns CAN_RECOVER, NEED_RESET or DISCONNECT.
5919 *
5920 * PCI AER driver calls
5921 * CAN_RECOVER - driver's pci_mmio_enabled(), mmio_enabled
5922 * returns RECOVERED or NEED_RESET if fw_hung
5923 * NEED_RESET - driver's slot_reset()
5924 * DISCONNECT - device is dead & cannot recover
5925 * RECOVERED - driver's pci_resume()
5926 */
5927static pci_ers_result_t
5928qla4xxx_pci_error_detected(struct pci_dev *pdev, pci_channel_state_t state)
5929{
5930 struct scsi_qla_host *ha = pci_get_drvdata(pdev);
5931
5932 ql4_printk(KERN_WARNING, ha, "scsi%ld: %s: error detected:state %x\n",
5933 ha->host_no, __func__, state);
5934
5935 if (!is_aer_supported(ha))
5936 return PCI_ERS_RESULT_NONE;
5937
5938 switch (state) {
5939 case pci_channel_io_normal:
5940 clear_bit(AF_EEH_BUSY, &ha->flags);
5941 return PCI_ERS_RESULT_CAN_RECOVER;
5942 case pci_channel_io_frozen:
5943 set_bit(AF_EEH_BUSY, &ha->flags);
5944 qla4xxx_mailbox_premature_completion(ha);
5945 qla4xxx_free_irqs(ha);
5946 pci_disable_device(pdev);
Vikas Chaudhary7b3595d2010-10-06 22:50:56 -07005947 /* Return back all IOs */
5948 qla4xxx_abort_active_cmds(ha, DID_RESET << 16);
Lalit Chandivade2232be02010-07-30 14:38:47 +05305949 return PCI_ERS_RESULT_NEED_RESET;
5950 case pci_channel_io_perm_failure:
5951 set_bit(AF_EEH_BUSY, &ha->flags);
5952 set_bit(AF_PCI_CHANNEL_IO_PERM_FAILURE, &ha->flags);
5953 qla4xxx_abort_active_cmds(ha, DID_NO_CONNECT << 16);
5954 return PCI_ERS_RESULT_DISCONNECT;
5955 }
5956 return PCI_ERS_RESULT_NEED_RESET;
5957}
5958
5959/**
5960 * qla4xxx_pci_mmio_enabled() gets called if
5961 * qla4xxx_pci_error_detected() returns PCI_ERS_RESULT_CAN_RECOVER
5962 * and read/write to the device still works.
5963 **/
5964static pci_ers_result_t
5965qla4xxx_pci_mmio_enabled(struct pci_dev *pdev)
5966{
5967 struct scsi_qla_host *ha = pci_get_drvdata(pdev);
5968
5969 if (!is_aer_supported(ha))
5970 return PCI_ERS_RESULT_NONE;
5971
Vikas Chaudhary7b3595d2010-10-06 22:50:56 -07005972 return PCI_ERS_RESULT_RECOVERED;
Lalit Chandivade2232be02010-07-30 14:38:47 +05305973}
5974
Vikas Chaudhary7b3595d2010-10-06 22:50:56 -07005975static uint32_t qla4_8xxx_error_recovery(struct scsi_qla_host *ha)
Lalit Chandivade2232be02010-07-30 14:38:47 +05305976{
5977 uint32_t rval = QLA_ERROR;
Vikas Chaudhary7b3595d2010-10-06 22:50:56 -07005978 uint32_t ret = 0;
Lalit Chandivade2232be02010-07-30 14:38:47 +05305979 int fn;
5980 struct pci_dev *other_pdev = NULL;
5981
5982 ql4_printk(KERN_WARNING, ha, "scsi%ld: In %s\n", ha->host_no, __func__);
5983
5984 set_bit(DPC_RESET_ACTIVE, &ha->dpc_flags);
5985
5986 if (test_bit(AF_ONLINE, &ha->flags)) {
5987 clear_bit(AF_ONLINE, &ha->flags);
Manish Rangankarb3a271a2011-07-25 13:48:53 -05005988 clear_bit(AF_LINK_UP, &ha->flags);
5989 iscsi_host_for_each_session(ha->host, qla4xxx_fail_session);
Lalit Chandivade2232be02010-07-30 14:38:47 +05305990 qla4xxx_process_aen(ha, FLUSH_DDB_CHANGED_AENS);
Lalit Chandivade2232be02010-07-30 14:38:47 +05305991 }
5992
5993 fn = PCI_FUNC(ha->pdev->devfn);
5994 while (fn > 0) {
5995 fn--;
5996 ql4_printk(KERN_INFO, ha, "scsi%ld: %s: Finding PCI device at "
5997 "func %x\n", ha->host_no, __func__, fn);
5998 /* Get the pci device given the domain, bus,
5999 * slot/function number */
6000 other_pdev =
6001 pci_get_domain_bus_and_slot(pci_domain_nr(ha->pdev->bus),
6002 ha->pdev->bus->number, PCI_DEVFN(PCI_SLOT(ha->pdev->devfn),
6003 fn));
6004
6005 if (!other_pdev)
6006 continue;
6007
6008 if (atomic_read(&other_pdev->enable_cnt)) {
6009 ql4_printk(KERN_INFO, ha, "scsi%ld: %s: Found PCI "
6010 "func in enabled state%x\n", ha->host_no,
6011 __func__, fn);
6012 pci_dev_put(other_pdev);
6013 break;
6014 }
6015 pci_dev_put(other_pdev);
6016 }
6017
6018 /* The first function on the card, the reset owner will
6019 * start & initialize the firmware. The other functions
6020 * on the card will reset the firmware context
6021 */
6022 if (!fn) {
6023 ql4_printk(KERN_INFO, ha, "scsi%ld: %s: devfn being reset "
6024 "0x%x is the owner\n", ha->host_no, __func__,
6025 ha->pdev->devfn);
6026
6027 qla4_8xxx_idc_lock(ha);
6028 qla4_8xxx_wr_32(ha, QLA82XX_CRB_DEV_STATE,
6029 QLA82XX_DEV_COLD);
6030
6031 qla4_8xxx_wr_32(ha, QLA82XX_CRB_DRV_IDC_VERSION,
6032 QLA82XX_IDC_VERSION);
6033
6034 qla4_8xxx_idc_unlock(ha);
6035 clear_bit(AF_FW_RECOVERY, &ha->flags);
Mike Christie13483732011-12-01 21:38:41 -06006036 rval = qla4xxx_initialize_adapter(ha, RESET_ADAPTER);
Lalit Chandivade2232be02010-07-30 14:38:47 +05306037 qla4_8xxx_idc_lock(ha);
6038
6039 if (rval != QLA_SUCCESS) {
6040 ql4_printk(KERN_INFO, ha, "scsi%ld: %s: HW State: "
6041 "FAILED\n", ha->host_no, __func__);
6042 qla4_8xxx_clear_drv_active(ha);
6043 qla4_8xxx_wr_32(ha, QLA82XX_CRB_DEV_STATE,
6044 QLA82XX_DEV_FAILED);
6045 } else {
6046 ql4_printk(KERN_INFO, ha, "scsi%ld: %s: HW State: "
6047 "READY\n", ha->host_no, __func__);
6048 qla4_8xxx_wr_32(ha, QLA82XX_CRB_DEV_STATE,
6049 QLA82XX_DEV_READY);
6050 /* Clear driver state register */
6051 qla4_8xxx_wr_32(ha, QLA82XX_CRB_DRV_STATE, 0);
6052 qla4_8xxx_set_drv_active(ha);
Vikas Chaudhary7b3595d2010-10-06 22:50:56 -07006053 ret = qla4xxx_request_irqs(ha);
6054 if (ret) {
6055 ql4_printk(KERN_WARNING, ha, "Failed to "
6056 "reserve interrupt %d already in use.\n",
6057 ha->pdev->irq);
6058 rval = QLA_ERROR;
6059 } else {
6060 ha->isp_ops->enable_intrs(ha);
6061 rval = QLA_SUCCESS;
6062 }
Lalit Chandivade2232be02010-07-30 14:38:47 +05306063 }
6064 qla4_8xxx_idc_unlock(ha);
6065 } else {
6066 ql4_printk(KERN_INFO, ha, "scsi%ld: %s: devfn 0x%x is not "
6067 "the reset owner\n", ha->host_no, __func__,
6068 ha->pdev->devfn);
6069 if ((qla4_8xxx_rd_32(ha, QLA82XX_CRB_DEV_STATE) ==
6070 QLA82XX_DEV_READY)) {
6071 clear_bit(AF_FW_RECOVERY, &ha->flags);
Mike Christie13483732011-12-01 21:38:41 -06006072 rval = qla4xxx_initialize_adapter(ha, RESET_ADAPTER);
Vikas Chaudhary7b3595d2010-10-06 22:50:56 -07006073 if (rval == QLA_SUCCESS) {
6074 ret = qla4xxx_request_irqs(ha);
6075 if (ret) {
6076 ql4_printk(KERN_WARNING, ha, "Failed to"
6077 " reserve interrupt %d already in"
6078 " use.\n", ha->pdev->irq);
6079 rval = QLA_ERROR;
6080 } else {
6081 ha->isp_ops->enable_intrs(ha);
6082 rval = QLA_SUCCESS;
6083 }
6084 }
Lalit Chandivade2232be02010-07-30 14:38:47 +05306085 qla4_8xxx_idc_lock(ha);
6086 qla4_8xxx_set_drv_active(ha);
6087 qla4_8xxx_idc_unlock(ha);
6088 }
6089 }
6090 clear_bit(DPC_RESET_ACTIVE, &ha->dpc_flags);
6091 return rval;
6092}
6093
6094static pci_ers_result_t
6095qla4xxx_pci_slot_reset(struct pci_dev *pdev)
6096{
6097 pci_ers_result_t ret = PCI_ERS_RESULT_DISCONNECT;
6098 struct scsi_qla_host *ha = pci_get_drvdata(pdev);
6099 int rc;
6100
6101 ql4_printk(KERN_WARNING, ha, "scsi%ld: %s: slot_reset\n",
6102 ha->host_no, __func__);
6103
6104 if (!is_aer_supported(ha))
6105 return PCI_ERS_RESULT_NONE;
6106
6107 /* Restore the saved state of PCIe device -
6108 * BAR registers, PCI Config space, PCIX, MSI,
6109 * IOV states
6110 */
6111 pci_restore_state(pdev);
6112
6113 /* pci_restore_state() clears the saved_state flag of the device
6114 * save restored state which resets saved_state flag
6115 */
6116 pci_save_state(pdev);
6117
6118 /* Initialize device or resume if in suspended state */
6119 rc = pci_enable_device(pdev);
6120 if (rc) {
Lucas De Marchi25985ed2011-03-30 22:57:33 -03006121 ql4_printk(KERN_WARNING, ha, "scsi%ld: %s: Can't re-enable "
Lalit Chandivade2232be02010-07-30 14:38:47 +05306122 "device after reset\n", ha->host_no, __func__);
6123 goto exit_slot_reset;
6124 }
6125
Vikas Chaudhary7b3595d2010-10-06 22:50:56 -07006126 ha->isp_ops->disable_intrs(ha);
Lalit Chandivade2232be02010-07-30 14:38:47 +05306127
6128 if (is_qla8022(ha)) {
6129 if (qla4_8xxx_error_recovery(ha) == QLA_SUCCESS) {
6130 ret = PCI_ERS_RESULT_RECOVERED;
6131 goto exit_slot_reset;
6132 } else
6133 goto exit_slot_reset;
6134 }
6135
6136exit_slot_reset:
6137 ql4_printk(KERN_WARNING, ha, "scsi%ld: %s: Return=%x\n"
6138 "device after reset\n", ha->host_no, __func__, ret);
6139 return ret;
6140}
6141
6142static void
6143qla4xxx_pci_resume(struct pci_dev *pdev)
6144{
6145 struct scsi_qla_host *ha = pci_get_drvdata(pdev);
6146 int ret;
6147
6148 ql4_printk(KERN_WARNING, ha, "scsi%ld: %s: pci_resume\n",
6149 ha->host_no, __func__);
6150
6151 ret = qla4xxx_wait_for_hba_online(ha);
6152 if (ret != QLA_SUCCESS) {
6153 ql4_printk(KERN_ERR, ha, "scsi%ld: %s: the device failed to "
6154 "resume I/O from slot/link_reset\n", ha->host_no,
6155 __func__);
6156 }
6157
6158 pci_cleanup_aer_uncorrect_error_status(pdev);
6159 clear_bit(AF_EEH_BUSY, &ha->flags);
6160}
6161
6162static struct pci_error_handlers qla4xxx_err_handler = {
6163 .error_detected = qla4xxx_pci_error_detected,
6164 .mmio_enabled = qla4xxx_pci_mmio_enabled,
6165 .slot_reset = qla4xxx_pci_slot_reset,
6166 .resume = qla4xxx_pci_resume,
6167};
6168
David Somayajuluafaf5a22006-09-19 10:28:00 -07006169static struct pci_device_id qla4xxx_pci_tbl[] = {
6170 {
6171 .vendor = PCI_VENDOR_ID_QLOGIC,
6172 .device = PCI_DEVICE_ID_QLOGIC_ISP4010,
6173 .subvendor = PCI_ANY_ID,
6174 .subdevice = PCI_ANY_ID,
6175 },
6176 {
6177 .vendor = PCI_VENDOR_ID_QLOGIC,
6178 .device = PCI_DEVICE_ID_QLOGIC_ISP4022,
6179 .subvendor = PCI_ANY_ID,
6180 .subdevice = PCI_ANY_ID,
6181 },
David C Somayajulud9150582006-11-15 17:38:40 -08006182 {
6183 .vendor = PCI_VENDOR_ID_QLOGIC,
6184 .device = PCI_DEVICE_ID_QLOGIC_ISP4032,
6185 .subvendor = PCI_ANY_ID,
6186 .subdevice = PCI_ANY_ID,
6187 },
Vikas Chaudharyf4f5df22010-07-28 15:53:44 +05306188 {
6189 .vendor = PCI_VENDOR_ID_QLOGIC,
6190 .device = PCI_DEVICE_ID_QLOGIC_ISP8022,
6191 .subvendor = PCI_ANY_ID,
6192 .subdevice = PCI_ANY_ID,
6193 },
David Somayajuluafaf5a22006-09-19 10:28:00 -07006194 {0, 0},
6195};
6196MODULE_DEVICE_TABLE(pci, qla4xxx_pci_tbl);
6197
Adrian Bunk47975472007-04-26 00:35:16 -07006198static struct pci_driver qla4xxx_pci_driver = {
David Somayajuluafaf5a22006-09-19 10:28:00 -07006199 .name = DRIVER_NAME,
6200 .id_table = qla4xxx_pci_tbl,
6201 .probe = qla4xxx_probe_adapter,
6202 .remove = qla4xxx_remove_adapter,
Lalit Chandivade2232be02010-07-30 14:38:47 +05306203 .err_handler = &qla4xxx_err_handler,
David Somayajuluafaf5a22006-09-19 10:28:00 -07006204};
6205
6206static int __init qla4xxx_module_init(void)
6207{
6208 int ret;
6209
6210 /* Allocate cache for SRBs. */
6211 srb_cachep = kmem_cache_create("qla4xxx_srbs", sizeof(struct srb), 0,
Paul Mundt20c2df82007-07-20 10:11:58 +09006212 SLAB_HWCACHE_ALIGN, NULL);
David Somayajuluafaf5a22006-09-19 10:28:00 -07006213 if (srb_cachep == NULL) {
6214 printk(KERN_ERR
6215 "%s: Unable to allocate SRB cache..."
6216 "Failing load!\n", DRIVER_NAME);
6217 ret = -ENOMEM;
6218 goto no_srp_cache;
6219 }
6220
6221 /* Derive version string. */
6222 strcpy(qla4xxx_version_str, QLA4XXX_DRIVER_VERSION);
Andrew Vasquez11010fe2006-10-06 09:54:59 -07006223 if (ql4xextended_error_logging)
David Somayajuluafaf5a22006-09-19 10:28:00 -07006224 strcat(qla4xxx_version_str, "-debug");
6225
6226 qla4xxx_scsi_transport =
6227 iscsi_register_transport(&qla4xxx_iscsi_transport);
6228 if (!qla4xxx_scsi_transport){
6229 ret = -ENODEV;
6230 goto release_srb_cache;
6231 }
6232
David Somayajuluafaf5a22006-09-19 10:28:00 -07006233 ret = pci_register_driver(&qla4xxx_pci_driver);
6234 if (ret)
6235 goto unregister_transport;
6236
6237 printk(KERN_INFO "QLogic iSCSI HBA Driver\n");
6238 return 0;
Doug Maxey5ae16db2006-10-05 23:50:07 -05006239
David Somayajuluafaf5a22006-09-19 10:28:00 -07006240unregister_transport:
6241 iscsi_unregister_transport(&qla4xxx_iscsi_transport);
6242release_srb_cache:
6243 kmem_cache_destroy(srb_cachep);
6244no_srp_cache:
6245 return ret;
6246}
6247
6248static void __exit qla4xxx_module_exit(void)
6249{
David Somayajuluafaf5a22006-09-19 10:28:00 -07006250 pci_unregister_driver(&qla4xxx_pci_driver);
6251 iscsi_unregister_transport(&qla4xxx_iscsi_transport);
6252 kmem_cache_destroy(srb_cachep);
6253}
6254
6255module_init(qla4xxx_module_init);
6256module_exit(qla4xxx_module_exit);
6257
6258MODULE_AUTHOR("QLogic Corporation");
6259MODULE_DESCRIPTION("QLogic iSCSI HBA Driver");
6260MODULE_LICENSE("GPL");
6261MODULE_VERSION(QLA4XXX_DRIVER_VERSION);